[PATCH v5 10/15] iommu/arm-smmu-v3: Support PRI Page Request in arm_smmu_handle_ppr()
From: Nicolin Chen <hidden>
Date: 2026-09-15 16:39:27
Also in:
linux-iommu, linux-pci, lkml
Subsystem:
arm smmu drivers, iommu subsystem, the rest · Maintainers:
Will Deacon, Joerg Roedel, Linus Torvalds
For a PRI-enabled master, convert every PRIQ entry into an iopf_fault and report it through iommu_report_device_fault(). For an unknown StreamID or a master without PRI enabled, keep the existing LAST-page DENY path. Merge its two messages into one ratelimited line so a faulty device cannot flood the kernel log. Discard any PASID Stop Marker (LRW = 0b100) prior to the fault report and the DENY fallback both, because a Stop Marker does not expect a response. The IOPF infrastructure requires the driver to discard it, as per the doc at iommu_report_device_fault(). This also matches the intel-iommu code. When SSV is clear, the same LRW encoding is a PRI Page Request that expects a response, so let it fall through. Note that master->pri_enabled will only be set by a later change, once all the PRI paths are ready. Co-developed-by: Barak Biber <redacted> Signed-off-by: Barak Biber <redacted> Co-developed-by: Stefan Kaestle <redacted> Signed-off-by: Stefan Kaestle <redacted> Signed-off-by: Malak Marrid <redacted> Signed-off-by: Nicolin Chen <redacted> --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 50 +++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 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 40ea5bd382d89..17ca3fcd1b9c0 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c@@ -2378,6 +2378,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev) static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt) { + struct arm_smmu_master *master; u32 sid, ssid; u16 grpid; bool ssv, last;
@@ -2388,9 +2389,52 @@ static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt) last = FIELD_GET(PRIQ_0_PRG_LAST, evt[0]); grpid = FIELD_GET(PRIQ_1_PRG_IDX, evt[1]); - dev_info(smmu->dev, "unexpected PRI request received:\n"); - dev_info(smmu->dev, - "\tsid 0x%08x.0x%05x: [%u%s] %sprivileged %s%s%s access at iova 0x%016llx\n", + /* + * A PASID Stop Marker (LRW = 0b100) does not expect a response and + * must be discarded before fault reporting: see the documentation + * at iommu_report_device_fault(). + * + * Gate it on SSV, as without a PASID that same encoding is a PRI Page + * Request and it does expect a response. So let it fall through and be + * answered with a PRI_RESP_FAIL, since iommu_sva_handle_mm() rejects a + * PASID-less fault, or by the PRI_RESP_DENY issued below. + */ + if (last && ssv && !(evt[0] & (PRIQ_0_PERM_READ | PRIQ_0_PERM_WRITE))) + return; + + mutex_lock(&smmu->streams_mutex); + master = arm_smmu_find_master(smmu, sid); + if (master && master->pri_enabled) { + struct iopf_fault iopf_fault = {}; + struct iommu_fault *fault = &iopf_fault.fault; + + fault->type = IOMMU_FAULT_PAGE_REQ; + if (last) + fault->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE; + if (ssv) { + fault->prm.flags |= + IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; + fault->prm.pasid = ssid; + } + fault->prm.grpid = grpid; + if (evt[0] & PRIQ_0_PERM_READ) + fault->prm.perm |= IOMMU_FAULT_PERM_READ; + if (evt[0] & PRIQ_0_PERM_WRITE) + fault->prm.perm |= IOMMU_FAULT_PERM_WRITE; + if (evt[0] & PRIQ_0_PERM_EXEC) + fault->prm.perm |= IOMMU_FAULT_PERM_EXEC; + if (evt[0] & PRIQ_0_PERM_PRIV) + fault->prm.perm |= IOMMU_FAULT_PERM_PRIV; + fault->prm.addr = FIELD_GET(PRIQ_1_ADDR_MASK, evt[1]) << 12; + + iommu_report_device_fault(master->dev, &iopf_fault); + mutex_unlock(&smmu->streams_mutex); + return; + } + mutex_unlock(&smmu->streams_mutex); + + dev_info_ratelimited(smmu->dev, + "unexpected PRI request: sid 0x%08x.0x%05x: [%u%s] %sprivileged %s%s%s access at iova 0x%016llx\n", sid, ssid, grpid, last ? "L" : "", evt[0] & PRIQ_0_PERM_PRIV ? "" : "un", evt[0] & PRIQ_0_PERM_READ ? "R" : "",
--
2.43.0