RE: [PATCH v2 13/13] iommu/arm-smmu-v3: Report IRQs that belong to devices attached to vIOMMU
From: "Tian, Kevin" <kevin.tian@intel.com>
Date: 2024-12-11 08:22:20
Also in:
linux-doc, linux-iommu, linux-kselftest, lkml
From: Nicolin Chen <redacted> Sent: Wednesday, December 4, 2024 6:10 AM + +/** + * struct iommu_virq_arm_smmuv3 - ARM SMMUv3 Virtual IRQ + * (IOMMU_VIRQ_TYPE_ARM_SMMUV3) + * @evt: 256-bit ARM SMMUv3 Event record, little-endian. + * + * StreamID field reports a virtual device ID. To receive a virtual IRQ for a + * device, a vDEVICE must be allocated via IOMMU_VDEVICE_ALLOC. + */
similar to what's provided for iommu_hw_info_arm_smmuv3, it'd be good to refer to a section in smmu spec for bit definitions.
quoted hunk ↗ jump to hunk
@@ -1779,33 +1779,6 @@ static int arm_smmu_handle_evt(structarm_smmu_device *smmu, u64 *evt) return -EOPNOTSUPP; } - if (!(evt[1] & EVTQ_1_STALL)) - return -EOPNOTSUPP; - - if (evt[1] & EVTQ_1_RnW) - perm |= IOMMU_FAULT_PERM_READ; - else - perm |= IOMMU_FAULT_PERM_WRITE; - - if (evt[1] & EVTQ_1_InD) - perm |= IOMMU_FAULT_PERM_EXEC; - - if (evt[1] & EVTQ_1_PnU) - perm |= IOMMU_FAULT_PERM_PRIV; - - flt->type = IOMMU_FAULT_PAGE_REQ; - flt->prm = (struct iommu_fault_page_request) { - .flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE, - .grpid = FIELD_GET(EVTQ_1_STAG, evt[1]), - .perm = perm, - .addr = FIELD_GET(EVTQ_2_ADDR, evt[2]), - }; - - if (ssid_valid) { - flt->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; - flt->prm.pasid = FIELD_GET(EVTQ_0_SSID, evt[0]); - } - mutex_lock(&smmu->streams_mutex); master = arm_smmu_find_master(smmu, sid); if (!master) {@@ -1813,7 +1786,40 @@ static int arm_smmu_handle_evt(structarm_smmu_device *smmu, u64 *evt) goto out_unlock; } - ret = iommu_report_device_fault(master->dev, &fault_evt); + down_read(&master->vmaster_rwsem);
this lock is not required if event is EVTQ_1_STALL?
+ if (evt[1] & EVTQ_1_STALL) {
+ if (evt[1] & EVTQ_1_RnW)
+ perm |= IOMMU_FAULT_PERM_READ;
+ else
+ perm |= IOMMU_FAULT_PERM_WRITE;
+
+ if (evt[1] & EVTQ_1_InD)
+ perm |= IOMMU_FAULT_PERM_EXEC;
+
+ if (evt[1] & EVTQ_1_PnU)
+ perm |= IOMMU_FAULT_PERM_PRIV;
+
+ flt->type = IOMMU_FAULT_PAGE_REQ;
+ flt->prm = (struct iommu_fault_page_request){
+ .flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE,
+ .grpid = FIELD_GET(EVTQ_1_STAG, evt[1]),
+ .perm = perm,
+ .addr = FIELD_GET(EVTQ_2_ADDR, evt[2]),
+ };
+
+ if (ssid_valid) {
+ flt->prm.flags |=
IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
+ flt->prm.pasid = FIELD_GET(EVTQ_0_SSID, evt[0]);
+ }
+
+ ret = iommu_report_device_fault(master->dev, &fault_evt);
+ } else if (master->vmaster && !(evt[1] & EVTQ_1_S2)) {
+ ret = arm_vmaster_report_event(master->vmaster, evt);
+ } else {
+ /* Unhandled events should be pinned */
+ ret = -EFAULT;
+ }
+ up_read(&master->vmaster_rwsem);
out_unlock:
mutex_unlock(&smmu->streams_mutex);
return ret;
--
2.43.0