1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2015 Intel Corporation 4 */ 5 6 #include <drm/drm_print.h> 7 8 #include "i915_drv.h" 9 10 #include "intel_engine.h" 11 #include "intel_gt.h" 12 #include "intel_gt_mcr.h" 13 #include "intel_gt_regs.h" 14 #include "intel_mocs.h" 15 #include "intel_ring.h" 16 17 /* structures required */ 18 struct drm_i915_mocs_entry { 19 u32 control_value; 20 u16 l3cc_value; 21 u16 used; 22 }; 23 24 struct drm_i915_mocs_table { 25 unsigned int size; 26 unsigned int n_entries; 27 const struct drm_i915_mocs_entry *table; 28 u8 uc_index; 29 u8 wb_index; /* Only used on HAS_L3_CCS_READ() platforms */ 30 u8 unused_entries_index; 31 }; 32 33 /* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */ 34 #define _LE_CACHEABILITY(value) ((value) << 0) 35 #define _LE_TGT_CACHE(value) ((value) << 2) 36 #define LE_LRUM(value) ((value) << 4) 37 #define LE_AOM(value) ((value) << 6) 38 #define LE_RSC(value) ((value) << 7) 39 #define LE_SCC(value) ((value) << 8) 40 #define LE_PFM(value) ((value) << 11) 41 #define LE_SCF(value) ((value) << 14) 42 #define LE_COS(value) ((value) << 15) 43 #define LE_SSE(value) ((value) << 17) 44 45 /* Defines for the tables (GLOB_MOCS_0 - GLOB_MOCS_16) */ 46 #define _L4_CACHEABILITY(value) ((value) << 2) 47 #define IG_PAT(value) ((value) << 8) 48 49 /* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */ 50 #define L3_ESC(value) ((value) << 0) 51 #define L3_SCC(value) ((value) << 1) 52 #define _L3_CACHEABILITY(value) ((value) << 4) 53 #define L3_GLBGO(value) ((value) << 6) 54 #define L3_LKUP(value) ((value) << 7) 55 56 /* Helper defines */ 57 #define GEN9_NUM_MOCS_ENTRIES 64 /* 63-64 are reserved, but configured. */ 58 #define MTL_NUM_MOCS_ENTRIES 16 59 60 /* (e)LLC caching options */ 61 /* 62 * Note: LE_0_PAGETABLE works only up to Gen11; for newer gens it means 63 * the same as LE_UC 64 */ 65 #define LE_0_PAGETABLE _LE_CACHEABILITY(0) 66 #define LE_1_UC _LE_CACHEABILITY(1) 67 #define LE_2_WT _LE_CACHEABILITY(2) 68 #define LE_3_WB _LE_CACHEABILITY(3) 69 70 /* Target cache */ 71 #define LE_TC_0_PAGETABLE _LE_TGT_CACHE(0) 72 #define LE_TC_1_LLC _LE_TGT_CACHE(1) 73 #define LE_TC_2_LLC_ELLC _LE_TGT_CACHE(2) 74 #define LE_TC_3_LLC_ELLC_ALT _LE_TGT_CACHE(3) 75 76 /* L3 caching options */ 77 #define L3_0_DIRECT _L3_CACHEABILITY(0) 78 #define L3_1_UC _L3_CACHEABILITY(1) 79 #define L3_2_RESERVED _L3_CACHEABILITY(2) 80 #define L3_3_WB _L3_CACHEABILITY(3) 81 82 /* L4 caching options */ 83 #define L4_0_WB _L4_CACHEABILITY(0) 84 #define L4_1_WT _L4_CACHEABILITY(1) 85 #define L4_2_RESERVED _L4_CACHEABILITY(2) 86 #define L4_3_UC _L4_CACHEABILITY(3) 87 88 #define MOCS_ENTRY(__idx, __control_value, __l3cc_value) \ 89 [__idx] = { \ 90 .control_value = __control_value, \ 91 .l3cc_value = __l3cc_value, \ 92 .used = 1, \ 93 } 94 95 /* 96 * MOCS tables 97 * 98 * These are the MOCS tables that are programmed across all the rings. 99 * The control value is programmed to all the rings that support the 100 * MOCS registers. While the l3cc_values are only programmed to the 101 * LNCFCMOCS0 - LNCFCMOCS32 registers. 102 * 103 * These tables are intended to be kept reasonably consistent across 104 * HW platforms, and for ICL+, be identical across OSes. To achieve 105 * that, for Icelake and above, list of entries is published as part 106 * of bspec. 107 * 108 * Entries not part of the following tables are undefined as far as 109 * userspace is concerned and shouldn't be relied upon. For Gen < 12 110 * they will be initialized to PTE. Gen >= 12 don't have a setting for 111 * PTE and those platforms except TGL/RKL will be initialized L3 WB to 112 * catch accidental use of reserved and unused mocs indexes. 113 * 114 * The last few entries are reserved by the hardware. For ICL+ they 115 * should be initialized according to bspec and never used, for older 116 * platforms they should never be written to. 117 * 118 * NOTE1: These tables are part of bspec and defined as part of hardware 119 * interface for ICL+. For older platforms, they are part of kernel 120 * ABI. It is expected that, for specific hardware platform, existing 121 * entries will remain constant and the table will only be updated by 122 * adding new entries, filling unused positions. 123 * 124 * NOTE2: For GEN >= 12 except TGL and RKL, reserved and unspecified MOCS 125 * indices have been set to L3 WB. These reserved entries should never 126 * be used, they may be changed to low performant variants with better 127 * coherency in the future if more entries are needed. 128 * For TGL/RKL, all the unspecified MOCS indexes are mapped to L3 UC. 129 */ 130 #define GEN9_MOCS_ENTRIES \ 131 MOCS_ENTRY(I915_MOCS_UNCACHED, \ 132 LE_1_UC | LE_TC_2_LLC_ELLC, \ 133 L3_1_UC), \ 134 MOCS_ENTRY(I915_MOCS_PTE, \ 135 LE_0_PAGETABLE | LE_TC_0_PAGETABLE | LE_LRUM(3), \ 136 L3_3_WB) 137 138 static const struct drm_i915_mocs_entry skl_mocs_table[] = { 139 GEN9_MOCS_ENTRIES, 140 MOCS_ENTRY(I915_MOCS_CACHED, 141 LE_3_WB | LE_TC_2_LLC_ELLC | LE_LRUM(3), 142 L3_3_WB), 143 144 /* 145 * mocs:63 146 * - used by the L3 for all of its evictions. 147 * Thus it is expected to allow LLC cacheability to enable coherent 148 * flows to be maintained. 149 * - used to force L3 uncachable cycles. 150 * Thus it is expected to make the surface L3 uncacheable. 151 */ 152 MOCS_ENTRY(63, 153 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), 154 L3_1_UC) 155 }; 156 157 /* NOTE: the LE_TGT_CACHE is not used on Broxton */ 158 static const struct drm_i915_mocs_entry broxton_mocs_table[] = { 159 GEN9_MOCS_ENTRIES, 160 MOCS_ENTRY(I915_MOCS_CACHED, 161 LE_1_UC | LE_TC_2_LLC_ELLC | LE_LRUM(3), 162 L3_3_WB) 163 }; 164 165 #define GEN11_MOCS_ENTRIES \ 166 /* Entries 0 and 1 are defined per-platform */ \ 167 /* Base - L3 + LLC */ \ 168 MOCS_ENTRY(2, \ 169 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), \ 170 L3_3_WB), \ 171 /* Base - Uncached */ \ 172 MOCS_ENTRY(3, \ 173 LE_1_UC | LE_TC_1_LLC, \ 174 L3_1_UC), \ 175 /* Base - L3 */ \ 176 MOCS_ENTRY(4, \ 177 LE_1_UC | LE_TC_1_LLC, \ 178 L3_3_WB), \ 179 /* Base - LLC */ \ 180 MOCS_ENTRY(5, \ 181 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), \ 182 L3_1_UC), \ 183 /* Age 0 - LLC */ \ 184 MOCS_ENTRY(6, \ 185 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1), \ 186 L3_1_UC), \ 187 /* Age 0 - L3 + LLC */ \ 188 MOCS_ENTRY(7, \ 189 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1), \ 190 L3_3_WB), \ 191 /* Age: Don't Chg. - LLC */ \ 192 MOCS_ENTRY(8, \ 193 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2), \ 194 L3_1_UC), \ 195 /* Age: Don't Chg. - L3 + LLC */ \ 196 MOCS_ENTRY(9, \ 197 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2), \ 198 L3_3_WB), \ 199 /* No AOM - LLC */ \ 200 MOCS_ENTRY(10, \ 201 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_AOM(1), \ 202 L3_1_UC), \ 203 /* No AOM - L3 + LLC */ \ 204 MOCS_ENTRY(11, \ 205 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_AOM(1), \ 206 L3_3_WB), \ 207 /* No AOM; Age 0 - LLC */ \ 208 MOCS_ENTRY(12, \ 209 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1) | LE_AOM(1), \ 210 L3_1_UC), \ 211 /* No AOM; Age 0 - L3 + LLC */ \ 212 MOCS_ENTRY(13, \ 213 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1) | LE_AOM(1), \ 214 L3_3_WB), \ 215 /* No AOM; Age:DC - LLC */ \ 216 MOCS_ENTRY(14, \ 217 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2) | LE_AOM(1), \ 218 L3_1_UC), \ 219 /* No AOM; Age:DC - L3 + LLC */ \ 220 MOCS_ENTRY(15, \ 221 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2) | LE_AOM(1), \ 222 L3_3_WB), \ 223 /* Bypass LLC - Uncached (EHL+) */ \ 224 MOCS_ENTRY(16, \ 225 LE_1_UC | LE_TC_1_LLC | LE_SCF(1), \ 226 L3_1_UC), \ 227 /* Bypass LLC - L3 (Read-Only) (EHL+) */ \ 228 MOCS_ENTRY(17, \ 229 LE_1_UC | LE_TC_1_LLC | LE_SCF(1), \ 230 L3_3_WB), \ 231 /* Self-Snoop - L3 + LLC */ \ 232 MOCS_ENTRY(18, \ 233 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SSE(3), \ 234 L3_3_WB), \ 235 /* Skip Caching - L3 + LLC(12.5%) */ \ 236 MOCS_ENTRY(19, \ 237 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(7), \ 238 L3_3_WB), \ 239 /* Skip Caching - L3 + LLC(25%) */ \ 240 MOCS_ENTRY(20, \ 241 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(3), \ 242 L3_3_WB), \ 243 /* Skip Caching - L3 + LLC(50%) */ \ 244 MOCS_ENTRY(21, \ 245 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(1), \ 246 L3_3_WB), \ 247 /* Skip Caching - L3 + LLC(75%) */ \ 248 MOCS_ENTRY(22, \ 249 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_RSC(1) | LE_SCC(3), \ 250 L3_3_WB), \ 251 /* Skip Caching - L3 + LLC(87.5%) */ \ 252 MOCS_ENTRY(23, \ 253 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_RSC(1) | LE_SCC(7), \ 254 L3_3_WB), \ 255 /* HW Reserved - SW program but never use */ \ 256 MOCS_ENTRY(62, \ 257 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), \ 258 L3_1_UC), \ 259 /* HW Reserved - SW program but never use */ \ 260 MOCS_ENTRY(63, \ 261 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), \ 262 L3_1_UC) 263 264 static const struct drm_i915_mocs_entry tgl_mocs_table[] = { 265 /* 266 * NOTE: 267 * Reserved and unspecified MOCS indices have been set to (L3 + LCC). 268 * These reserved entries should never be used, they may be changed 269 * to low performant variants with better coherency in the future if 270 * more entries are needed. We are programming index I915_MOCS_PTE(1) 271 * only, __init_mocs_table() take care to program unused index with 272 * this entry. 273 */ 274 MOCS_ENTRY(I915_MOCS_PTE, 275 LE_0_PAGETABLE | LE_TC_0_PAGETABLE, 276 L3_1_UC), 277 GEN11_MOCS_ENTRIES, 278 279 /* Implicitly enable L1 - HDC:L1 + L3 + LLC */ 280 MOCS_ENTRY(48, 281 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), 282 L3_3_WB), 283 /* Implicitly enable L1 - HDC:L1 + L3 */ 284 MOCS_ENTRY(49, 285 LE_1_UC | LE_TC_1_LLC, 286 L3_3_WB), 287 /* Implicitly enable L1 - HDC:L1 + LLC */ 288 MOCS_ENTRY(50, 289 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), 290 L3_1_UC), 291 /* Implicitly enable L1 - HDC:L1 */ 292 MOCS_ENTRY(51, 293 LE_1_UC | LE_TC_1_LLC, 294 L3_1_UC), 295 /* HW Special Case (CCS) */ 296 MOCS_ENTRY(60, 297 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), 298 L3_1_UC), 299 /* HW Special Case (Displayable) */ 300 MOCS_ENTRY(61, 301 LE_1_UC | LE_TC_1_LLC, 302 L3_3_WB), 303 }; 304 305 static const struct drm_i915_mocs_entry icl_mocs_table[] = { 306 /* Base - Uncached (Deprecated) */ 307 MOCS_ENTRY(I915_MOCS_UNCACHED, 308 LE_1_UC | LE_TC_1_LLC, 309 L3_1_UC), 310 /* Base - L3 + LeCC:PAT (Deprecated) */ 311 MOCS_ENTRY(I915_MOCS_PTE, 312 LE_0_PAGETABLE | LE_TC_0_PAGETABLE, 313 L3_3_WB), 314 315 GEN11_MOCS_ENTRIES 316 }; 317 318 static const struct drm_i915_mocs_entry dg1_mocs_table[] = { 319 /* UC */ 320 MOCS_ENTRY(1, 0, L3_1_UC), 321 /* WB - L3 */ 322 MOCS_ENTRY(5, 0, L3_3_WB), 323 /* WB - L3 50% */ 324 MOCS_ENTRY(6, 0, L3_ESC(1) | L3_SCC(1) | L3_3_WB), 325 /* WB - L3 25% */ 326 MOCS_ENTRY(7, 0, L3_ESC(1) | L3_SCC(3) | L3_3_WB), 327 /* WB - L3 12.5% */ 328 MOCS_ENTRY(8, 0, L3_ESC(1) | L3_SCC(7) | L3_3_WB), 329 330 /* HDC:L1 + L3 */ 331 MOCS_ENTRY(48, 0, L3_3_WB), 332 /* HDC:L1 */ 333 MOCS_ENTRY(49, 0, L3_1_UC), 334 335 /* HW Reserved */ 336 MOCS_ENTRY(60, 0, L3_1_UC), 337 MOCS_ENTRY(61, 0, L3_1_UC), 338 MOCS_ENTRY(62, 0, L3_1_UC), 339 MOCS_ENTRY(63, 0, L3_1_UC), 340 }; 341 342 static const struct drm_i915_mocs_entry gen12_mocs_table[] = { 343 GEN11_MOCS_ENTRIES, 344 /* Implicitly enable L1 - HDC:L1 + L3 + LLC */ 345 MOCS_ENTRY(48, 346 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), 347 L3_3_WB), 348 /* Implicitly enable L1 - HDC:L1 + L3 */ 349 MOCS_ENTRY(49, 350 LE_1_UC | LE_TC_1_LLC, 351 L3_3_WB), 352 /* Implicitly enable L1 - HDC:L1 + LLC */ 353 MOCS_ENTRY(50, 354 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), 355 L3_1_UC), 356 /* Implicitly enable L1 - HDC:L1 */ 357 MOCS_ENTRY(51, 358 LE_1_UC | LE_TC_1_LLC, 359 L3_1_UC), 360 /* HW Special Case (CCS) */ 361 MOCS_ENTRY(60, 362 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), 363 L3_1_UC), 364 /* HW Special Case (Displayable) */ 365 MOCS_ENTRY(61, 366 LE_1_UC | LE_TC_1_LLC, 367 L3_3_WB), 368 }; 369 370 static const struct drm_i915_mocs_entry dg2_mocs_table[] = { 371 /* UC - Coherent; GO:L3 */ 372 MOCS_ENTRY(0, 0, L3_1_UC | L3_LKUP(1)), 373 /* UC - Coherent; GO:Memory */ 374 MOCS_ENTRY(1, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)), 375 /* UC - Non-Coherent; GO:Memory */ 376 MOCS_ENTRY(2, 0, L3_1_UC | L3_GLBGO(1)), 377 378 /* WB - LC */ 379 MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)), 380 }; 381 382 static const struct drm_i915_mocs_entry mtl_mocs_table[] = { 383 /* Error - Reserved for Non-Use */ 384 MOCS_ENTRY(0, 385 IG_PAT(0), 386 L3_LKUP(1) | L3_3_WB), 387 /* Cached - L3 + L4 */ 388 MOCS_ENTRY(1, 389 IG_PAT(1), 390 L3_LKUP(1) | L3_3_WB), 391 /* L4 - GO:L3 */ 392 MOCS_ENTRY(2, 393 IG_PAT(1), 394 L3_LKUP(1) | L3_1_UC), 395 /* Uncached - GO:L3 */ 396 MOCS_ENTRY(3, 397 IG_PAT(1) | L4_3_UC, 398 L3_LKUP(1) | L3_1_UC), 399 /* L4 - GO:Mem */ 400 MOCS_ENTRY(4, 401 IG_PAT(1), 402 L3_LKUP(1) | L3_GLBGO(1) | L3_1_UC), 403 /* Uncached - GO:Mem */ 404 MOCS_ENTRY(5, 405 IG_PAT(1) | L4_3_UC, 406 L3_LKUP(1) | L3_GLBGO(1) | L3_1_UC), 407 /* L4 - L3:NoLKUP; GO:L3 */ 408 MOCS_ENTRY(6, 409 IG_PAT(1), 410 L3_1_UC), 411 /* Uncached - L3:NoLKUP; GO:L3 */ 412 MOCS_ENTRY(7, 413 IG_PAT(1) | L4_3_UC, 414 L3_1_UC), 415 /* L4 - L3:NoLKUP; GO:Mem */ 416 MOCS_ENTRY(8, 417 IG_PAT(1), 418 L3_GLBGO(1) | L3_1_UC), 419 /* Uncached - L3:NoLKUP; GO:Mem */ 420 MOCS_ENTRY(9, 421 IG_PAT(1) | L4_3_UC, 422 L3_GLBGO(1) | L3_1_UC), 423 /* Display - L3; L4:WT */ 424 MOCS_ENTRY(14, 425 IG_PAT(1) | L4_1_WT, 426 L3_LKUP(1) | L3_3_WB), 427 /* CCS - Non-Displayable */ 428 MOCS_ENTRY(15, 429 IG_PAT(1), 430 L3_GLBGO(1) | L3_1_UC), 431 }; 432 433 enum { 434 HAS_GLOBAL_MOCS = BIT(0), 435 HAS_ENGINE_MOCS = BIT(1), 436 HAS_RENDER_L3CC = BIT(2), 437 }; 438 439 static bool has_l3cc(const struct drm_i915_private *i915) 440 { 441 return true; 442 } 443 444 static bool has_global_mocs(const struct drm_i915_private *i915) 445 { 446 return HAS_GLOBAL_MOCS_REGISTERS(i915); 447 } 448 449 static bool has_mocs(const struct drm_i915_private *i915) 450 { 451 return !IS_DGFX(i915); 452 } 453 454 static unsigned int get_mocs_settings(struct drm_i915_private *i915, 455 struct drm_i915_mocs_table *table) 456 { 457 unsigned int flags; 458 459 memset(table, 0, sizeof(struct drm_i915_mocs_table)); 460 461 table->unused_entries_index = I915_MOCS_PTE; 462 if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 74))) { 463 table->size = ARRAY_SIZE(mtl_mocs_table); 464 table->table = mtl_mocs_table; 465 table->n_entries = MTL_NUM_MOCS_ENTRIES; 466 table->uc_index = 9; 467 table->unused_entries_index = 1; 468 } else if (IS_DG2(i915)) { 469 table->size = ARRAY_SIZE(dg2_mocs_table); 470 table->table = dg2_mocs_table; 471 table->uc_index = 1; 472 table->n_entries = GEN9_NUM_MOCS_ENTRIES; 473 table->unused_entries_index = 3; 474 } else if (IS_DG1(i915)) { 475 table->size = ARRAY_SIZE(dg1_mocs_table); 476 table->table = dg1_mocs_table; 477 table->uc_index = 1; 478 table->n_entries = GEN9_NUM_MOCS_ENTRIES; 479 table->uc_index = 1; 480 table->unused_entries_index = 5; 481 } else if (IS_TIGERLAKE(i915) || IS_ROCKETLAKE(i915)) { 482 /* For TGL/RKL, Can't be changed now for ABI reasons */ 483 table->size = ARRAY_SIZE(tgl_mocs_table); 484 table->table = tgl_mocs_table; 485 table->n_entries = GEN9_NUM_MOCS_ENTRIES; 486 table->uc_index = 3; 487 } else if (GRAPHICS_VER(i915) >= 12) { 488 table->size = ARRAY_SIZE(gen12_mocs_table); 489 table->table = gen12_mocs_table; 490 table->n_entries = GEN9_NUM_MOCS_ENTRIES; 491 table->uc_index = 3; 492 table->unused_entries_index = 2; 493 } else if (GRAPHICS_VER(i915) == 11) { 494 table->size = ARRAY_SIZE(icl_mocs_table); 495 table->table = icl_mocs_table; 496 table->n_entries = GEN9_NUM_MOCS_ENTRIES; 497 } else if (IS_GEN9_BC(i915)) { 498 table->size = ARRAY_SIZE(skl_mocs_table); 499 table->n_entries = GEN9_NUM_MOCS_ENTRIES; 500 table->table = skl_mocs_table; 501 } else if (IS_GEN9_LP(i915)) { 502 table->size = ARRAY_SIZE(broxton_mocs_table); 503 table->n_entries = GEN9_NUM_MOCS_ENTRIES; 504 table->table = broxton_mocs_table; 505 } else { 506 drm_WARN_ONCE(&i915->drm, GRAPHICS_VER(i915) >= 9, 507 "Platform that should have a MOCS table does not.\n"); 508 return 0; 509 } 510 511 if (GEM_DEBUG_WARN_ON(table->size > table->n_entries)) 512 return 0; 513 514 /* WaDisableSkipCaching:skl,bxt,kbl,glk */ 515 if (GRAPHICS_VER(i915) == 9) { 516 int i; 517 518 for (i = 0; i < table->size; i++) 519 if (GEM_DEBUG_WARN_ON(table->table[i].l3cc_value & 520 (L3_ESC(1) | L3_SCC(0x7)))) 521 return 0; 522 } 523 524 flags = 0; 525 if (has_mocs(i915)) { 526 if (has_global_mocs(i915)) 527 flags |= HAS_GLOBAL_MOCS; 528 else 529 flags |= HAS_ENGINE_MOCS; 530 } 531 if (has_l3cc(i915)) 532 flags |= HAS_RENDER_L3CC; 533 534 return flags; 535 } 536 537 /* 538 * Get control_value from MOCS entry taking into account when it's not used 539 * then if unused_entries_index is non-zero then its value will be returned 540 * otherwise I915_MOCS_PTE's value is returned in this case. 541 */ 542 static u32 get_entry_control(const struct drm_i915_mocs_table *table, 543 unsigned int index) 544 { 545 if (index < table->size && table->table[index].used) 546 return table->table[index].control_value; 547 return table->table[table->unused_entries_index].control_value; 548 } 549 550 #define for_each_mocs(mocs, t, i) \ 551 for (i = 0; \ 552 i < (t)->n_entries ? (mocs = get_entry_control((t), i)), 1 : 0;\ 553 i++) 554 555 static void __init_mocs_table(struct intel_uncore *uncore, 556 const struct drm_i915_mocs_table *table, 557 u32 addr) 558 { 559 unsigned int i; 560 u32 mocs; 561 562 drm_WARN_ONCE(&uncore->i915->drm, !table->unused_entries_index, 563 "Unused entries index should have been defined\n"); 564 for_each_mocs(mocs, table, i) 565 intel_uncore_write_fw(uncore, _MMIO(addr + i * 4), mocs); 566 } 567 568 static u32 mocs_offset(const struct intel_engine_cs *engine) 569 { 570 static const u32 offset[] = { 571 [RCS0] = __GEN9_RCS0_MOCS0, 572 [VCS0] = __GEN9_VCS0_MOCS0, 573 [VCS1] = __GEN9_VCS1_MOCS0, 574 [VECS0] = __GEN9_VECS0_MOCS0, 575 [BCS0] = __GEN9_BCS0_MOCS0, 576 [VCS2] = __GEN11_VCS2_MOCS0, 577 }; 578 579 GEM_BUG_ON(engine->id >= ARRAY_SIZE(offset)); 580 return offset[engine->id]; 581 } 582 583 static void init_mocs_table(struct intel_engine_cs *engine, 584 const struct drm_i915_mocs_table *table) 585 { 586 __init_mocs_table(engine->uncore, table, mocs_offset(engine)); 587 } 588 589 /* 590 * Get l3cc_value from MOCS entry taking into account when it's not used 591 * then if unused_entries_index is not zero then its value will be returned 592 * otherwise I915_MOCS_PTE's value is returned in this case. 593 */ 594 static u16 get_entry_l3cc(const struct drm_i915_mocs_table *table, 595 unsigned int index) 596 { 597 if (index < table->size && table->table[index].used) 598 return table->table[index].l3cc_value; 599 return table->table[table->unused_entries_index].l3cc_value; 600 } 601 602 static u32 l3cc_combine(u16 low, u16 high) 603 { 604 return low | (u32)high << 16; 605 } 606 607 #define for_each_l3cc(l3cc, t, i) \ 608 for (i = 0; \ 609 i < ((t)->n_entries + 1) / 2 ? \ 610 (l3cc = l3cc_combine(get_entry_l3cc((t), 2 * i), \ 611 get_entry_l3cc((t), 2 * i + 1))), 1 : \ 612 0; \ 613 i++) 614 615 static void init_l3cc_table(struct intel_gt *gt, 616 const struct drm_i915_mocs_table *table) 617 { 618 unsigned long flags; 619 unsigned int i; 620 u32 l3cc; 621 622 intel_gt_mcr_lock(gt, &flags); 623 for_each_l3cc(l3cc, table, i) 624 if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 55)) 625 intel_gt_mcr_multicast_write_fw(gt, XEHP_LNCFCMOCS(i), l3cc); 626 else 627 intel_uncore_write_fw(gt->uncore, GEN9_LNCFCMOCS(i), l3cc); 628 intel_gt_mcr_unlock(gt, flags); 629 } 630 631 void intel_mocs_init_engine(struct intel_engine_cs *engine) 632 { 633 struct drm_i915_mocs_table table; 634 unsigned int flags; 635 636 /* Called under a blanket forcewake */ 637 assert_forcewakes_active(engine->uncore, FORCEWAKE_ALL); 638 639 flags = get_mocs_settings(engine->i915, &table); 640 if (!flags) 641 return; 642 643 /* Platforms with global MOCS do not need per-engine initialization. */ 644 if (flags & HAS_ENGINE_MOCS) 645 init_mocs_table(engine, &table); 646 647 if (flags & HAS_RENDER_L3CC && engine->class == RENDER_CLASS) 648 init_l3cc_table(engine->gt, &table); 649 } 650 651 static u32 global_mocs_offset(void) 652 { 653 return i915_mmio_reg_offset(GEN12_GLOBAL_MOCS(0)); 654 } 655 656 void intel_set_mocs_index(struct intel_gt *gt) 657 { 658 struct drm_i915_mocs_table table; 659 660 get_mocs_settings(gt->i915, &table); 661 gt->mocs.uc_index = table.uc_index; 662 if (HAS_L3_CCS_READ(gt->i915)) 663 gt->mocs.wb_index = table.wb_index; 664 } 665 666 void intel_mocs_init(struct intel_gt *gt) 667 { 668 struct drm_i915_mocs_table table; 669 unsigned int flags; 670 671 /* 672 * LLC and eDRAM control values are not applicable to dgfx 673 */ 674 flags = get_mocs_settings(gt->i915, &table); 675 if (flags & HAS_GLOBAL_MOCS) 676 __init_mocs_table(gt->uncore, &table, global_mocs_offset()); 677 678 /* 679 * Initialize the L3CC table as part of mocs initialization to make 680 * sure the LNCFCMOCSx registers are programmed for the subsequent 681 * memory transactions including guc transactions 682 */ 683 if (flags & HAS_RENDER_L3CC) 684 init_l3cc_table(gt, &table); 685 } 686 687 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 688 #include "selftest_mocs.c" 689 #endif 690