mirror of
https://github.com/torvalds/linux.git
synced 2026-10-08 11:36:02 +02:00
iommu/tegra241-cmdqv: Don't run the error ISR before probe sets up vintfs
__tegra241_cmdqv_probe() requests the error IRQ before it has allocated the
cmdqv->vintfs array and set cmdqv->num_vintfs. A CMDQV left enabled with a
latched error across a kexec fires the IRQ as soon as it is requested, and
tegra241_cmdqv_isr() then walks the uninitialized cmdqv->vintfs array.
Request the IRQ only after cmdqv->vintfs is allocated and zeroed, so that
a latched interrupt firing early runs the ISR against a valid array of NULL
slots that it safely skips.
Fixes: 918eb5c856 ("iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
a2ee315db4
commit
5acd67ceb3
|
|
@ -983,17 +983,6 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
|
|||
cmdqv->dev = smmu->impl_dev;
|
||||
cmdqv->base_phys = res->start;
|
||||
|
||||
if (cmdqv->irq > 0) {
|
||||
ret = request_threaded_irq(irq, NULL, tegra241_cmdqv_isr,
|
||||
IRQF_ONESHOT, "tegra241-cmdqv",
|
||||
cmdqv);
|
||||
if (ret) {
|
||||
dev_err(cmdqv->dev, "failed to request irq (%d): %d\n",
|
||||
cmdqv->irq, ret);
|
||||
goto iounmap;
|
||||
}
|
||||
}
|
||||
|
||||
regval = readl_relaxed(REG_CMDQV(cmdqv, PARAM));
|
||||
cmdqv->num_vintfs = 1 << FIELD_GET(CMDQV_NUM_VINTF_LOG2, regval);
|
||||
cmdqv->num_vcmdqs = 1 << FIELD_GET(CMDQV_NUM_VCMDQ_LOG2, regval);
|
||||
|
|
@ -1004,10 +993,25 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
|
|||
cmdqv->vintfs =
|
||||
kzalloc_objs(*cmdqv->vintfs, cmdqv->num_vintfs);
|
||||
if (!cmdqv->vintfs)
|
||||
goto free_irq;
|
||||
goto iounmap;
|
||||
|
||||
ida_init(&cmdqv->vintf_ids);
|
||||
|
||||
/*
|
||||
* Request the IRQ only after cmdqv->vintfs is allocated and zeroed, so
|
||||
* the ISR would not walk an uninitialized array.
|
||||
*/
|
||||
if (cmdqv->irq > 0) {
|
||||
ret = request_threaded_irq(irq, NULL, tegra241_cmdqv_isr,
|
||||
IRQF_ONESHOT, "tegra241-cmdqv",
|
||||
cmdqv);
|
||||
if (ret) {
|
||||
dev_err(cmdqv->dev, "failed to request irq (%d): %d\n",
|
||||
cmdqv->irq, ret);
|
||||
goto free_vintfs;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IOMMU_DEBUGFS
|
||||
if (!cmdqv_debugfs_dir) {
|
||||
cmdqv_debugfs_dir =
|
||||
|
|
@ -1022,9 +1026,9 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
|
|||
|
||||
return new_smmu;
|
||||
|
||||
free_irq:
|
||||
if (cmdqv->irq > 0)
|
||||
free_irq(cmdqv->irq, cmdqv);
|
||||
free_vintfs:
|
||||
ida_destroy(&cmdqv->vintf_ids);
|
||||
kfree(cmdqv->vintfs);
|
||||
iounmap:
|
||||
iounmap(base);
|
||||
return NULL;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user