]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommu/arm-smmu-v3: Introduce struct arm_smmu_event
authorPranjal Shrivastava <praan@google.com>
Tue, 3 Dec 2024 18:49:05 +0000 (18:49 +0000)
committerWill Deacon <will@kernel.org>
Mon, 9 Dec 2024 21:43:43 +0000 (21:43 +0000)
Introduce `struct arm_smmu_event` to represent event records.
Parse out relevant fields from raw event records for ease and
use the new `struct arm_smmu_event` instead.

Signed-off-by: Pranjal Shrivastava <praan@google.com>
Link: https://lore.kernel.org/r/20241203184906.2264528-2-praan@google.com
Signed-off-by: Will Deacon <will@kernel.org>
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h

index a5c7002ff75bb0ce377e60faa29ae1c6d01fb18e..9fcba8fab9e3a236c3438ac235efc2e69df17fe0 100644 (file)
@@ -1759,17 +1759,34 @@ arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
 }
 
 /* IRQ and event handlers */
-static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
+static void arm_smmu_decode_event(u64 *raw, struct arm_smmu_event *event)
+{
+       event->id = FIELD_GET(EVTQ_0_ID, raw[0]);
+       event->sid = FIELD_GET(EVTQ_0_SID, raw[0]);
+       event->ssv = FIELD_GET(EVTQ_0_SSV, raw[0]);
+       event->ssid = event->ssv ? FIELD_GET(EVTQ_0_SSID, raw[0]) : IOMMU_NO_PASID;
+       event->privileged = FIELD_GET(EVTQ_1_PnU, raw[1]);
+       event->instruction = FIELD_GET(EVTQ_1_InD, raw[1]);
+       event->s2 = FIELD_GET(EVTQ_1_S2, raw[1]);
+       event->read = FIELD_GET(EVTQ_1_RnW, raw[1]);
+       event->stag = FIELD_GET(EVTQ_1_STAG, raw[1]);
+       event->stall = FIELD_GET(EVTQ_1_STALL, raw[1]);
+       event->class = FIELD_GET(EVTQ_1_CLASS, raw[1]);
+       event->iova = FIELD_GET(EVTQ_2_ADDR, raw[2]);
+       event->ipa = raw[3] & EVTQ_3_IPA;
+       event->fetch_addr = raw[3] & EVTQ_3_FETCH_ADDR;
+}
+
+static int arm_smmu_handle_evt(struct arm_smmu_device *smmu,
+                              struct arm_smmu_event *event)
 {
        int ret = 0;
        u32 perm = 0;
        struct arm_smmu_master *master;
-       bool ssid_valid = evt[0] & EVTQ_0_SSV;
-       u32 sid = FIELD_GET(EVTQ_0_SID, evt[0]);
        struct iopf_fault fault_evt = { };
        struct iommu_fault *flt = &fault_evt.fault;
 
-       switch (FIELD_GET(EVTQ_0_ID, evt[0])) {
+       switch (event->id) {
        case EVT_ID_TRANSLATION_FAULT:
        case EVT_ID_ADDR_SIZE_FAULT:
        case EVT_ID_ACCESS_FAULT:
@@ -1779,35 +1796,35 @@ static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
                return -EOPNOTSUPP;
        }
 
-       if (!(evt[1] & EVTQ_1_STALL))
+       if (!event->stall)
                return -EOPNOTSUPP;
 
-       if (evt[1] & EVTQ_1_RnW)
+       if (event->read)
                perm |= IOMMU_FAULT_PERM_READ;
        else
                perm |= IOMMU_FAULT_PERM_WRITE;
 
-       if (evt[1] & EVTQ_1_InD)
+       if (event->instruction)
                perm |= IOMMU_FAULT_PERM_EXEC;
 
-       if (evt[1] & EVTQ_1_PnU)
+       if (event->privileged)
                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]),
+               .grpid = event->stag,
                .perm = perm,
-               .addr = FIELD_GET(EVTQ_2_ADDR, evt[2]),
+               .addr = event->iova,
        };
 
-       if (ssid_valid) {
+       if (event->ssv) {
                flt->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
-               flt->prm.pasid = FIELD_GET(EVTQ_0_SSID, evt[0]);
+               flt->prm.pasid = event->ssid;
        }
 
        mutex_lock(&smmu->streams_mutex);
-       master = arm_smmu_find_master(smmu, sid);
+       master = arm_smmu_find_master(smmu, event->sid);
        if (!master) {
                ret = -EINVAL;
                goto out_unlock;
@@ -1822,23 +1839,23 @@ out_unlock:
 static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 {
        int i, ret;
+       u64 evt[EVTQ_ENT_DWORDS];
+       struct arm_smmu_event event = {0};
        struct arm_smmu_device *smmu = dev;
        struct arm_smmu_queue *q = &smmu->evtq.q;
        struct arm_smmu_ll_queue *llq = &q->llq;
        static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
                                      DEFAULT_RATELIMIT_BURST);
-       u64 evt[EVTQ_ENT_DWORDS];
 
        do {
                while (!queue_remove_raw(q, evt)) {
-                       u8 id = FIELD_GET(EVTQ_0_ID, evt[0]);
-
-                       ret = arm_smmu_handle_evt(smmu, evt);
+                       arm_smmu_decode_event(evt, &event);
+                       ret = arm_smmu_handle_evt(smmu, &event);
                        if (!ret || !__ratelimit(&rs))
                                continue;
 
-                       dev_info(smmu->dev, "event 0x%02x received:\n", id);
-                       for (i = 0; i < ARRAY_SIZE(evt); ++i)
+                       dev_info(smmu->dev, "event 0x%02x received:\n", event.id);
+                       for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
                                dev_info(smmu->dev, "\t0x%016llx\n",
                                         (unsigned long long)evt[i]);
 
index 0107d3f333a1cc2121ad5680d410199431f219a8..c37ed3c925ec70e0e428255050acba33ea9581b6 100644 (file)
@@ -470,6 +470,7 @@ static inline unsigned int arm_smmu_cdtab_l2_idx(unsigned int ssid)
 #define EVTQ_1_TT_READ                 (1UL << 44)
 #define EVTQ_2_ADDR                    GENMASK_ULL(63, 0)
 #define EVTQ_3_IPA                     GENMASK_ULL(51, 12)
+#define EVTQ_3_FETCH_ADDR              GENMASK_ULL(51, 3)
 
 /* PRI queue */
 #define PRIQ_ENT_SZ_SHIFT              4
@@ -789,6 +790,23 @@ struct arm_smmu_stream {
        struct rb_node                  node;
 };
 
+struct arm_smmu_event {
+       u8                              stall : 1,
+                                       ssv : 1,
+                                       privileged : 1,
+                                       instruction : 1,
+                                       s2 : 1,
+                                       read : 1;
+       u8                              id;
+       u8                              class;
+       u16                             stag;
+       u32                             sid;
+       u32                             ssid;
+       u64                             iova;
+       u64                             ipa;
+       u64                             fetch_addr;
+};
+
 /* SMMU private data for each master */
 struct arm_smmu_master {
        struct arm_smmu_device          *smmu;