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