]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/xe/xe2: Program PAT tables
authorMatt Roper <matthew.d.roper@intel.com>
Fri, 6 Oct 2023 18:23:22 +0000 (11:23 -0700)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Thu, 21 Dec 2023 16:42:57 +0000 (11:42 -0500)
The PAT tables become significantly more complicated on Xe2 platforms.
They now control L3, L4, and coherency settings, as well as additional
characteristics such as compression.

Aside from the main PAT table, there's an additional register that
also needs to be programmed with PAT settings for PCI Address
Translation Services.

Bspec: 71582
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Balasubramani Vivekanandan <balasubramani.vivekanandan@intel.com>
Link: https://lore.kernel.org/r/20231006182325.3617685-1-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_pat.c

index 4668ca3932c558da38b80cca1208d0ef3561fff0..296763594370bd920c1b23b2c9795eac55efee07 100644 (file)
 #include "xe_gt_mcr.h"
 #include "xe_mmio.h"
 
+#define _PAT_ATS                               0x47fc
 #define _PAT_INDEX(index)                      _PICK_EVEN_2RANGES(index, 8, \
                                                                   0x4800, 0x4804, \
                                                                   0x4848, 0x484c)
 
+#define XE2_NO_PROMOTE                         REG_BIT(10)
+#define XE2_COMP_EN                            REG_BIT(9)
+#define XE2_L3_CLOS                            REG_GENMASK(7, 6)
+#define XE2_L3_POLICY                          REG_GENMASK(5, 4)
+#define XE2_L4_POLICY                          REG_GENMASK(3, 2)
+#define XE2_COH_MODE                           REG_GENMASK(1, 0)
+
 #define XELPG_L4_POLICY_MASK                   REG_GENMASK(3, 2)
 #define XELPG_PAT_3_UC                         REG_FIELD_PREP(XELPG_L4_POLICY_MASK, 3)
 #define XELPG_PAT_1_WT                         REG_FIELD_PREP(XELPG_L4_POLICY_MASK, 1)
@@ -67,6 +75,64 @@ static const u32 xelpg_pat_table[] = {
        [4] = XELPG_PAT_0_WB | XELPG_3_COH_2W,
 };
 
