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