]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/xe/pat: Add debugfs node to dump PAT
authorLucas De Marchi <lucas.demarchi@intel.com>
Fri, 6 Oct 2023 18:23:24 +0000 (11:23 -0700)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Thu, 21 Dec 2023 16:42:57 +0000 (11:42 -0500)
This is useful to debug cache issues, to double check if the PAT
indexes match what they were supposed to be set to from spec.

v2: Add separate functions for XeHP, XeHPC and XeLPG so it correctly
    reads the index based on MCR/REG registers and also decodes the
    fields (Matt Roper)
v3: Starting with XeHPC, do not translate values to human-readable
    formats as the main goal is to make it easy to compare the table
    with the spec. Also, share a single array for xelp/xehp str map
    (Matt Roper)

Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
Link: https://lore.kernel.org/r/20231006182325.3617685-3-lucas.demarchi@intel.com
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
drivers/gpu/drm/xe/xe_gt_debugfs.c
drivers/gpu/drm/xe/xe_pat.c
drivers/gpu/drm/xe/xe_pat.h

index ec1ae00f6bfcf554d697f76d2795bdf9d0d8a3b1..cd6d28c7b923abf5879b4ce521497b8e191be11e 100644 (file)
@@ -16,6 +16,7 @@
 #include "xe_gt_topology.h"
 #include "xe_hw_engine.h"
 #include "xe_macros.h"
+#include "xe_pat.h"
 #include "xe_reg_sr.h"
 #include "xe_reg_whitelist.h"
 #include "xe_uc_debugfs.h"
@@ -138,6 +139,16 @@ static int workarounds(struct seq_file *m, void *data)
        return 0;
 }
 
+static int pat(struct seq_file *m, void *data)
+{
+       struct xe_gt *gt = node_to_gt(m->private);
+       struct drm_printer p = drm_seq_file_printer(m);
+
+       xe_pat_dump(gt, &p);
+
+       return 0;
+}
+
 static const struct drm_info_list debugfs_list[] = {
        {"hw_engines", hw_engines, 0},
        {"force_reset", force_reset, 0},
@@ -147,6 +158,7 @@ static const struct drm_info_list debugfs_list[] = {
        {"ggtt", ggtt, 0},
        {"register-save-restore", register_save_restore, 0},
        {"workarounds", workarounds, 0},
+       {"pat", pat, 0},
 };
 
 void xe_gt_debugfs_register(struct xe_gt *gt)
index 296763594370bd920c1b23b2c9795eac55efee07..31565ccbb0ec10bcc93514ab50eb6c80f6f42efa 100644 (file)
@@ -6,6 +6,8 @@
 #include "xe_pat.h"
 
 #include "regs/xe_reg_defs.h"
+#include "xe_assert.h"
+#include "xe_device.h"
 #include "xe_gt.h"
 #include "xe_gt_mcr.h"
 #include "xe_mmio.h"
@@ -14,6 +16,7 @@
 #define _PAT_INDEX(index)                      _PICK_EVEN_2RANGES(index, 8, \
                                                                   0x4800, 0x4804, \
                                                                   0x4848, 0x484c)
+#define _PAT_PTA                               0x4820
 
 #define XE2_NO_PROMOTE                         REG_BIT(10)
 #define XE2_COMP_EN                            REG_BIT(9)
 #define XELP_PAT_WC                            REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 1)
 #define XELP_PAT_UC                            REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 0)
 
+static const char *XELP_MEM_TYPE_STR_MAP[] = { "UC", "WC", "WT", "WB" };
+
 struct xe_pat_ops {
        void (*program_graphics)(struct xe_gt *gt, const u32 table[], int n_entries);
        void (*program_media)(struct xe_gt *gt, const u32 table[], int n_entries);
+       void (*dump)(struct xe_gt *gt, struct drm_printer *p);
 };
 
 static const u32 xelp_pat_table[] = {
@@ -151,14 +157,132 @@ static void program_pat_mcr(struct xe_gt *gt, const u32 table[], int n_entries)
        }
 }
 
