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.
Unified · Split
| @@ -433,4 +433,21 @@ struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev, · 432 unmodified lines | |||
| 433 | return &vsmmu->core; | 433 | return &vsmmu->core; |
| 434 | } | 434 | } |
| 435 | 435 | ||
| 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 | |||
| 436 | MODULE_IMPORT_NS("IOMMUFD"); | 453 | MODULE_IMPORT_NS("IOMMUFD"); |
| @@ -1813,8 +1813,8 @@ static void arm_smmu_decode_event(struct arm_smmu_device *smmu, u64 *raw, · 1812 unmodified lines | |||
| 1813 | mutex_unlock(&smmu->streams_mutex); | 1813 | mutex_unlock(&smmu->streams_mutex); |
| 1814 | } | 1814 | } |
| 1815 | 1815 | ||
| 1816 | static int arm_smmu_handle_event(struct arm_smmu_device *smmu, | 1816 | static int arm_smmu_handle_event(struct arm_smmu_device *smmu, u64 *evt, |
| 1817 | struct arm_smmu_event *event) | 1817 | struct arm_smmu_event *event) |
| 1818 | { | 1818 | { |
| 1819 | int ret = 0; | 1819 | int ret = 0; |
| 1820 | u32 perm = 0; | 1820 | u32 perm = 0; |
| @@ -1823,6 +1823,10 @@ static int arm_smmu_handle_event(struct arm_smmu_device *smmu, · 2 unmodified lines | |||
| 1823 | struct iommu_fault *flt = &fault_evt.fault; | 1823 | struct iommu_fault *flt = &fault_evt.fault; |
| 1824 | 1824 | ||
| 1825 | switch (event->id) { | 1825 | 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: | ||
| 1826 | case EVT_ID_TRANSLATION_FAULT: | 1830 | case EVT_ID_TRANSLATION_FAULT: |
| 1827 | case EVT_ID_ADDR_SIZE_FAULT: | 1831 | case EVT_ID_ADDR_SIZE_FAULT: |
| 1828 | case EVT_ID_ACCESS_FAULT: | 1832 | case EVT_ID_ACCESS_FAULT: |
| @@ -1832,31 +1836,30 @@ static int arm_smmu_handle_event(struct arm_smmu_device *smmu, · 3 unmodified lines | |||
| 1832 | return -EOPNOTSUPP; | 1836 | return -EOPNOTSUPP; |
| 1833 | } | 1837 | } |
| 1834 | 1838 | ||
| 1835 | if (!event->stall) | 1839 | if (event->stall) { |
| 1836 | return -EOPNOTSUPP; | 1840 | if (event->read) |
| 1837 | 1841 | perm |= IOMMU_FAULT_PERM_READ; | |
| 1838 | if (event->read) | 1842 | else |
| 1839 | perm |= IOMMU_FAULT_PERM_READ; | 1843 | perm |= IOMMU_FAULT_PERM_WRITE; |
| 1840 | else | ||
| 1841 | perm |= IOMMU_FAULT_PERM_WRITE; | ||
| 1842 | 1844 | ||
| 1843 | if (event->instruction) | 1845 | if (event->instruction) |
| 1844 | perm |= IOMMU_FAULT_PERM_EXEC; | 1846 | perm |= IOMMU_FAULT_PERM_EXEC; |
| 1845 | 1847 | ||
| 1846 | if (event->privileged) | 1848 | if (event->privileged) |
| 1847 | perm |= IOMMU_FAULT_PERM_PRIV; | 1849 | perm |= IOMMU_FAULT_PERM_PRIV; |
| 1848 | 1850 | ||
| 1849 | flt->type = IOMMU_FAULT_PAGE_REQ; | 1851 | flt->type = IOMMU_FAULT_PAGE_REQ; |
| 1850 | flt->prm = (struct iommu_fault_page_request) { | 1852 | flt->prm = (struct iommu_fault_page_request){ |
| 1851 | .flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE, | 1853 | .flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE, |
| 1852 | .grpid = event->stag, | 1854 | .grpid = event->stag, |
| 1853 | .perm = perm, | 1855 | .perm = perm, |
| 1854 | .addr = event->iova, | 1856 | .addr = event->iova, |
| 1855 | }; | 1857 | }; |
| 1856 | 1858 | ||
| 1857 | if (event->ssv) { | 1859 | if (event->ssv) { |
| 1858 | flt->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; | 1860 | flt->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; |
| 1859 | flt->prm.pasid = event->ssid; | 1861 | flt->prm.pasid = event->ssid; |
| 1862 | } | ||
| 1860 | } | 1863 | } |
| 1861 | 1864 | ||
| 1862 | mutex_lock(&smmu->streams_mutex); | 1865 | mutex_lock(&smmu->streams_mutex); |
| @@ -1866,7 +1869,12 @@ static int arm_smmu_handle_event(struct arm_smmu_device *smmu, · 3 unmodified lines | |||
| 1866 | goto out_unlock; | 1869 | goto out_unlock; |
| 1867 | } | 1870 | } |
| 1868 | 1871 | ||
| 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 */ | ||
| 1870 | out_unlock: | 1878 | out_unlock: |
| 1871 | mutex_unlock(&smmu->streams_mutex); | 1879 | mutex_unlock(&smmu->streams_mutex); |
| 1872 | return ret; | 1880 | return ret; |
| @@ -1944,7 +1952,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev) · 71 unmodified lines | |||
| 1944 | do { | 1952 | do { |
| 1945 | while (!queue_remove_raw(q, evt)) { | 1953 | while (!queue_remove_raw(q, evt)) { |
| 1946 | arm_smmu_decode_event(smmu, evt, &event); | 1954 | arm_smmu_decode_event(smmu, evt, &event); |
| 1947 | if (arm_smmu_handle_event(smmu, &event)) | 1955 | if (arm_smmu_handle_event(smmu, evt, &event)) |
| 1948 | arm_smmu_dump_event(smmu, evt, &event, &rs); | 1956 | arm_smmu_dump_event(smmu, evt, &event, &rs); |
| 1949 | 1957 | ||
| 1950 | put_device(event.dev); | 1958 | put_device(event.dev); |
| @@ -1066,6 +1066,7 @@ int arm_smmu_attach_prepare_vmaster(struct arm_smmu_attach_state *state, · 1065 unmodified lines | |||
| 1066 | struct arm_smmu_nested_domain *nested_domain); | 1066 | struct arm_smmu_nested_domain *nested_domain); |
| 1067 | void arm_smmu_attach_commit_vmaster(struct arm_smmu_attach_state *state); | 1067 | void arm_smmu_attach_commit_vmaster(struct arm_smmu_attach_state *state); |
| 1068 | void arm_smmu_master_clear_vmaster(struct arm_smmu_master *master); | 1068 | void arm_smmu_master_clear_vmaster(struct arm_smmu_master *master); |
| 1069 | int arm_vmaster_report_event(struct arm_smmu_vmaster *vmaster, u64 *evt); | ||
| 1069 | #else | 1070 | #else |
| 1070 | #define arm_smmu_hw_info NULL | 1071 | #define arm_smmu_hw_info NULL |
| 1071 | #define arm_vsmmu_alloc NULL | 1072 | #define arm_vsmmu_alloc NULL |
| @@ -1086,6 +1087,12 @@ static inline void · 14 unmodified lines | |||
| 1086 | arm_smmu_master_clear_vmaster(struct arm_smmu_master *master) | 1087 | arm_smmu_master_clear_vmaster(struct arm_smmu_master *master) |
| 1087 | { | 1088 | { |
| 1088 | } | 1089 | } |
| 1090 | |||
| 1091 | static inline int arm_vmaster_report_event(struct arm_smmu_vmaster *vmaster, | ||
| 1092 | u64 *evt) | ||
| 1093 | { | ||
| 1094 | return -EOPNOTSUPP; | ||
| 1095 | } | ||
| 1089 | #endif /* CONFIG_ARM_SMMU_V3_IOMMUFD */ | 1096 | #endif /* CONFIG_ARM_SMMU_V3_IOMMUFD */ |
| 1090 | 1097 | ||
| 1091 | #endif /* _ARM_SMMU_V3_H */ | 1098 | #endif /* _ARM_SMMU_V3_H */ |
| @@ -1054,9 +1054,32 @@ struct iommufd_vevent_header { · 1053 unmodified lines | |||
| 1054 | /** | 1054 | /** |
| 1055 | * enum iommu_veventq_type - Virtual Event Queue Type | 1055 | * enum iommu_veventq_type - Virtual Event Queue Type |
| 1056 | * @IOMMU_VEVENTQ_TYPE_DEFAULT: Reserved for future use | 1056 | * @IOMMU_VEVENTQ_TYPE_DEFAULT: Reserved for future use |
| 1057 | * @IOMMU_VEVENTQ_TYPE_ARM_SMMUV3: ARM SMMUv3 Virtual Event Queue | ||
| 1057 | */ | 1058 | */ |
| 1058 | enum iommu_veventq_type { | 1059 | enum iommu_veventq_type { |
| 1059 | IOMMU_VEVENTQ_TYPE_DEFAULT = 0, | 1060 | 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]; | ||
| 1060 | }; | 1083 | }; |
| 1061 | 1084 | ||
| 1062 | /** | 1085 | /** |