+/*
+ * The Xe2 table is getting large/complicated so it's easier to review if
+ * provided in a form that exactly matches the bspec's formatting.  The meaning
+ * of the fields here are:
+ *   - no_promote:  0=promotable, 1=no promote
+ *   - comp_en:     0=disable, 1=enable
+ *   - l3clos:      L3 class of service (0-3)
+ *   - l3_policy:   0=WB, 1=XD ("WB - Transient Display"), 3=UC
+ *   - l4_policy:   0=WB, 1=WT, 3=UC
+ *   - coh_mode:    0=no snoop, 2=1-way coherent, 3=2-way coherent
+ *
+ * Reserved entries should be programmed with the maximum caching, minimum
+ * coherency (which matches an all-0's encoding), so we can just omit them
+ * in the table.
+ */
+#define XE2_PAT(no_promote, comp_en, l3clos, l3_policy, l4_policy, coh_mode) \
+       (no_promote ? XE2_NO_PROMOTE : 0) | \
+       (comp_en ? XE2_COMP_EN : 0) | \
+       REG_FIELD_PREP(XE2_L3_CLOS, l3clos) | \
+       REG_FIELD_PREP(XE2_L3_POLICY, l3_policy) | \
+       REG_FIELD_PREP(XE2_L4_POLICY, l4_policy) | \
+       REG_FIELD_PREP(XE2_COH_MODE, coh_mode)
+
+static const u32 xe2_pat_table[] = {
+       [ 0] = XE2_PAT( 0, 0, 0, 0, 3, 0 ),
+       [ 1] = XE2_PAT( 0, 0, 0, 0, 3, 2 ),
+       [ 2] = XE2_PAT( 0, 0, 0, 0, 3, 3 ),
+       [ 3] = XE2_PAT( 0, 0, 0, 3, 3, 0 ),
+       [ 4] = XE2_PAT( 0, 0, 0, 3, 0, 2 ),
+       [ 5] = XE2_PAT( 0, 0, 0, 3, 3, 2 ),
+       [ 6] = XE2_PAT( 1, 0, 0, 1, 3, 0 ),
+       [ 7] = XE2_PAT( 0, 0, 0, 3, 0, 3 ),
+       [ 8] = XE2_PAT( 0, 0, 0, 3, 0, 0 ),
+       [ 9] = XE2_PAT( 0, 1, 0, 0, 3, 0 ),
+       [10] = XE2_PAT( 0, 1, 0, 3, 0, 0 ),
+       [11] = XE2_PAT( 1, 1, 0, 1, 3, 0 ),
+       [12] = XE2_PAT( 0, 1, 0, 3, 3, 0 ),
+       [13] = XE2_PAT( 0, 0, 0, 0, 0, 0 ),
+       [14] = XE2_PAT( 0, 1, 0, 0, 0, 0 ),
+       [15] = XE2_PAT( 1, 1, 0, 1, 1, 0 ),
+       /* 16..19 are reserved; leave set to all 0's */
+       [20] = XE2_PAT( 0, 0, 1, 0, 3, 0 ),
+       [21] = XE2_PAT( 0, 1, 1, 0, 3, 0 ),
+       [22] = XE2_PAT( 0, 0, 1, 0, 3, 2 ),
+       [23] = XE2_PAT( 0, 0, 1, 0, 3, 3 ),
+       [24] = XE2_PAT( 0, 0, 2, 0, 3, 0 ),
+       [25] = XE2_PAT( 0, 1, 2, 0, 3, 0 ),
+       [26] = XE2_PAT( 0, 0, 2, 0, 3, 2 ),
+       [27] = XE2_PAT( 0, 0, 2, 0, 3, 3 ),
+       [28] = XE2_PAT( 0, 0, 3, 0, 3, 0 ),
+       [29] = XE2_PAT( 0, 1, 3, 0, 3, 0 ),
+       [30] = XE2_PAT( 0, 0, 3, 0, 3, 2 ),
+       [31] = XE2_PAT( 0, 0, 3, 0, 3, 3 ),
+};
+
+/* Special PAT values programmed outside the main table */
+#define XE2_PAT_ATS    XE2_PAT( 0, 0, 0, 0, 3, 3 )
+
 static void program_pat(struct xe_gt *gt, const u32 table[], int n_entries)
 {
        for (int i = 0; i < n_entries; i++) {
@@ -102,9 +168,33 @@ static const struct xe_pat_ops xelpg_pat_ops = {
        .program_media = program_pat_mcr,
 };
 
+static void xe2lpg_program_pat(struct xe_gt *gt, const u32 table[], int n_entries)
+{
+       program_pat_mcr(gt, table, n_entries);
+       xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_ATS), XE2_PAT_ATS);
+}
+
+static void xe2lpm_program_pat(struct xe_gt *gt, const u32 table[], int n_entries)
+{
+       program_pat(gt, table, n_entries);
+       xe_mmio_write32(gt, XE_REG(_PAT_ATS), XE2_PAT_ATS);
+}
+
+static const struct xe_pat_ops xe2_pat_ops = {
+       .program_graphics = xe2lpg_program_pat,
+       .program_media = xe2lpm_program_pat,
+};
+
 void xe_pat_init_early(struct xe_device *xe)
 {
-       if (xe->info.platform == XE_METEORLAKE) {
+       if (GRAPHICS_VER(xe) == 20) {
+               xe->pat.ops = &xe2_pat_ops;
+               xe->pat.table = xe2_pat_table;
+               xe->pat.n_entries = ARRAY_SIZE(xe2_pat_table);
+               xe->pat.idx[XE_CACHE_NONE] = 3;
+               xe->pat.idx[XE_CACHE_WT] = 15;
+               xe->pat.idx[XE_CACHE_WB] = 2;
+       } else if (xe->info.platform == XE_METEORLAKE) {
                xe->pat.ops = &xelpg_pat_ops;
                xe->pat.table = xelpg_pat_table;
                xe->pat.n_entries = ARRAY_SIZE(xelpg_pat_table);