1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include "xe_pat.h" 7 8 #include <uapi/drm/xe_drm.h> 9 10 #include <generated/xe_wa_oob.h> 11 12 #include "regs/xe_gt_regs.h" 13 #include "regs/xe_reg_defs.h" 14 #include "xe_assert.h" 15 #include "xe_device.h" 16 #include "xe_force_wake.h" 17 #include "xe_gt.h" 18 #include "xe_gt_mcr.h" 19 #include "xe_mmio.h" 20 #include "xe_sriov.h" 21 #include "xe_wa.h" 22 23 #define _PAT_ATS 0x47fc 24 #define _PAT_INDEX(index) _PICK_EVEN_2RANGES(index, 8, \ 25 0x4800, 0x4804, \ 26 0x4848, 0x484c) 27 #define _PAT_PTA 0x4820 28 29 #define XE2_NO_PROMOTE REG_BIT(10) 30 #define XE2_COMP_EN REG_BIT(9) 31 #define XE2_L3_CLOS REG_GENMASK(7, 6) 32 #define XE2_L3_POLICY REG_GENMASK(5, 4) 33 #define XE2_L4_POLICY REG_GENMASK(3, 2) 34 #define XE2_COH_MODE REG_GENMASK(1, 0) 35 36 #define XELPG_L4_POLICY_MASK REG_GENMASK(3, 2) 37 #define XELPG_PAT_3_UC REG_FIELD_PREP(XELPG_L4_POLICY_MASK, 3) 38 #define XELPG_PAT_1_WT REG_FIELD_PREP(XELPG_L4_POLICY_MASK, 1) 39 #define XELPG_PAT_0_WB REG_FIELD_PREP(XELPG_L4_POLICY_MASK, 0) 40 #define XELPG_INDEX_COH_MODE_MASK REG_GENMASK(1, 0) 41 #define XELPG_3_COH_2W REG_FIELD_PREP(XELPG_INDEX_COH_MODE_MASK, 3) 42 #define XELPG_2_COH_1W REG_FIELD_PREP(XELPG_INDEX_COH_MODE_MASK, 2) 43 #define XELPG_0_COH_NON REG_FIELD_PREP(XELPG_INDEX_COH_MODE_MASK, 0) 44 45 #define XEHPC_CLOS_LEVEL_MASK REG_GENMASK(3, 2) 46 #define XEHPC_PAT_CLOS(x) REG_FIELD_PREP(XEHPC_CLOS_LEVEL_MASK, x) 47 48 #define XELP_MEM_TYPE_MASK REG_GENMASK(1, 0) 49 #define XELP_PAT_WB REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 3) 50 #define XELP_PAT_WT REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 2) 51 #define XELP_PAT_WC REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 1) 52 #define XELP_PAT_UC REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 0) 53 54 #define PAT_LABEL_LEN 20 55 56 static const char *XELP_MEM_TYPE_STR_MAP[] = { "UC", "WC", "WT", "WB" }; 57 58 static void xe_pat_index_label(char *label, size_t len, int index) 59 { 60 snprintf(label, len, "PAT[%2d] ", index); 61 } 62 63 static void xelp_pat_entry_dump(struct drm_printer *p, int index, u32 pat) 64 { 65 u8 mem_type = REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat); 66 67 drm_printf(p, "PAT[%2d] = %s (%#8x)\n", index, 68 XELP_MEM_TYPE_STR_MAP[mem_type], pat); 69 } 70 71 static void xehpc_pat_entry_dump(struct drm_printer *p, int index, u32 pat) 72 { 73 drm_printf(p, "PAT[%2d] = [ %u, %u ] (%#8x)\n", index, 74 REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat), 75 REG_FIELD_GET(XEHPC_CLOS_LEVEL_MASK, pat), pat); 76 } 77 78 static void xelpg_pat_entry_dump(struct drm_printer *p, int index, u32 pat) 79 { 80 drm_printf(p, "PAT[%2d] = [ %u, %u ] (%#8x)\n", index, 81 REG_FIELD_GET(XELPG_L4_POLICY_MASK, pat), 82 REG_FIELD_GET(XELPG_INDEX_COH_MODE_MASK, pat), pat); 83 } 84 85 struct xe_pat_ops { 86 void (*program_graphics)(struct xe_gt *gt, const struct xe_pat_table_entry table[], 87 int n_entries); 88 void (*program_media)(struct xe_gt *gt, const struct xe_pat_table_entry table[], 89 int n_entries); 90 int (*dump)(struct xe_gt *gt, struct drm_printer *p); 91 }; 92 93 static const struct xe_pat_table_entry xelp_pat_table[] = { 94 [0] = { XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 95 [1] = { XELP_PAT_WC, XE_COH_NONE }, 96 [2] = { XELP_PAT_WT, XE_COH_NONE }, 97 [3] = { XELP_PAT_UC, XE_COH_NONE }, 98 }; 99 100 static const struct xe_pat_table_entry xehpc_pat_table[] = { 101 [0] = { XELP_PAT_UC, XE_COH_NONE }, 102 [1] = { XELP_PAT_WC, XE_COH_NONE }, 103 [2] = { XELP_PAT_WT, XE_COH_NONE }, 104 [3] = { XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 105 [4] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WT, XE_COH_NONE }, 106 [5] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 107 [6] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WT, XE_COH_NONE }, 108 [7] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 109 }; 110 111 static const struct xe_pat_table_entry xelpg_pat_table[] = { 112 [0] = { XELPG_PAT_0_WB, XE_COH_NONE }, 113 [1] = { XELPG_PAT_1_WT, XE_COH_NONE }, 114 [2] = { XELPG_PAT_3_UC, XE_COH_NONE }, 115 [3] = { XELPG_PAT_0_WB | XELPG_2_COH_1W, XE_COH_AT_LEAST_1WAY }, 116 [4] = { XELPG_PAT_0_WB | XELPG_3_COH_2W, XE_COH_AT_LEAST_1WAY }, 117 }; 118 119 /* 120 * The Xe2 table is getting large/complicated so it's easier to review if 121 * provided in a form that exactly matches the bspec's formatting. The meaning 122 * of the fields here are: 123 * - no_promote: 0=promotable, 1=no promote 124 * - comp_en: 0=disable, 1=enable 125 * - l3clos: L3 class of service (0-3) 126 * - l3_policy: 0=WB, 1=XD ("WB - Transient Display"), 3=UC 127 * - l4_policy: 0=WB, 1=WT, 3=UC 128 * - coh_mode: 0=no snoop, 2=1-way coherent, 3=2-way coherent 129 * 130 * Reserved entries should be programmed with the maximum caching, minimum 131 * coherency (which matches an all-0's encoding), so we can just omit them 132 * in the table. 133 * 134 * Note: There is an implicit assumption in the driver that compression and 135 * coh_1way+ are mutually exclusive for platforms prior to Xe3. Starting 136 * with Xe3, compression can be combined with coherency. If using compression 137 * with coherency, userptr and imported dma-buf from external device will 138 * have uncleared ccs state. See also xe_bo_needs_ccs_pages(). 139 */ 140 #define XE2_PAT(no_promote, comp_en, l3clos, l3_policy, l4_policy, __coh_mode) \ 141 { \ 142 .value = (no_promote ? XE2_NO_PROMOTE : 0) | \ 143 (comp_en ? XE2_COMP_EN : 0) | \ 144 REG_FIELD_PREP(XE2_L3_CLOS, l3clos) | \ 145 REG_FIELD_PREP(XE2_L3_POLICY, l3_policy) | \ 146 REG_FIELD_PREP(XE2_L4_POLICY, l4_policy) | \ 147 REG_FIELD_PREP(XE2_COH_MODE, __coh_mode), \ 148 .coh_mode = __coh_mode ? XE_COH_AT_LEAST_1WAY : XE_COH_NONE, \ 149 .valid = 1 \ 150 } 151 152 static const struct xe_pat_table_entry xe2_pat_table[] = { 153 [ 0] = XE2_PAT( 0, 0, 0, 0, 3, 0 ), 154 [ 1] = XE2_PAT( 0, 0, 0, 0, 3, 2 ), 155 [ 2] = XE2_PAT( 0, 0, 0, 0, 3, 3 ), 156 [ 3] = XE2_PAT( 0, 0, 0, 3, 3, 0 ), 157 [ 4] = XE2_PAT( 0, 0, 0, 3, 0, 2 ), 158 [ 5] = XE2_PAT( 0, 0, 0, 3, 3, 2 ), 159 [ 6] = XE2_PAT( 1, 0, 0, 1, 3, 0 ), 160 [ 7] = XE2_PAT( 0, 0, 0, 3, 0, 3 ), 161 [ 8] = XE2_PAT( 0, 0, 0, 3, 0, 0 ), 162 [ 9] = XE2_PAT( 0, 1, 0, 0, 3, 0 ), 163 [10] = XE2_PAT( 0, 1, 0, 3, 0, 0 ), 164 [11] = XE2_PAT( 1, 1, 0, 1, 3, 0 ), 165 [12] = XE2_PAT( 0, 1, 0, 3, 3, 0 ), 166 [13] = XE2_PAT( 0, 0, 0, 0, 0, 0 ), 167 [14] = XE2_PAT( 0, 1, 0, 0, 0, 0 ), 168 [15] = XE2_PAT( 1, 1, 0, 1, 1, 0 ), 169 /* 16..19 are reserved; leave set to all 0's */ 170 [20] = XE2_PAT( 0, 0, 1, 0, 3, 0 ), 171 [21] = XE2_PAT( 0, 1, 1, 0, 3, 0 ), 172 [22] = XE2_PAT( 0, 0, 1, 0, 3, 2 ), 173 [23] = XE2_PAT( 0, 0, 1, 0, 3, 3 ), 174 [24] = XE2_PAT( 0, 0, 2, 0, 3, 0 ), 175 [25] = XE2_PAT( 0, 1, 2, 0, 3, 0 ), 176 [26] = XE2_PAT( 0, 0, 2, 0, 3, 2 ), 177 [27] = XE2_PAT( 0, 0, 2, 0, 3, 3 ), 178 [28] = XE2_PAT( 0, 0, 3, 0, 3, 0 ), 179 [29] = XE2_PAT( 0, 1, 3, 0, 3, 0 ), 180 [30] = XE2_PAT( 0, 0, 3, 0, 3, 2 ), 181 [31] = XE2_PAT( 0, 0, 3, 0, 3, 3 ), 182 }; 183 184 static const struct xe_pat_table_entry xe3_lpg_pat_table[] = { 185 [ 0] = XE2_PAT( 0, 0, 0, 0, 3, 0 ), 186 [ 1] = XE2_PAT( 0, 0, 0, 0, 3, 2 ), 187 [ 2] = XE2_PAT( 0, 0, 0, 0, 3, 3 ), 188 [ 3] = XE2_PAT( 0, 0, 0, 3, 3, 0 ), 189 [ 4] = XE2_PAT( 0, 0, 0, 3, 0, 2 ), 190 [ 5] = XE2_PAT( 0, 0, 0, 3, 3, 2 ), 191 [ 6] = XE2_PAT( 1, 0, 0, 1, 3, 0 ), 192 [ 7] = XE2_PAT( 0, 0, 0, 3, 0, 3 ), 193 [ 8] = XE2_PAT( 0, 0, 0, 3, 0, 0 ), 194 [ 9] = XE2_PAT( 0, 1, 0, 0, 3, 0 ), 195 [10] = XE2_PAT( 0, 1, 0, 3, 0, 0 ), 196 [11] = XE2_PAT( 1, 1, 0, 1, 3, 0 ), 197 [12] = XE2_PAT( 0, 1, 0, 3, 3, 0 ), 198 [13] = XE2_PAT( 0, 0, 0, 0, 0, 0 ), 199 [14] = XE2_PAT( 0, 1, 0, 0, 0, 0 ), 200 [15] = XE2_PAT( 1, 1, 0, 1, 1, 0 ), 201 [16] = XE2_PAT( 0, 1, 0, 0, 3, 2 ), 202 /* 17..19 are reserved; leave set to all 0's */ 203 [20] = XE2_PAT( 0, 0, 1, 0, 3, 0 ), 204 [21] = XE2_PAT( 0, 1, 1, 0, 3, 0 ), 205 [22] = XE2_PAT( 0, 0, 1, 0, 3, 2 ), 206 [23] = XE2_PAT( 0, 0, 1, 0, 3, 3 ), 207 [24] = XE2_PAT( 0, 0, 2, 0, 3, 0 ), 208 [25] = XE2_PAT( 0, 1, 2, 0, 3, 0 ), 209 [26] = XE2_PAT( 0, 0, 2, 0, 3, 2 ), 210 [27] = XE2_PAT( 0, 0, 2, 0, 3, 3 ), 211 [28] = XE2_PAT( 0, 0, 3, 0, 3, 0 ), 212 [29] = XE2_PAT( 0, 1, 3, 0, 3, 0 ), 213 [30] = XE2_PAT( 0, 0, 3, 0, 3, 2 ), 214 [31] = XE2_PAT( 0, 0, 3, 0, 3, 3 ), 215 }; 216 /* Special PAT values programmed outside the main table */ 217 static const struct xe_pat_table_entry xe2_pat_ats = XE2_PAT( 0, 0, 0, 0, 3, 3 ); 218 static const struct xe_pat_table_entry xe2_pat_pta = XE2_PAT( 0, 0, 0, 0, 3, 0 ); 219 220 /* 221 * Xe3p_XPC PAT table uses the same layout as Xe2/Xe3, except that there's no 222 * option for compression. Also note that the "L3" and "L4" register fields 223 * actually control L2 and L3 cache respectively on this platform. 224 */ 225 #define XE3P_XPC_PAT(no_promote, l3clos, l3_policy, l4_policy, __coh_mode) \ 226 XE2_PAT(no_promote, 0, l3clos, l3_policy, l4_policy, __coh_mode) 227 228 static const struct xe_pat_table_entry xe3p_xpc_pat_ats = XE3P_XPC_PAT( 0, 0, 0, 0, 3 ); 229 static const struct xe_pat_table_entry xe3p_xpc_pat_pta = XE3P_XPC_PAT( 0, 0, 0, 0, 0 ); 230 231 static const struct xe_pat_table_entry xe3p_xpc_pat_table[] = { 232 [ 0] = XE3P_XPC_PAT( 0, 0, 0, 0, 0 ), 233 [ 1] = XE3P_XPC_PAT( 0, 0, 0, 0, 2 ), 234 [ 2] = XE3P_XPC_PAT( 0, 0, 0, 0, 3 ), 235 [ 3] = XE3P_XPC_PAT( 0, 0, 3, 3, 0 ), 236 [ 4] = XE3P_XPC_PAT( 0, 0, 3, 3, 2 ), 237 [ 5] = XE3P_XPC_PAT( 0, 0, 3, 0, 0 ), 238 [ 6] = XE3P_XPC_PAT( 0, 0, 3, 0, 2 ), 239 [ 7] = XE3P_XPC_PAT( 0, 0, 3, 0, 3 ), 240 [ 8] = XE3P_XPC_PAT( 0, 0, 0, 3, 0 ), 241 [ 9] = XE3P_XPC_PAT( 0, 0, 0, 3, 2 ), 242 [10] = XE3P_XPC_PAT( 0, 0, 0, 3, 3 ), 243 /* 11..22 are reserved; leave set to all 0's */ 244 [23] = XE3P_XPC_PAT( 0, 1, 0, 0, 0 ), 245 [24] = XE3P_XPC_PAT( 0, 1, 0, 0, 2 ), 246 [25] = XE3P_XPC_PAT( 0, 1, 0, 0, 3 ), 247 [26] = XE3P_XPC_PAT( 0, 2, 0, 0, 0 ), 248 [27] = XE3P_XPC_PAT( 0, 2, 0, 0, 2 ), 249 [28] = XE3P_XPC_PAT( 0, 2, 0, 0, 3 ), 250 [29] = XE3P_XPC_PAT( 0, 3, 0, 0, 0 ), 251 [30] = XE3P_XPC_PAT( 0, 3, 0, 0, 2 ), 252 [31] = XE3P_XPC_PAT( 0, 3, 0, 0, 3 ), 253 }; 254 255 u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index) 256 { 257 WARN_ON(pat_index >= xe->pat.n_entries); 258 return xe->pat.table[pat_index].coh_mode; 259 } 260 261 bool xe_pat_index_get_comp_en(struct xe_device *xe, u16 pat_index) 262 { 263 WARN_ON(pat_index >= xe->pat.n_entries); 264 return !!(xe->pat.table[pat_index].value & XE2_COMP_EN); 265 } 266 267 u16 xe_pat_index_get_l3_policy(struct xe_device *xe, u16 pat_index) 268 { 269 WARN_ON(pat_index >= xe->pat.n_entries); 270 271 return REG_FIELD_GET(XE2_L3_POLICY, xe->pat.table[pat_index].value); 272 } 273 274 static void program_pat(struct xe_gt *gt, const struct xe_pat_table_entry table[], 275 int n_entries) 276 { 277 struct xe_device *xe = gt_to_xe(gt); 278 279 for (int i = 0; i < n_entries; i++) { 280 struct xe_reg reg = XE_REG(_PAT_INDEX(i)); 281 282 xe_mmio_write32(>->mmio, reg, table[i].value); 283 } 284 285 if (xe->pat.pat_ats) 286 xe_mmio_write32(>->mmio, XE_REG(_PAT_ATS), xe->pat.pat_ats->value); 287 if (xe->pat.pat_pta) 288 xe_mmio_write32(>->mmio, XE_REG(_PAT_PTA), xe->pat.pat_pta->value); 289 } 290 291 static void program_pat_mcr(struct xe_gt *gt, const struct xe_pat_table_entry table[], 292 int n_entries) 293 { 294 struct xe_device *xe = gt_to_xe(gt); 295 296 for (int i = 0; i < n_entries; i++) { 297 struct xe_reg_mcr reg_mcr = XE_REG_MCR(_PAT_INDEX(i)); 298 299 xe_gt_mcr_multicast_write(gt, reg_mcr, table[i].value); 300 } 301 302 if (xe->pat.pat_ats) 303 xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_ATS), xe->pat.pat_ats->value); 304 if (xe->pat.pat_pta) 305 xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_PTA), xe->pat.pat_pta->value); 306 } 307 308 static int xelp_dump(struct xe_gt *gt, struct drm_printer *p) 309 { 310 struct xe_device *xe = gt_to_xe(gt); 311 int i; 312 313 CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); 314 if (!fw_ref.domains) 315 return -ETIMEDOUT; 316 317 drm_printf(p, "PAT table:\n"); 318 319 for (i = 0; i < xe->pat.n_entries; i++) { 320 u32 pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_INDEX(i))); 321 322 xelp_pat_entry_dump(p, i, pat); 323 } 324 325 return 0; 326 } 327 328 static const struct xe_pat_ops xelp_pat_ops = { 329 .program_graphics = program_pat, 330 .dump = xelp_dump, 331 }; 332 333 static int xehp_dump(struct xe_gt *gt, struct drm_printer *p) 334 { 335 struct xe_device *xe = gt_to_xe(gt); 336 int i; 337 338 CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); 339 if (!fw_ref.domains) 340 return -ETIMEDOUT; 341 342 drm_printf(p, "PAT table:\n"); 343 344 for (i = 0; i < xe->pat.n_entries; i++) { 345 u32 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); 346 347 xelp_pat_entry_dump(p, i, pat); 348 } 349 350 return 0; 351 } 352 353 static const struct xe_pat_ops xehp_pat_ops = { 354 .program_graphics = program_pat_mcr, 355 .dump = xehp_dump, 356 }; 357 358 static int xehpc_dump(struct xe_gt *gt, struct drm_printer *p) 359 { 360 struct xe_device *xe = gt_to_xe(gt); 361 int i; 362 363 CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); 364 if (!fw_ref.domains) 365 return -ETIMEDOUT; 366 367 drm_printf(p, "PAT table:\n"); 368 369 for (i = 0; i < xe->pat.n_entries; i++) { 370 u32 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); 371 372 xehpc_pat_entry_dump(p, i, pat); 373 } 374 375 return 0; 376 } 377 378 static const struct xe_pat_ops xehpc_pat_ops = { 379 .program_graphics = program_pat_mcr, 380 .dump = xehpc_dump, 381 }; 382 383 static int xelpg_dump(struct xe_gt *gt, struct drm_printer *p) 384 { 385 struct xe_device *xe = gt_to_xe(gt); 386 int i; 387 388 CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); 389 if (!fw_ref.domains) 390 return -ETIMEDOUT; 391 392 drm_printf(p, "PAT table:\n"); 393 394 for (i = 0; i < xe->pat.n_entries; i++) { 395 u32 pat; 396 397 if (xe_gt_is_media_type(gt)) 398 pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_INDEX(i))); 399 else 400 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); 401 402 xelpg_pat_entry_dump(p, i, pat); 403 } 404 405 return 0; 406 } 407 408 /* 409 * SAMedia register offsets are adjusted by the write methods and they target 410 * registers that are not MCR, while for normal GT they are MCR 411 */ 412 static const struct xe_pat_ops xelpg_pat_ops = { 413 .program_graphics = program_pat, 414 .program_media = program_pat_mcr, 415 .dump = xelpg_dump, 416 }; 417 418 static void xe2_pat_entry_dump(struct drm_printer *p, const char *label, u32 pat, bool rsvd) 419 { 420 drm_printf(p, "%s= [ %u, %u, %u, %u, %u, %u ] (%#8x)%s\n", label, 421 !!(pat & XE2_NO_PROMOTE), 422 !!(pat & XE2_COMP_EN), 423 REG_FIELD_GET(XE2_L3_CLOS, pat), 424 REG_FIELD_GET(XE2_L3_POLICY, pat), 425 REG_FIELD_GET(XE2_L4_POLICY, pat), 426 REG_FIELD_GET(XE2_COH_MODE, pat), 427 pat, rsvd ? " *" : ""); 428 } 429 430 static void xe3p_xpc_pat_entry_dump(struct drm_printer *p, const char *label, u32 pat, bool rsvd) 431 { 432 drm_printf(p, "%s= [ %u, %u, %u, %u, %u ] (%#8x)%s\n", label, 433 !!(pat & XE2_NO_PROMOTE), 434 REG_FIELD_GET(XE2_L3_CLOS, pat), 435 REG_FIELD_GET(XE2_L3_POLICY, pat), 436 REG_FIELD_GET(XE2_L4_POLICY, pat), 437 REG_FIELD_GET(XE2_COH_MODE, pat), 438 pat, rsvd ? " *" : ""); 439 } 440 441 static int xe2_dump(struct xe_gt *gt, struct drm_printer *p) 442 { 443 struct xe_device *xe = gt_to_xe(gt); 444 u32 pat; 445 int i; 446 char label[PAT_LABEL_LEN]; 447 448 CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); 449 if (!fw_ref.domains) 450 return -ETIMEDOUT; 451 452 drm_printf(p, "PAT table: (* = reserved entry)\n"); 453 454 for (i = 0; i < xe->pat.n_entries; i++) { 455 if (xe_gt_is_media_type(gt)) 456 pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_INDEX(i))); 457 else 458 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); 459 460 xe_pat_index_label(label, sizeof(label), i); 461 xe2_pat_entry_dump(p, label, pat, !xe->pat.table[i].valid); 462 } 463 464 /* 465 * Also print PTA_MODE, which describes how the hardware accesses 466 * PPGTT entries. 467 */ 468 if (xe_gt_is_media_type(gt)) 469 pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_PTA)); 470 else 471 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_PTA)); 472 473 drm_printf(p, "Page Table Access:\n"); 474 xe2_pat_entry_dump(p, "PTA_MODE", pat, false); 475 476 return 0; 477 } 478 479 static const struct xe_pat_ops xe2_pat_ops = { 480 .program_graphics = program_pat_mcr, 481 .program_media = program_pat, 482 .dump = xe2_dump, 483 }; 484 485 static int xe3p_xpc_dump(struct xe_gt *gt, struct drm_printer *p) 486 { 487 struct xe_device *xe = gt_to_xe(gt); 488 u32 pat; 489 int i; 490 char label[PAT_LABEL_LEN]; 491 492 CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); 493 if (!fw_ref.domains) 494 return -ETIMEDOUT; 495 496 drm_printf(p, "PAT table: (* = reserved entry)\n"); 497 498 for (i = 0; i < xe->pat.n_entries; i++) { 499 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); 500 501 xe_pat_index_label(label, sizeof(label), i); 502 xe3p_xpc_pat_entry_dump(p, label, pat, !xe->pat.table[i].valid); 503 } 504 505 /* 506 * Also print PTA_MODE, which describes how the hardware accesses 507 * PPGTT entries. 508 */ 509 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_PTA)); 510 511 drm_printf(p, "Page Table Access:\n"); 512 xe3p_xpc_pat_entry_dump(p, "PTA_MODE", pat, false); 513 514 return 0; 515 } 516 517 static const struct xe_pat_ops xe3p_xpc_pat_ops = { 518 .program_graphics = program_pat_mcr, 519 .program_media = program_pat, 520 .dump = xe3p_xpc_dump, 521 }; 522 523 void xe_pat_init_early(struct xe_device *xe) 524 { 525 xe->pat.idx[XE_CACHE_WB_COMPRESSION] = XE_PAT_INVALID_IDX; 526 if (GRAPHICS_VERx100(xe) == 3511) { 527 xe->pat.ops = &xe3p_xpc_pat_ops; 528 xe->pat.table = xe3p_xpc_pat_table; 529 xe->pat.pat_ats = &xe3p_xpc_pat_ats; 530 xe->pat.pat_pta = &xe3p_xpc_pat_pta; 531 xe->pat.n_entries = ARRAY_SIZE(xe3p_xpc_pat_table); 532 xe->pat.idx[XE_CACHE_NONE] = 3; 533 xe->pat.idx[XE_CACHE_WT] = 3; /* N/A (no display); use UC */ 534 xe->pat.idx[XE_CACHE_WB] = 2; 535 } else if (GRAPHICS_VER(xe) == 30 || GRAPHICS_VER(xe) == 20) { 536 xe->pat.ops = &xe2_pat_ops; 537 if (GRAPHICS_VER(xe) == 30) { 538 xe->pat.table = xe3_lpg_pat_table; 539 xe->pat.idx[XE_CACHE_WB_COMPRESSION] = 16; 540 } else { 541 xe->pat.table = xe2_pat_table; 542 } 543 xe->pat.pat_ats = &xe2_pat_ats; 544 if (IS_DGFX(xe)) 545 xe->pat.pat_pta = &xe2_pat_pta; 546 547 /* Wa_16023588340. XXX: Should use XE_WA */ 548 if (GRAPHICS_VERx100(xe) == 2001) 549 xe->pat.n_entries = 28; /* Disable CLOS3 */ 550 else 551 xe->pat.n_entries = ARRAY_SIZE(xe2_pat_table); 552 553 xe->pat.idx[XE_CACHE_NONE] = 3; 554 xe->pat.idx[XE_CACHE_WT] = 15; 555 xe->pat.idx[XE_CACHE_WB] = 2; 556 xe->pat.idx[XE_CACHE_NONE_COMPRESSION] = 12; /*Applicable on xe2 and beyond */ 557 } else if (xe->info.platform == XE_METEORLAKE) { 558 xe->pat.ops = &xelpg_pat_ops; 559 xe->pat.table = xelpg_pat_table; 560 xe->pat.n_entries = ARRAY_SIZE(xelpg_pat_table); 561 xe->pat.idx[XE_CACHE_NONE] = 2; 562 xe->pat.idx[XE_CACHE_WT] = 1; 563 xe->pat.idx[XE_CACHE_WB] = 3; 564 } else if (xe->info.platform == XE_PVC) { 565 xe->pat.ops = &xehpc_pat_ops; 566 xe->pat.table = xehpc_pat_table; 567 xe->pat.n_entries = ARRAY_SIZE(xehpc_pat_table); 568 xe->pat.idx[XE_CACHE_NONE] = 0; 569 xe->pat.idx[XE_CACHE_WT] = 2; 570 xe->pat.idx[XE_CACHE_WB] = 3; 571 } else if (xe->info.platform == XE_DG2) { 572 /* 573 * Table is the same as previous platforms, but programming 574 * method has changed. 575 */ 576 xe->pat.ops = &xehp_pat_ops; 577 xe->pat.table = xelp_pat_table; 578 xe->pat.n_entries = ARRAY_SIZE(xelp_pat_table); 579 xe->pat.idx[XE_CACHE_NONE] = 3; 580 xe->pat.idx[XE_CACHE_WT] = 2; 581 xe->pat.idx[XE_CACHE_WB] = 0; 582 } else if (GRAPHICS_VERx100(xe) <= 1210) { 583 WARN_ON_ONCE(!IS_DGFX(xe) && !xe->info.has_llc); 584 xe->pat.ops = &xelp_pat_ops; 585 xe->pat.table = xelp_pat_table; 586 xe->pat.n_entries = ARRAY_SIZE(xelp_pat_table); 587 xe->pat.idx[XE_CACHE_NONE] = 3; 588 xe->pat.idx[XE_CACHE_WT] = 2; 589 xe->pat.idx[XE_CACHE_WB] = 0; 590 } else { 591 /* 592 * Going forward we expect to need new PAT settings for most 593 * new platforms; failure to provide a new table can easily 594 * lead to subtle, hard-to-debug problems. If none of the 595 * conditions above match the platform we're running on we'll 596 * raise an error rather than trying to silently inherit the 597 * most recent platform's behavior. 598 */ 599 drm_err(&xe->drm, "Missing PAT table for platform with graphics version %d.%02d!\n", 600 GRAPHICS_VER(xe), GRAPHICS_VERx100(xe) % 100); 601 } 602 603 /* VFs can't program nor dump PAT settings */ 604 if (IS_SRIOV_VF(xe)) 605 xe->pat.ops = NULL; 606 607 xe_assert(xe, !xe->pat.ops || xe->pat.ops->dump); 608 xe_assert(xe, !xe->pat.ops || xe->pat.ops->program_graphics); 609 xe_assert(xe, !xe->pat.ops || MEDIA_VER(xe) < 13 || xe->pat.ops->program_media); 610 } 611 612 void xe_pat_init(struct xe_gt *gt) 613 { 614 struct xe_device *xe = gt_to_xe(gt); 615 616 if (!xe->pat.ops) 617 return; 618 619 if (xe_gt_is_media_type(gt)) 620 xe->pat.ops->program_media(gt, xe->pat.table, xe->pat.n_entries); 621 else 622 xe->pat.ops->program_graphics(gt, xe->pat.table, xe->pat.n_entries); 623 } 624 625 /** 626 * xe_pat_dump() - Dump GT PAT table into a drm printer. 627 * @gt: the &xe_gt 628 * @p: the &drm_printer 629 * 630 * Return: 0 on success or a negative error code on failure. 631 */ 632 int xe_pat_dump(struct xe_gt *gt, struct drm_printer *p) 633 { 634 struct xe_device *xe = gt_to_xe(gt); 635 636 if (!xe->pat.ops) 637 return -EOPNOTSUPP; 638 639 return xe->pat.ops->dump(gt, p); 640 } 641 642 /** 643 * xe_pat_dump_sw_config() - Dump the software-configured GT PAT table into a drm printer. 644 * @gt: the &xe_gt 645 * @p: the &drm_printer 646 * 647 * Return: 0 on success or a negative error code on failure. 648 */ 649 int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p) 650 { 651 struct xe_device *xe = gt_to_xe(gt); 652 char label[PAT_LABEL_LEN]; 653 654 if (!xe->pat.table || !xe->pat.n_entries) 655 return -EOPNOTSUPP; 656 657 drm_printf(p, "PAT table:%s\n", GRAPHICS_VER(xe) >= 20 ? " (* = reserved entry)" : ""); 658 for (u32 i = 0; i < xe->pat.n_entries; i++) { 659 u32 pat = xe->pat.table[i].value; 660 661 if (GRAPHICS_VERx100(xe) == 3511) { 662 xe_pat_index_label(label, sizeof(label), i); 663 xe3p_xpc_pat_entry_dump(p, label, pat, !xe->pat.table[i].valid); 664 } else if (GRAPHICS_VER(xe) == 30 || GRAPHICS_VER(xe) == 20) { 665 xe_pat_index_label(label, sizeof(label), i); 666 xe2_pat_entry_dump(p, label, pat, !xe->pat.table[i].valid); 667 } else if (xe->info.platform == XE_METEORLAKE) { 668 xelpg_pat_entry_dump(p, i, pat); 669 } else if (xe->info.platform == XE_PVC) { 670 xehpc_pat_entry_dump(p, i, pat); 671 } else if (xe->info.platform == XE_DG2 || GRAPHICS_VERx100(xe) <= 1210) { 672 xelp_pat_entry_dump(p, i, pat); 673 } else { 674 return -EOPNOTSUPP; 675 } 676 } 677 678 if (xe->pat.pat_pta) { 679 u32 pat = xe->pat.pat_pta->value; 680 681 drm_printf(p, "Page Table Access:\n"); 682 xe2_pat_entry_dump(p, "PTA_MODE", pat, false); 683 } 684 685 if (xe->pat.pat_ats) { 686 u32 pat = xe->pat.pat_ats->value; 687 688 drm_printf(p, "PCIe ATS/PASID:\n"); 689 xe2_pat_entry_dump(p, "PAT_ATS ", pat, false); 690 } 691 692 drm_printf(p, "Cache Level:\n"); 693 drm_printf(p, "IDX[XE_CACHE_NONE] = %d\n", xe->pat.idx[XE_CACHE_NONE]); 694 drm_printf(p, "IDX[XE_CACHE_WT] = %d\n", xe->pat.idx[XE_CACHE_WT]); 695 drm_printf(p, "IDX[XE_CACHE_WB] = %d\n", xe->pat.idx[XE_CACHE_WB]); 696 if (GRAPHICS_VER(xe) >= 20) { 697 drm_printf(p, "IDX[XE_CACHE_NONE_COMPRESSION] = %d\n", 698 xe->pat.idx[XE_CACHE_NONE_COMPRESSION]); 699 drm_printf(p, "IDX[XE_CACHE_WB_COMPRESSION] = %d\n", 700 xe->pat.idx[XE_CACHE_WB_COMPRESSION]); 701 } 702 703 return 0; 704 } 705