]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/arm-smmu-v3: Log better event records
authorPranjal Shrivastava <praan@google.com>
Tue, 3 Dec 2024 18:49:06 +0000 (18:49 +0000)
committerWill Deacon <will@kernel.org>
Mon, 9 Dec 2024 21:43:43 +0000 (21:43 +0000)
Currently, the driver dumps the raw hex for a received event record.
Improve this by leveraging `struct arm_smmu_event` for event fields
and log human-readable event records with meaningful information.

Signed-off-by: Pranjal Shrivastava <praan@google.com>
Link: https://lore.kernel.org/r/20241203184906.2264528-3-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 9fcba8fab9e3a236c3438ac235efc2e69df17fe0..143ff6336a95c076340fc4030655c76043d4a2f7 100644 (file)
@@ -83,6 +83,28 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
        { 0, NULL},
 };
 
+static const char * const event_str[] = {
+       [EVT_ID_BAD_STREAMID_CONFIG] = "C_BAD_STREAMID",
+       [EVT_ID_STE_FETCH_FAULT] = "F_STE_FETCH",
+       [EVT_ID_BAD_STE_CONFIG] = "C_BAD_STE",
+       [EVT_ID_STREAM_DISABLED_FAULT] = "F_STREAM_DISABLED",
+       [EVT_ID_BAD_SUBSTREAMID_CONFIG] = "C_BAD_SUBSTREAMID",
+       [EVT_ID_CD_FETCH_FAULT] = "F_CD_FETCH",
+       [EVT_ID_BAD_CD_CONFIG] = "C_BAD_CD",
+       [EVT_ID_TRANSLATION_FAULT] = "F_TRANSLATION",
+       [EVT_ID_ADDR_SIZE_FAULT] = "F_ADDR_SIZE",
+       [EVT_ID_ACCESS_FAULT] = "F_ACCESS",
+       [EVT_ID_PERMISSION_FAULT] = "F_PERMISSION",
+       [EVT_ID_VMS_FETCH_FAULT] = "F_VMS_FETCH",
+};
+
+static const char * const event_class_str[] = {
+       [0] = "CD fetch",
+       [1] = "Stage 1 translation table fetch",
+       [2] = "Input address caused fault",
+       [3] = "Reserved",
+};
+
 static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
                                    struct arm_smmu_device *smmu, u32 flags);
 static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master);
@@ -1759,8 +1781,11 @@ arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
 }
 
 /* IRQ and event handlers */
-static void arm_smmu_decode_event(u64 *raw, struct arm_smmu_event *event)
+static void arm_smmu_decode_event(struct arm_smmu_device *smmu, u64 *raw,
+                                 struct arm_smmu_event *event)
 {
+       struct arm_smmu_master *master;
+
        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]);
@@ -1775,9 +1800,21 @@ static void arm_smmu_decode_event(u64 *raw, struct arm_smmu_event *event)
        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;
+       event->ttrnw = FIELD_GET(EVTQ_1_TT_READ, raw[1]);
+       event->class_tt = false;
+       event->dev = NULL;
+
+       if (event->id == EVT_ID_PERMISSION_FAULT)
+               event->class_tt = (event->class == EVTQ_1_CLASS_TT);
+
+       mutex_lock(&smmu->streams_mutex);
+       master = arm_smmu_find_master(smmu, event->sid);
+       if (master)
+               event->dev = get_device(master->dev);
+       mutex_unlock(&smmu->streams_mutex);
 }
 
