[PATCH v2 07/11] iommu/arm-smmu-v3: Disable PRI when no IRQ handler is registered

From: Nicolin Chen

Date: Thu May 28 2026 - 04:10:47 EST


arm_smmu_setup_irqs() has three failure paths that leave the priq without
a handler: a missing priq IRQ line, devm_request_threaded_irq() failure on
the priq IRQ, and devm_request_threaded_irq() failure on the combined IRQ.
Each path warned but kept ARM_SMMU_FEAT_PRI set in smmu->features.

With FEAT_PRI still set, arm_smmu_probe_device() calls pci_enable_pri() on
PCIe endpoints, which then issue PRI Page Requests that pile up in a priq
with no drainer; arm_smmu_setup_irqs() also enables IRQ_CTRL_PRIQ_IRQEN
against a handler that does not exist. Separately, arm_smmu_device_reset()
has already enabled CR0_PRIQEN before calling arm_smmu_setup_irqs(), so
the hardware queue stays enabled regardless of what setup_irqs decides.

Clear ARM_SMMU_FEAT_PRI from all three failure paths so subsequent code
treats PRI as unavailable. And disable CR0_PRIQEN after the setup function
returns.

Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Nicolin Chen <nicolinc@xxxxxxxxxx>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 371a8bbdf6756..72fd5caa27368 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4738,11 +4738,14 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
IRQF_ONESHOT,
"arm-smmu-v3-priq",
smmu);
- if (ret < 0)
+ if (ret < 0) {
dev_warn(smmu->dev,
"failed to enable priq irq\n");
+ smmu->features &= ~ARM_SMMU_FEAT_PRI;
+ }
} else {
dev_warn(smmu->dev, "no priq irq - PRI will be broken\n");
+ smmu->features &= ~ARM_SMMU_FEAT_PRI;
}
}
}
@@ -4771,8 +4774,10 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
arm_smmu_combined_irq_thread,
IRQF_ONESHOT,
"arm-smmu-v3-combined-irq", smmu);
- if (ret < 0)
+ if (ret < 0) {
dev_warn(smmu->dev, "failed to enable combined irq\n");
+ smmu->features &= ~ARM_SMMU_FEAT_PRI;
+ }
} else
arm_smmu_setup_unique_irqs(smmu);

@@ -4931,6 +4936,10 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
return ret;
}

+ /* arm_smmu_setup_irqs() might have unset the ARM_SMMU_FEAT_PRI */
+ if (!(smmu->features & ARM_SMMU_FEAT_PRI))
+ enables &= ~CR0_PRIQEN;
+
if (is_kdump_kernel())
enables &= ~(CR0_EVTQEN | CR0_PRIQEN);

--
2.43.0