Skip to content

Commit e7d3fa3

Browse files
nicolincjgunthorpe
authored andcommitted
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. Link: https://patch.msgid.link/r/5cf6719682fdfdabffdb08374cdf31ad2466d75a.1741719725.git.nicolinc@nvidia.com Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Reviewed-by: Pranjal Shrivastava <[email protected]> Acked-by: Will Deacon <[email protected]> Signed-off-by: Nicolin Chen <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent f0ea207 commit e7d3fa3

File tree

4 files changed

+80
-25
lines changed

4 files changed

+80
-25
lines changed

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,4 +433,21 @@ struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,
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

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,8 +1813,8 @@ static void arm_smmu_decode_event(struct arm_smmu_device *smmu, u64 *raw,
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,
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,
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,
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)
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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,7 @@ int arm_smmu_attach_prepare_vmaster(struct arm_smmu_attach_state *state,
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
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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,9 +1054,32 @@ struct iommufd_vevent_header {
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
/**

0 commit comments

Comments
 (0)