+static void xelp_dump(struct xe_gt *gt, struct drm_printer *p)
+{
+       struct xe_device *xe = gt_to_xe(gt);
+       int i, err;
+
+       xe_device_mem_access_get(xe);
+       err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
+       if (err)
+               goto err_fw;
+
+       drm_printf(p, "PAT table:\n");
+
+       for (i = 0; i < xe->pat.n_entries; i++) {
+               u32 pat = xe_mmio_read32(gt, XE_REG(_PAT_INDEX(i)));
+               u8 mem_type = REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat);
+
+               drm_printf(p, "PAT[%2d] = %s (%#8x)\n", i,
+                          XELP_MEM_TYPE_STR_MAP[mem_type], pat);
+       }
+
+       err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
+err_fw:
+       xe_assert(xe, !err);
+       xe_device_mem_access_put(xe);
+}
+
 static const struct xe_pat_ops xelp_pat_ops = {
        .program_graphics = program_pat,
+       .dump = xelp_dump,
 };
 
+static void xehp_dump(struct xe_gt *gt, struct drm_printer *p)
+{
+       struct xe_device *xe = gt_to_xe(gt);
+       int i, err;
+
+       xe_device_mem_access_get(xe);
+       err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
+       if (err)
+               goto err_fw;
+
+       drm_printf(p, "PAT table:\n");
+
+       for (i = 0; i < xe->pat.n_entries; i++) {
+               u32 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i)));
+               u8 mem_type;
+
+               mem_type = REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat);
+
+               drm_printf(p, "PAT[%2d] = %s (%#8x)\n", i,
+                          XELP_MEM_TYPE_STR_MAP[mem_type], pat);
+       }
+
+       err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
+err_fw:
+       xe_assert(xe, !err);
+       xe_device_mem_access_put(xe);
+}
+
 static const struct xe_pat_ops xehp_pat_ops = {
        .program_graphics = program_pat_mcr,
+       .dump = xehp_dump,
+};
+
+static void xehpc_dump(struct xe_gt *gt, struct drm_printer *p)
+{
+       struct xe_device *xe = gt_to_xe(gt);
+       int i, err;
+
+       xe_device_mem_access_get(xe);
+       err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
+       if (err)
+               goto err_fw;
+
+       drm_printf(p, "PAT table:\n");
+
+       for (i = 0; i < xe->pat.n_entries; i++) {
+               u32 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i)));
+
+               drm_printf(p, "PAT[%2d] = [ %u, %u ] (%#8x)\n", i,
+                          REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat),
+                          REG_FIELD_GET(XEHPC_CLOS_LEVEL_MASK, pat), pat);
+       }
+
+       err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
+err_fw:
+       xe_assert(xe, !err);
+       xe_device_mem_access_put(xe);
+}
+
+static const struct xe_pat_ops xehpc_pat_ops = {
+       .program_graphics = program_pat_mcr,
+       .dump = xehpc_dump,
 };
 
