Linux Audio

Check our new training course

Loading...
v6.13.7
  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(&gt->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(&gt->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(&gt->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(&gt->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(&gt->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(&gt->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(&gt->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(&gt->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
v6.8
  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(&gt_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(&gt_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(&gt_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(&gt_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(&gt_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