-static int arm_smmu_handle_evt(struct arm_smmu_device *smmu,
+static int arm_smmu_handle_event(struct arm_smmu_device *smmu,
                               struct arm_smmu_event *event)
 {
        int ret = 0;
@@ -1836,9 +1873,67 @@ out_unlock:
        return ret;
 }
 
+static void arm_smmu_dump_raw_event(struct arm_smmu_device *smmu, u64 *raw,
+                                   struct arm_smmu_event *event)
+{
+       int i;
+
+       dev_err(smmu->dev, "event 0x%02x received:\n", event->id);
+
+       for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
+               dev_err(smmu->dev, "\t0x%016llx\n", raw[i]);
+}
+
+#define ARM_SMMU_EVT_KNOWN(e)  ((e)->id < ARRAY_SIZE(event_str) && event_str[(e)->id])
+#define ARM_SMMU_LOG_EVT_STR(e) ARM_SMMU_EVT_KNOWN(e) ? event_str[(e)->id] : "UNKNOWN"
+#define ARM_SMMU_LOG_CLIENT(e) (e)->dev ? dev_name((e)->dev) : "(unassigned sid)"
+
+static void arm_smmu_dump_event(struct arm_smmu_device *smmu, u64 *raw,
+                               struct arm_smmu_event *evt,
+                               struct ratelimit_state *rs)
+{
+       if (!__ratelimit(rs))
+               return;
+
+       arm_smmu_dump_raw_event(smmu, raw, evt);
+
+       switch (evt->id) {
+       case EVT_ID_TRANSLATION_FAULT:
+       case EVT_ID_ADDR_SIZE_FAULT:
+       case EVT_ID_ACCESS_FAULT:
+       case EVT_ID_PERMISSION_FAULT:
+               dev_err(smmu->dev, "event: %s client: %s sid: %#x ssid: %#x iova: %#llx ipa: %#llx",
+                       ARM_SMMU_LOG_EVT_STR(evt), ARM_SMMU_LOG_CLIENT(evt),
+                       evt->sid, evt->ssid, evt->iova, evt->ipa);
+
+               dev_err(smmu->dev, "%s %s %s %s \"%s\"%s%s stag: %#x",
+                       evt->privileged ? "priv" : "unpriv",
+                       evt->instruction ? "inst" : "data",
+                       evt->read ? "read" : "write",
+                       evt->s2 ? "s2" : "s1", event_class_str[evt->class],
+                       evt->class_tt ? (evt->ttrnw ? " ttd_read" : " ttd_write") : "",
+                       evt->stall ? " stall" : "", evt->stag);
+
+               break;
+
+       case EVT_ID_STE_FETCH_FAULT:
+       case EVT_ID_CD_FETCH_FAULT:
+       case EVT_ID_VMS_FETCH_FAULT:
+               dev_err(smmu->dev, "event: %s client: %s sid: %#x ssid: %#x fetch_addr: %#llx",
+                       ARM_SMMU_LOG_EVT_STR(evt), ARM_SMMU_LOG_CLIENT(evt),
+                       evt->sid, evt->ssid, evt->fetch_addr);
+
+               break;
+
+       default:
+               dev_err(smmu->dev, "event: %s client: %s sid: %#x ssid: %#x",
+                       ARM_SMMU_LOG_EVT_STR(evt), ARM_SMMU_LOG_CLIENT(evt),
+                       evt->sid, evt->ssid);
+       }
+}
+
 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;
@@ -1849,16 +1944,11 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 
        do {
                while (!queue_remove_raw(q, 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", event.id);
-                       for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
-                               dev_info(smmu->dev, "\t0x%016llx\n",
-                                        (unsigned long long)evt[i]);
+                       arm_smmu_decode_event(smmu, evt, &event);
+                       if (arm_smmu_handle_event(smmu, &event))
+                               arm_smmu_dump_event(smmu, evt, &event, &rs);
 
+                       put_device(event.dev);
                        cond_resched();
                }
 
index c37ed3c925ec70e0e428255050acba33ea9581b6..c7f37fd47768f2cdd7e4140d13adb0636e093b0a 100644 (file)
@@ -452,10 +452,18 @@ static inline unsigned int arm_smmu_cdtab_l2_idx(unsigned int ssid)
 
 #define EVTQ_0_ID                      GENMASK_ULL(7, 0)
 
+#define EVT_ID_BAD_STREAMID_CONFIG     0x02
+#define EVT_ID_STE_FETCH_FAULT         0x03
+#define EVT_ID_BAD_STE_CONFIG          0x04
+#define EVT_ID_STREAM_DISABLED_FAULT   0x06
+#define EVT_ID_BAD_SUBSTREAMID_CONFIG  0x08
+#define EVT_ID_CD_FETCH_FAULT          0x09
+#define EVT_ID_BAD_CD_CONFIG           0x0a
 #define EVT_ID_TRANSLATION_FAULT       0x10
 #define EVT_ID_ADDR_SIZE_FAULT         0x11
 #define EVT_ID_ACCESS_FAULT            0x12
 #define EVT_ID_PERMISSION_FAULT                0x13
+#define EVT_ID_VMS_FETCH_FAULT         0x25
 
 #define EVTQ_0_SSV                     (1UL << 11)
 #define EVTQ_0_SSID                    GENMASK_ULL(31, 12)
@@ -467,6 +475,7 @@ static inline unsigned int arm_smmu_cdtab_l2_idx(unsigned int ssid)
 #define EVTQ_1_RnW                     (1UL << 35)
 #define EVTQ_1_S2                      (1UL << 39)
 #define EVTQ_1_CLASS                   GENMASK_ULL(41, 40)
+#define EVTQ_1_CLASS_TT                        0x01
 #define EVTQ_1_TT_READ                 (1UL << 44)
 #define EVTQ_2_ADDR                    GENMASK_ULL(63, 0)
 #define EVTQ_3_IPA                     GENMASK_ULL(51, 12)
@@ -796,7 +805,9 @@ struct arm_smmu_event {
                                        privileged : 1,
                                        instruction : 1,
                                        s2 : 1,
-                                       read : 1;
+                                       read : 1,
+                                       ttrnw : 1,
+                                       class_tt : 1;
        u8                              id;
        u8                              class;
        u16                             stag;
@@ -805,6 +816,7 @@ struct arm_smmu_event {
        u64                             iova;
        u64                             ipa;
        u64                             fetch_addr;
+       struct device                   *dev;
 };
 
 /* SMMU private data for each master */