Loading...
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2022 Intel Corporation
4 */
5
6#include "xe_mocs.h"
7
8#include "regs/xe_gt_regs.h"
9#include "xe_bo.h"
10#include "xe_device.h"
11#include "xe_exec_queue.h"
12#include "xe_force_wake.h"
13#include "xe_gt.h"
14#include "xe_gt_mcr.h"
15#include "xe_gt_printk.h"
16#include "xe_mmio.h"
17#include "xe_platform_types.h"
18#include "xe_pm.h"
19#include "xe_sriov.h"
20#include "xe_step_types.h"
21
22#if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
23#define mocs_dbg xe_gt_dbg
24#else
25__printf(2, 3)
26static inline void mocs_dbg(const struct xe_gt *gt,
27 const char *format, ...)
28{ /* noop */ }
29#endif
30
31enum {
32 HAS_GLOBAL_MOCS = BIT(0),
33 HAS_LNCF_MOCS = BIT(1),
34};
35
36struct xe_mocs_entry {
37 u32 control_value;
38 u16 l3cc_value;
39 u16 used;
40};
41
42struct xe_mocs_info;
43
44struct xe_mocs_ops {
45 void (*dump)(struct xe_mocs_info *mocs, unsigned int flags,
46 struct xe_gt *gt, struct drm_printer *p);
47};
48
49struct xe_mocs_info {
50 /*
51 * Size of the spec's suggested MOCS programming table. The list of
52 * table entries from the spec can potentially be smaller than the
53 * number of hardware registers used to program the MOCS table; in such
54 * cases the registers for the remaining indices will be programmed to
55 * match unused_entries_index.
56 */
57 unsigned int table_size;
58 /* Number of MOCS entries supported by the hardware */
59 unsigned int num_mocs_regs;
60 const struct xe_mocs_entry *table;
61 const struct xe_mocs_ops *ops;
62 u8 uc_index;
63 u8 wb_index;
64 u8 unused_entries_index;
65};
66
67/* Defines for the tables (GLOB_MOCS_0 - GLOB_MOCS_16) */
68#define IG_PAT REG_BIT(8)
69#define L3_CACHE_POLICY_MASK REG_GENMASK(5, 4)
70#define L4_CACHE_POLICY_MASK REG_GENMASK(3, 2)
71
72/* Helper defines */
73#define XELP_NUM_MOCS_ENTRIES 64 /* 63-64 are reserved, but configured. */
74#define PVC_NUM_MOCS_ENTRIES 3
75#define MTL_NUM_MOCS_ENTRIES 16
76#define XE2_NUM_MOCS_ENTRIES 16
77
78/* (e)LLC caching options */
79/*
80 * Note: LE_0_PAGETABLE works only up to Gen11; for newer gens it means
81 * the same as LE_UC
82 */
83#define LE_0_PAGETABLE LE_CACHEABILITY(0)
84#define LE_1_UC LE_CACHEABILITY(1)
85#define LE_2_WT LE_CACHEABILITY(2)
86#define LE_3_WB LE_CACHEABILITY(3)
87
88/* Target cache */
89#define LE_TC_0_PAGETABLE LE_TGT_CACHE(0)
90#define LE_TC_1_LLC LE_TGT_CACHE(1)
91#define LE_TC_2_LLC_ELLC LE_TGT_CACHE(2)
92#define LE_TC_3_LLC_ELLC_ALT LE_TGT_CACHE(3)
93
94/* L3 caching options */
95#define L3_0_DIRECT L3_CACHEABILITY(0)
96#define L3_1_UC L3_CACHEABILITY(1)
97#define L3_2_RESERVED L3_CACHEABILITY(2)
98#define L3_3_WB L3_CACHEABILITY(3)
99
100/* L4 caching options */
101#define L4_0_WB REG_FIELD_PREP(L4_CACHE_POLICY_MASK, 0)
102#define L4_1_WT REG_FIELD_PREP(L4_CACHE_POLICY_MASK, 1)
103#define L4_3_UC REG_FIELD_PREP(L4_CACHE_POLICY_MASK, 3)
104
105#define XE2_L3_0_WB REG_FIELD_PREP(L3_CACHE_POLICY_MASK, 0)
106/* XD: WB Transient Display */
107#define XE2_L3_1_XD REG_FIELD_PREP(L3_CACHE_POLICY_MASK, 1)
108#define XE2_L3_3_UC REG_FIELD_PREP(L3_CACHE_POLICY_MASK, 3)
109
110#define XE2_L3_CLOS_MASK REG_GENMASK(7, 6)
111
112#define MOCS_ENTRY(__idx, __control_value, __l3cc_value) \
113 [__idx] = { \
114 .control_value = __control_value, \
115 .l3cc_value = __l3cc_value, \
116 .used = 1, \
117 }
118
119/*
120 * MOCS tables
121 *
122 * These are the MOCS tables that are programmed across all the rings.
123 * The control value is programmed to all the rings that support the
124 * MOCS registers. While the l3cc_values are only programmed to the
125 * LNCFCMOCS0 - LNCFCMOCS32 registers.
126 *
127 * These tables are intended to be kept reasonably consistent across
128 * HW platforms, and for ICL+, be identical across OSes. To achieve
129 * that, the list of entries is published as part of bspec.
130 *
131 * Entries not part of the following tables are undefined as far as userspace is
132 * concerned and shouldn't be relied upon. The last few entries are reserved by
133 * the hardware. They should be initialized according to bspec and never used.
134 *
135 * NOTE1: These tables are part of bspec and defined as part of the hardware
136 * interface. It is expected that, for specific hardware platform, existing
137 * entries will remain constant and the table will only be updated by adding new
138 * entries, filling unused positions.
139 *
140 * NOTE2: Reserved and unspecified MOCS indices have been set to L3 WB. These
141 * reserved entries should never be used. They may be changed to low performant
142 * variants with better coherency in the future if more entries are needed.
143 */
144
145static const struct xe_mocs_entry gen12_mocs_desc[] = {
146 /* Base - L3 + LLC */
147 MOCS_ENTRY(2,
148 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
149 L3_3_WB),
150 /* Base - Uncached */
151 MOCS_ENTRY(3,
152 LE_1_UC | LE_TC_1_LLC,
153 L3_1_UC),
154 /* Base - L3 */
155 MOCS_ENTRY(4,
156 LE_1_UC | LE_TC_1_LLC,
157 L3_3_WB),
158 /* Base - LLC */
159 MOCS_ENTRY(5,
160 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
161 L3_1_UC),
162 /* Age 0 - LLC */
163 MOCS_ENTRY(6,
164 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1),
165 L3_1_UC),
166 /* Age 0 - L3 + LLC */
167 MOCS_ENTRY(7,
168 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1),
169 L3_3_WB),
170 /* Age: Don't Chg. - LLC */
171 MOCS_ENTRY(8,
172 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2),
173 L3_1_UC),
174 /* Age: Don't Chg. - L3 + LLC */
175 MOCS_ENTRY(9,
176 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2),
177 L3_3_WB),
178 /* No AOM - LLC */
179 MOCS_ENTRY(10,
180 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_AOM(1),
181 L3_1_UC),
182 /* No AOM - L3 + LLC */
183 MOCS_ENTRY(11,
184 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_AOM(1),
185 L3_3_WB),
186 /* No AOM; Age 0 - LLC */
187 MOCS_ENTRY(12,
188 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1) | LE_AOM(1),
189 L3_1_UC),
190 /* No AOM; Age 0 - L3 + LLC */
191 MOCS_ENTRY(13,
192 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1) | LE_AOM(1),
193 L3_3_WB),
194 /* No AOM; Age:DC - LLC */
195 MOCS_ENTRY(14,
196 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2) | LE_AOM(1),
197 L3_1_UC),
198 /* No AOM; Age:DC - L3 + LLC */
199 MOCS_ENTRY(15,
200 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2) | LE_AOM(1),
201 L3_3_WB),
202 /* Self-Snoop - L3 + LLC */
203 MOCS_ENTRY(18,
204 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SSE(3),
205 L3_3_WB),
206 /* Skip Caching - L3 + LLC(12.5%) */
207 MOCS_ENTRY(19,
208 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(7),
209 L3_3_WB),
210 /* Skip Caching - L3 + LLC(25%) */
211 MOCS_ENTRY(20,
212 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(3),
213 L3_3_WB),
214 /* Skip Caching - L3 + LLC(50%) */
215 MOCS_ENTRY(21,
216 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(1),
217 L3_3_WB),
218 /* Skip Caching - L3 + LLC(75%) */
219 MOCS_ENTRY(22,
220 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_RSC(1) | LE_SCC(3),
221 L3_3_WB),
222 /* Skip Caching - L3 + LLC(87.5%) */
223 MOCS_ENTRY(23,
224 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_RSC(1) | LE_SCC(7),
225 L3_3_WB),
226 /* Implicitly enable L1 - HDC:L1 + L3 + LLC */
227 MOCS_ENTRY(48,
228 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
229 L3_3_WB),
230 /* Implicitly enable L1 - HDC:L1 + L3 */
231 MOCS_ENTRY(49,
232 LE_1_UC | LE_TC_1_LLC,
233 L3_3_WB),
234 /* Implicitly enable L1 - HDC:L1 + LLC */
235 MOCS_ENTRY(50,
236 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
237 L3_1_UC),
238 /* Implicitly enable L1 - HDC:L1 */
239 MOCS_ENTRY(51,
240 LE_1_UC | LE_TC_1_LLC,
241 L3_1_UC),
242 /* HW Special Case (CCS) */
243 MOCS_ENTRY(60,
244 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
245 L3_1_UC),
246 /* HW Special Case (Displayable) */
247 MOCS_ENTRY(61,
248 LE_1_UC | LE_TC_1_LLC,
249 L3_3_WB),
250 /* HW Reserved - SW program but never use */
251 MOCS_ENTRY(62,
252 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
253 L3_1_UC),
254 /* HW Reserved - SW program but never use */
255 MOCS_ENTRY(63,
256 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
257 L3_1_UC)
258};
259
260static bool regs_are_mcr(struct xe_gt *gt)
261{
262 struct xe_device *xe = gt_to_xe(gt);
263
264 if (xe_gt_is_media_type(gt))
265 return MEDIA_VER(xe) >= 20;
266 else
267 return GRAPHICS_VERx100(xe) >= 1250;
268}
269
270static void xelp_lncf_dump(struct xe_mocs_info *info, struct xe_gt *gt, struct drm_printer *p)
271{
272 unsigned int i, j;
273 u32 reg_val;
274
275 drm_printf(p, "LNCFCMOCS[idx] = [ESC, SCC, L3CC] (value)\n\n");
276
277 for (i = 0, j = 0; i < (info->num_mocs_regs + 1) / 2; i++, j++) {
278 if (regs_are_mcr(gt))
279 reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_LNCFCMOCS(i));
280 else
281 reg_val = xe_mmio_read32(>->mmio, XELP_LNCFCMOCS(i));
282
283 drm_printf(p, "LNCFCMOCS[%2d] = [%u, %u, %u] (%#8x)\n",
284 j++,
285 !!(reg_val & L3_ESC_MASK),
286 REG_FIELD_GET(L3_SCC_MASK, reg_val),
287 REG_FIELD_GET(L3_CACHEABILITY_MASK, reg_val),
288 reg_val);
289
290 drm_printf(p, "LNCFCMOCS[%2d] = [%u, %u, %u] (%#8x)\n",
291 j,
292 !!(reg_val & L3_UPPER_IDX_ESC_MASK),
293 REG_FIELD_GET(L3_UPPER_IDX_SCC_MASK, reg_val),
294 REG_FIELD_GET(L3_UPPER_IDX_CACHEABILITY_MASK, reg_val),
295 reg_val);
296 }
297}
298
299static void xelp_mocs_dump(struct xe_mocs_info *info, unsigned int flags,
300 struct xe_gt *gt, struct drm_printer *p)
301{
302 unsigned int i;
303 u32 reg_val;
304
305 if (flags & HAS_GLOBAL_MOCS) {
306 drm_printf(p, "Global mocs table configuration:\n");
307 drm_printf(p, "GLOB_MOCS[idx] = [LeCC, TC, LRUM, AOM, RSC, SCC, PFM, SCF, CoS, SSE] (value)\n\n");
308
309 for (i = 0; i < info->num_mocs_regs; i++) {
310 if (regs_are_mcr(gt))
311 reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i));
312 else
313 reg_val = xe_mmio_read32(>->mmio, XELP_GLOBAL_MOCS(i));
314
315 drm_printf(p, "GLOB_MOCS[%2d] = [%u, %u, %u, %u, %u, %u, %u, %u, %u, %u ] (%#8x)\n",
316 i,
317 REG_FIELD_GET(LE_CACHEABILITY_MASK, reg_val),
318 REG_FIELD_GET(LE_TGT_CACHE_MASK, reg_val),
319 REG_FIELD_GET(LE_LRUM_MASK, reg_val),
320 !!(reg_val & LE_AOM_MASK),
321 !!(reg_val & LE_RSC_MASK),
322 REG_FIELD_GET(LE_SCC_MASK, reg_val),
323 REG_FIELD_GET(LE_PFM_MASK, reg_val),
324 !!(reg_val & LE_SCF_MASK),
325 REG_FIELD_GET(LE_COS_MASK, reg_val),
326 REG_FIELD_GET(LE_SSE_MASK, reg_val),
327 reg_val);
328 }
329 }
330
331 xelp_lncf_dump(info, gt, p);
332}
333
334static const struct xe_mocs_ops xelp_mocs_ops = {
335 .dump = xelp_mocs_dump,
336};
337
338static const struct xe_mocs_entry dg1_mocs_desc[] = {
339 /* UC */
340 MOCS_ENTRY(1, 0, L3_1_UC),
341 /* WB - L3 */
342 MOCS_ENTRY(5, 0, L3_3_WB),
343 /* WB - L3 50% */
344 MOCS_ENTRY(6, 0, L3_ESC(1) | L3_SCC(1) | L3_3_WB),
345 /* WB - L3 25% */
346 MOCS_ENTRY(7, 0, L3_ESC(1) | L3_SCC(3) | L3_3_WB),
347 /* WB - L3 12.5% */
348 MOCS_ENTRY(8, 0, L3_ESC(1) | L3_SCC(7) | L3_3_WB),
349
350 /* HDC:L1 + L3 */
351 MOCS_ENTRY(48, 0, L3_3_WB),
352 /* HDC:L1 */
353 MOCS_ENTRY(49, 0, L3_1_UC),
354
355 /* HW Reserved */
356 MOCS_ENTRY(60, 0, L3_1_UC),
357 MOCS_ENTRY(61, 0, L3_1_UC),
358 MOCS_ENTRY(62, 0, L3_1_UC),
359 MOCS_ENTRY(63, 0, L3_1_UC),
360};
361
362static const struct xe_mocs_entry dg2_mocs_desc[] = {
363 /* UC - Coherent; GO:L3 */
364 MOCS_ENTRY(0, 0, L3_1_UC | L3_LKUP(1)),
365 /* UC - Coherent; GO:Memory */
366 MOCS_ENTRY(1, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)),
367 /* UC - Non-Coherent; GO:Memory */
368 MOCS_ENTRY(2, 0, L3_1_UC | L3_GLBGO(1)),
369
370 /* WB - LC */
371 MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)),
372};
373
374static void xehp_lncf_dump(struct xe_mocs_info *info, unsigned int flags,
375 struct xe_gt *gt, struct drm_printer *p)
376{
377 unsigned int i, j;
378 u32 reg_val;
379
380 drm_printf(p, "LNCFCMOCS[idx] = [UCL3LOOKUP, GLBGO, L3CC] (value)\n\n");
381
382 for (i = 0, j = 0; i < (info->num_mocs_regs + 1) / 2; i++, j++) {
383 if (regs_are_mcr(gt))
384 reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_LNCFCMOCS(i));
385 else
386 reg_val = xe_mmio_read32(>->mmio, XELP_LNCFCMOCS(i));
387
388 drm_printf(p, "LNCFCMOCS[%2d] = [%u, %u, %u] (%#8x)\n",
389 j++,
390 !!(reg_val & L3_LKUP_MASK),
391 !!(reg_val & L3_GLBGO_MASK),
392 REG_FIELD_GET(L3_CACHEABILITY_MASK, reg_val),
393 reg_val);
394
395 drm_printf(p, "LNCFCMOCS[%2d] = [%u, %u, %u] (%#8x)\n",
396 j,
397 !!(reg_val & L3_UPPER_LKUP_MASK),
398 !!(reg_val & L3_UPPER_GLBGO_MASK),
399 REG_FIELD_GET(L3_UPPER_IDX_CACHEABILITY_MASK, reg_val),
400 reg_val);
401 }
402}
403
404static const struct xe_mocs_ops xehp_mocs_ops = {
405 .dump = xehp_lncf_dump,
406};
407
408static const struct xe_mocs_entry pvc_mocs_desc[] = {
409 /* Error */
410 MOCS_ENTRY(0, 0, L3_3_WB),
411
412 /* UC */
413 MOCS_ENTRY(1, 0, L3_1_UC),
414
415 /* WB */
416 MOCS_ENTRY(2, 0, L3_3_WB),
417};
418
419static void pvc_mocs_dump(struct xe_mocs_info *info, unsigned int flags, struct xe_gt *gt,
420 struct drm_printer *p)
421{
422 unsigned int i, j;
423 u32 reg_val;
424
425 drm_printf(p, "LNCFCMOCS[idx] = [ L3CC ] (value)\n\n");
426
427 for (i = 0, j = 0; i < (info->num_mocs_regs + 1) / 2; i++, j++) {
428 if (regs_are_mcr(gt))
429 reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_LNCFCMOCS(i));
430 else
431 reg_val = xe_mmio_read32(>->mmio, XELP_LNCFCMOCS(i));
432
433 drm_printf(p, "LNCFCMOCS[%2d] = [ %u ] (%#8x)\n",
434 j++,
435 REG_FIELD_GET(L3_CACHEABILITY_MASK, reg_val),
436 reg_val);
437
438 drm_printf(p, "LNCFCMOCS[%2d] = [ %u ] (%#8x)\n",
439 j,
440 REG_FIELD_GET(L3_UPPER_IDX_CACHEABILITY_MASK, reg_val),
441 reg_val);
442 }
443}
444
445static const struct xe_mocs_ops pvc_mocs_ops = {
446 .dump = pvc_mocs_dump,
447};
448
449static const struct xe_mocs_entry mtl_mocs_desc[] = {
450 /* Error - Reserved for Non-Use */
451 MOCS_ENTRY(0,
452 0,
453 L3_LKUP(1) | L3_3_WB),
454 /* Cached - L3 + L4 */
455 MOCS_ENTRY(1,
456 IG_PAT,
457 L3_LKUP(1) | L3_3_WB),
458 /* L4 - GO:L3 */
459 MOCS_ENTRY(2,
460 IG_PAT,
461 L3_LKUP(1) | L3_1_UC),
462 /* Uncached - GO:L3 */
463 MOCS_ENTRY(3,
464 IG_PAT | L4_3_UC,
465 L3_LKUP(1) | L3_1_UC),
466 /* L4 - GO:Mem */
467 MOCS_ENTRY(4,
468 IG_PAT,
469 L3_LKUP(1) | L3_GLBGO(1) | L3_1_UC),
470 /* Uncached - GO:Mem */
471 MOCS_ENTRY(5,
472 IG_PAT | L4_3_UC,
473 L3_LKUP(1) | L3_GLBGO(1) | L3_1_UC),
474 /* L4 - L3:NoLKUP; GO:L3 */
475 MOCS_ENTRY(6,
476 IG_PAT,
477 L3_1_UC),
478 /* Uncached - L3:NoLKUP; GO:L3 */
479 MOCS_ENTRY(7,
480 IG_PAT | L4_3_UC,
481 L3_1_UC),
482 /* L4 - L3:NoLKUP; GO:Mem */
483 MOCS_ENTRY(8,
484 IG_PAT,
485 L3_GLBGO(1) | L3_1_UC),
486 /* Uncached - L3:NoLKUP; GO:Mem */
487 MOCS_ENTRY(9,
488 IG_PAT | L4_3_UC,
489 L3_GLBGO(1) | L3_1_UC),
490 /* Display - L3; L4:WT */
491 MOCS_ENTRY(14,
492 IG_PAT | L4_1_WT,
493 L3_LKUP(1) | L3_3_WB),
494 /* CCS - Non-Displayable */
495 MOCS_ENTRY(15,
496 IG_PAT,
497 L3_GLBGO(1) | L3_1_UC),
498};
499
500static void mtl_mocs_dump(struct xe_mocs_info *info, unsigned int flags,
501 struct xe_gt *gt, struct drm_printer *p)
502{
503 unsigned int i;
504 u32 reg_val;
505
506 drm_printf(p, "Global mocs table configuration:\n");
507 drm_printf(p, "GLOB_MOCS[idx] = [IG_PAT, L4_CACHE_POLICY] (value)\n\n");
508
509 for (i = 0; i < info->num_mocs_regs; i++) {
510 if (regs_are_mcr(gt))
511 reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i));
512 else
513 reg_val = xe_mmio_read32(>->mmio, XELP_GLOBAL_MOCS(i));
514
515 drm_printf(p, "GLOB_MOCS[%2d] = [%u, %u] (%#8x)\n",
516 i,
517 !!(reg_val & IG_PAT),
518 REG_FIELD_GET(L4_CACHE_POLICY_MASK, reg_val),
519 reg_val);
520 }
521
522 /* MTL lncf mocs table pattern is similar to that of xehp */
523 xehp_lncf_dump(info, flags, gt, p);
524}
525
526static const struct xe_mocs_ops mtl_mocs_ops = {
527 .dump = mtl_mocs_dump,
528};
529
530static const struct xe_mocs_entry xe2_mocs_table[] = {
531 /* Defer to PAT */
532 MOCS_ENTRY(0, XE2_L3_0_WB | L4_3_UC, 0),
533 /* Cached L3, Uncached L4 */
534 MOCS_ENTRY(1, IG_PAT | XE2_L3_0_WB | L4_3_UC, 0),
535 /* Uncached L3, Cached L4 */
536 MOCS_ENTRY(2, IG_PAT | XE2_L3_3_UC | L4_0_WB, 0),
537 /* Uncached L3 + L4 */
538 MOCS_ENTRY(3, IG_PAT | XE2_L3_3_UC | L4_3_UC, 0),
539 /* Cached L3 + L4 */
540 MOCS_ENTRY(4, IG_PAT | XE2_L3_0_WB | L4_0_WB, 0),
541};
542
543static void xe2_mocs_dump(struct xe_mocs_info *info, unsigned int flags,
544 struct xe_gt *gt, struct drm_printer *p)
545{
546 unsigned int i;
547 u32 reg_val;
548
549 drm_printf(p, "Global mocs table configuration:\n");
550 drm_printf(p, "GLOB_MOCS[idx] = [IG_PAT, L3_CLOS, L3_CACHE_POLICY, L4_CACHE_POLICY] (value)\n\n");
551
552 for (i = 0; i < info->num_mocs_regs; i++) {
553 if (regs_are_mcr(gt))
554 reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i));
555 else
556 reg_val = xe_mmio_read32(>->mmio, XELP_GLOBAL_MOCS(i));
557
558 drm_printf(p, "GLOB_MOCS[%2d] = [%u, %u, %u] (%#8x)\n",
559 i,
560 !!(reg_val & IG_PAT),
561 REG_FIELD_GET(XE2_L3_CLOS_MASK, reg_val),
562 REG_FIELD_GET(L4_CACHE_POLICY_MASK, reg_val),
563 reg_val);
564 }
565}
566
567static const struct xe_mocs_ops xe2_mocs_ops = {
568 .dump = xe2_mocs_dump,
569};
570
571static unsigned int get_mocs_settings(struct xe_device *xe,
572 struct xe_mocs_info *info)
573{
574 unsigned int flags = 0;
575
576 memset(info, 0, sizeof(struct xe_mocs_info));
577
578 switch (xe->info.platform) {
579 case XE_PANTHERLAKE:
580 case XE_LUNARLAKE:
581 case XE_BATTLEMAGE:
582 info->ops = &xe2_mocs_ops;
583 info->table_size = ARRAY_SIZE(xe2_mocs_table);
584 info->table = xe2_mocs_table;
585 info->num_mocs_regs = XE2_NUM_MOCS_ENTRIES;
586 info->uc_index = 3;
587 info->wb_index = 4;
588 info->unused_entries_index = 4;
589 break;
590 case XE_PVC:
591 info->ops = &pvc_mocs_ops;
592 info->table_size = ARRAY_SIZE(pvc_mocs_desc);
593 info->table = pvc_mocs_desc;
594 info->num_mocs_regs = PVC_NUM_MOCS_ENTRIES;
595 info->uc_index = 1;
596 info->wb_index = 2;
597 info->unused_entries_index = 2;
598 break;
599 case XE_METEORLAKE:
600 info->ops = &mtl_mocs_ops;
601 info->table_size = ARRAY_SIZE(mtl_mocs_desc);
602 info->table = mtl_mocs_desc;
603 info->num_mocs_regs = MTL_NUM_MOCS_ENTRIES;
604 info->uc_index = 9;
605 info->unused_entries_index = 1;
606 break;
607 case XE_DG2:
608 info->ops = &xehp_mocs_ops;
609 info->table_size = ARRAY_SIZE(dg2_mocs_desc);
610 info->table = dg2_mocs_desc;
611 info->uc_index = 1;
612 /*
613 * Last entry is RO on hardware, don't bother with what was
614 * written when checking later
615 */
616 info->num_mocs_regs = XELP_NUM_MOCS_ENTRIES - 1;
617 info->unused_entries_index = 3;
618 break;
619 case XE_DG1:
620 info->ops = &xelp_mocs_ops;
621 info->table_size = ARRAY_SIZE(dg1_mocs_desc);
622 info->table = dg1_mocs_desc;
623 info->uc_index = 1;
624 info->num_mocs_regs = XELP_NUM_MOCS_ENTRIES;
625 info->unused_entries_index = 5;
626 break;
627 case XE_TIGERLAKE:
628 case XE_ROCKETLAKE:
629 case XE_ALDERLAKE_S:
630 case XE_ALDERLAKE_P:
631 case XE_ALDERLAKE_N:
632 info->ops = &xelp_mocs_ops;
633 info->table_size = ARRAY_SIZE(gen12_mocs_desc);
634 info->table = gen12_mocs_desc;
635 info->num_mocs_regs = XELP_NUM_MOCS_ENTRIES;
636 info->uc_index = 3;
637 info->unused_entries_index = 2;
638 break;
639 default:
640 drm_err(&xe->drm, "Platform that should have a MOCS table does not.\n");
641 return 0;
642 }
643
644 /*
645 * Index 0 is a reserved/unused table entry on most platforms, but
646 * even on those where it does represent a legitimate MOCS entry, it
647 * never represents the "most cached, least coherent" behavior we want
648 * to populate undefined table rows with. So if unused_entries_index
649 * is still 0 at this point, we'll assume that it was omitted by
650 * mistake in the switch statement above.
651 */
652 xe_assert(xe, info->unused_entries_index != 0);
653
654 xe_assert(xe, info->ops && info->ops->dump);
655 xe_assert(xe, info->table_size <= info->num_mocs_regs);
656
657 if (!IS_DGFX(xe) || GRAPHICS_VER(xe) >= 20)
658 flags |= HAS_GLOBAL_MOCS;
659 if (GRAPHICS_VER(xe) < 20)
660 flags |= HAS_LNCF_MOCS;
661
662 return flags;
663}
664
665/*
666 * Get control_value from MOCS entry. If the table entry is not defined, the
667 * settings from unused_entries_index will be returned.
668 */
669static u32 get_entry_control(const struct xe_mocs_info *info,
670 unsigned int index)
671{
672 if (index < info->table_size && info->table[index].used)
673 return info->table[index].control_value;
674 return info->table[info->unused_entries_index].control_value;
675}
676
677static void __init_mocs_table(struct xe_gt *gt,
678 const struct xe_mocs_info *info)
679{
680 unsigned int i;
681 u32 mocs;
682
683 mocs_dbg(gt, "mocs entries: %d\n", info->num_mocs_regs);
684
685 for (i = 0; i < info->num_mocs_regs; i++) {
686 mocs = get_entry_control(info, i);
687
688 mocs_dbg(gt, "GLOB_MOCS[%d] 0x%x 0x%x\n", i,
689 XELP_GLOBAL_MOCS(i).addr, mocs);
690
691 if (regs_are_mcr(gt))
692 xe_gt_mcr_multicast_write(gt, XEHP_GLOBAL_MOCS(i), mocs);
693 else
694 xe_mmio_write32(>->mmio, XELP_GLOBAL_MOCS(i), mocs);
695 }
696}
697
698/*
699 * Get l3cc_value from MOCS entry taking into account when it's not used
700 * then if unused_entries_index is not zero then its value will be returned
701 * otherwise I915_MOCS_PTE's value is returned in this case.
702 */
703static u16 get_entry_l3cc(const struct xe_mocs_info *info,
704 unsigned int index)
705{
706 if (index < info->table_size && info->table[index].used)
707 return info->table[index].l3cc_value;
708 return info->table[info->unused_entries_index].l3cc_value;
709}
710
711static u32 l3cc_combine(u16 low, u16 high)
712{
713 return low | (u32)high << 16;
714}
715
716static void init_l3cc_table(struct xe_gt *gt,
717 const struct xe_mocs_info *info)
718{
719 unsigned int i;
720 u32 l3cc;
721
722 mocs_dbg(gt, "l3cc entries: %d\n", info->num_mocs_regs);
723
724 for (i = 0; i < (info->num_mocs_regs + 1) / 2; i++) {
725 l3cc = l3cc_combine(get_entry_l3cc(info, 2 * i),
726 get_entry_l3cc(info, 2 * i + 1));
727
728 mocs_dbg(gt, "LNCFCMOCS[%d] 0x%x 0x%x\n", i,
729 XELP_LNCFCMOCS(i).addr, l3cc);
730
731 if (regs_are_mcr(gt))
732 xe_gt_mcr_multicast_write(gt, XEHP_LNCFCMOCS(i), l3cc);
733 else
734 xe_mmio_write32(>->mmio, XELP_LNCFCMOCS(i), l3cc);
735 }
736}
737
738void xe_mocs_init_early(struct xe_gt *gt)
739{
740 struct xe_mocs_info table;
741
742 get_mocs_settings(gt_to_xe(gt), &table);
743 gt->mocs.uc_index = table.uc_index;
744 gt->mocs.wb_index = table.wb_index;
745}
746
747void xe_mocs_init(struct xe_gt *gt)
748{
749 struct xe_mocs_info table;
750 unsigned int flags;
751
752 if (IS_SRIOV_VF(gt_to_xe(gt)))
753 return;
754
755 /*
756 * MOCS settings are split between "GLOB_MOCS" and/or "LNCFCMOCS"
757 * registers depending on platform.
758 *
759 * These registers should be programmed before GuC initialization
760 * since their values will affect some of the memory transactions
761 * performed by the GuC.
762 */
763 flags = get_mocs_settings(gt_to_xe(gt), &table);
764 mocs_dbg(gt, "flag:0x%x\n", flags);
765
766 if (IS_SRIOV_VF(gt_to_xe(gt)))
767 return;
768
769 if (flags & HAS_GLOBAL_MOCS)
770 __init_mocs_table(gt, &table);
771 if (flags & HAS_LNCF_MOCS)
772 init_l3cc_table(gt, &table);
773}
774
775void xe_mocs_dump(struct xe_gt *gt, struct drm_printer *p)
776{
777 struct xe_device *xe = gt_to_xe(gt);
778 struct xe_mocs_info table;
779 unsigned int fw_ref, flags;
780
781 flags = get_mocs_settings(xe, &table);
782
783 xe_pm_runtime_get_noresume(xe);
784 fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
785 if (!fw_ref)
786 goto err_fw;
787
788 table.ops->dump(&table, flags, gt, p);
789
790 xe_force_wake_put(gt_to_fw(gt), fw_ref);
791err_fw:
792 xe_pm_runtime_put(xe);
793}
794
795#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
796#include "tests/xe_mocs.c"
797#endif
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2022 Intel Corporation
4 */
5
6#include "xe_mocs.h"
7
8#include "regs/xe_gt_regs.h"
9#include "xe_bo.h"
10#include "xe_device.h"
11#include "xe_exec_queue.h"
12#include "xe_gt.h"
13#include "xe_gt_mcr.h"
14#include "xe_mmio.h"
15#include "xe_platform_types.h"
16#include "xe_step_types.h"
17
18#if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
19#define mocs_dbg drm_dbg
20#else
21__printf(2, 3)
22static inline void mocs_dbg(const struct drm_device *dev,
23 const char *format, ...)
24{ /* noop */ }
25#endif
26
27enum {
28 HAS_GLOBAL_MOCS = BIT(0),
29 HAS_LNCF_MOCS = BIT(1),
30};
31
32struct xe_mocs_entry {
33 u32 control_value;
34 u16 l3cc_value;
35 u16 used;
36};
37
38struct xe_mocs_info {
39 unsigned int size;
40 unsigned int n_entries;
41 const struct xe_mocs_entry *table;
42 u8 uc_index;
43 u8 wb_index;
44 u8 unused_entries_index;
45};
46
47/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
48#define _LE_CACHEABILITY(value) ((value) << 0)
49#define _LE_TGT_CACHE(value) ((value) << 2)
50#define LE_LRUM(value) ((value) << 4)
51#define LE_AOM(value) ((value) << 6)
52#define LE_RSC(value) ((value) << 7)
53#define LE_SCC(value) ((value) << 8)
54#define LE_PFM(value) ((value) << 11)
55#define LE_SCF(value) ((value) << 14)
56#define LE_COS(value) ((value) << 15)
57#define LE_SSE(value) ((value) << 17)
58
59/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */
60#define L3_ESC(value) ((value) << 0)
61#define L3_SCC(value) ((value) << 1)
62#define _L3_CACHEABILITY(value) ((value) << 4)
63#define L3_GLBGO(value) ((value) << 6)
64#define L3_LKUP(value) ((value) << 7)
65
66/* Defines for the tables (GLOB_MOCS_0 - GLOB_MOCS_16) */
67#define IG_PAT REG_BIT(8)
68#define L3_CACHE_POLICY_MASK REG_GENMASK(5, 4)
69#define L4_CACHE_POLICY_MASK REG_GENMASK(3, 2)
70
71/* Helper defines */
72#define XELP_NUM_MOCS_ENTRIES 64 /* 63-64 are reserved, but configured. */
73#define PVC_NUM_MOCS_ENTRIES 3
74#define MTL_NUM_MOCS_ENTRIES 16
75#define XE2_NUM_MOCS_ENTRIES 16
76
77/* (e)LLC caching options */
78/*
79 * Note: LE_0_PAGETABLE works only up to Gen11; for newer gens it means
80 * the same as LE_UC
81 */
82#define LE_0_PAGETABLE _LE_CACHEABILITY(0)
83#define LE_1_UC _LE_CACHEABILITY(1)
84#define LE_2_WT _LE_CACHEABILITY(2)
85#define LE_3_WB _LE_CACHEABILITY(3)
86
87/* Target cache */
88#define LE_TC_0_PAGETABLE _LE_TGT_CACHE(0)
89#define LE_TC_1_LLC _LE_TGT_CACHE(1)
90#define LE_TC_2_LLC_ELLC _LE_TGT_CACHE(2)
91#define LE_TC_3_LLC_ELLC_ALT _LE_TGT_CACHE(3)
92
93/* L3 caching options */
94#define L3_0_DIRECT _L3_CACHEABILITY(0)
95#define L3_1_UC _L3_CACHEABILITY(1)
96#define L3_2_RESERVED _L3_CACHEABILITY(2)
97#define L3_3_WB _L3_CACHEABILITY(3)
98
99/* L4 caching options */
100#define L4_0_WB REG_FIELD_PREP(L4_CACHE_POLICY_MASK, 0)
101#define L4_1_WT REG_FIELD_PREP(L4_CACHE_POLICY_MASK, 1)
102#define L4_3_UC REG_FIELD_PREP(L4_CACHE_POLICY_MASK, 3)
103
104#define XE2_L3_0_WB REG_FIELD_PREP(L3_CACHE_POLICY_MASK, 0)
105/* XD: WB Transient Display */
106#define XE2_L3_1_XD REG_FIELD_PREP(L3_CACHE_POLICY_MASK, 1)
107#define XE2_L3_3_UC REG_FIELD_PREP(L3_CACHE_POLICY_MASK, 3)
108
109#define MOCS_ENTRY(__idx, __control_value, __l3cc_value) \
110 [__idx] = { \
111 .control_value = __control_value, \
112 .l3cc_value = __l3cc_value, \
113 .used = 1, \
114 }
115
116/*
117 * MOCS tables
118 *
119 * These are the MOCS tables that are programmed across all the rings.
120 * The control value is programmed to all the rings that support the
121 * MOCS registers. While the l3cc_values are only programmed to the
122 * LNCFCMOCS0 - LNCFCMOCS32 registers.
123 *
124 * These tables are intended to be kept reasonably consistent across
125 * HW platforms, and for ICL+, be identical across OSes. To achieve
126 * that, the list of entries is published as part of bspec.
127 *
128 * Entries not part of the following tables are undefined as far as userspace is
129 * concerned and shouldn't be relied upon. The last few entries are reserved by
130 * the hardware. They should be initialized according to bspec and never used.
131 *
132 * NOTE1: These tables are part of bspec and defined as part of the hardware
133 * interface. It is expected that, for specific hardware platform, existing
134 * entries will remain constant and the table will only be updated by adding new
135 * entries, filling unused positions.
136 *
137 * NOTE2: Reserved and unspecified MOCS indices have been set to L3 WB. These
138 * reserved entries should never be used. They may be changed to low performant
139 * variants with better coherency in the future if more entries are needed.
140 */
141
142static const struct xe_mocs_entry gen12_mocs_desc[] = {
143 /* Base - L3 + LLC */
144 MOCS_ENTRY(2,
145 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
146 L3_3_WB),
147 /* Base - Uncached */
148 MOCS_ENTRY(3,
149 LE_1_UC | LE_TC_1_LLC,
150 L3_1_UC),
151 /* Base - L3 */
152 MOCS_ENTRY(4,
153 LE_1_UC | LE_TC_1_LLC,
154 L3_3_WB),
155 /* Base - LLC */
156 MOCS_ENTRY(5,
157 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
158 L3_1_UC),
159 /* Age 0 - LLC */
160 MOCS_ENTRY(6,
161 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1),
162 L3_1_UC),
163 /* Age 0 - L3 + LLC */
164 MOCS_ENTRY(7,
165 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1),
166 L3_3_WB),
167 /* Age: Don't Chg. - LLC */
168 MOCS_ENTRY(8,
169 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2),
170 L3_1_UC),
171 /* Age: Don't Chg. - L3 + LLC */
172 MOCS_ENTRY(9,
173 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2),
174 L3_3_WB),
175 /* No AOM - LLC */
176 MOCS_ENTRY(10,
177 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_AOM(1),
178 L3_1_UC),
179 /* No AOM - L3 + LLC */
180 MOCS_ENTRY(11,
181 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_AOM(1),
182 L3_3_WB),
183 /* No AOM; Age 0 - LLC */
184 MOCS_ENTRY(12,
185 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1) | LE_AOM(1),
186 L3_1_UC),
187 /* No AOM; Age 0 - L3 + LLC */
188 MOCS_ENTRY(13,
189 LE_3_WB | LE_TC_1_LLC | LE_LRUM(1) | LE_AOM(1),
190 L3_3_WB),
191 /* No AOM; Age:DC - LLC */
192 MOCS_ENTRY(14,
193 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2) | LE_AOM(1),
194 L3_1_UC),
195 /* No AOM; Age:DC - L3 + LLC */
196 MOCS_ENTRY(15,
197 LE_3_WB | LE_TC_1_LLC | LE_LRUM(2) | LE_AOM(1),
198 L3_3_WB),
199 /* Self-Snoop - L3 + LLC */
200 MOCS_ENTRY(18,
201 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SSE(3),
202 L3_3_WB),
203 /* Skip Caching - L3 + LLC(12.5%) */
204 MOCS_ENTRY(19,
205 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(7),
206 L3_3_WB),
207 /* Skip Caching - L3 + LLC(25%) */
208 MOCS_ENTRY(20,
209 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(3),
210 L3_3_WB),
211 /* Skip Caching - L3 + LLC(50%) */
212 MOCS_ENTRY(21,
213 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(1),
214 L3_3_WB),
215 /* Skip Caching - L3 + LLC(75%) */
216 MOCS_ENTRY(22,
217 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_RSC(1) | LE_SCC(3),
218 L3_3_WB),
219 /* Skip Caching - L3 + LLC(87.5%) */
220 MOCS_ENTRY(23,
221 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_RSC(1) | LE_SCC(7),
222 L3_3_WB),
223 /* Implicitly enable L1 - HDC:L1 + L3 + LLC */
224 MOCS_ENTRY(48,
225 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
226 L3_3_WB),
227 /* Implicitly enable L1 - HDC:L1 + L3 */
228 MOCS_ENTRY(49,
229 LE_1_UC | LE_TC_1_LLC,
230 L3_3_WB),
231 /* Implicitly enable L1 - HDC:L1 + LLC */
232 MOCS_ENTRY(50,
233 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
234 L3_1_UC),
235 /* Implicitly enable L1 - HDC:L1 */
236 MOCS_ENTRY(51,
237 LE_1_UC | LE_TC_1_LLC,
238 L3_1_UC),
239 /* HW Special Case (CCS) */
240 MOCS_ENTRY(60,
241 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
242 L3_1_UC),
243 /* HW Special Case (Displayable) */
244 MOCS_ENTRY(61,
245 LE_1_UC | LE_TC_1_LLC,
246 L3_3_WB),
247 /* HW Reserved - SW program but never use */
248 MOCS_ENTRY(62,
249 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
250 L3_1_UC),
251 /* HW Reserved - SW program but never use */
252 MOCS_ENTRY(63,
253 LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
254 L3_1_UC)
255};
256
257static const struct xe_mocs_entry dg1_mocs_desc[] = {
258 /* UC */
259 MOCS_ENTRY(1, 0, L3_1_UC),
260 /* WB - L3 */
261 MOCS_ENTRY(5, 0, L3_3_WB),
262 /* WB - L3 50% */
263 MOCS_ENTRY(6, 0, L3_ESC(1) | L3_SCC(1) | L3_3_WB),
264 /* WB - L3 25% */
265 MOCS_ENTRY(7, 0, L3_ESC(1) | L3_SCC(3) | L3_3_WB),
266 /* WB - L3 12.5% */
267 MOCS_ENTRY(8, 0, L3_ESC(1) | L3_SCC(7) | L3_3_WB),
268
269 /* HDC:L1 + L3 */
270 MOCS_ENTRY(48, 0, L3_3_WB),
271 /* HDC:L1 */
272 MOCS_ENTRY(49, 0, L3_1_UC),
273
274 /* HW Reserved */
275 MOCS_ENTRY(60, 0, L3_1_UC),
276 MOCS_ENTRY(61, 0, L3_1_UC),
277 MOCS_ENTRY(62, 0, L3_1_UC),
278 MOCS_ENTRY(63, 0, L3_1_UC),
279};
280
281static const struct xe_mocs_entry dg2_mocs_desc[] = {
282 /* UC - Coherent; GO:L3 */
283 MOCS_ENTRY(0, 0, L3_1_UC | L3_LKUP(1)),
284 /* UC - Coherent; GO:Memory */
285 MOCS_ENTRY(1, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)),
286 /* UC - Non-Coherent; GO:Memory */
287 MOCS_ENTRY(2, 0, L3_1_UC | L3_GLBGO(1)),
288
289 /* WB - LC */
290 MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)),
291};
292
293static const struct xe_mocs_entry dg2_mocs_desc_g10_ax[] = {
294 /* Wa_14011441408: Set Go to Memory for MOCS#0 */
295 MOCS_ENTRY(0, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)),
296 /* UC - Coherent; GO:Memory */
297 MOCS_ENTRY(1, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)),
298 /* UC - Non-Coherent; GO:Memory */
299 MOCS_ENTRY(2, 0, L3_1_UC | L3_GLBGO(1)),
300
301 /* WB - LC */
302 MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)),
303};
304
305static const struct xe_mocs_entry pvc_mocs_desc[] = {
306 /* Error */
307 MOCS_ENTRY(0, 0, L3_3_WB),
308
309 /* UC */
310 MOCS_ENTRY(1, 0, L3_1_UC),
311
312 /* WB */
313 MOCS_ENTRY(2, 0, L3_3_WB),
314};
315
316static const struct xe_mocs_entry mtl_mocs_desc[] = {
317 /* Error - Reserved for Non-Use */
318 MOCS_ENTRY(0,
319 0,
320 L3_LKUP(1) | L3_3_WB),
321 /* Cached - L3 + L4 */
322 MOCS_ENTRY(1,
323 IG_PAT,
324 L3_LKUP(1) | L3_3_WB),
325 /* L4 - GO:L3 */
326 MOCS_ENTRY(2,
327 IG_PAT,
328 L3_LKUP(1) | L3_1_UC),
329 /* Uncached - GO:L3 */
330 MOCS_ENTRY(3,
331 IG_PAT | L4_3_UC,
332 L3_LKUP(1) | L3_1_UC),
333 /* L4 - GO:Mem */
334 MOCS_ENTRY(4,
335 IG_PAT,
336 L3_LKUP(1) | L3_GLBGO(1) | L3_1_UC),
337 /* Uncached - GO:Mem */
338 MOCS_ENTRY(5,
339 IG_PAT | L4_3_UC,
340 L3_LKUP(1) | L3_GLBGO(1) | L3_1_UC),
341 /* L4 - L3:NoLKUP; GO:L3 */
342 MOCS_ENTRY(6,
343 IG_PAT,
344 L3_1_UC),
345 /* Uncached - L3:NoLKUP; GO:L3 */
346 MOCS_ENTRY(7,
347 IG_PAT | L4_3_UC,
348 L3_1_UC),
349 /* L4 - L3:NoLKUP; GO:Mem */
350 MOCS_ENTRY(8,
351 IG_PAT,
352 L3_GLBGO(1) | L3_1_UC),
353 /* Uncached - L3:NoLKUP; GO:Mem */
354 MOCS_ENTRY(9,
355 IG_PAT | L4_3_UC,
356 L3_GLBGO(1) | L3_1_UC),
357 /* Display - L3; L4:WT */
358 MOCS_ENTRY(14,
359 IG_PAT | L4_1_WT,
360 L3_LKUP(1) | L3_3_WB),
361 /* CCS - Non-Displayable */
362 MOCS_ENTRY(15,
363 IG_PAT,
364 L3_GLBGO(1) | L3_1_UC),
365};
366
367static const struct xe_mocs_entry xe2_mocs_table[] = {
368 /* Defer to PAT */
369 MOCS_ENTRY(0, XE2_L3_0_WB | L4_3_UC, 0),
370 /* Cached L3, Uncached L4 */
371 MOCS_ENTRY(1, IG_PAT | XE2_L3_0_WB | L4_3_UC, 0),
372 /* Uncached L3, Cached L4 */
373 MOCS_ENTRY(2, IG_PAT | XE2_L3_3_UC | L4_0_WB, 0),
374 /* Uncached L3 + L4 */
375 MOCS_ENTRY(3, IG_PAT | XE2_L3_3_UC | L4_3_UC, 0),
376 /* Cached L3 + L4 */
377 MOCS_ENTRY(4, IG_PAT | XE2_L3_0_WB | L4_0_WB, 0),
378};
379
380static unsigned int get_mocs_settings(struct xe_device *xe,
381 struct xe_mocs_info *info)
382{
383 unsigned int flags = 0;
384
385 memset(info, 0, sizeof(struct xe_mocs_info));
386
387 switch (xe->info.platform) {
388 case XE_LUNARLAKE:
389 info->size = ARRAY_SIZE(xe2_mocs_table);
390 info->table = xe2_mocs_table;
391 info->n_entries = XE2_NUM_MOCS_ENTRIES;
392 info->uc_index = 3;
393 info->wb_index = 4;
394 info->unused_entries_index = 4;
395 break;
396 case XE_PVC:
397 info->size = ARRAY_SIZE(pvc_mocs_desc);
398 info->table = pvc_mocs_desc;
399 info->n_entries = PVC_NUM_MOCS_ENTRIES;
400 info->uc_index = 1;
401 info->wb_index = 2;
402 info->unused_entries_index = 2;
403 break;
404 case XE_METEORLAKE:
405 info->size = ARRAY_SIZE(mtl_mocs_desc);
406 info->table = mtl_mocs_desc;
407 info->n_entries = MTL_NUM_MOCS_ENTRIES;
408 info->uc_index = 9;
409 info->unused_entries_index = 1;
410 break;
411 case XE_DG2:
412 if (xe->info.subplatform == XE_SUBPLATFORM_DG2_G10 &&
413 xe->info.step.graphics >= STEP_A0 &&
414 xe->info.step.graphics <= STEP_B0) {
415 info->size = ARRAY_SIZE(dg2_mocs_desc_g10_ax);
416 info->table = dg2_mocs_desc_g10_ax;
417 } else {
418 info->size = ARRAY_SIZE(dg2_mocs_desc);
419 info->table = dg2_mocs_desc;
420 }
421 info->uc_index = 1;
422 info->n_entries = XELP_NUM_MOCS_ENTRIES;
423 info->unused_entries_index = 3;
424 break;
425 case XE_DG1:
426 info->size = ARRAY_SIZE(dg1_mocs_desc);
427 info->table = dg1_mocs_desc;
428 info->uc_index = 1;
429 info->n_entries = XELP_NUM_MOCS_ENTRIES;
430 info->unused_entries_index = 5;
431 break;
432 case XE_TIGERLAKE:
433 case XE_ROCKETLAKE:
434 case XE_ALDERLAKE_S:
435 case XE_ALDERLAKE_P:
436 case XE_ALDERLAKE_N:
437 info->size = ARRAY_SIZE(gen12_mocs_desc);
438 info->table = gen12_mocs_desc;
439 info->n_entries = XELP_NUM_MOCS_ENTRIES;
440 info->uc_index = 3;
441 info->unused_entries_index = 2;
442 break;
443 default:
444 drm_err(&xe->drm, "Platform that should have a MOCS table does not.\n");
445 return 0;
446 }
447
448 /*
449 * Index 0 is a reserved/unused table entry on most platforms, but
450 * even on those where it does represent a legitimate MOCS entry, it
451 * never represents the "most cached, least coherent" behavior we want
452 * to populate undefined table rows with. So if unused_entries_index
453 * is still 0 at this point, we'll assume that it was omitted by
454 * mistake in the switch statement above.
455 */
456 xe_assert(xe, info->unused_entries_index != 0);
457
458 if (XE_WARN_ON(info->size > info->n_entries)) {
459 info->table = NULL;
460 return 0;
461 }
462
463 if (!IS_DGFX(xe) || GRAPHICS_VER(xe) >= 20)
464 flags |= HAS_GLOBAL_MOCS;
465 if (GRAPHICS_VER(xe) < 20)
466 flags |= HAS_LNCF_MOCS;
467
468 return flags;
469}
470
471/*
472 * Get control_value from MOCS entry. If the table entry is not defined, the
473 * settings from unused_entries_index will be returned.
474 */
475static u32 get_entry_control(const struct xe_mocs_info *info,
476 unsigned int index)
477{
478 if (index < info->size && info->table[index].used)
479 return info->table[index].control_value;
480 return info->table[info->unused_entries_index].control_value;
481}
482
483static void __init_mocs_table(struct xe_gt *gt,
484 const struct xe_mocs_info *info)
485{
486 struct xe_device *xe = gt_to_xe(gt);
487
488 unsigned int i;
489 u32 mocs;
490
491 mocs_dbg(>_to_xe(gt)->drm, "entries:%d\n", info->n_entries);
492 drm_WARN_ONCE(&xe->drm, !info->unused_entries_index,
493 "Unused entries index should have been defined\n");
494 for (i = 0;
495 i < info->n_entries ? (mocs = get_entry_control(info, i)), 1 : 0;
496 i++) {
497 mocs_dbg(>_to_xe(gt)->drm, "GLOB_MOCS[%d] 0x%x 0x%x\n", i,
498 XELP_GLOBAL_MOCS(i).addr, mocs);
499
500 if (GRAPHICS_VERx100(gt_to_xe(gt)) > 1250)
501 xe_gt_mcr_multicast_write(gt, XEHP_GLOBAL_MOCS(i), mocs);
502 else
503 xe_mmio_write32(gt, XELP_GLOBAL_MOCS(i), mocs);
504 }
505}
506
507/*
508 * Get l3cc_value from MOCS entry taking into account when it's not used
509 * then if unused_entries_index is not zero then its value will be returned
510 * otherwise I915_MOCS_PTE's value is returned in this case.
511 */
512static u16 get_entry_l3cc(const struct xe_mocs_info *info,
513 unsigned int index)
514{
515 if (index < info->size && info->table[index].used)
516 return info->table[index].l3cc_value;
517 return info->table[info->unused_entries_index].l3cc_value;
518}
519
520static u32 l3cc_combine(u16 low, u16 high)
521{
522 return low | (u32)high << 16;
523}
524
525static void init_l3cc_table(struct xe_gt *gt,
526 const struct xe_mocs_info *info)
527{
528 unsigned int i;
529 u32 l3cc;
530
531 mocs_dbg(>_to_xe(gt)->drm, "entries:%d\n", info->n_entries);
532 for (i = 0;
533 i < (info->n_entries + 1) / 2 ?
534 (l3cc = l3cc_combine(get_entry_l3cc(info, 2 * i),
535 get_entry_l3cc(info, 2 * i + 1))), 1 : 0;
536 i++) {
537 mocs_dbg(>_to_xe(gt)->drm, "LNCFCMOCS[%d] 0x%x 0x%x\n", i, XELP_LNCFCMOCS(i).addr,
538 l3cc);
539
540 if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 1250)
541 xe_gt_mcr_multicast_write(gt, XEHP_LNCFCMOCS(i), l3cc);
542 else
543 xe_mmio_write32(gt, XELP_LNCFCMOCS(i), l3cc);
544 }
545}
546
547void xe_mocs_init_early(struct xe_gt *gt)
548{
549 struct xe_mocs_info table;
550
551 get_mocs_settings(gt_to_xe(gt), &table);
552 gt->mocs.uc_index = table.uc_index;
553 gt->mocs.wb_index = table.wb_index;
554}
555
556void xe_mocs_init(struct xe_gt *gt)
557{
558 struct xe_mocs_info table;
559 unsigned int flags;
560
561 /*
562 * MOCS settings are split between "GLOB_MOCS" and/or "LNCFCMOCS"
563 * registers depending on platform.
564 *
565 * These registers should be programmed before GuC initialization
566 * since their values will affect some of the memory transactions
567 * performed by the GuC.
568 */
569 flags = get_mocs_settings(gt_to_xe(gt), &table);
570 mocs_dbg(>_to_xe(gt)->drm, "flag:0x%x\n", flags);
571
572 if (flags & HAS_GLOBAL_MOCS)
573 __init_mocs_table(gt, &table);
574 if (flags & HAS_LNCF_MOCS)
575 init_l3cc_table(gt, &table);
576}
577
578#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
579#include "tests/xe_mocs.c"
580#endif