History

iommu/arm-smmu-v3: Report events that belong to devices attached to vIOMMU

Aside from the IOPF framework, iommufd provides an additional pathway to report hardware events, via the vEVENTQ of vIOMMU infrastructure. Define an iommu_vevent_arm_smmuv3 uAPI structure, and report stage-1 events in the threaded IRQ handler. Also, add another four event record types that can be forwarded to a VM.

Nicolin Chen committed 1 year ago

Commit e7d3fa31 parent f0ea2074 files · +80 −25Browse files

Unified · Split

4 files
  1. drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +17 −0
  2. drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +33 −25
  3. drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +7 −0
  4. include/uapi/linux/iommufd.h +23 −0
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c+17−0
@@ -433,4 +433,21 @@ struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev, · 432 unmodified lines
433433 return &vsmmu->core;
434434 }
435435
436+int arm_vmaster_report_event(struct arm_smmu_vmaster *vmaster, u64 *evt)
437+{
438+ struct iommu_vevent_arm_smmuv3 vevt;
439+ int i;
440+
441+ lockdep_assert_held(&vmaster->vsmmu->smmu->streams_mutex);
442+
443+ vevt.evt[0] = cpu_to_le64((evt[0] & ~EVTQ_0_SID) |
444+ FIELD_PREP(EVTQ_0_SID, vmaster->vsid));
445+ for (i = 1; i < EVTQ_ENT_DWORDS; i++)
446+ vevt.evt[i] = cpu_to_le64(evt[i]);
447+
448+ return iommufd_viommu_report_event(&vmaster->vsmmu->core,
449+ IOMMU_VEVENTQ_TYPE_ARM_SMMUV3, &vevt,
450+ sizeof(vevt));
451+}
452+
436453 MODULE_IMPORT_NS("IOMMUFD");
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c+33−25
@@ -1813,8 +1813,8 @@ static void arm_smmu_decode_event(struct arm_smmu_device *smmu, u64 *raw, · 1812 unmodified lines
18131813 mutex_unlock(&smmu->streams_mutex);
18141814 }
18151815
1816−static int arm_smmu_handle_event(struct arm_smmu_device *smmu,
1817− struct arm_smmu_event *event)
1816+static int arm_smmu_handle_event(struct arm_smmu_device *smmu, u64 *evt,
1817+ struct arm_smmu_event *event)
18181818 {
18191819 int ret = 0;
18201820 u32 perm = 0;
@@ -1823,6 +1823,10 @@ static int arm_smmu_handle_event(struct arm_smmu_device *smmu, · 2 unmodified lines
18231823 struct iommu_fault *flt = &fault_evt.fault;
18241824
18251825 switch (event->id) {
1826+ case EVT_ID_BAD_STE_CONFIG:
1827+ case EVT_ID_STREAM_DISABLED_FAULT:
1828+ case EVT_ID_BAD_SUBSTREAMID_CONFIG:
1829+ case EVT_ID_BAD_CD_CONFIG:
18261830 case EVT_ID_TRANSLATION_FAULT:
18271831 case EVT_ID_ADDR_SIZE_FAULT:
18281832 case EVT_ID_ACCESS_FAULT:
@@ -1832,31 +1836,30 @@ static int arm_smmu_handle_event(struct arm_smmu_device *smmu, · 3 unmodified lines
18321836 return -EOPNOTSUPP;
18331837 }
18341838
1835− if (!event->stall)
1836− return -EOPNOTSUPP;
1837−
1838− if (event->read)
1839− perm |= IOMMU_FAULT_PERM_READ;
1840− else
1841− perm |= IOMMU_FAULT_PERM_WRITE;
1839+ if (event->stall) {
1840+ if (event->read)
1841+ perm |= IOMMU_FAULT_PERM_READ;
1842+ else
1843+ perm |= IOMMU_FAULT_PERM_WRITE;
18421844
1843− if (event->instruction)
1844− perm |= IOMMU_FAULT_PERM_EXEC;
1845+ if (event->instruction)
1846+ perm |= IOMMU_FAULT_PERM_EXEC;
18451847
1846− if (event->privileged)
1847− perm |= IOMMU_FAULT_PERM_PRIV;
1848+ if (event->privileged)
1849+ perm |= IOMMU_FAULT_PERM_PRIV;
18481850
1849− flt->type = IOMMU_FAULT_PAGE_REQ;
1850− flt->prm = (struct iommu_fault_page_request) {
1851− .flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE,
1852− .grpid = event->stag,
1853− .perm = perm,
1854− .addr = event->iova,
1855− };
1851+ flt->type = IOMMU_FAULT_PAGE_REQ;
1852+ flt->prm = (struct iommu_fault_page_request){
1853+ .flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE,
1854+ .grpid = event->stag,
1855+ .perm = perm,
1856+ .addr = event->iova,
1857+ };
18561858
1857− if (event->ssv) {
1858− flt->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
1859− flt->prm.pasid = event->ssid;
1859+ if (event->ssv) {
1860+ flt->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
1861+ flt->prm.pasid = event->ssid;
1862+ }
18601863 }
18611864
18621865 mutex_lock(&smmu->streams_mutex);
@@ -1866,7 +1869,12 @@ static int arm_smmu_handle_event(struct arm_smmu_device *smmu, · 3 unmodified lines
18661869 goto out_unlock;
18671870 }
18681871
1869− ret = iommu_report_device_fault(master->dev, &fault_evt);
1872+ if (event->stall)
1873+ ret = iommu_report_device_fault(master->dev, &fault_evt);
1874+ else if (master->vmaster && !event->s2)
1875+ ret = arm_vmaster_report_event(master->vmaster, evt);
1876+ else
1877+ ret = -EOPNOTSUPP; /* Unhandled events should be pinned */
18701878 out_unlock:
18711879 mutex_unlock(&smmu->streams_mutex);
18721880 return ret;
@@ -1944,7 +1952,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev) · 71 unmodified lines
19441952 do {
19451953 while (!queue_remove_raw(q, evt)) {
19461954 arm_smmu_decode_event(smmu, evt, &event);
1947− if (arm_smmu_handle_event(smmu, &event))
1955+ if (arm_smmu_handle_event(smmu, evt, &event))
19481956 arm_smmu_dump_event(smmu, evt, &event, &rs);
19491957
19501958 put_device(event.dev);
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h+7−0
@@ -1066,6 +1066,7 @@ int arm_smmu_attach_prepare_vmaster(struct arm_smmu_attach_state *state, · 1065 unmodified lines
10661066 struct arm_smmu_nested_domain *nested_domain);
10671067 void arm_smmu_attach_commit_vmaster(struct arm_smmu_attach_state *state);
10681068 void arm_smmu_master_clear_vmaster(struct arm_smmu_master *master);
1069+int arm_vmaster_report_event(struct arm_smmu_vmaster *vmaster, u64 *evt);
10691070 #else
10701071 #define arm_smmu_hw_info NULL
10711072 #define arm_vsmmu_alloc NULL
@@ -1086,6 +1087,12 @@ static inline void · 14 unmodified lines
10861087 arm_smmu_master_clear_vmaster(struct arm_smmu_master *master)
10871088 {
10881089 }
1090+
1091+static inline int arm_vmaster_report_event(struct arm_smmu_vmaster *vmaster,
1092+ u64 *evt)
1093+{
1094+ return -EOPNOTSUPP;
1095+}
10891096 #endif /* CONFIG_ARM_SMMU_V3_IOMMUFD */
10901097
10911098 #endif /* _ARM_SMMU_V3_H */
include/uapi/linux/iommufd.h+23−0
@@ -1054,9 +1054,32 @@ struct iommufd_vevent_header { · 1053 unmodified lines
10541054 /**
10551055 * enum iommu_veventq_type - Virtual Event Queue Type
10561056 * @IOMMU_VEVENTQ_TYPE_DEFAULT: Reserved for future use
1057+ * @IOMMU_VEVENTQ_TYPE_ARM_SMMUV3: ARM SMMUv3 Virtual Event Queue
10571058 */
10581059 enum iommu_veventq_type {
10591060 IOMMU_VEVENTQ_TYPE_DEFAULT = 0,
1061+ IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 = 1,
1062+};
1063+
1064+/**
1065+ * struct iommu_vevent_arm_smmuv3 - ARM SMMUv3 Virtual Event
1066+ * (IOMMU_VEVENTQ_TYPE_ARM_SMMUV3)
1067+ * @evt: 256-bit ARM SMMUv3 Event record, little-endian.
1068+ * Reported event records: (Refer to "7.3 Event records" in SMMUv3 HW Spec)
1069+ * - 0x04 C_BAD_STE
1070+ * - 0x06 F_STREAM_DISABLED
1071+ * - 0x08 C_BAD_SUBSTREAMID
1072+ * - 0x0a C_BAD_CD
1073+ * - 0x10 F_TRANSLATION
1074+ * - 0x11 F_ADDR_SIZE
1075+ * - 0x12 F_ACCESS
1076+ * - 0x13 F_PERMISSION
1077+ *
1078+ * StreamID field reports a virtual device ID. To receive a virtual event for a
1079+ * device, a vDEVICE must be allocated via IOMMU_VDEVICE_ALLOC.
1080+ */
1081+struct iommu_vevent_arm_smmuv3 {
1082+ __aligned_le64 evt[4];
10601083 };
10611084
10621085 /**