xref: /dragonfly/sys/dev/drm/i915/intel_mocs.c (revision 3f2dd94a)
1a05eeebfSFrançois Tigeot /*
2a05eeebfSFrançois Tigeot  * Copyright (c) 2015 Intel Corporation
3a05eeebfSFrançois Tigeot  *
4a05eeebfSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5a05eeebfSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6a05eeebfSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7a05eeebfSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8a05eeebfSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9a05eeebfSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions: *
10a05eeebfSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
11a05eeebfSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
12a05eeebfSFrançois Tigeot  * Software.
13a05eeebfSFrançois Tigeot  *
14a05eeebfSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15a05eeebfSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16a05eeebfSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17a05eeebfSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18a05eeebfSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19a05eeebfSFrançois Tigeot  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20a05eeebfSFrançois Tigeot  * SOFTWARE.
21a05eeebfSFrançois Tigeot  */
22a05eeebfSFrançois Tigeot 
23a05eeebfSFrançois Tigeot #include "intel_mocs.h"
24a05eeebfSFrançois Tigeot #include "intel_lrc.h"
25a05eeebfSFrançois Tigeot #include "intel_ringbuffer.h"
26a05eeebfSFrançois Tigeot 
27a05eeebfSFrançois Tigeot /* structures required */
28a05eeebfSFrançois Tigeot struct drm_i915_mocs_entry {
29a05eeebfSFrançois Tigeot 	u32 control_value;
30a05eeebfSFrançois Tigeot 	u16 l3cc_value;
31a05eeebfSFrançois Tigeot };
32a05eeebfSFrançois Tigeot 
33a05eeebfSFrançois Tigeot struct drm_i915_mocs_table {
34a05eeebfSFrançois Tigeot 	u32 size;
35a05eeebfSFrançois Tigeot 	const struct drm_i915_mocs_entry *table;
36a05eeebfSFrançois Tigeot };
37a05eeebfSFrançois Tigeot 
38a05eeebfSFrançois Tigeot /* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
39a05eeebfSFrançois Tigeot #define LE_CACHEABILITY(value)	((value) << 0)
40a05eeebfSFrançois Tigeot #define LE_TGT_CACHE(value)	((value) << 2)
41a05eeebfSFrançois Tigeot #define LE_LRUM(value)		((value) << 4)
42a05eeebfSFrançois Tigeot #define LE_AOM(value)		((value) << 6)
43a05eeebfSFrançois Tigeot #define LE_RSC(value)		((value) << 7)
44a05eeebfSFrançois Tigeot #define LE_SCC(value)		((value) << 8)
45a05eeebfSFrançois Tigeot #define LE_PFM(value)		((value) << 11)
46a05eeebfSFrançois Tigeot #define LE_SCF(value)		((value) << 14)
47a05eeebfSFrançois Tigeot 
48a05eeebfSFrançois Tigeot /* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */
49a05eeebfSFrançois Tigeot #define L3_ESC(value)		((value) << 0)
50a05eeebfSFrançois Tigeot #define L3_SCC(value)		((value) << 1)
51a05eeebfSFrançois Tigeot #define L3_CACHEABILITY(value)	((value) << 4)
52a05eeebfSFrançois Tigeot 
53a05eeebfSFrançois Tigeot /* Helper defines */
54a05eeebfSFrançois Tigeot #define GEN9_NUM_MOCS_ENTRIES	62  /* 62 out of 64 - 63 & 64 are reserved. */
55a05eeebfSFrançois Tigeot 
56a05eeebfSFrançois Tigeot /* (e)LLC caching options */
57a05eeebfSFrançois Tigeot #define LE_PAGETABLE		0
58a05eeebfSFrançois Tigeot #define LE_UC			1
59a05eeebfSFrançois Tigeot #define LE_WT			2
60a05eeebfSFrançois Tigeot #define LE_WB			3
61a05eeebfSFrançois Tigeot 
62a05eeebfSFrançois Tigeot /* L3 caching options */
63a05eeebfSFrançois Tigeot #define L3_DIRECT		0
64a05eeebfSFrançois Tigeot #define L3_UC			1
65a05eeebfSFrançois Tigeot #define L3_RESERVED		2
66a05eeebfSFrançois Tigeot #define L3_WB			3
67a05eeebfSFrançois Tigeot 
68a05eeebfSFrançois Tigeot /* Target cache */
69bf017597SFrançois Tigeot #define LE_TC_PAGETABLE		0
70bf017597SFrançois Tigeot #define LE_TC_LLC		1
71bf017597SFrançois Tigeot #define LE_TC_LLC_ELLC		2
72bf017597SFrançois Tigeot #define LE_TC_LLC_ELLC_ALT	3
73a05eeebfSFrançois Tigeot 
74a05eeebfSFrançois Tigeot /*
75a05eeebfSFrançois Tigeot  * MOCS tables
76a05eeebfSFrançois Tigeot  *
77a05eeebfSFrançois Tigeot  * These are the MOCS tables that are programmed across all the rings.
78a05eeebfSFrançois Tigeot  * The control value is programmed to all the rings that support the
79a05eeebfSFrançois Tigeot  * MOCS registers. While the l3cc_values are only programmed to the
80a05eeebfSFrançois Tigeot  * LNCFCMOCS0 - LNCFCMOCS32 registers.
81a05eeebfSFrançois Tigeot  *
82a05eeebfSFrançois Tigeot  * These tables are intended to be kept reasonably consistent across
83a05eeebfSFrançois Tigeot  * platforms. However some of the fields are not applicable to all of
84a05eeebfSFrançois Tigeot  * them.
85a05eeebfSFrançois Tigeot  *
86a05eeebfSFrançois Tigeot  * Entries not part of the following tables are undefined as far as
87a05eeebfSFrançois Tigeot  * userspace is concerned and shouldn't be relied upon.  For the time
88a05eeebfSFrançois Tigeot  * being they will be implicitly initialized to the strictest caching
89a05eeebfSFrançois Tigeot  * configuration (uncached) to guarantee forwards compatibility with
90a05eeebfSFrançois Tigeot  * userspace programs written against more recent kernels providing
91a05eeebfSFrançois Tigeot  * additional MOCS entries.
92a05eeebfSFrançois Tigeot  *
93a05eeebfSFrançois Tigeot  * NOTE: These tables MUST start with being uncached and the length
94a05eeebfSFrançois Tigeot  *       MUST be less than 63 as the last two registers are reserved
95a05eeebfSFrançois Tigeot  *       by the hardware.  These tables are part of the kernel ABI and
96a05eeebfSFrançois Tigeot  *       may only be updated incrementally by adding entries at the
97a05eeebfSFrançois Tigeot  *       end.
98a05eeebfSFrançois Tigeot  */
99a05eeebfSFrançois Tigeot static const struct drm_i915_mocs_entry skylake_mocs_table[] = {
10087df8fc6SFrançois Tigeot 	[I915_MOCS_UNCACHED] = {
10187df8fc6SFrançois Tigeot 	  /* 0x00000009 */
102bf017597SFrançois Tigeot 	  .control_value = LE_CACHEABILITY(LE_UC) |
103bf017597SFrançois Tigeot 			   LE_TGT_CACHE(LE_TC_LLC_ELLC) |
104bf017597SFrançois Tigeot 			   LE_LRUM(0) | LE_AOM(0) | LE_RSC(0) | LE_SCC(0) |
105bf017597SFrançois Tigeot 			   LE_PFM(0) | LE_SCF(0),
106bf017597SFrançois Tigeot 
107bf017597SFrançois Tigeot 	  /* 0x0010 */
108bf017597SFrançois Tigeot 	  .l3cc_value =    L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_UC),
109bf017597SFrançois Tigeot 	},
11087df8fc6SFrançois Tigeot 	[I915_MOCS_PTE] = {
111bf017597SFrançois Tigeot 	  /* 0x00000038 */
112bf017597SFrançois Tigeot 	  .control_value = LE_CACHEABILITY(LE_PAGETABLE) |
113bf017597SFrançois Tigeot 			   LE_TGT_CACHE(LE_TC_LLC_ELLC) |
114bf017597SFrançois Tigeot 			   LE_LRUM(3) | LE_AOM(0) | LE_RSC(0) | LE_SCC(0) |
115bf017597SFrançois Tigeot 			   LE_PFM(0) | LE_SCF(0),
116bf017597SFrançois Tigeot 	  /* 0x0030 */
117bf017597SFrançois Tigeot 	  .l3cc_value =    L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB),
118bf017597SFrançois Tigeot 	},
11987df8fc6SFrançois Tigeot 	[I915_MOCS_CACHED] = {
120bf017597SFrançois Tigeot 	  /* 0x0000003b */
121bf017597SFrançois Tigeot 	  .control_value = LE_CACHEABILITY(LE_WB) |
122bf017597SFrançois Tigeot 			   LE_TGT_CACHE(LE_TC_LLC_ELLC) |
123bf017597SFrançois Tigeot 			   LE_LRUM(3) | LE_AOM(0) | LE_RSC(0) | LE_SCC(0) |
124bf017597SFrançois Tigeot 			   LE_PFM(0) | LE_SCF(0),
125bf017597SFrançois Tigeot 	  /* 0x0030 */
126bf017597SFrançois Tigeot 	  .l3cc_value =   L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB),
127bf017597SFrançois Tigeot 	},
128a05eeebfSFrançois Tigeot };
129a05eeebfSFrançois Tigeot 
130a05eeebfSFrançois Tigeot /* NOTE: the LE_TGT_CACHE is not used on Broxton */
131a05eeebfSFrançois Tigeot static const struct drm_i915_mocs_entry broxton_mocs_table[] = {
13287df8fc6SFrançois Tigeot 	[I915_MOCS_UNCACHED] = {
133bf017597SFrançois Tigeot 	  /* 0x00000009 */
134bf017597SFrançois Tigeot 	  .control_value = LE_CACHEABILITY(LE_UC) |
135bf017597SFrançois Tigeot 			   LE_TGT_CACHE(LE_TC_LLC_ELLC) |
136bf017597SFrançois Tigeot 			   LE_LRUM(0) | LE_AOM(0) | LE_RSC(0) | LE_SCC(0) |
137bf017597SFrançois Tigeot 			   LE_PFM(0) | LE_SCF(0),
138bf017597SFrançois Tigeot 
139bf017597SFrançois Tigeot 	  /* 0x0010 */
140bf017597SFrançois Tigeot 	  .l3cc_value =    L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_UC),
141bf017597SFrançois Tigeot 	},
14287df8fc6SFrançois Tigeot 	[I915_MOCS_PTE] = {
143bf017597SFrançois Tigeot 	  /* 0x00000038 */
144bf017597SFrançois Tigeot 	  .control_value = LE_CACHEABILITY(LE_PAGETABLE) |
145bf017597SFrançois Tigeot 			   LE_TGT_CACHE(LE_TC_LLC_ELLC) |
146bf017597SFrançois Tigeot 			   LE_LRUM(3) | LE_AOM(0) | LE_RSC(0) | LE_SCC(0) |
147bf017597SFrançois Tigeot 			   LE_PFM(0) | LE_SCF(0),
148bf017597SFrançois Tigeot 
149bf017597SFrançois Tigeot 	  /* 0x0030 */
150bf017597SFrançois Tigeot 	  .l3cc_value =    L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB),
151bf017597SFrançois Tigeot 	},
15287df8fc6SFrançois Tigeot 	[I915_MOCS_CACHED] = {
153bf017597SFrançois Tigeot 	  /* 0x00000039 */
154bf017597SFrançois Tigeot 	  .control_value = LE_CACHEABILITY(LE_UC) |
155bf017597SFrançois Tigeot 			   LE_TGT_CACHE(LE_TC_LLC_ELLC) |
156bf017597SFrançois Tigeot 			   LE_LRUM(3) | LE_AOM(0) | LE_RSC(0) | LE_SCC(0) |
157bf017597SFrançois Tigeot 			   LE_PFM(0) | LE_SCF(0),
158bf017597SFrançois Tigeot 
159bf017597SFrançois Tigeot 	  /* 0x0030 */
160bf017597SFrançois Tigeot 	  .l3cc_value =    L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB),
161bf017597SFrançois Tigeot 	},
162a05eeebfSFrançois Tigeot };
163a05eeebfSFrançois Tigeot 
164a05eeebfSFrançois Tigeot /**
165a05eeebfSFrançois Tigeot  * get_mocs_settings()
1668621f407SFrançois Tigeot  * @dev_priv:	i915 device.
167a05eeebfSFrançois Tigeot  * @table:      Output table that will be made to point at appropriate
168a05eeebfSFrançois Tigeot  *	      MOCS values for the device.
169a05eeebfSFrançois Tigeot  *
170a05eeebfSFrançois Tigeot  * This function will return the values of the MOCS table that needs to
171a05eeebfSFrançois Tigeot  * be programmed for the platform. It will return the values that need
172a05eeebfSFrançois Tigeot  * to be programmed and if they need to be programmed.
173a05eeebfSFrançois Tigeot  *
174a05eeebfSFrançois Tigeot  * Return: true if there are applicable MOCS settings for the device.
175a05eeebfSFrançois Tigeot  */
get_mocs_settings(struct drm_i915_private * dev_priv,struct drm_i915_mocs_table * table)1768621f407SFrançois Tigeot static bool get_mocs_settings(struct drm_i915_private *dev_priv,
177a05eeebfSFrançois Tigeot 			      struct drm_i915_mocs_table *table)
178a05eeebfSFrançois Tigeot {
179a05eeebfSFrançois Tigeot 	bool result = false;
180a05eeebfSFrançois Tigeot 
181*3f2dd94aSFrançois Tigeot 	if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) {
182a05eeebfSFrançois Tigeot 		table->size  = ARRAY_SIZE(skylake_mocs_table);
183a05eeebfSFrançois Tigeot 		table->table = skylake_mocs_table;
184a05eeebfSFrançois Tigeot 		result = true;
185a85cb24fSFrançois Tigeot 	} else if (IS_GEN9_LP(dev_priv)) {
186a05eeebfSFrançois Tigeot 		table->size  = ARRAY_SIZE(broxton_mocs_table);
187a05eeebfSFrançois Tigeot 		table->table = broxton_mocs_table;
188a05eeebfSFrançois Tigeot 		result = true;
189a05eeebfSFrançois Tigeot 	} else {
1908621f407SFrançois Tigeot 		WARN_ONCE(INTEL_INFO(dev_priv)->gen >= 9,
191a05eeebfSFrançois Tigeot 			  "Platform that should have a MOCS table does not.\n");
192a05eeebfSFrançois Tigeot 	}
193a05eeebfSFrançois Tigeot 
194a85cb24fSFrançois Tigeot 	/* WaDisableSkipCaching:skl,bxt,kbl,glk */
1951487f786SFrançois Tigeot 	if (IS_GEN9(dev_priv)) {
1961487f786SFrançois Tigeot 		int i;
1971487f786SFrançois Tigeot 
1981487f786SFrançois Tigeot 		for (i = 0; i < table->size; i++)
1991487f786SFrançois Tigeot 			if (WARN_ON(table->table[i].l3cc_value &
2001487f786SFrançois Tigeot 				    (L3_ESC(1) | L3_SCC(0x7))))
2011487f786SFrançois Tigeot 				return false;
2021487f786SFrançois Tigeot 	}
2031487f786SFrançois Tigeot 
204a05eeebfSFrançois Tigeot 	return result;
205a05eeebfSFrançois Tigeot }
206a05eeebfSFrançois Tigeot 
mocs_register(enum intel_engine_id engine_id,int index)20787df8fc6SFrançois Tigeot static i915_reg_t mocs_register(enum intel_engine_id engine_id, int index)
208aee94f86SFrançois Tigeot {
20987df8fc6SFrançois Tigeot 	switch (engine_id) {
210aee94f86SFrançois Tigeot 	case RCS:
211aee94f86SFrançois Tigeot 		return GEN9_GFX_MOCS(index);
212aee94f86SFrançois Tigeot 	case VCS:
213aee94f86SFrançois Tigeot 		return GEN9_MFX0_MOCS(index);
214aee94f86SFrançois Tigeot 	case BCS:
215aee94f86SFrançois Tigeot 		return GEN9_BLT_MOCS(index);
216aee94f86SFrançois Tigeot 	case VECS:
217aee94f86SFrançois Tigeot 		return GEN9_VEBOX_MOCS(index);
218aee94f86SFrançois Tigeot 	case VCS2:
219aee94f86SFrançois Tigeot 		return GEN9_MFX1_MOCS(index);
220aee94f86SFrançois Tigeot 	default:
22187df8fc6SFrançois Tigeot 		MISSING_CASE(engine_id);
222aee94f86SFrançois Tigeot 		return INVALID_MMIO_REG;
223aee94f86SFrançois Tigeot 	}
224aee94f86SFrançois Tigeot }
225aee94f86SFrançois Tigeot 
226a05eeebfSFrançois Tigeot /**
2278621f407SFrançois Tigeot  * intel_mocs_init_engine() - emit the mocs control table
2288621f407SFrançois Tigeot  * @engine:	The engine for whom to emit the registers.
2298621f407SFrançois Tigeot  *
2308621f407SFrançois Tigeot  * This function simply emits a MI_LOAD_REGISTER_IMM command for the
2318621f407SFrançois Tigeot  * given table starting at the given address.
2328621f407SFrançois Tigeot  *
2338621f407SFrançois Tigeot  * Return: 0 on success, otherwise the error status.
2348621f407SFrançois Tigeot  */
intel_mocs_init_engine(struct intel_engine_cs * engine)2358621f407SFrançois Tigeot int intel_mocs_init_engine(struct intel_engine_cs *engine)
2368621f407SFrançois Tigeot {
2371487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
2388621f407SFrançois Tigeot 	struct drm_i915_mocs_table table;
2398621f407SFrançois Tigeot 	unsigned int index;
2408621f407SFrançois Tigeot 
2418621f407SFrançois Tigeot 	if (!get_mocs_settings(dev_priv, &table))
2428621f407SFrançois Tigeot 		return 0;
2438621f407SFrançois Tigeot 
2448621f407SFrançois Tigeot 	if (WARN_ON(table.size > GEN9_NUM_MOCS_ENTRIES))
2458621f407SFrançois Tigeot 		return -ENODEV;
2468621f407SFrançois Tigeot 
2478621f407SFrançois Tigeot 	for (index = 0; index < table.size; index++)
2488621f407SFrançois Tigeot 		I915_WRITE(mocs_register(engine->id, index),
2498621f407SFrançois Tigeot 			   table.table[index].control_value);
2508621f407SFrançois Tigeot 
2518621f407SFrançois Tigeot 	/*
2528621f407SFrançois Tigeot 	 * Ok, now set the unused entries to uncached. These entries
2538621f407SFrançois Tigeot 	 * are officially undefined and no contract for the contents
2548621f407SFrançois Tigeot 	 * and settings is given for these entries.
2558621f407SFrançois Tigeot 	 *
2568621f407SFrançois Tigeot 	 * Entry 0 in the table is uncached - so we are just writing
2578621f407SFrançois Tigeot 	 * that value to all the used entries.
2588621f407SFrançois Tigeot 	 */
2598621f407SFrançois Tigeot 	for (; index < GEN9_NUM_MOCS_ENTRIES; index++)
2608621f407SFrançois Tigeot 		I915_WRITE(mocs_register(engine->id, index),
2618621f407SFrançois Tigeot 			   table.table[0].control_value);
2628621f407SFrançois Tigeot 
2638621f407SFrançois Tigeot 	return 0;
2648621f407SFrançois Tigeot }
2658621f407SFrançois Tigeot 
2668621f407SFrançois Tigeot /**
267a05eeebfSFrançois Tigeot  * emit_mocs_control_table() - emit the mocs control table
268a05eeebfSFrançois Tigeot  * @req:	Request to set up the MOCS table for.
269a05eeebfSFrançois Tigeot  * @table:	The values to program into the control regs.
270a05eeebfSFrançois Tigeot  *
271a05eeebfSFrançois Tigeot  * This function simply emits a MI_LOAD_REGISTER_IMM command for the
272a05eeebfSFrançois Tigeot  * given table starting at the given address.
273a05eeebfSFrançois Tigeot  *
274a05eeebfSFrançois Tigeot  * Return: 0 on success, otherwise the error status.
275a05eeebfSFrançois Tigeot  */
emit_mocs_control_table(struct drm_i915_gem_request * req,const struct drm_i915_mocs_table * table)276a05eeebfSFrançois Tigeot static int emit_mocs_control_table(struct drm_i915_gem_request *req,
2778621f407SFrançois Tigeot 				   const struct drm_i915_mocs_table *table)
278a05eeebfSFrançois Tigeot {
2798621f407SFrançois Tigeot 	enum intel_engine_id engine = req->engine->id;
280a05eeebfSFrançois Tigeot 	unsigned int index;
281a85cb24fSFrançois Tigeot 	u32 *cs;
282a05eeebfSFrançois Tigeot 
283a05eeebfSFrançois Tigeot 	if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES))
284a05eeebfSFrançois Tigeot 		return -ENODEV;
285a05eeebfSFrançois Tigeot 
286a85cb24fSFrançois Tigeot 	cs = intel_ring_begin(req, 2 + 2 * GEN9_NUM_MOCS_ENTRIES);
287a85cb24fSFrançois Tigeot 	if (IS_ERR(cs))
288a85cb24fSFrançois Tigeot 		return PTR_ERR(cs);
289a05eeebfSFrançois Tigeot 
290a85cb24fSFrançois Tigeot 	*cs++ = MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES);
291a05eeebfSFrançois Tigeot 
292a05eeebfSFrançois Tigeot 	for (index = 0; index < table->size; index++) {
293a85cb24fSFrançois Tigeot 		*cs++ = i915_mmio_reg_offset(mocs_register(engine, index));
294a85cb24fSFrançois Tigeot 		*cs++ = table->table[index].control_value;
295a05eeebfSFrançois Tigeot 	}
296a05eeebfSFrançois Tigeot 
297a05eeebfSFrançois Tigeot 	/*
298a05eeebfSFrançois Tigeot 	 * Ok, now set the unused entries to uncached. These entries
299a05eeebfSFrançois Tigeot 	 * are officially undefined and no contract for the contents
300a05eeebfSFrançois Tigeot 	 * and settings is given for these entries.
301a05eeebfSFrançois Tigeot 	 *
302a05eeebfSFrançois Tigeot 	 * Entry 0 in the table is uncached - so we are just writing
303a05eeebfSFrançois Tigeot 	 * that value to all the used entries.
304a05eeebfSFrançois Tigeot 	 */
305a05eeebfSFrançois Tigeot 	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
306a85cb24fSFrançois Tigeot 		*cs++ = i915_mmio_reg_offset(mocs_register(engine, index));
307a85cb24fSFrançois Tigeot 		*cs++ = table->table[0].control_value;
308a05eeebfSFrançois Tigeot 	}
309a05eeebfSFrançois Tigeot 
310a85cb24fSFrançois Tigeot 	*cs++ = MI_NOOP;
311a85cb24fSFrançois Tigeot 	intel_ring_advance(req, cs);
312a05eeebfSFrançois Tigeot 
313a05eeebfSFrançois Tigeot 	return 0;
314a05eeebfSFrançois Tigeot }
315a05eeebfSFrançois Tigeot 
l3cc_combine(const struct drm_i915_mocs_table * table,u16 low,u16 high)3168621f407SFrançois Tigeot static inline u32 l3cc_combine(const struct drm_i915_mocs_table *table,
3178621f407SFrançois Tigeot 			       u16 low,
3188621f407SFrançois Tigeot 			       u16 high)
3198621f407SFrançois Tigeot {
3208621f407SFrançois Tigeot 	return table->table[low].l3cc_value |
3218621f407SFrançois Tigeot 	       table->table[high].l3cc_value << 16;
3228621f407SFrançois Tigeot }
3238621f407SFrançois Tigeot 
324a05eeebfSFrançois Tigeot /**
325a05eeebfSFrançois Tigeot  * emit_mocs_l3cc_table() - emit the mocs control table
326a05eeebfSFrançois Tigeot  * @req:	Request to set up the MOCS table for.
327a05eeebfSFrançois Tigeot  * @table:	The values to program into the control regs.
328a05eeebfSFrançois Tigeot  *
329a05eeebfSFrançois Tigeot  * This function simply emits a MI_LOAD_REGISTER_IMM command for the
330a05eeebfSFrançois Tigeot  * given table starting at the given address. This register set is
331a05eeebfSFrançois Tigeot  * programmed in pairs.
332a05eeebfSFrançois Tigeot  *
333a05eeebfSFrançois Tigeot  * Return: 0 on success, otherwise the error status.
334a05eeebfSFrançois Tigeot  */
emit_mocs_l3cc_table(struct drm_i915_gem_request * req,const struct drm_i915_mocs_table * table)335a05eeebfSFrançois Tigeot static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req,
336a05eeebfSFrançois Tigeot 				const struct drm_i915_mocs_table *table)
337a05eeebfSFrançois Tigeot {
338a05eeebfSFrançois Tigeot 	unsigned int i;
339a85cb24fSFrançois Tigeot 	u32 *cs;
340a05eeebfSFrançois Tigeot 
341a05eeebfSFrançois Tigeot 	if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES))
342a05eeebfSFrançois Tigeot 		return -ENODEV;
343a05eeebfSFrançois Tigeot 
344a85cb24fSFrançois Tigeot 	cs = intel_ring_begin(req, 2 + GEN9_NUM_MOCS_ENTRIES);
345a85cb24fSFrançois Tigeot 	if (IS_ERR(cs))
346a85cb24fSFrançois Tigeot 		return PTR_ERR(cs);
347a05eeebfSFrançois Tigeot 
348a85cb24fSFrançois Tigeot 	*cs++ = MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2);
349a05eeebfSFrançois Tigeot 
3508621f407SFrançois Tigeot 	for (i = 0; i < table->size/2; i++) {
351a85cb24fSFrançois Tigeot 		*cs++ = i915_mmio_reg_offset(GEN9_LNCFCMOCS(i));
352a85cb24fSFrançois Tigeot 		*cs++ = l3cc_combine(table, 2 * i, 2 * i + 1);
353a05eeebfSFrançois Tigeot 	}
354a05eeebfSFrançois Tigeot 
355a05eeebfSFrançois Tigeot 	if (table->size & 0x01) {
356a05eeebfSFrançois Tigeot 		/* Odd table size - 1 left over */
357a85cb24fSFrançois Tigeot 		*cs++ = i915_mmio_reg_offset(GEN9_LNCFCMOCS(i));
358a85cb24fSFrançois Tigeot 		*cs++ = l3cc_combine(table, 2 * i, 0);
3598621f407SFrançois Tigeot 		i++;
3608621f407SFrançois Tigeot 	}
361a05eeebfSFrançois Tigeot 
362a05eeebfSFrançois Tigeot 	/*
363a05eeebfSFrançois Tigeot 	 * Now set the rest of the table to uncached - use entry 0 as
364a05eeebfSFrançois Tigeot 	 * this will be uncached. Leave the last pair uninitialised as
365a05eeebfSFrançois Tigeot 	 * they are reserved by the hardware.
366a05eeebfSFrançois Tigeot 	 */
367a05eeebfSFrançois Tigeot 	for (; i < GEN9_NUM_MOCS_ENTRIES / 2; i++) {
368a85cb24fSFrançois Tigeot 		*cs++ = i915_mmio_reg_offset(GEN9_LNCFCMOCS(i));
369a85cb24fSFrançois Tigeot 		*cs++ = l3cc_combine(table, 0, 0);
370a05eeebfSFrançois Tigeot 	}
371a05eeebfSFrançois Tigeot 
372a85cb24fSFrançois Tigeot 	*cs++ = MI_NOOP;
373a85cb24fSFrançois Tigeot 	intel_ring_advance(req, cs);
374a05eeebfSFrançois Tigeot 
375a05eeebfSFrançois Tigeot 	return 0;
376a05eeebfSFrançois Tigeot }
377a05eeebfSFrançois Tigeot 
378a05eeebfSFrançois Tigeot /**
3798621f407SFrançois Tigeot  * intel_mocs_init_l3cc_table() - program the mocs control table
380a85cb24fSFrançois Tigeot  * @dev_priv:      i915 device private
3818621f407SFrançois Tigeot  *
3828621f407SFrançois Tigeot  * This function simply programs the mocs registers for the given table
3838621f407SFrançois Tigeot  * starting at the given address. This register set is  programmed in pairs.
3848621f407SFrançois Tigeot  *
3858621f407SFrançois Tigeot  * These registers may get programmed more than once, it is simpler to
3868621f407SFrançois Tigeot  * re-program 32 registers than maintain the state of when they were programmed.
3878621f407SFrançois Tigeot  * We are always reprogramming with the same values and this only on context
3888621f407SFrançois Tigeot  * start.
3898621f407SFrançois Tigeot  *
3908621f407SFrançois Tigeot  * Return: Nothing.
3918621f407SFrançois Tigeot  */
intel_mocs_init_l3cc_table(struct drm_i915_private * dev_priv)392a85cb24fSFrançois Tigeot void intel_mocs_init_l3cc_table(struct drm_i915_private *dev_priv)
3938621f407SFrançois Tigeot {
3948621f407SFrançois Tigeot 	struct drm_i915_mocs_table table;
3958621f407SFrançois Tigeot 	unsigned int i;
3968621f407SFrançois Tigeot 
3978621f407SFrançois Tigeot 	if (!get_mocs_settings(dev_priv, &table))
3988621f407SFrançois Tigeot 		return;
3998621f407SFrançois Tigeot 
4008621f407SFrançois Tigeot 	for (i = 0; i < table.size/2; i++)
4018621f407SFrançois Tigeot 		I915_WRITE(GEN9_LNCFCMOCS(i), l3cc_combine(&table, 2*i, 2*i+1));
4028621f407SFrançois Tigeot 
4038621f407SFrançois Tigeot 	/* Odd table size - 1 left over */
4048621f407SFrançois Tigeot 	if (table.size & 0x01) {
4058621f407SFrançois Tigeot 		I915_WRITE(GEN9_LNCFCMOCS(i), l3cc_combine(&table, 2*i, 0));
4068621f407SFrançois Tigeot 		i++;
4078621f407SFrançois Tigeot 	}
4088621f407SFrançois Tigeot 
4098621f407SFrançois Tigeot 	/*
4108621f407SFrançois Tigeot 	 * Now set the rest of the table to uncached - use entry 0 as
4118621f407SFrançois Tigeot 	 * this will be uncached. Leave the last pair as initialised as
4128621f407SFrançois Tigeot 	 * they are reserved by the hardware.
4138621f407SFrançois Tigeot 	 */
4148621f407SFrançois Tigeot 	for (; i < (GEN9_NUM_MOCS_ENTRIES / 2); i++)
4158621f407SFrançois Tigeot 		I915_WRITE(GEN9_LNCFCMOCS(i), l3cc_combine(&table, 0, 0));
4168621f407SFrançois Tigeot }
4178621f407SFrançois Tigeot 
4188621f407SFrançois Tigeot /**
419a05eeebfSFrançois Tigeot  * intel_rcs_context_init_mocs() - program the MOCS register.
420a05eeebfSFrançois Tigeot  * @req:	Request to set up the MOCS tables for.
421a05eeebfSFrançois Tigeot  *
422a05eeebfSFrançois Tigeot  * This function will emit a batch buffer with the values required for
423a05eeebfSFrançois Tigeot  * programming the MOCS register values for all the currently supported
424a05eeebfSFrançois Tigeot  * rings.
425a05eeebfSFrançois Tigeot  *
426a05eeebfSFrançois Tigeot  * These registers are partially stored in the RCS context, so they are
427a05eeebfSFrançois Tigeot  * emitted at the same time so that when a context is created these registers
428a05eeebfSFrançois Tigeot  * are set up. These registers have to be emitted into the start of the
429a05eeebfSFrançois Tigeot  * context as setting the ELSP will re-init some of these registers back
430a05eeebfSFrançois Tigeot  * to the hw values.
431a05eeebfSFrançois Tigeot  *
432a05eeebfSFrançois Tigeot  * Return: 0 on success, otherwise the error status.
433a05eeebfSFrançois Tigeot  */
intel_rcs_context_init_mocs(struct drm_i915_gem_request * req)434a05eeebfSFrançois Tigeot int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req)
435a05eeebfSFrançois Tigeot {
436a05eeebfSFrançois Tigeot 	struct drm_i915_mocs_table t;
437a05eeebfSFrançois Tigeot 	int ret;
438a05eeebfSFrançois Tigeot 
4398621f407SFrançois Tigeot 	if (get_mocs_settings(req->i915, &t)) {
4408621f407SFrançois Tigeot 		/* Program the RCS control registers */
4418621f407SFrançois Tigeot 		ret = emit_mocs_control_table(req, &t);
442a05eeebfSFrançois Tigeot 		if (ret)
443a05eeebfSFrançois Tigeot 			return ret;
444a05eeebfSFrançois Tigeot 
445a05eeebfSFrançois Tigeot 		/* Now program the l3cc registers */
446a05eeebfSFrançois Tigeot 		ret = emit_mocs_l3cc_table(req, &t);
447a05eeebfSFrançois Tigeot 		if (ret)
448a05eeebfSFrançois Tigeot 			return ret;
449a05eeebfSFrançois Tigeot 	}
450a05eeebfSFrançois Tigeot 
451a05eeebfSFrançois Tigeot 	return 0;
452a05eeebfSFrançois Tigeot }
453