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