+static void xelpg_dump(struct xe_gt *gt, struct drm_printer *p)
+{
+       struct xe_device *xe = gt_to_xe(gt);
+       int i, err;
+
+       xe_device_mem_access_get(xe);
+       err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
+       if (err)
+               goto err_fw;
+
+       drm_printf(p, "PAT table:\n");
+
+       for (i = 0; i < xe->pat.n_entries; i++) {
+               u32 pat;
+
+               if (xe_gt_is_media_type(gt))
+                       pat = xe_mmio_read32(gt, XE_REG(_PAT_INDEX(i)));
+               else
+                       pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i)));
+
+               drm_printf(p, "PAT[%2d] = [ %u, %u ] (%#8x)\n", i,
+                          REG_FIELD_GET(XELPG_L4_POLICY_MASK, pat),
+                          REG_FIELD_GET(XELPG_INDEX_COH_MODE_MASK, pat), pat);
+       }
+
+       err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
+err_fw:
+       xe_assert(xe, !err);
+       xe_device_mem_access_put(xe);
+}
+
 /*
  * SAMedia register offsets are adjusted by the write methods and they target
  * registers that are not MCR, while for normal GT they are MCR
@@ -166,6 +290,7 @@ static const struct xe_pat_ops xehp_pat_ops = {
 static const struct xe_pat_ops xelpg_pat_ops = {
        .program_graphics = program_pat,
        .program_media = program_pat_mcr,
+       .dump = xelpg_dump,
 };
 
 static void xe2lpg_program_pat(struct xe_gt *gt, const u32 table[], int n_entries)
@@ -180,9 +305,64 @@ static void xe2lpm_program_pat(struct xe_gt *gt, const u32 table[], int n_entrie
        xe_mmio_write32(gt, XE_REG(_PAT_ATS), XE2_PAT_ATS);
 }
 
+static void xe2_dump(struct xe_gt *gt, struct drm_printer *p)
+{
+       struct xe_device *xe = gt_to_xe(gt);
+       int i, err;
+       u32 pat;
+
+       xe_device_mem_access_get(xe);
+       err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
+       if (err)
+               goto err_fw;
+
+       drm_printf(p, "PAT table:\n");
+
+       for (i = 0; i < xe->pat.n_entries; i++) {
+               if (xe_gt_is_media_type(gt))
+                       pat = xe_mmio_read32(gt, XE_REG(_PAT_INDEX(i)));
+               else
+                       pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i)));
+
+               drm_printf(p, "PAT[%2d] = [ %u, %u, %u, %u, %u, %u ]  (%#8x)\n", i,
+                          !!(pat & XE2_NO_PROMOTE),
+                          !!(pat & XE2_COMP_EN),
+                          REG_FIELD_GET(XE2_L3_CLOS, pat),
+                          REG_FIELD_GET(XE2_L3_POLICY, pat),
+                          REG_FIELD_GET(XE2_L4_POLICY, pat),
+                          REG_FIELD_GET(XE2_COH_MODE, pat),
+                          pat);
+       }
+
+       /*
+        * Also print PTA_MODE, which describes how the hardware accesses
+        * PPGTT entries.
+        */
+       if (xe_gt_is_media_type(gt))
+               pat = xe_mmio_read32(gt, XE_REG(_PAT_PTA));
+       else
+               pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_PTA));
+
+       drm_printf(p, "Page Table Access:\n");
+       drm_printf(p, "PTA_MODE= [ %u, %u, %u, %u, %u, %u ]  (%#8x)\n",
+                  !!(pat & XE2_NO_PROMOTE),
+                  !!(pat & XE2_COMP_EN),
+                  REG_FIELD_GET(XE2_L3_CLOS, pat),
+                  REG_FIELD_GET(XE2_L3_POLICY, pat),
+                  REG_FIELD_GET(XE2_L4_POLICY, pat),
+                  REG_FIELD_GET(XE2_COH_MODE, pat),
+                  pat);
+
+       err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
+err_fw:
+       xe_assert(xe, !err);
+       xe_device_mem_access_put(xe);
+}
+
 static const struct xe_pat_ops xe2_pat_ops = {
        .program_graphics = xe2lpg_program_pat,
        .program_media = xe2lpm_program_pat,
+       .dump = xe2_dump,
 };
 
 void xe_pat_init_early(struct xe_device *xe)
@@ -202,7 +382,7 @@ void xe_pat_init_early(struct xe_device *xe)
                xe->pat.idx[XE_CACHE_WT] = 1;
                xe->pat.idx[XE_CACHE_WB] = 3;
        } else if (xe->info.platform == XE_PVC) {
-               xe->pat.ops = &xehp_pat_ops;
+               xe->pat.ops = &xehpc_pat_ops;
                xe->pat.table = xehpc_pat_table;
                xe->pat.n_entries = ARRAY_SIZE(xehpc_pat_table);
                xe->pat.idx[XE_CACHE_NONE] = 0;
@@ -252,3 +432,13 @@ void xe_pat_init(struct xe_gt *gt)
        else
                xe->pat.ops->program_graphics(gt, xe->pat.table, xe->pat.n_entries);
 }
+
+void xe_pat_dump(struct xe_gt *gt, struct drm_printer *p)
+{
+       struct xe_device *xe = gt_to_xe(gt);
+
+       if (!xe->pat.ops->dump)
+               return;
+
+       xe->pat.ops->dump(gt, p);
+}
index 168e80e63809a331d45696fc0458ca38ec0b97d4..09c491ab9f15df5f765a6750f744b49c2f9da258 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef _XE_PAT_H_
 #define _XE_PAT_H_
 
+struct drm_printer;
 struct xe_gt;
 struct xe_device;
 
@@ -21,4 +22,11 @@ void xe_pat_init_early(struct xe_device *xe);
  */
 void xe_pat_init(struct xe_gt *gt);
 
+/**
+ * xe_pat_dump - Dump PAT table
+ * @gt: GT structure
+ * @p: Printer to dump info to
+ */
+void xe_pat_dump(struct xe_gt *gt, struct drm_printer *p);
+
 #endif