1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include "xe_pat.h" 7 8 #include <drm/xe_drm.h> 9 10 #include "regs/xe_reg_defs.h" 11 #include "xe_assert.h" 12 #include "xe_device.h" 13 #include "xe_gt.h" 14 #include "xe_gt_mcr.h" 15 #include "xe_mmio.h" 16 #include "xe_sriov.h" 17 18 #define _PAT_ATS 0x47fc 19 #define _PAT_INDEX(index) _PICK_EVEN_2RANGES(index, 8, \ 20 0x4800, 0x4804, \ 21 0x4848, 0x484c) 22 #define _PAT_PTA 0x4820 23 24 #define XE2_NO_PROMOTE REG_BIT(10) 25 #define XE2_COMP_EN REG_BIT(9) 26 #define XE2_L3_CLOS REG_GENMASK(7, 6) 27 #define XE2_L3_POLICY REG_GENMASK(5, 4) 28 #define XE2_L4_POLICY REG_GENMASK(3, 2) 29 #define XE2_COH_MODE REG_GENMASK(1, 0) 30 31 #define XELPG_L4_POLICY_MASK REG_GENMASK(3, 2) 32 #define XELPG_PAT_3_UC REG_FIELD_PREP(XELPG_L4_POLICY_MASK, 3) 33 #define XELPG_PAT_1_WT REG_FIELD_PREP(XELPG_L4_POLICY_MASK, 1) 34 #define XELPG_PAT_0_WB REG_FIELD_PREP(XELPG_L4_POLICY_MASK, 0) 35 #define XELPG_INDEX_COH_MODE_MASK REG_GENMASK(1, 0) 36 #define XELPG_3_COH_2W REG_FIELD_PREP(XELPG_INDEX_COH_MODE_MASK, 3) 37 #define XELPG_2_COH_1W REG_FIELD_PREP(XELPG_INDEX_COH_MODE_MASK, 2) 38 #define XELPG_0_COH_NON REG_FIELD_PREP(XELPG_INDEX_COH_MODE_MASK, 0) 39 40 #define XEHPC_CLOS_LEVEL_MASK REG_GENMASK(3, 2) 41 #define XEHPC_PAT_CLOS(x) REG_FIELD_PREP(XEHPC_CLOS_LEVEL_MASK, x) 42 43 #define XELP_MEM_TYPE_MASK REG_GENMASK(1, 0) 44 #define XELP_PAT_WB REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 3) 45 #define XELP_PAT_WT REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 2) 46 #define XELP_PAT_WC REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 1) 47 #define XELP_PAT_UC REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 0) 48 49 static const char *XELP_MEM_TYPE_STR_MAP[] = { "UC", "WC", "WT", "WB" }; 50 51 struct xe_pat_ops { 52 void (*program_graphics)(struct xe_gt *gt, const struct xe_pat_table_entry table[], 53 int n_entries); 54 void (*program_media)(struct xe_gt *gt, const struct xe_pat_table_entry table[], 55 int n_entries); 56 void (*dump)(struct xe_gt *gt, struct drm_printer *p); 57 }; 58 59 static const struct xe_pat_table_entry xelp_pat_table[] = { 60 [0] = { XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 61 [1] = { XELP_PAT_WC, XE_COH_NONE }, 62 [2] = { XELP_PAT_WT, XE_COH_NONE }, 63 [3] = { XELP_PAT_UC, XE_COH_NONE }, 64 }; 65 66 static const struct xe_pat_table_entry xehpc_pat_table[] = { 67 [0] = { XELP_PAT_UC, XE_COH_NONE }, 68 [1] = { XELP_PAT_WC, XE_COH_NONE }, 69 [2] = { XELP_PAT_WT, XE_COH_NONE }, 70 [3] = { XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 71 [4] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WT, XE_COH_NONE }, 72 [5] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 73 [6] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WT, XE_COH_NONE }, 74 [7] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WB, XE_COH_AT_LEAST_1WAY }, 75 }; 76 77 static const struct xe_pat_table_entry xelpg_pat_table[] = { 78 [0] = { XELPG_PAT_0_WB, XE_COH_NONE }, 79 [1] = { XELPG_PAT_1_WT, XE_COH_NONE }, 80 [2] = { XELPG_PAT_3_UC, XE_COH_NONE }, 81 [3] = { XELPG_PAT_0_WB | XELPG_2_COH_1W, XE_COH_AT_LEAST_1WAY }, 82 [4] = { XELPG_PAT_0_WB | XELPG_3_COH_2W, XE_COH_AT_LEAST_1WAY }, 83 }; 84 85 /* 86 * The Xe2 table is getting large/complicated so it's easier to review if 87 * provided in a form that exactly matches the bspec's formatting. The meaning 88 * of the fields here are: 89 * - no_promote: 0=promotable, 1=no promote 90 * - comp_en: 0=disable, 1=enable 91 * - l3clos: L3 class of service (0-3) 92 * - l3_policy: 0=WB, 1=XD ("WB - Transient Display"), 3=UC 93 * - l4_policy: 0=WB, 1=WT, 3=UC 94 * - coh_mode: 0=no snoop, 2=1-way coherent, 3=2-way coherent 95 * 96 * Reserved entries should be programmed with the maximum caching, minimum 97 * coherency (which matches an all-0's encoding), so we can just omit them 98 * in the table. 99 */ 100 #define XE2_PAT(no_promote, comp_en, l3clos, l3_policy, l4_policy, __coh_mode) \ 101 { \ 102 .value = (no_promote ? XE2_NO_PROMOTE : 0) | \ 103 (comp_en ? XE2_COMP_EN : 0) | \ 104 REG_FIELD_PREP(XE2_L3_CLOS, l3clos) | \ 105 REG_FIELD_PREP(XE2_L3_POLICY, l3_policy) | \ 106 REG_FIELD_PREP(XE2_L4_POLICY, l4_policy) | \ 107 REG_FIELD_PREP(XE2_COH_MODE, __coh_mode), \ 108 .coh_mode = __coh_mode ? XE_COH_AT_LEAST_1WAY : XE_COH_NONE \ 109 } 110 111 static const struct xe_pat_table_entry xe2_pat_table[] = { 112 [ 0] = XE2_PAT( 0, 0, 0, 0, 3, 0 ), 113 [ 1] = XE2_PAT( 0, 0, 0, 0, 3, 2 ), 114 [ 2] = XE2_PAT( 0, 0, 0, 0, 3, 3 ), 115 [ 3] = XE2_PAT( 0, 0, 0, 3, 3, 0 ), 116 [ 4] = XE2_PAT( 0, 0, 0, 3, 0, 2 ), 117 [ 5] = XE2_PAT( 0, 0, 0, 3, 3, 2 ), 118 [ 6] = XE2_PAT( 1, 0, 0, 1, 3, 0 ), 119 [ 7] = XE2_PAT( 0, 0, 0, 3, 0, 3 ), 120 [ 8] = XE2_PAT( 0, 0, 0, 3, 0, 0 ), 121 [ 9] = XE2_PAT( 0, 1, 0, 0, 3, 0 ), 122 [10] = XE2_PAT( 0, 1, 0, 3, 0, 0 ), 123 [11] = XE2_PAT( 1, 1, 0, 1, 3, 0 ), 124 [12] = XE2_PAT( 0, 1, 0, 3, 3, 0 ), 125 [13] = XE2_PAT( 0, 0, 0, 0, 0, 0 ), 126 [14] = XE2_PAT( 0, 1, 0, 0, 0, 0 ), 127 [15] = XE2_PAT( 1, 1, 0, 1, 1, 0 ), 128 /* 16..19 are reserved; leave set to all 0's */ 129 [20] = XE2_PAT( 0, 0, 1, 0, 3, 0 ), 130 [21] = XE2_PAT( 0, 1, 1, 0, 3, 0 ), 131 [22] = XE2_PAT( 0, 0, 1, 0, 3, 2 ), 132 [23] = XE2_PAT( 0, 0, 1, 0, 3, 3 ), 133 [24] = XE2_PAT( 0, 0, 2, 0, 3, 0 ), 134 [25] = XE2_PAT( 0, 1, 2, 0, 3, 0 ), 135 [26] = XE2_PAT( 0, 0, 2, 0, 3, 2 ), 136 [27] = XE2_PAT( 0, 0, 2, 0, 3, 3 ), 137 [28] = XE2_PAT( 0, 0, 3, 0, 3, 0 ), 138 [29] = XE2_PAT( 0, 1, 3, 0, 3, 0 ), 139 [30] = XE2_PAT( 0, 0, 3, 0, 3, 2 ), 140 [31] = XE2_PAT( 0, 0, 3, 0, 3, 3 ), 141 }; 142 143 /* Special PAT values programmed outside the main table */ 144 static const struct xe_pat_table_entry xe2_pat_ats = XE2_PAT( 0, 0, 0, 0, 3, 3 ); 145 static const struct xe_pat_table_entry xe2_pat_pta = XE2_PAT( 0, 0, 0, 0, 3, 0 ); 146 147 u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index) 148 { 149 WARN_ON(pat_index >= xe->pat.n_entries); 150 return xe->pat.table[pat_index].coh_mode; 151 } 152 153 static void program_pat(struct xe_gt *gt, const struct xe_pat_table_entry table[], 154 int n_entries) 155 { 156 for (int i = 0; i < n_entries; i++) { 157 struct xe_reg reg = XE_REG(_PAT_INDEX(i)); 158 159 xe_mmio_write32(gt, reg, table[i].value); 160 } 161 } 162 163 static void program_pat_mcr(struct xe_gt *gt, const struct xe_pat_table_entry table[], 164 int n_entries) 165 { 166 for (int i = 0; i < n_entries; i++) { 167 struct xe_reg_mcr reg_mcr = XE_REG_MCR(_PAT_INDEX(i)); 168 169 xe_gt_mcr_multicast_write(gt, reg_mcr, table[i].value); 170 } 171 } 172 173 static void xelp_dump(struct xe_gt *gt, struct drm_printer *p) 174 { 175 struct xe_device *xe = gt_to_xe(gt); 176 int i, err; 177 178 err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); 179 if (err) 180 goto err_fw; 181 182 drm_printf(p, "PAT table:\n"); 183 184 for (i = 0; i < xe->pat.n_entries; i++) { 185 u32 pat = xe_mmio_read32(gt, XE_REG(_PAT_INDEX(i))); 186 u8 mem_type = REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat); 187 188 drm_printf(p, "PAT[%2d] = %s (%#8x)\n", i, 189 XELP_MEM_TYPE_STR_MAP[mem_type], pat); 190 } 191 192 err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); 193 err_fw: 194 xe_assert(xe, !err); 195 } 196 197 static const struct xe_pat_ops xelp_pat_ops = { 198 .program_graphics = program_pat, 199 .dump = xelp_dump, 200 }; 201 202 static void xehp_dump(struct xe_gt *gt, struct drm_printer *p) 203 { 204 struct xe_device *xe = gt_to_xe(gt); 205 int i, err; 206 207 err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); 208 if (err) 209 goto err_fw; 210 211 drm_printf(p, "PAT table:\n"); 212 213 for (i = 0; i < xe->pat.n_entries; i++) { 214 u32 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); 215 u8 mem_type; 216 217 mem_type = REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat); 218 219 drm_printf(p, "PAT[%2d] = %s (%#8x)\n", i, 220 XELP_MEM_TYPE_STR_MAP[mem_type], pat); 221 } 222 223 err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); 224 err_fw: 225 xe_assert(xe, !err); 226 } 227 228 static const struct xe_pat_ops xehp_pat_ops = { 229 .program_graphics = program_pat_mcr, 230 .dump = xehp_dump, 231 }; 232 233 static void xehpc_dump(struct xe_gt *gt, struct drm_printer *p) 234 { 235 struct xe_device *xe = gt_to_xe(gt); 236 int i, err; 237 238 err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); 239 if (err) 240 goto err_fw; 241 242 drm_printf(p, "PAT table:\n"); 243 244 for (i = 0; i < xe->pat.n_entries; i++) { 245 u32 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); 246 247 drm_printf(p, "PAT[%2d] = [ %u, %u ] (%#8x)\n", i, 248 REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat), 249 REG_FIELD_GET(XEHPC_CLOS_LEVEL_MASK, pat), pat); 250 } 251 252 err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); 253 err_fw: 254 xe_assert(xe, !err); 255 } 256 257 static const struct xe_pat_ops xehpc_pat_ops = { 258 .program_graphics = program_pat_mcr, 259 .dump = xehpc_dump, 260 }; 261 262 static void xelpg_dump(struct xe_gt *gt, struct drm_printer *p) 263 { 264 struct xe_device *xe = gt_to_xe(gt); 265 int i, err; 266 267 err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); 268 if (err) 269 goto err_fw; 270 271 drm_printf(p, "PAT table:\n"); 272 273 for (i = 0; i < xe->pat.n_entries; i++) { 274 u32 pat; 275 276 if (xe_gt_is_media_type(gt)) 277 pat = xe_mmio_read32(gt, XE_REG(_PAT_INDEX(i))); 278 else 279 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); 280 281 drm_printf(p, "PAT[%2d] = [ %u, %u ] (%#8x)\n", i, 282 REG_FIELD_GET(XELPG_L4_POLICY_MASK, pat), 283 REG_FIELD_GET(XELPG_INDEX_COH_MODE_MASK, pat), pat); 284 } 285 286 err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); 287 err_fw: 288 xe_assert(xe, !err); 289 } 290 291 /* 292 * SAMedia register offsets are adjusted by the write methods and they target 293 * registers that are not MCR, while for normal GT they are MCR 294 */ 295 static const struct xe_pat_ops xelpg_pat_ops = { 296 .program_graphics = program_pat, 297 .program_media = program_pat_mcr, 298 .dump = xelpg_dump, 299 }; 300 301 static void xe2lpg_program_pat(struct xe_gt *gt, const struct xe_pat_table_entry table[], 302 int n_entries) 303 { 304 program_pat_mcr(gt, table, n_entries); 305 xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_ATS), xe2_pat_ats.value); 306 307 if (IS_DGFX(gt_to_xe(gt))) 308 xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_PTA), xe2_pat_pta.value); 309 } 310 311 static void xe2lpm_program_pat(struct xe_gt *gt, const struct xe_pat_table_entry table[], 312 int n_entries) 313 { 314 program_pat(gt, table, n_entries); 315 xe_mmio_write32(gt, XE_REG(_PAT_ATS), xe2_pat_ats.value); 316 317 if (IS_DGFX(gt_to_xe(gt))) 318 xe_mmio_write32(gt, XE_REG(_PAT_PTA), xe2_pat_pta.value); 319 } 320 321 static void xe2_dump(struct xe_gt *gt, struct drm_printer *p) 322 { 323 struct xe_device *xe = gt_to_xe(gt); 324 int i, err; 325 u32 pat; 326 327 err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); 328 if (err) 329 goto err_fw; 330 331 drm_printf(p, "PAT table:\n"); 332 333 for (i = 0; i < xe->pat.n_entries; i++) { 334 if (xe_gt_is_media_type(gt)) 335 pat = xe_mmio_read32(gt, XE_REG(_PAT_INDEX(i))); 336 else 337 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); 338 339 drm_printf(p, "PAT[%2d] = [ %u, %u, %u, %u, %u, %u ] (%#8x)\n", i, 340 !!(pat & XE2_NO_PROMOTE), 341 !!(pat & XE2_COMP_EN), 342 REG_FIELD_GET(XE2_L3_CLOS, pat), 343 REG_FIELD_GET(XE2_L3_POLICY, pat), 344 REG_FIELD_GET(XE2_L4_POLICY, pat), 345 REG_FIELD_GET(XE2_COH_MODE, pat), 346 pat); 347 } 348 349 /* 350 * Also print PTA_MODE, which describes how the hardware accesses 351 * PPGTT entries. 352 */ 353 if (xe_gt_is_media_type(gt)) 354 pat = xe_mmio_read32(gt, XE_REG(_PAT_PTA)); 355 else 356 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_PTA)); 357 358 drm_printf(p, "Page Table Access:\n"); 359 drm_printf(p, "PTA_MODE= [ %u, %u, %u, %u, %u, %u ] (%#8x)\n", 360 !!(pat & XE2_NO_PROMOTE), 361 !!(pat & XE2_COMP_EN), 362 REG_FIELD_GET(XE2_L3_CLOS, pat), 363 REG_FIELD_GET(XE2_L3_POLICY, pat), 364 REG_FIELD_GET(XE2_L4_POLICY, pat), 365 REG_FIELD_GET(XE2_COH_MODE, pat), 366 pat); 367 368 err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); 369 err_fw: 370 xe_assert(xe, !err); 371 } 372 373 static const struct xe_pat_ops xe2_pat_ops = { 374 .program_graphics = xe2lpg_program_pat, 375 .program_media = xe2lpm_program_pat, 376 .dump = xe2_dump, 377 }; 378 379 void xe_pat_init_early(struct xe_device *xe) 380 { 381 if (GRAPHICS_VER(xe) == 20) { 382 xe->pat.ops = &xe2_pat_ops; 383 xe->pat.table = xe2_pat_table; 384 xe->pat.n_entries = ARRAY_SIZE(xe2_pat_table); 385 xe->pat.idx[XE_CACHE_NONE] = 3; 386 xe->pat.idx[XE_CACHE_WT] = 15; 387 xe->pat.idx[XE_CACHE_WB] = 2; 388 xe->pat.idx[XE_CACHE_NONE_COMPRESSION] = 12; /*Applicable on xe2 and beyond */ 389 } else if (xe->info.platform == XE_METEORLAKE) { 390 xe->pat.ops = &xelpg_pat_ops; 391 xe->pat.table = xelpg_pat_table; 392 xe->pat.n_entries = ARRAY_SIZE(xelpg_pat_table); 393 xe->pat.idx[XE_CACHE_NONE] = 2; 394 xe->pat.idx[XE_CACHE_WT] = 1; 395 xe->pat.idx[XE_CACHE_WB] = 3; 396 } else if (xe->info.platform == XE_PVC) { 397 xe->pat.ops = &xehpc_pat_ops; 398 xe->pat.table = xehpc_pat_table; 399 xe->pat.n_entries = ARRAY_SIZE(xehpc_pat_table); 400 xe->pat.idx[XE_CACHE_NONE] = 0; 401 xe->pat.idx[XE_CACHE_WT] = 2; 402 xe->pat.idx[XE_CACHE_WB] = 3; 403 } else if (xe->info.platform == XE_DG2) { 404 /* 405 * Table is the same as previous platforms, but programming 406 * method has changed. 407 */ 408 xe->pat.ops = &xehp_pat_ops; 409 xe->pat.table = xelp_pat_table; 410 xe->pat.n_entries = ARRAY_SIZE(xelp_pat_table); 411 xe->pat.idx[XE_CACHE_NONE] = 3; 412 xe->pat.idx[XE_CACHE_WT] = 2; 413 xe->pat.idx[XE_CACHE_WB] = 0; 414 } else if (GRAPHICS_VERx100(xe) <= 1210) { 415 WARN_ON_ONCE(!IS_DGFX(xe) && !xe->info.has_llc); 416 xe->pat.ops = &xelp_pat_ops; 417 xe->pat.table = xelp_pat_table; 418 xe->pat.n_entries = ARRAY_SIZE(xelp_pat_table); 419 xe->pat.idx[XE_CACHE_NONE] = 3; 420 xe->pat.idx[XE_CACHE_WT] = 2; 421 xe->pat.idx[XE_CACHE_WB] = 0; 422 } else { 423 /* 424 * Going forward we expect to need new PAT settings for most 425 * new platforms; failure to provide a new table can easily 426 * lead to subtle, hard-to-debug problems. If none of the 427 * conditions above match the platform we're running on we'll 428 * raise an error rather than trying to silently inherit the 429 * most recent platform's behavior. 430 */ 431 drm_err(&xe->drm, "Missing PAT table for platform with graphics version %d.%02d!\n", 432 GRAPHICS_VER(xe), GRAPHICS_VERx100(xe) % 100); 433 } 434 435 /* VFs can't program nor dump PAT settings */ 436 if (IS_SRIOV_VF(xe)) 437 xe->pat.ops = NULL; 438 439 xe_assert(xe, !xe->pat.ops || xe->pat.ops->dump); 440 xe_assert(xe, !xe->pat.ops || xe->pat.ops->program_graphics); 441 xe_assert(xe, !xe->pat.ops || MEDIA_VER(xe) < 13 || xe->pat.ops->program_media); 442 } 443 444 void xe_pat_init(struct xe_gt *gt) 445 { 446 struct xe_device *xe = gt_to_xe(gt); 447 448 if (!xe->pat.ops) 449 return; 450 451 if (xe_gt_is_media_type(gt)) 452 xe->pat.ops->program_media(gt, xe->pat.table, xe->pat.n_entries); 453 else 454 xe->pat.ops->program_graphics(gt, xe->pat.table, xe->pat.n_entries); 455 } 456 457 void xe_pat_dump(struct xe_gt *gt, struct drm_printer *p) 458 { 459 struct xe_device *xe = gt_to_xe(gt); 460 461 if (!xe->pat.ops) 462 return; 463 464 xe->pat.ops->dump(gt, p); 465 } 466