Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe/pat: annotate pat_index with coherency mode

Future uapi needs to give userspace the ability to select the pat_index
for a given vm_bind. However we need to be able to extract the coherency
mode from the provided pat_index to ensure it's compatible with the
cpu_caching mode set at object creation. There are various security
reasons for why this matters. However the pat_index itself is very
platform specific, so seems reasonable to annotate each platform
definition of the pat table. On some older platforms there is no
explicit coherency mode, so we just pick whatever makes sense.

v2:
- Simplify with COH_AT_LEAST_1_WAY
- Add some kernel-doc
v3 (Matt Roper):
- Some small tweaks
v4:
- Rebase
v5:
- Rebase on Xe2 PAT additions
v6:
- Rebase on removal of coh_mode from uapi

Bspec: 45101, 44235 #xe
Bspec: 70552, 71582, 59400 #xe2
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Pallavi Mishra <pallavi.mishra@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Cc: José Roberto de Souza <jose.souza@intel.com>
Cc: Filip Hazubski <filip.hazubski@intel.com>
Cc: Carl Zhang <carl.zhang@intel.com>
Cc: Effie Yu <effie.yu@intel.com>
Cc: Zhengguo Xu <zhengguo.xu@intel.com>
Cc: Francois Dugast <francois.dugast@intel.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: José Roberto de Souza <jose.souza@intel.com>
Reviewed-by: Pallavi Mishra <pallavi.mishra@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

authored by

Matthew Auld and committed by
Rodrigo Vivi
f6a22e68 622f709c

