[PATCH RFTv1 3/3] iommu/arm-smmu-v3: Support PRI Page Request

From: Nicolin Chen

Date: Tue Mar 03 2026 - 15:14:43 EST


From: Malak Marrid <mmarrid@xxxxxxxxxx>

Now, arm_smmu_page_response() can issue CMDQ_OP_PRI_RESP for page requests
from the IOPF infrastructure. Decode the page requests from the PRI queue,
and report it to the IOPF infrastructure.

This fills the final piece for PRI support.

Co-developed-by: Barak Biber <bbiber@xxxxxxxxxx>
Signed-off-by: Barak Biber <bbiber@xxxxxxxxxx>
Co-developed-by: Stefan Kaestle <skaestle@xxxxxxxxxx>
Signed-off-by: Stefan Kaestle <skaestle@xxxxxxxxxx>
Signed-off-by: Malak Marrid <mmarrid@xxxxxxxxxx>
Signed-off-by: Nicolin Chen <nicolinc@xxxxxxxxxx>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 65 +++++++++++----------
1 file changed, 33 insertions(+), 32 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 055dde5367131..277d753c7675c 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2061,40 +2061,41 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)

static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
{
- u32 sid, ssid;
- u16 grpid;
- bool ssv, last;
-
- sid = FIELD_GET(PRIQ_0_SID, evt[0]);
- ssv = FIELD_GET(PRIQ_0_SSID_V, evt[0]);
- ssid = ssv ? FIELD_GET(PRIQ_0_SSID, evt[0]) : IOMMU_NO_PASID;
- 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",
- sid, ssid, grpid, last ? "L" : "",
- evt[0] & PRIQ_0_PERM_PRIV ? "" : "un",
- evt[0] & PRIQ_0_PERM_READ ? "R" : "",
- evt[0] & PRIQ_0_PERM_WRITE ? "W" : "",
- evt[0] & PRIQ_0_PERM_EXEC ? "X" : "",
- evt[1] & PRIQ_1_ADDR_MASK);
-
- if (last) {
- struct arm_smmu_cmdq_ent cmd = {
- .opcode = CMDQ_OP_PRI_RESP,
- .substream_valid = ssv,
- .pri = {
- .sid = sid,
- .ssid = ssid,
- .grpid = grpid,
- .resp = PRI_RESP_DENY,
- },
- };
+ u32 sid = FIELD_GET(PRIQ_0_SID, evt[0]);
+ struct iopf_fault iopf_fault = {0};
+ struct iommu_fault *fault = &iopf_fault.fault;
+ struct arm_smmu_master *master;
+
+ INIT_LIST_HEAD(&iopf_fault.list);

- arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+ fault->type = IOMMU_FAULT_PAGE_REQ;
+
+ if (FIELD_GET(PRIQ_0_PRG_LAST, evt[0]))
+ fault->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
+ if (FIELD_GET(PRIQ_0_SSID_V, evt[0])) {
+ fault->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
+ fault->prm.pasid = FIELD_GET(PRIQ_0_SSID, evt[0]);
}
+
+ fault->prm.grpid = FIELD_GET(PRIQ_1_PRG_IDX, evt[1]);
+
+ 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;
+
+ guard(mutex)(&smmu->streams_mutex);
+ master = arm_smmu_find_master(smmu, sid);
+ if (master)
+ iommu_report_device_fault(master->dev, &iopf_fault);
+ else
+ dev_warn(smmu->dev, "PPR: unrecognized StreamID 0x%x\n", sid);
}

static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
--
2.43.0