+88 -41
+1 -1
drivers/gpu/drm/xe/xe_device_types.h
··· 368 368 /** Internal operations to abstract platforms */ 369 369 const struct xe_pat_ops *ops; 370 370 /** PAT table to program in the HW */ 371 - const u32 *table; 371 + const struct xe_pat_table_entry *table; 372 372 /** Number of PAT entries */ 373 373 int n_entries; 374 374 u32 idx[__XE_CACHE_LEVEL_COUNT];
+57 -39
drivers/gpu/drm/xe/xe_pat.c
··· 5 5 6 6 #include "xe_pat.h" 7 7 8 + #include <drm/xe_drm.h> 9 + 8 10 #include "regs/xe_reg_defs.h" 9 11 #include "xe_assert.h" 10 12 #include "xe_device.h" ··· 48 46 static const char *XELP_MEM_TYPE_STR_MAP[] = { "UC", "WC", "WT", "WB" }; 49 47 50 48 struct xe_pat_ops { 51 - void (*program_graphics)(struct xe_gt *gt, const u32 table[], int n_entries); 52 - void (*program_media)(struct xe_gt *gt, const u32 table[], int n_entries); 49 + void (*program_graphics)(struct xe_gt *gt, const struct xe_pat_table_entry table[], 50 + int n_entries); 51 + void (*program_media)(struct xe_gt *gt, const struct xe_pat_table_entry table[], 52 + int n_entries); 53 53 void (*dump)(struct xe_gt *gt, struct drm_printer *p); 54 54 }; 55 55 56 - static const u32 xelp_pat_table[] = { 57 - [0] = XELP_PAT_WB, 58 - [1] = XELP_PAT_WC, 59 - [2] = XELP_PAT_WT, 60 - [3] = XELP_PAT_UC, 56 + static const struct xe_pat_table_entry xelp_pat_table[] = { 57 + [0] = { XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 58 + [1] = { XELP_PAT_WC, XE_COH_NONE }, 59 + [2] = { XELP_PAT_WT, XE_COH_NONE }, 60 + [3] = { XELP_PAT_UC, XE_COH_NONE }, 61 61 }; 62 62 63 - static const u32 xehpc_pat_table[] = { 64 - [0] = XELP_PAT_UC, 65 - [1] = XELP_PAT_WC, 66 - [2] = XELP_PAT_WT, 67 - [3] = XELP_PAT_WB, 68 - [4] = XEHPC_PAT_CLOS(1) | XELP_PAT_WT, 69 - [5] = XEHPC_PAT_CLOS(1) | XELP_PAT_WB, 70 - [6] = XEHPC_PAT_CLOS(2) | XELP_PAT_WT, 71 - [7] = XEHPC_PAT_CLOS(2) | XELP_PAT_WB, 63 + static const struct xe_pat_table_entry xehpc_pat_table[] = { 64 + [0] = { XELP_PAT_UC, XE_COH_NONE }, 65 + [1] = { XELP_PAT_WC, XE_COH_NONE }, 66 + [2] = { XELP_PAT_WT, XE_COH_NONE }, 67 + [3] = { XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 68 + [4] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WT, XE_COH_NONE }, 69 + [5] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 70 + [6] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WT, XE_COH_NONE }, 71 + [7] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 72 72 }; 73 73 74 - static const u32 xelpg_pat_table[] = { 75 - [0] = XELPG_PAT_0_WB, 76 - [1] = XELPG_PAT_1_WT, 77 - [2] = XELPG_PAT_3_UC, 78 - [3] = XELPG_PAT_0_WB | XELPG_2_COH_1W, 79 - [4] = XELPG_PAT_0_WB | XELPG_3_COH_2W, 74 + static const struct xe_pat_table_entry xelpg_pat_table[] = { 75 + [0] = { XELPG_PAT_0_WB, XE_COH_NONE }, 76 + [1] = { XELPG_PAT_1_WT, XE_COH_NONE }, 77 + [2] = { XELPG_PAT_3_UC, XE_COH_NONE }, 78 + [3] = { XELPG_PAT_0_WB | XELPG_2_COH_1W, XE_COH_AT_LEAST_1WAY }, 79 + [4] = { XELPG_PAT_0_WB | XELPG_3_COH_2W, XE_COH_AT_LEAST_1WAY }, 80 80 }; 81 81 82 82 /* ··· 96 92 * coherency (which matches an all-0's encoding), so we can just omit them 97 93 * in the table. 98 94 */ 99 - #define XE2_PAT(no_promote, comp_en, l3clos, l3_policy, l4_policy, coh_mode) \ 100 - (no_promote ? XE2_NO_PROMOTE : 0) | \ 101 - (comp_en ? XE2_COMP_EN : 0) | \ 102 - REG_FIELD_PREP(XE2_L3_CLOS, l3clos) | \ 103 - REG_FIELD_PREP(XE2_L3_POLICY, l3_policy) | \ 104 - REG_FIELD_PREP(XE2_L4_POLICY, l4_policy) | \ 105 - REG_FIELD_PREP(XE2_COH_MODE, coh_mode) 95 + #define XE2_PAT(no_promote, comp_en, l3clos, l3_policy, l4_policy, __coh_mode) \ 96 + { \ 97 + .value = (no_promote ? XE2_NO_PROMOTE : 0) | \ 98 + (comp_en ? XE2_COMP_EN : 0) | \ 99 + REG_FIELD_PREP(XE2_L3_CLOS, l3clos) | \ 100 + REG_FIELD_PREP(XE2_L3_POLICY, l3_policy) | \ 101 + REG_FIELD_PREP(XE2_L4_POLICY, l4_policy) | \ 102 + REG_FIELD_PREP(XE2_COH_MODE, __coh_mode), \ 103 + .coh_mode = __coh_mode ? XE_COH_AT_LEAST_1WAY : XE_COH_NONE \ 104 + } 106 105 107 - static const u32 xe2_pat_table[] = { 106 + static const struct xe_pat_table_entry xe2_pat_table[] = { 108 107 [ 0] = XE2_PAT( 0, 0, 0, 0, 3, 0 ), 109 108 [ 1] = XE2_PAT( 0, 0, 0, 0, 3, 2 ), 110 109 [ 2] = XE2_PAT( 0, 0, 0, 0, 3, 3 ), ··· 140 133 }; 141 134 142 135 /* Special PAT values programmed outside the main table */ 143 - #define XE2_PAT_ATS XE2_PAT( 0, 0, 0, 0, 3, 3 ) 136 + static const struct xe_pat_table_entry xe2_pat_ats = XE2_PAT( 0, 0, 0, 0, 3, 3 ); 144 137 145 - static void program_pat(struct xe_gt *gt, const u32 table[], int n_entries) 138 + u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index) 139 + { 140 + WARN_ON(pat_index >= xe->pat.n_entries); 141 + return xe->pat.table[pat_index].coh_mode; 142 + } 143 + 144 + static void program_pat(struct xe_gt *gt, const struct xe_pat_table_entry table[], 145 + int n_entries) 146 146 { 147 147 for (int i = 0; i < n_entries; i++) { 148 148 struct xe_reg reg = XE_REG(_PAT_INDEX(i)); 149 149 150 - xe_mmio_write32(gt, reg, table[i]); 150 + xe_mmio_write32(gt, reg, table[i].value); 151 151 } 152 152 } 153 153 154 - static void program_pat_mcr(struct xe_gt *gt, const u32 table[], int n_entries) 154 + static void program_pat_mcr(struct xe_gt *gt, const struct xe_pat_table_entry table[], 155 + int n_entries) 155 156 { 156 157 for (int i = 0; i < n_entries; i++) { 157 158 struct xe_reg_mcr reg_mcr = XE_REG_MCR(_PAT_INDEX(i)); 158 159 159 - xe_gt_mcr_multicast_write(gt, reg_mcr, table[i]); 160 + xe_gt_mcr_multicast_write(gt, reg_mcr, table[i].value); 160 161 } 161 162 } 162 163 ··· 304 289 .dump = xelpg_dump, 305 290 }; 306 291 307 - static void xe2lpg_program_pat(struct xe_gt *gt, const u32 table[], int n_entries) 292 + static void xe2lpg_program_pat(struct xe_gt *gt, const struct xe_pat_table_entry table[], 293 + int n_entries) 308 294 { 309 295 program_pat_mcr(gt, table, n_entries); 310 - xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_ATS), XE2_PAT_ATS); 296 + xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_ATS), xe2_pat_ats.value); 311 297 } 312 298 313 - static void xe2lpm_program_pat(struct xe_gt *gt, const u32 table[], int n_entries) 299 + static void xe2lpm_program_pat(struct xe_gt *gt, const struct xe_pat_table_entry table[], 300 + int n_entries) 314 301 { 315 302 program_pat(gt, table, n_entries); 316 - xe_mmio_write32(gt, XE_REG(_PAT_ATS), XE2_PAT_ATS); 303 + xe_mmio_write32(gt, XE_REG(_PAT_ATS), xe2_pat_ats.value); 317 304 } 318 305 319 306 static void xe2_dump(struct xe_gt *gt, struct drm_printer *p) ··· 413 396 xe->pat.idx[XE_CACHE_WT] = 2; 414 397 xe->pat.idx[XE_CACHE_WB] = 0; 415 398 } else if (GRAPHICS_VERx100(xe) <= 1210) { 399 + WARN_ON_ONCE(!IS_DGFX(xe) && !xe->info.has_llc); 416 400 xe->pat.ops = &xelp_pat_ops; 417 401 xe->pat.table = xelp_pat_table; 418 402 xe->pat.n_entries = ARRAY_SIZE(xelp_pat_table);
+30 -1
drivers/gpu/drm/xe/xe_pat.h
··· 6 6 #ifndef _XE_PAT_H_ 7 7 #define _XE_PAT_H_ 8 8 9 + #include <linux/types.h> 10 + 9 11 struct drm_printer; 10 - struct xe_gt; 11 12 struct xe_device; 13 + struct xe_gt; 14 + 15 + /** 16 + * struct xe_pat_table_entry - The pat_index encoding and other meta information. 17 + */ 18 + struct xe_pat_table_entry { 19 + /** 20 + * @value: The platform specific value encoding the various memory 21 + * attributes (this maps to some fixed pat_index). So things like 22 + * caching, coherency, compression etc can be encoded here. 23 + */ 24 + u32 value; 25 + 26 + /** 27 + * @coh_mode: The GPU coherency mode that @value maps to. 28 + */ 29 + #define XE_COH_NONE 1 30 + #define XE_COH_AT_LEAST_1WAY 2 31 + u16 coh_mode; 32 + }; 12 33 13 34 /** 14 35 * xe_pat_init_early - SW initialization, setting up data based on device ··· 49 28 * @p: Printer to dump info to 50 29 */ 51 30 void xe_pat_dump(struct xe_gt *gt, struct drm_printer *p); 31 + 32 + /** 33 + * xe_pat_index_get_coh_mode - Extract the coherency mode for the given 34 + * pat_index. 35 + * @xe: xe device 36 + * @pat_index: The pat_index to query 37 + */ 38 + u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index); 52 39 53 40 #endif