11b13d190SFrançois Tigeot /* 21b13d190SFrançois Tigeot * Copyright © 2014 Intel Corporation 31b13d190SFrançois Tigeot * 41b13d190SFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 51b13d190SFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 61b13d190SFrançois Tigeot * to deal in the Software without restriction, including without limitation 71b13d190SFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 81b13d190SFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 91b13d190SFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 101b13d190SFrançois Tigeot * 111b13d190SFrançois Tigeot * The above copyright notice and this permission notice (including the next 121b13d190SFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the 131b13d190SFrançois Tigeot * Software. 141b13d190SFrançois Tigeot * 151b13d190SFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161b13d190SFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 171b13d190SFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 181b13d190SFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 191b13d190SFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 201b13d190SFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 211b13d190SFrançois Tigeot * IN THE SOFTWARE. 221b13d190SFrançois Tigeot * 231b13d190SFrançois Tigeot * Authors: 241b13d190SFrançois Tigeot * Ben Widawsky <ben@bwidawsk.net> 251b13d190SFrançois Tigeot * Michel Thierry <michel.thierry@intel.com> 261b13d190SFrançois Tigeot * Thomas Daniel <thomas.daniel@intel.com> 271b13d190SFrançois Tigeot * Oscar Mateo <oscar.mateo@intel.com> 281b13d190SFrançois Tigeot * 291b13d190SFrançois Tigeot */ 301b13d190SFrançois Tigeot 311b13d190SFrançois Tigeot /** 321b13d190SFrançois Tigeot * DOC: Logical Rings, Logical Ring Contexts and Execlists 331b13d190SFrançois Tigeot * 341b13d190SFrançois Tigeot * Motivation: 351b13d190SFrançois Tigeot * GEN8 brings an expansion of the HW contexts: "Logical Ring Contexts". 361b13d190SFrançois Tigeot * These expanded contexts enable a number of new abilities, especially 371b13d190SFrançois Tigeot * "Execlists" (also implemented in this file). 381b13d190SFrançois Tigeot * 391b13d190SFrançois Tigeot * One of the main differences with the legacy HW contexts is that logical 401b13d190SFrançois Tigeot * ring contexts incorporate many more things to the context's state, like 411b13d190SFrançois Tigeot * PDPs or ringbuffer control registers: 421b13d190SFrançois Tigeot * 431b13d190SFrançois Tigeot * The reason why PDPs are included in the context is straightforward: as 441b13d190SFrançois Tigeot * PPGTTs (per-process GTTs) are actually per-context, having the PDPs 451b13d190SFrançois Tigeot * contained there mean you don't need to do a ppgtt->switch_mm yourself, 461b13d190SFrançois Tigeot * instead, the GPU will do it for you on the context switch. 471b13d190SFrançois Tigeot * 481b13d190SFrançois Tigeot * But, what about the ringbuffer control registers (head, tail, etc..)? 491b13d190SFrançois Tigeot * shouldn't we just need a set of those per engine command streamer? This is 501b13d190SFrançois Tigeot * where the name "Logical Rings" starts to make sense: by virtualizing the 511b13d190SFrançois Tigeot * rings, the engine cs shifts to a new "ring buffer" with every context 521b13d190SFrançois Tigeot * switch. When you want to submit a workload to the GPU you: A) choose your 531b13d190SFrançois Tigeot * context, B) find its appropriate virtualized ring, C) write commands to it 541b13d190SFrançois Tigeot * and then, finally, D) tell the GPU to switch to that context. 551b13d190SFrançois Tigeot * 561b13d190SFrançois Tigeot * Instead of the legacy MI_SET_CONTEXT, the way you tell the GPU to switch 571b13d190SFrançois Tigeot * to a contexts is via a context execution list, ergo "Execlists". 581b13d190SFrançois Tigeot * 591b13d190SFrançois Tigeot * LRC implementation: 601b13d190SFrançois Tigeot * Regarding the creation of contexts, we have: 611b13d190SFrançois Tigeot * 621b13d190SFrançois Tigeot * - One global default context. 631b13d190SFrançois Tigeot * - One local default context for each opened fd. 641b13d190SFrançois Tigeot * - One local extra context for each context create ioctl call. 651b13d190SFrançois Tigeot * 661b13d190SFrançois Tigeot * Now that ringbuffers belong per-context (and not per-engine, like before) 671b13d190SFrançois Tigeot * and that contexts are uniquely tied to a given engine (and not reusable, 681b13d190SFrançois Tigeot * like before) we need: 691b13d190SFrançois Tigeot * 701b13d190SFrançois Tigeot * - One ringbuffer per-engine inside each context. 711b13d190SFrançois Tigeot * - One backing object per-engine inside each context. 721b13d190SFrançois Tigeot * 731b13d190SFrançois Tigeot * The global default context starts its life with these new objects fully 741b13d190SFrançois Tigeot * allocated and populated. The local default context for each opened fd is 751b13d190SFrançois Tigeot * more complex, because we don't know at creation time which engine is going 761b13d190SFrançois Tigeot * to use them. To handle this, we have implemented a deferred creation of LR 771b13d190SFrançois Tigeot * contexts: 781b13d190SFrançois Tigeot * 791b13d190SFrançois Tigeot * The local context starts its life as a hollow or blank holder, that only 801b13d190SFrançois Tigeot * gets populated for a given engine once we receive an execbuffer. If later 811b13d190SFrançois Tigeot * on we receive another execbuffer ioctl for the same context but a different 821b13d190SFrançois Tigeot * engine, we allocate/populate a new ringbuffer and context backing object and 831b13d190SFrançois Tigeot * so on. 841b13d190SFrançois Tigeot * 851b13d190SFrançois Tigeot * Finally, regarding local contexts created using the ioctl call: as they are 861b13d190SFrançois Tigeot * only allowed with the render ring, we can allocate & populate them right 871b13d190SFrançois Tigeot * away (no need to defer anything, at least for now). 881b13d190SFrançois Tigeot * 891b13d190SFrançois Tigeot * Execlists implementation: 901b13d190SFrançois Tigeot * Execlists are the new method by which, on gen8+ hardware, workloads are 911b13d190SFrançois Tigeot * submitted for execution (as opposed to the legacy, ringbuffer-based, method). 921b13d190SFrançois Tigeot * This method works as follows: 931b13d190SFrançois Tigeot * 941b13d190SFrançois Tigeot * When a request is committed, its commands (the BB start and any leading or 951b13d190SFrançois Tigeot * trailing commands, like the seqno breadcrumbs) are placed in the ringbuffer 961b13d190SFrançois Tigeot * for the appropriate context. The tail pointer in the hardware context is not 971b13d190SFrançois Tigeot * updated at this time, but instead, kept by the driver in the ringbuffer 981b13d190SFrançois Tigeot * structure. A structure representing this request is added to a request queue 991b13d190SFrançois Tigeot * for the appropriate engine: this structure contains a copy of the context's 1001b13d190SFrançois Tigeot * tail after the request was written to the ring buffer and a pointer to the 1011b13d190SFrançois Tigeot * context itself. 1021b13d190SFrançois Tigeot * 1031b13d190SFrançois Tigeot * If the engine's request queue was empty before the request was added, the 1041b13d190SFrançois Tigeot * queue is processed immediately. Otherwise the queue will be processed during 1051b13d190SFrançois Tigeot * a context switch interrupt. In any case, elements on the queue will get sent 1061b13d190SFrançois Tigeot * (in pairs) to the GPU's ExecLists Submit Port (ELSP, for short) with a 1071b13d190SFrançois Tigeot * globally unique 20-bits submission ID. 1081b13d190SFrançois Tigeot * 1091b13d190SFrançois Tigeot * When execution of a request completes, the GPU updates the context status 1101b13d190SFrançois Tigeot * buffer with a context complete event and generates a context switch interrupt. 1111b13d190SFrançois Tigeot * During the interrupt handling, the driver examines the events in the buffer: 1121b13d190SFrançois Tigeot * for each context complete event, if the announced ID matches that on the head 1131b13d190SFrançois Tigeot * of the request queue, then that request is retired and removed from the queue. 1141b13d190SFrançois Tigeot * 1151b13d190SFrançois Tigeot * After processing, if any requests were retired and the queue is not empty 1161b13d190SFrançois Tigeot * then a new execution list can be submitted. The two requests at the front of 1171b13d190SFrançois Tigeot * the queue are next to be submitted but since a context may not occur twice in 1181b13d190SFrançois Tigeot * an execution list, if subsequent requests have the same ID as the first then 1191b13d190SFrançois Tigeot * the two requests must be combined. This is done simply by discarding requests 1201b13d190SFrançois Tigeot * at the head of the queue until either only one requests is left (in which case 1211b13d190SFrançois Tigeot * we use a NULL second context) or the first two requests have unique IDs. 1221b13d190SFrançois Tigeot * 1231b13d190SFrançois Tigeot * By always executing the first two requests in the queue the driver ensures 1241b13d190SFrançois Tigeot * that the GPU is kept as busy as possible. In the case where a single context 1251b13d190SFrançois Tigeot * completes but a second context is still executing, the request for this second 1261b13d190SFrançois Tigeot * context will be at the head of the queue when we remove the first one. This 1271b13d190SFrançois Tigeot * request will then be resubmitted along with a new request for a different context, 1281b13d190SFrançois Tigeot * which will cause the hardware to continue executing the second request and queue 1291b13d190SFrançois Tigeot * the new request (the GPU detects the condition of a context getting preempted 1301b13d190SFrançois Tigeot * with the same context and optimizes the context switch flow by not doing 1311b13d190SFrançois Tigeot * preemption, but just sampling the new tail pointer). 1321b13d190SFrançois Tigeot * 1331b13d190SFrançois Tigeot */ 1348621f407SFrançois Tigeot #include <linux/interrupt.h> 1351b13d190SFrançois Tigeot 1361b13d190SFrançois Tigeot #include <drm/drmP.h> 1371b13d190SFrançois Tigeot #include <drm/i915_drm.h> 1381b13d190SFrançois Tigeot #include "i915_drv.h" 139a05eeebfSFrançois Tigeot #include "intel_mocs.h" 1401b13d190SFrançois Tigeot 1412c9916cdSFrançois Tigeot #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE) 1421b13d190SFrançois Tigeot #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE) 1431b13d190SFrançois Tigeot #define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE) 1441b13d190SFrançois Tigeot 1451b13d190SFrançois Tigeot #define RING_EXECLIST_QFULL (1 << 0x2) 1461b13d190SFrançois Tigeot #define RING_EXECLIST1_VALID (1 << 0x3) 1471b13d190SFrançois Tigeot #define RING_EXECLIST0_VALID (1 << 0x4) 1481b13d190SFrançois Tigeot #define RING_EXECLIST_ACTIVE_STATUS (3 << 0xE) 1491b13d190SFrançois Tigeot #define RING_EXECLIST1_ACTIVE (1 << 0x11) 1501b13d190SFrançois Tigeot #define RING_EXECLIST0_ACTIVE (1 << 0x12) 1511b13d190SFrançois Tigeot 1521b13d190SFrançois Tigeot #define GEN8_CTX_STATUS_IDLE_ACTIVE (1 << 0) 1531b13d190SFrançois Tigeot #define GEN8_CTX_STATUS_PREEMPTED (1 << 1) 1541b13d190SFrançois Tigeot #define GEN8_CTX_STATUS_ELEMENT_SWITCH (1 << 2) 1551b13d190SFrançois Tigeot #define GEN8_CTX_STATUS_ACTIVE_IDLE (1 << 3) 1561b13d190SFrançois Tigeot #define GEN8_CTX_STATUS_COMPLETE (1 << 4) 1571b13d190SFrançois Tigeot #define GEN8_CTX_STATUS_LITE_RESTORE (1 << 15) 1581b13d190SFrançois Tigeot 1591b13d190SFrançois Tigeot #define CTX_LRI_HEADER_0 0x01 1601b13d190SFrançois Tigeot #define CTX_CONTEXT_CONTROL 0x02 1611b13d190SFrançois Tigeot #define CTX_RING_HEAD 0x04 1621b13d190SFrançois Tigeot #define CTX_RING_TAIL 0x06 1631b13d190SFrançois Tigeot #define CTX_RING_BUFFER_START 0x08 1641b13d190SFrançois Tigeot #define CTX_RING_BUFFER_CONTROL 0x0a 1651b13d190SFrançois Tigeot #define CTX_BB_HEAD_U 0x0c 1661b13d190SFrançois Tigeot #define CTX_BB_HEAD_L 0x0e 1671b13d190SFrançois Tigeot #define CTX_BB_STATE 0x10 1681b13d190SFrançois Tigeot #define CTX_SECOND_BB_HEAD_U 0x12 1691b13d190SFrançois Tigeot #define CTX_SECOND_BB_HEAD_L 0x14 1701b13d190SFrançois Tigeot #define CTX_SECOND_BB_STATE 0x16 1711b13d190SFrançois Tigeot #define CTX_BB_PER_CTX_PTR 0x18 1721b13d190SFrançois Tigeot #define CTX_RCS_INDIRECT_CTX 0x1a 1731b13d190SFrançois Tigeot #define CTX_RCS_INDIRECT_CTX_OFFSET 0x1c 1741b13d190SFrançois Tigeot #define CTX_LRI_HEADER_1 0x21 1751b13d190SFrançois Tigeot #define CTX_CTX_TIMESTAMP 0x22 1761b13d190SFrançois Tigeot #define CTX_PDP3_UDW 0x24 1771b13d190SFrançois Tigeot #define CTX_PDP3_LDW 0x26 1781b13d190SFrançois Tigeot #define CTX_PDP2_UDW 0x28 1791b13d190SFrançois Tigeot #define CTX_PDP2_LDW 0x2a 1801b13d190SFrançois Tigeot #define CTX_PDP1_UDW 0x2c 1811b13d190SFrançois Tigeot #define CTX_PDP1_LDW 0x2e 1821b13d190SFrançois Tigeot #define CTX_PDP0_UDW 0x30 1831b13d190SFrançois Tigeot #define CTX_PDP0_LDW 0x32 1841b13d190SFrançois Tigeot #define CTX_LRI_HEADER_2 0x41 1851b13d190SFrançois Tigeot #define CTX_R_PWR_CLK_STATE 0x42 1861b13d190SFrançois Tigeot #define CTX_GPGPU_CSR_BASE_ADDRESS 0x44 1871b13d190SFrançois Tigeot 1881b13d190SFrançois Tigeot #define GEN8_CTX_VALID (1<<0) 1891b13d190SFrançois Tigeot #define GEN8_CTX_FORCE_PD_RESTORE (1<<1) 1901b13d190SFrançois Tigeot #define GEN8_CTX_FORCE_RESTORE (1<<2) 1911b13d190SFrançois Tigeot #define GEN8_CTX_L3LLC_COHERENT (1<<5) 1921b13d190SFrançois Tigeot #define GEN8_CTX_PRIVILEGE (1<<8) 19319c468b4SFrançois Tigeot 194aee94f86SFrançois Tigeot #define ASSIGN_CTX_REG(reg_state, pos, reg, val) do { \ 195aee94f86SFrançois Tigeot (reg_state)[(pos)+0] = i915_mmio_reg_offset(reg); \ 196aee94f86SFrançois Tigeot (reg_state)[(pos)+1] = (val); \ 197aee94f86SFrançois Tigeot } while (0) 198aee94f86SFrançois Tigeot 199aee94f86SFrançois Tigeot #define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do { \ 200a05eeebfSFrançois Tigeot const u64 _addr = i915_page_dir_dma_addr((ppgtt), (n)); \ 20119c468b4SFrançois Tigeot reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \ 20219c468b4SFrançois Tigeot reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \ 203aee94f86SFrançois Tigeot } while (0) 20419c468b4SFrançois Tigeot 205aee94f86SFrançois Tigeot #define ASSIGN_CTX_PML4(ppgtt, reg_state) do { \ 206352ff8bdSFrançois Tigeot reg_state[CTX_PDP0_UDW + 1] = upper_32_bits(px_dma(&ppgtt->pml4)); \ 207352ff8bdSFrançois Tigeot reg_state[CTX_PDP0_LDW + 1] = lower_32_bits(px_dma(&ppgtt->pml4)); \ 208aee94f86SFrançois Tigeot } while (0) 209352ff8bdSFrançois Tigeot 2101b13d190SFrançois Tigeot enum { 2111b13d190SFrançois Tigeot ADVANCED_CONTEXT = 0, 212352ff8bdSFrançois Tigeot LEGACY_32B_CONTEXT, 2131b13d190SFrançois Tigeot ADVANCED_AD_CONTEXT, 2141b13d190SFrançois Tigeot LEGACY_64B_CONTEXT 2151b13d190SFrançois Tigeot }; 216352ff8bdSFrançois Tigeot #define GEN8_CTX_ADDRESSING_MODE_SHIFT 3 217352ff8bdSFrançois Tigeot #define GEN8_CTX_ADDRESSING_MODE(dev) (USES_FULL_48BIT_PPGTT(dev) ?\ 218352ff8bdSFrançois Tigeot LEGACY_64B_CONTEXT :\ 219352ff8bdSFrançois Tigeot LEGACY_32B_CONTEXT) 2201b13d190SFrançois Tigeot enum { 2211b13d190SFrançois Tigeot FAULT_AND_HANG = 0, 2221b13d190SFrançois Tigeot FAULT_AND_HALT, /* Debug only */ 2231b13d190SFrançois Tigeot FAULT_AND_STREAM, 2241b13d190SFrançois Tigeot FAULT_AND_CONTINUE /* Unsupported */ 2251b13d190SFrançois Tigeot }; 2261b13d190SFrançois Tigeot #define GEN8_CTX_ID_SHIFT 32 227c0e85e96SFrançois Tigeot #define GEN8_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17 228c0e85e96SFrançois Tigeot #define GEN9_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x26 2291b13d190SFrançois Tigeot 230c0e85e96SFrançois Tigeot static int intel_lr_context_pin(struct intel_context *ctx, 231c0e85e96SFrançois Tigeot struct intel_engine_cs *engine); 2322c9916cdSFrançois Tigeot 2331b13d190SFrançois Tigeot /** 2341b13d190SFrançois Tigeot * intel_sanitize_enable_execlists() - sanitize i915.enable_execlists 2351b13d190SFrançois Tigeot * @dev: DRM device. 2361b13d190SFrançois Tigeot * @enable_execlists: value of i915.enable_execlists module parameter. 2371b13d190SFrançois Tigeot * 2381b13d190SFrançois Tigeot * Only certain platforms support Execlists (the prerequisites being 2392c9916cdSFrançois Tigeot * support for Logical Ring Contexts and Aliasing PPGTT or better). 2401b13d190SFrançois Tigeot * 2411b13d190SFrançois Tigeot * Return: 1 if Execlists is supported and has to be enabled. 2421b13d190SFrançois Tigeot */ 2431b13d190SFrançois Tigeot int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists) 2441b13d190SFrançois Tigeot { 2451b13d190SFrançois Tigeot WARN_ON(i915.enable_ppgtt == -1); 2461b13d190SFrançois Tigeot 247352ff8bdSFrançois Tigeot /* On platforms with execlist available, vGPU will only 248352ff8bdSFrançois Tigeot * support execlist mode, no ring buffer mode. 249352ff8bdSFrançois Tigeot */ 250352ff8bdSFrançois Tigeot if (HAS_LOGICAL_RING_CONTEXTS(dev) && intel_vgpu_active(dev)) 251352ff8bdSFrançois Tigeot return 1; 252352ff8bdSFrançois Tigeot 2532c9916cdSFrançois Tigeot if (INTEL_INFO(dev)->gen >= 9) 2542c9916cdSFrançois Tigeot return 1; 2552c9916cdSFrançois Tigeot 2561b13d190SFrançois Tigeot if (enable_execlists == 0) 2571b13d190SFrançois Tigeot return 0; 2581b13d190SFrançois Tigeot 2591b13d190SFrançois Tigeot if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev) && 2601b13d190SFrançois Tigeot i915.use_mmio_flip >= 0) 2611b13d190SFrançois Tigeot return 1; 2621b13d190SFrançois Tigeot 2631b13d190SFrançois Tigeot return 0; 2641b13d190SFrançois Tigeot } 2651b13d190SFrançois Tigeot 266c0e85e96SFrançois Tigeot static void 2678621f407SFrançois Tigeot logical_ring_init_platform_invariants(struct intel_engine_cs *engine) 268c0e85e96SFrançois Tigeot { 2698621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 270c0e85e96SFrançois Tigeot 2718621f407SFrançois Tigeot if (IS_GEN8(dev) || IS_GEN9(dev)) 2728621f407SFrançois Tigeot engine->idle_lite_restore_wa = ~0; 2738621f407SFrançois Tigeot 2748621f407SFrançois Tigeot engine->disable_lite_restore_wa = (IS_SKL_REVID(dev, 0, SKL_REVID_B0) || 275c0e85e96SFrançois Tigeot IS_BXT_REVID(dev, 0, BXT_REVID_A1)) && 2768621f407SFrançois Tigeot (engine->id == VCS || engine->id == VCS2); 277c0e85e96SFrançois Tigeot 2788621f407SFrançois Tigeot engine->ctx_desc_template = GEN8_CTX_VALID; 2798621f407SFrançois Tigeot engine->ctx_desc_template |= GEN8_CTX_ADDRESSING_MODE(dev) << 280c0e85e96SFrançois Tigeot GEN8_CTX_ADDRESSING_MODE_SHIFT; 281c0e85e96SFrançois Tigeot if (IS_GEN8(dev)) 2828621f407SFrançois Tigeot engine->ctx_desc_template |= GEN8_CTX_L3LLC_COHERENT; 2838621f407SFrançois Tigeot engine->ctx_desc_template |= GEN8_CTX_PRIVILEGE; 284c0e85e96SFrançois Tigeot 285c0e85e96SFrançois Tigeot /* TODO: WaDisableLiteRestore when we start using semaphore 286c0e85e96SFrançois Tigeot * signalling between Command Streamers */ 287c0e85e96SFrançois Tigeot /* ring->ctx_desc_template |= GEN8_CTX_FORCE_RESTORE; */ 288c0e85e96SFrançois Tigeot 289c0e85e96SFrançois Tigeot /* WaEnableForceRestoreInCtxtDescForVCS:skl */ 290c0e85e96SFrançois Tigeot /* WaEnableForceRestoreInCtxtDescForVCS:bxt */ 2918621f407SFrançois Tigeot if (engine->disable_lite_restore_wa) 2928621f407SFrançois Tigeot engine->ctx_desc_template |= GEN8_CTX_FORCE_RESTORE; 293c0e85e96SFrançois Tigeot } 294c0e85e96SFrançois Tigeot 295c0e85e96SFrançois Tigeot /** 296c0e85e96SFrançois Tigeot * intel_lr_context_descriptor_update() - calculate & cache the descriptor 297c0e85e96SFrançois Tigeot * descriptor for a pinned context 298c0e85e96SFrançois Tigeot * 299c0e85e96SFrançois Tigeot * @ctx: Context to work on 300c0e85e96SFrançois Tigeot * @ring: Engine the descriptor will be used with 301c0e85e96SFrançois Tigeot * 302c0e85e96SFrançois Tigeot * The context descriptor encodes various attributes of a context, 303c0e85e96SFrançois Tigeot * including its GTT address and some flags. Because it's fairly 304c0e85e96SFrançois Tigeot * expensive to calculate, we'll just do it once and cache the result, 305c0e85e96SFrançois Tigeot * which remains valid until the context is unpinned. 306c0e85e96SFrançois Tigeot * 307c0e85e96SFrançois Tigeot * This is what a descriptor looks like, from LSB to MSB: 308c0e85e96SFrançois Tigeot * bits 0-11: flags, GEN8_CTX_* (cached in ctx_desc_template) 309c0e85e96SFrançois Tigeot * bits 12-31: LRCA, GTT address of (the HWSP of) this context 310c0e85e96SFrançois Tigeot * bits 32-51: ctx ID, a globally unique tag (the LRCA again!) 311c0e85e96SFrançois Tigeot * bits 52-63: reserved, may encode the engine ID (for GuC) 312c0e85e96SFrançois Tigeot */ 313c0e85e96SFrançois Tigeot static void 314c0e85e96SFrançois Tigeot intel_lr_context_descriptor_update(struct intel_context *ctx, 3158621f407SFrançois Tigeot struct intel_engine_cs *engine) 316c0e85e96SFrançois Tigeot { 317c0e85e96SFrançois Tigeot uint64_t lrca, desc; 318c0e85e96SFrançois Tigeot 3198621f407SFrançois Tigeot lrca = ctx->engine[engine->id].lrc_vma->node.start + 320c0e85e96SFrançois Tigeot LRC_PPHWSP_PN * PAGE_SIZE; 321c0e85e96SFrançois Tigeot 3228621f407SFrançois Tigeot desc = engine->ctx_desc_template; /* bits 0-11 */ 323c0e85e96SFrançois Tigeot desc |= lrca; /* bits 12-31 */ 324c0e85e96SFrançois Tigeot desc |= (lrca >> PAGE_SHIFT) << GEN8_CTX_ID_SHIFT; /* bits 32-51 */ 325c0e85e96SFrançois Tigeot 3268621f407SFrançois Tigeot ctx->engine[engine->id].lrc_desc = desc; 327c0e85e96SFrançois Tigeot } 328c0e85e96SFrançois Tigeot 329c0e85e96SFrançois Tigeot uint64_t intel_lr_context_descriptor(struct intel_context *ctx, 3308621f407SFrançois Tigeot struct intel_engine_cs *engine) 331c0e85e96SFrançois Tigeot { 3328621f407SFrançois Tigeot return ctx->engine[engine->id].lrc_desc; 333c0e85e96SFrançois Tigeot } 334c0e85e96SFrançois Tigeot 3351b13d190SFrançois Tigeot /** 3361b13d190SFrançois Tigeot * intel_execlists_ctx_id() - get the Execlists Context ID 337c0e85e96SFrançois Tigeot * @ctx: Context to get the ID for 338c0e85e96SFrançois Tigeot * @ring: Engine to get the ID for 3391b13d190SFrançois Tigeot * 3401b13d190SFrançois Tigeot * Do not confuse with ctx->id! Unfortunately we have a name overload 3411b13d190SFrançois Tigeot * here: the old context ID we pass to userspace as a handler so that 3421b13d190SFrançois Tigeot * they can refer to a context, and the new context ID we pass to the 3431b13d190SFrançois Tigeot * ELSP so that the GPU can inform us of the context status via 3441b13d190SFrançois Tigeot * interrupts. 3451b13d190SFrançois Tigeot * 346c0e85e96SFrançois Tigeot * The context ID is a portion of the context descriptor, so we can 347c0e85e96SFrançois Tigeot * just extract the required part from the cached descriptor. 348c0e85e96SFrançois Tigeot * 3491b13d190SFrançois Tigeot * Return: 20-bits globally unique context ID. 3501b13d190SFrançois Tigeot */ 351c0e85e96SFrançois Tigeot u32 intel_execlists_ctx_id(struct intel_context *ctx, 3528621f407SFrançois Tigeot struct intel_engine_cs *engine) 353352ff8bdSFrançois Tigeot { 3548621f407SFrançois Tigeot return intel_lr_context_descriptor(ctx, engine) >> GEN8_CTX_ID_SHIFT; 3551b13d190SFrançois Tigeot } 3561b13d190SFrançois Tigeot 357a05eeebfSFrançois Tigeot static void execlists_elsp_write(struct drm_i915_gem_request *rq0, 358a05eeebfSFrançois Tigeot struct drm_i915_gem_request *rq1) 3591b13d190SFrançois Tigeot { 360a05eeebfSFrançois Tigeot 3618621f407SFrançois Tigeot struct intel_engine_cs *engine = rq0->engine; 3628621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 3632c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 364a05eeebfSFrançois Tigeot uint64_t desc[2]; 3651b13d190SFrançois Tigeot 366a05eeebfSFrançois Tigeot if (rq1) { 3678621f407SFrançois Tigeot desc[1] = intel_lr_context_descriptor(rq1->ctx, rq1->engine); 368a05eeebfSFrançois Tigeot rq1->elsp_submitted++; 369a05eeebfSFrançois Tigeot } else { 370a05eeebfSFrançois Tigeot desc[1] = 0; 371a05eeebfSFrançois Tigeot } 3721b13d190SFrançois Tigeot 3738621f407SFrançois Tigeot desc[0] = intel_lr_context_descriptor(rq0->ctx, rq0->engine); 374a05eeebfSFrançois Tigeot rq0->elsp_submitted++; 3751b13d190SFrançois Tigeot 376a05eeebfSFrançois Tigeot /* You must always write both descriptors in the order below. */ 3778621f407SFrançois Tigeot I915_WRITE_FW(RING_ELSP(engine), upper_32_bits(desc[1])); 3788621f407SFrançois Tigeot I915_WRITE_FW(RING_ELSP(engine), lower_32_bits(desc[1])); 3792c9916cdSFrançois Tigeot 3808621f407SFrançois Tigeot I915_WRITE_FW(RING_ELSP(engine), upper_32_bits(desc[0])); 3811b13d190SFrançois Tigeot /* The context is automatically loaded after the following */ 3828621f407SFrançois Tigeot I915_WRITE_FW(RING_ELSP(engine), lower_32_bits(desc[0])); 3831b13d190SFrançois Tigeot 384a05eeebfSFrançois Tigeot /* ELSP is a wo register, use another nearby reg for posting */ 3858621f407SFrançois Tigeot POSTING_READ_FW(RING_EXECLIST_STATUS_LO(engine)); 3861b13d190SFrançois Tigeot } 3871b13d190SFrançois Tigeot 3888621f407SFrançois Tigeot static void 3898621f407SFrançois Tigeot execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state) 3901b13d190SFrançois Tigeot { 39119c468b4SFrançois Tigeot ASSIGN_CTX_PDP(ppgtt, reg_state, 3); 39219c468b4SFrançois Tigeot ASSIGN_CTX_PDP(ppgtt, reg_state, 2); 39319c468b4SFrançois Tigeot ASSIGN_CTX_PDP(ppgtt, reg_state, 1); 39419c468b4SFrançois Tigeot ASSIGN_CTX_PDP(ppgtt, reg_state, 0); 39519c468b4SFrançois Tigeot } 39619c468b4SFrançois Tigeot 3978621f407SFrançois Tigeot static void execlists_update_context(struct drm_i915_gem_request *rq) 3988621f407SFrançois Tigeot { 3998621f407SFrançois Tigeot struct intel_engine_cs *engine = rq->engine; 4008621f407SFrançois Tigeot struct i915_hw_ppgtt *ppgtt = rq->ctx->ppgtt; 4018621f407SFrançois Tigeot uint32_t *reg_state = rq->ctx->engine[engine->id].lrc_reg_state; 4028621f407SFrançois Tigeot 4038621f407SFrançois Tigeot reg_state[CTX_RING_TAIL+1] = rq->tail; 4048621f407SFrançois Tigeot 4058621f407SFrançois Tigeot /* True 32b PPGTT with dynamic page allocation: update PDP 4068621f407SFrançois Tigeot * registers and point the unallocated PDPs to scratch page. 4078621f407SFrançois Tigeot * PML4 is allocated during ppgtt init, so this is not needed 4088621f407SFrançois Tigeot * in 48-bit mode. 4098621f407SFrançois Tigeot */ 4108621f407SFrançois Tigeot if (ppgtt && !USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) 4118621f407SFrançois Tigeot execlists_update_context_pdps(ppgtt, reg_state); 4121b13d190SFrançois Tigeot } 4131b13d190SFrançois Tigeot 414a05eeebfSFrançois Tigeot static void execlists_submit_requests(struct drm_i915_gem_request *rq0, 415a05eeebfSFrançois Tigeot struct drm_i915_gem_request *rq1) 4161b13d190SFrançois Tigeot { 4178621f407SFrançois Tigeot struct drm_i915_private *dev_priv = rq0->i915; 4188621f407SFrançois Tigeot unsigned int fw_domains = rq0->engine->fw_domains; 4198621f407SFrançois Tigeot 420a05eeebfSFrançois Tigeot execlists_update_context(rq0); 4211b13d190SFrançois Tigeot 422a05eeebfSFrançois Tigeot if (rq1) 423a05eeebfSFrançois Tigeot execlists_update_context(rq1); 4241b13d190SFrançois Tigeot 4258621f407SFrançois Tigeot spin_lock_irq(&dev_priv->uncore.lock); 4268621f407SFrançois Tigeot intel_uncore_forcewake_get__locked(dev_priv, fw_domains); 4278621f407SFrançois Tigeot 428a05eeebfSFrançois Tigeot execlists_elsp_write(rq0, rq1); 4298621f407SFrançois Tigeot 4308621f407SFrançois Tigeot intel_uncore_forcewake_put__locked(dev_priv, fw_domains); 4318621f407SFrançois Tigeot spin_unlock_irq(&dev_priv->uncore.lock); 4321b13d190SFrançois Tigeot } 4331b13d190SFrançois Tigeot 4348621f407SFrançois Tigeot static void execlists_context_unqueue(struct intel_engine_cs *engine) 4351b13d190SFrançois Tigeot { 4362c9916cdSFrançois Tigeot struct drm_i915_gem_request *req0 = NULL, *req1 = NULL; 4378621f407SFrançois Tigeot struct drm_i915_gem_request *cursor, *tmp; 4381b13d190SFrançois Tigeot 4398621f407SFrançois Tigeot assert_spin_locked(&engine->execlist_lock); 4401b13d190SFrançois Tigeot 44119c468b4SFrançois Tigeot /* 44219c468b4SFrançois Tigeot * If irqs are not active generate a warning as batches that finish 44319c468b4SFrançois Tigeot * without the irqs may get lost and a GPU Hang may occur. 44419c468b4SFrançois Tigeot */ 4458621f407SFrançois Tigeot WARN_ON(!intel_irqs_enabled(engine->dev->dev_private)); 4461b13d190SFrançois Tigeot 4471b13d190SFrançois Tigeot /* Try to read in pairs */ 4488621f407SFrançois Tigeot list_for_each_entry_safe(cursor, tmp, &engine->execlist_queue, 4491b13d190SFrançois Tigeot execlist_link) { 4501b13d190SFrançois Tigeot if (!req0) { 4511b13d190SFrançois Tigeot req0 = cursor; 4521b13d190SFrançois Tigeot } else if (req0->ctx == cursor->ctx) { 4531b13d190SFrançois Tigeot /* Same ctx: ignore first request, as second request 4541b13d190SFrançois Tigeot * will update tail past first request's workload */ 4551b13d190SFrançois Tigeot cursor->elsp_submitted = req0->elsp_submitted; 456c0e85e96SFrançois Tigeot list_move_tail(&req0->execlist_link, 4578621f407SFrançois Tigeot &engine->execlist_retired_req_list); 4581b13d190SFrançois Tigeot req0 = cursor; 4591b13d190SFrançois Tigeot } else { 4601b13d190SFrançois Tigeot req1 = cursor; 4618621f407SFrançois Tigeot WARN_ON(req1->elsp_submitted); 4621b13d190SFrançois Tigeot break; 4631b13d190SFrançois Tigeot } 4641b13d190SFrançois Tigeot } 4651b13d190SFrançois Tigeot 4668621f407SFrançois Tigeot if (unlikely(!req0)) 4678621f407SFrançois Tigeot return; 4688621f407SFrançois Tigeot 4698621f407SFrançois Tigeot if (req0->elsp_submitted & engine->idle_lite_restore_wa) { 470477eb7f9SFrançois Tigeot /* 4718621f407SFrançois Tigeot * WaIdleLiteRestore: make sure we never cause a lite restore 4728621f407SFrançois Tigeot * with HEAD==TAIL. 4738621f407SFrançois Tigeot * 4748621f407SFrançois Tigeot * Apply the wa NOOPS to prevent ring:HEAD == req:TAIL as we 4758621f407SFrançois Tigeot * resubmit the request. See gen8_emit_request() for where we 4768621f407SFrançois Tigeot * prepare the padding after the end of the request. 477477eb7f9SFrançois Tigeot */ 478477eb7f9SFrançois Tigeot struct intel_ringbuffer *ringbuf; 479477eb7f9SFrançois Tigeot 4808621f407SFrançois Tigeot ringbuf = req0->ctx->engine[engine->id].ringbuf; 481477eb7f9SFrançois Tigeot req0->tail += 8; 482477eb7f9SFrançois Tigeot req0->tail &= ringbuf->size - 1; 483477eb7f9SFrançois Tigeot } 4841b13d190SFrançois Tigeot 485a05eeebfSFrançois Tigeot execlists_submit_requests(req0, req1); 4861b13d190SFrançois Tigeot } 4871b13d190SFrançois Tigeot 4888621f407SFrançois Tigeot static unsigned int 4898621f407SFrançois Tigeot execlists_check_remove_request(struct intel_engine_cs *engine, u32 request_id) 4901b13d190SFrançois Tigeot { 4912c9916cdSFrançois Tigeot struct drm_i915_gem_request *head_req; 4921b13d190SFrançois Tigeot 4938621f407SFrançois Tigeot assert_spin_locked(&engine->execlist_lock); 4941b13d190SFrançois Tigeot 4958621f407SFrançois Tigeot head_req = list_first_entry_or_null(&engine->execlist_queue, 4962c9916cdSFrançois Tigeot struct drm_i915_gem_request, 4971b13d190SFrançois Tigeot execlist_link); 4981b13d190SFrançois Tigeot 4998621f407SFrançois Tigeot if (!head_req) 5008621f407SFrançois Tigeot return 0; 5011b13d190SFrançois Tigeot 5028621f407SFrançois Tigeot if (unlikely(intel_execlists_ctx_id(head_req->ctx, engine) != request_id)) 5038621f407SFrançois Tigeot return 0; 5048621f407SFrançois Tigeot 5058621f407SFrançois Tigeot WARN(head_req->elsp_submitted == 0, "Never submitted head request\n"); 5068621f407SFrançois Tigeot 5078621f407SFrançois Tigeot if (--head_req->elsp_submitted > 0) 5088621f407SFrançois Tigeot return 0; 5098621f407SFrançois Tigeot 510c0e85e96SFrançois Tigeot list_move_tail(&head_req->execlist_link, 5118621f407SFrançois Tigeot &engine->execlist_retired_req_list); 5128621f407SFrançois Tigeot 5138621f407SFrançois Tigeot return 1; 5141b13d190SFrançois Tigeot } 5151b13d190SFrançois Tigeot 5168621f407SFrançois Tigeot static u32 5178621f407SFrançois Tigeot get_context_status(struct intel_engine_cs *engine, unsigned int read_pointer, 5188621f407SFrançois Tigeot u32 *context_id) 519c0e85e96SFrançois Tigeot { 5208621f407SFrançois Tigeot struct drm_i915_private *dev_priv = engine->dev->dev_private; 5218621f407SFrançois Tigeot u32 status; 522c0e85e96SFrançois Tigeot 5238621f407SFrançois Tigeot read_pointer %= GEN8_CSB_ENTRIES; 524c0e85e96SFrançois Tigeot 5258621f407SFrançois Tigeot status = I915_READ_FW(RING_CONTEXT_STATUS_BUF_LO(engine, read_pointer)); 5268621f407SFrançois Tigeot 5278621f407SFrançois Tigeot if (status & GEN8_CTX_STATUS_IDLE_ACTIVE) 5288621f407SFrançois Tigeot return 0; 5298621f407SFrançois Tigeot 5308621f407SFrançois Tigeot *context_id = I915_READ_FW(RING_CONTEXT_STATUS_BUF_HI(engine, 5318621f407SFrançois Tigeot read_pointer)); 5328621f407SFrançois Tigeot 5338621f407SFrançois Tigeot return status; 534c0e85e96SFrançois Tigeot } 535c0e85e96SFrançois Tigeot 5361b13d190SFrançois Tigeot /** 5372c9916cdSFrançois Tigeot * intel_lrc_irq_handler() - handle Context Switch interrupts 5388621f407SFrançois Tigeot * @engine: Engine Command Streamer to handle. 5391b13d190SFrançois Tigeot * 5401b13d190SFrançois Tigeot * Check the unread Context Status Buffers and manage the submission of new 5411b13d190SFrançois Tigeot * contexts to the ELSP accordingly. 5421b13d190SFrançois Tigeot */ 5438621f407SFrançois Tigeot static void intel_lrc_irq_handler(unsigned long data) 5441b13d190SFrançois Tigeot { 5458621f407SFrançois Tigeot struct intel_engine_cs *engine = (struct intel_engine_cs *)data; 5468621f407SFrançois Tigeot struct drm_i915_private *dev_priv = engine->dev->dev_private; 5471b13d190SFrançois Tigeot u32 status_pointer; 5488621f407SFrançois Tigeot unsigned int read_pointer, write_pointer; 5498621f407SFrançois Tigeot u32 csb[GEN8_CSB_ENTRIES][2]; 5508621f407SFrançois Tigeot unsigned int csb_read = 0, i; 5518621f407SFrançois Tigeot unsigned int submit_contexts = 0; 5521b13d190SFrançois Tigeot 5538621f407SFrançois Tigeot intel_uncore_forcewake_get(dev_priv, engine->fw_domains); 5541b13d190SFrançois Tigeot 5558621f407SFrançois Tigeot status_pointer = I915_READ_FW(RING_CONTEXT_STATUS_PTR(engine)); 5568621f407SFrançois Tigeot 5578621f407SFrançois Tigeot read_pointer = engine->next_context_status_buffer; 558c0e85e96SFrançois Tigeot write_pointer = GEN8_CSB_WRITE_PTR(status_pointer); 5591b13d190SFrançois Tigeot if (read_pointer > write_pointer) 560a05eeebfSFrançois Tigeot write_pointer += GEN8_CSB_ENTRIES; 5611b13d190SFrançois Tigeot 5621b13d190SFrançois Tigeot while (read_pointer < write_pointer) { 5638621f407SFrançois Tigeot if (WARN_ON_ONCE(csb_read == GEN8_CSB_ENTRIES)) 5648621f407SFrançois Tigeot break; 5658621f407SFrançois Tigeot csb[csb_read][0] = get_context_status(engine, ++read_pointer, 5668621f407SFrançois Tigeot &csb[csb_read][1]); 5678621f407SFrançois Tigeot csb_read++; 5688621f407SFrançois Tigeot } 569c0e85e96SFrançois Tigeot 5708621f407SFrançois Tigeot engine->next_context_status_buffer = write_pointer % GEN8_CSB_ENTRIES; 571a05eeebfSFrançois Tigeot 5728621f407SFrançois Tigeot /* Update the read pointer to the old write pointer. Manual ringbuffer 5738621f407SFrançois Tigeot * management ftw </sarcasm> */ 5748621f407SFrançois Tigeot I915_WRITE_FW(RING_CONTEXT_STATUS_PTR(engine), 5758621f407SFrançois Tigeot _MASKED_FIELD(GEN8_CSB_READ_PTR_MASK, 5768621f407SFrançois Tigeot engine->next_context_status_buffer << 8)); 5771b13d190SFrançois Tigeot 5788621f407SFrançois Tigeot intel_uncore_forcewake_put(dev_priv, engine->fw_domains); 5798621f407SFrançois Tigeot 5808621f407SFrançois Tigeot lockmgr(&engine->execlist_lock, LK_EXCLUSIVE); 5818621f407SFrançois Tigeot 5828621f407SFrançois Tigeot for (i = 0; i < csb_read; i++) { 5838621f407SFrançois Tigeot if (unlikely(csb[i][0] & GEN8_CTX_STATUS_PREEMPTED)) { 5848621f407SFrançois Tigeot if (csb[i][0] & GEN8_CTX_STATUS_LITE_RESTORE) { 5858621f407SFrançois Tigeot if (execlists_check_remove_request(engine, csb[i][1])) 5861b13d190SFrançois Tigeot WARN(1, "Lite Restored request removed from queue\n"); 5871b13d190SFrançois Tigeot } else 5881b13d190SFrançois Tigeot WARN(1, "Preemption without Lite Restore\n"); 5891b13d190SFrançois Tigeot } 5901b13d190SFrançois Tigeot 5918621f407SFrançois Tigeot if (csb[i][0] & (GEN8_CTX_STATUS_ACTIVE_IDLE | 5928621f407SFrançois Tigeot GEN8_CTX_STATUS_ELEMENT_SWITCH)) 5938621f407SFrançois Tigeot submit_contexts += 5948621f407SFrançois Tigeot execlists_check_remove_request(engine, csb[i][1]); 5951b13d190SFrançois Tigeot } 5961b13d190SFrançois Tigeot 5978621f407SFrançois Tigeot if (submit_contexts) { 5988621f407SFrançois Tigeot if (!engine->disable_lite_restore_wa || 5998621f407SFrançois Tigeot (csb[i][0] & GEN8_CTX_STATUS_ACTIVE_IDLE)) 6008621f407SFrançois Tigeot execlists_context_unqueue(engine); 601352ff8bdSFrançois Tigeot } 6021b13d190SFrançois Tigeot 6038621f407SFrançois Tigeot lockmgr(&engine->execlist_lock, LK_RELEASE); 6041b13d190SFrançois Tigeot 605c0e85e96SFrançois Tigeot if (unlikely(submit_contexts > 2)) 606c0e85e96SFrançois Tigeot DRM_ERROR("More than two context complete events?\n"); 6071b13d190SFrançois Tigeot } 6081b13d190SFrançois Tigeot 6098621f407SFrançois Tigeot static void execlists_context_queue(struct drm_i915_gem_request *request) 6101b13d190SFrançois Tigeot { 6118621f407SFrançois Tigeot struct intel_engine_cs *engine = request->engine; 6122c9916cdSFrançois Tigeot struct drm_i915_gem_request *cursor; 6131b13d190SFrançois Tigeot int num_elements = 0; 6141b13d190SFrançois Tigeot 615c0e85e96SFrançois Tigeot if (request->ctx != request->i915->kernel_context) 6168621f407SFrançois Tigeot intel_lr_context_pin(request->ctx, engine); 6172c9916cdSFrançois Tigeot 6182c9916cdSFrançois Tigeot i915_gem_request_reference(request); 619a05eeebfSFrançois Tigeot 6208621f407SFrançois Tigeot spin_lock_bh(&engine->execlist_lock); 6211b13d190SFrançois Tigeot 6228621f407SFrançois Tigeot list_for_each_entry(cursor, &engine->execlist_queue, execlist_link) 6231b13d190SFrançois Tigeot if (++num_elements > 2) 6241b13d190SFrançois Tigeot break; 6251b13d190SFrançois Tigeot 6261b13d190SFrançois Tigeot if (num_elements > 2) { 6272c9916cdSFrançois Tigeot struct drm_i915_gem_request *tail_req; 6281b13d190SFrançois Tigeot 6298621f407SFrançois Tigeot tail_req = list_last_entry(&engine->execlist_queue, 6302c9916cdSFrançois Tigeot struct drm_i915_gem_request, 6311b13d190SFrançois Tigeot execlist_link); 6321b13d190SFrançois Tigeot 633a05eeebfSFrançois Tigeot if (request->ctx == tail_req->ctx) { 6341b13d190SFrançois Tigeot WARN(tail_req->elsp_submitted != 0, 6351b13d190SFrançois Tigeot "More than 2 already-submitted reqs queued\n"); 636c0e85e96SFrançois Tigeot list_move_tail(&tail_req->execlist_link, 6378621f407SFrançois Tigeot &engine->execlist_retired_req_list); 6381b13d190SFrançois Tigeot } 6391b13d190SFrançois Tigeot } 6401b13d190SFrançois Tigeot 6418621f407SFrançois Tigeot list_add_tail(&request->execlist_link, &engine->execlist_queue); 6421b13d190SFrançois Tigeot if (num_elements == 0) 6438621f407SFrançois Tigeot execlists_context_unqueue(engine); 6441b13d190SFrançois Tigeot 6458621f407SFrançois Tigeot spin_unlock_bh(&engine->execlist_lock); 6461b13d190SFrançois Tigeot } 6471b13d190SFrançois Tigeot 648a05eeebfSFrançois Tigeot static int logical_ring_invalidate_all_caches(struct drm_i915_gem_request *req) 6491b13d190SFrançois Tigeot { 6508621f407SFrançois Tigeot struct intel_engine_cs *engine = req->engine; 6511b13d190SFrançois Tigeot uint32_t flush_domains; 6521b13d190SFrançois Tigeot int ret; 6531b13d190SFrançois Tigeot 6541b13d190SFrançois Tigeot flush_domains = 0; 6558621f407SFrançois Tigeot if (engine->gpu_caches_dirty) 6561b13d190SFrançois Tigeot flush_domains = I915_GEM_GPU_DOMAINS; 6571b13d190SFrançois Tigeot 6588621f407SFrançois Tigeot ret = engine->emit_flush(req, I915_GEM_GPU_DOMAINS, flush_domains); 6591b13d190SFrançois Tigeot if (ret) 6601b13d190SFrançois Tigeot return ret; 6611b13d190SFrançois Tigeot 6628621f407SFrançois Tigeot engine->gpu_caches_dirty = false; 6631b13d190SFrançois Tigeot return 0; 6641b13d190SFrançois Tigeot } 6651b13d190SFrançois Tigeot 666a05eeebfSFrançois Tigeot static int execlists_move_to_gpu(struct drm_i915_gem_request *req, 6671b13d190SFrançois Tigeot struct list_head *vmas) 6681b13d190SFrançois Tigeot { 6698621f407SFrançois Tigeot const unsigned other_rings = ~intel_engine_flag(req->engine); 6701b13d190SFrançois Tigeot struct i915_vma *vma; 6711b13d190SFrançois Tigeot uint32_t flush_domains = 0; 6721b13d190SFrançois Tigeot bool flush_chipset = false; 6731b13d190SFrançois Tigeot int ret; 6741b13d190SFrançois Tigeot 6751b13d190SFrançois Tigeot list_for_each_entry(vma, vmas, exec_list) { 6761b13d190SFrançois Tigeot struct drm_i915_gem_object *obj = vma->obj; 6771b13d190SFrançois Tigeot 67819c468b4SFrançois Tigeot if (obj->active & other_rings) { 6798621f407SFrançois Tigeot ret = i915_gem_object_sync(obj, req->engine, &req); 6801b13d190SFrançois Tigeot if (ret) 6811b13d190SFrançois Tigeot return ret; 68219c468b4SFrançois Tigeot } 6831b13d190SFrançois Tigeot 6841b13d190SFrançois Tigeot if (obj->base.write_domain & I915_GEM_DOMAIN_CPU) 6851b13d190SFrançois Tigeot flush_chipset |= i915_gem_clflush_object(obj, false); 6861b13d190SFrançois Tigeot 6871b13d190SFrançois Tigeot flush_domains |= obj->base.write_domain; 6881b13d190SFrançois Tigeot } 6891b13d190SFrançois Tigeot 6901b13d190SFrançois Tigeot if (flush_domains & I915_GEM_DOMAIN_GTT) 6911b13d190SFrançois Tigeot wmb(); 6921b13d190SFrançois Tigeot 6931b13d190SFrançois Tigeot /* Unconditionally invalidate gpu caches and ensure that we do flush 6941b13d190SFrançois Tigeot * any residual writes from the previous batch. 6951b13d190SFrançois Tigeot */ 696a05eeebfSFrançois Tigeot return logical_ring_invalidate_all_caches(req); 6971b13d190SFrançois Tigeot } 6981b13d190SFrançois Tigeot 699a05eeebfSFrançois Tigeot int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request) 70019c468b4SFrançois Tigeot { 701c0e85e96SFrançois Tigeot int ret = 0; 70219c468b4SFrançois Tigeot 7038621f407SFrançois Tigeot request->ringbuf = request->ctx->engine[request->engine->id].ringbuf; 704a05eeebfSFrançois Tigeot 705c0e85e96SFrançois Tigeot if (i915.enable_guc_submission) { 706c0e85e96SFrançois Tigeot /* 707c0e85e96SFrançois Tigeot * Check that the GuC has space for the request before 708c0e85e96SFrançois Tigeot * going any further, as the i915_add_request() call 709c0e85e96SFrançois Tigeot * later on mustn't fail ... 710c0e85e96SFrançois Tigeot */ 711c0e85e96SFrançois Tigeot struct intel_guc *guc = &request->i915->guc; 712c0e85e96SFrançois Tigeot 713c0e85e96SFrançois Tigeot ret = i915_guc_wq_check_space(guc->execbuf_client); 71419c468b4SFrançois Tigeot if (ret) 71519c468b4SFrançois Tigeot return ret; 71619c468b4SFrançois Tigeot } 71719c468b4SFrançois Tigeot 718c0e85e96SFrançois Tigeot if (request->ctx != request->i915->kernel_context) 7198621f407SFrançois Tigeot ret = intel_lr_context_pin(request->ctx, request->engine); 720c0e85e96SFrançois Tigeot 721c0e85e96SFrançois Tigeot return ret; 72219c468b4SFrançois Tigeot } 72319c468b4SFrançois Tigeot 72419c468b4SFrançois Tigeot /* 72519c468b4SFrançois Tigeot * intel_logical_ring_advance_and_submit() - advance the tail and submit the workload 726a05eeebfSFrançois Tigeot * @request: Request to advance the logical ringbuffer of. 72719c468b4SFrançois Tigeot * 72819c468b4SFrançois Tigeot * The tail is updated in our logical ringbuffer struct, not in the actual context. What 72919c468b4SFrançois Tigeot * really happens during submission is that the context and current tail will be placed 73019c468b4SFrançois Tigeot * on a queue waiting for the ELSP to be ready to accept a new context submission. At that 73119c468b4SFrançois Tigeot * point, the tail *inside* the context is updated and the ELSP written to. 73219c468b4SFrançois Tigeot */ 733c0e85e96SFrançois Tigeot static int 734a05eeebfSFrançois Tigeot intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request) 73519c468b4SFrançois Tigeot { 736c0e85e96SFrançois Tigeot struct intel_ringbuffer *ringbuf = request->ringbuf; 7378cd49a21SFrançois Tigeot struct drm_i915_private *dev_priv = request->i915; 7388621f407SFrançois Tigeot struct intel_engine_cs *engine = request->engine; 73919c468b4SFrançois Tigeot 740c0e85e96SFrançois Tigeot intel_logical_ring_advance(ringbuf); 741c0e85e96SFrançois Tigeot request->tail = ringbuf->tail; 74219c468b4SFrançois Tigeot 743c0e85e96SFrançois Tigeot /* 744c0e85e96SFrançois Tigeot * Here we add two extra NOOPs as padding to avoid 745c0e85e96SFrançois Tigeot * lite restore of a context with HEAD==TAIL. 746c0e85e96SFrançois Tigeot * 747c0e85e96SFrançois Tigeot * Caller must reserve WA_TAIL_DWORDS for us! 748c0e85e96SFrançois Tigeot */ 749c0e85e96SFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_NOOP); 750c0e85e96SFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_NOOP); 751c0e85e96SFrançois Tigeot intel_logical_ring_advance(ringbuf); 752352ff8bdSFrançois Tigeot 7538621f407SFrançois Tigeot if (intel_engine_stopped(engine)) 754c0e85e96SFrançois Tigeot return 0; 755c0e85e96SFrançois Tigeot 756c0e85e96SFrançois Tigeot if (engine->last_context != request->ctx) { 757c0e85e96SFrançois Tigeot if (engine->last_context) 758c0e85e96SFrançois Tigeot intel_lr_context_unpin(engine->last_context, engine); 759c0e85e96SFrançois Tigeot if (request->ctx != request->i915->kernel_context) { 760c0e85e96SFrançois Tigeot intel_lr_context_pin(request->ctx, engine); 761c0e85e96SFrançois Tigeot engine->last_context = request->ctx; 762c0e85e96SFrançois Tigeot } else { 763c0e85e96SFrançois Tigeot engine->last_context = NULL; 764c0e85e96SFrançois Tigeot } 765c0e85e96SFrançois Tigeot } 76619c468b4SFrançois Tigeot 767352ff8bdSFrançois Tigeot if (dev_priv->guc.execbuf_client) 768352ff8bdSFrançois Tigeot i915_guc_submit(dev_priv->guc.execbuf_client, request); 769352ff8bdSFrançois Tigeot else 770a05eeebfSFrançois Tigeot execlists_context_queue(request); 771c0e85e96SFrançois Tigeot 772c0e85e96SFrançois Tigeot return 0; 77319c468b4SFrançois Tigeot } 77419c468b4SFrançois Tigeot 775a05eeebfSFrançois Tigeot int intel_logical_ring_reserve_space(struct drm_i915_gem_request *request) 776a05eeebfSFrançois Tigeot { 777a05eeebfSFrançois Tigeot /* 778a05eeebfSFrançois Tigeot * The first call merely notes the reserve request and is common for 779a05eeebfSFrançois Tigeot * all back ends. The subsequent localised _begin() call actually 780a05eeebfSFrançois Tigeot * ensures that the reservation is available. Without the begin, if 781a05eeebfSFrançois Tigeot * the request creator immediately submitted the request without 782a05eeebfSFrançois Tigeot * adding any commands to it then there might not actually be 783a05eeebfSFrançois Tigeot * sufficient room for the submission commands. 784a05eeebfSFrançois Tigeot */ 785a05eeebfSFrançois Tigeot intel_ring_reserved_space_reserve(request->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); 786a05eeebfSFrançois Tigeot 7878621f407SFrançois Tigeot return intel_ring_begin(request, 0); 788a05eeebfSFrançois Tigeot } 789a05eeebfSFrançois Tigeot 7901b13d190SFrançois Tigeot /** 7911b13d190SFrançois Tigeot * execlists_submission() - submit a batchbuffer for execution, Execlists style 7921b13d190SFrançois Tigeot * @dev: DRM device. 7931b13d190SFrançois Tigeot * @file: DRM file. 7941b13d190SFrançois Tigeot * @ring: Engine Command Streamer to submit to. 7951b13d190SFrançois Tigeot * @ctx: Context to employ for this submission. 7961b13d190SFrançois Tigeot * @args: execbuffer call arguments. 7971b13d190SFrançois Tigeot * @vmas: list of vmas. 7981b13d190SFrançois Tigeot * @batch_obj: the batchbuffer to submit. 7991b13d190SFrançois Tigeot * @exec_start: batchbuffer start virtual address pointer. 800477eb7f9SFrançois Tigeot * @dispatch_flags: translated execbuffer call flags. 8011b13d190SFrançois Tigeot * 8021b13d190SFrançois Tigeot * This is the evil twin version of i915_gem_ringbuffer_submission. It abstracts 8031b13d190SFrançois Tigeot * away the submission details of the execbuffer ioctl call. 8041b13d190SFrançois Tigeot * 8051b13d190SFrançois Tigeot * Return: non-zero if the submission fails. 8061b13d190SFrançois Tigeot */ 807a05eeebfSFrançois Tigeot int intel_execlists_submission(struct i915_execbuffer_params *params, 8081b13d190SFrançois Tigeot struct drm_i915_gem_execbuffer2 *args, 809a05eeebfSFrançois Tigeot struct list_head *vmas) 8101b13d190SFrançois Tigeot { 811a05eeebfSFrançois Tigeot struct drm_device *dev = params->dev; 8128621f407SFrançois Tigeot struct intel_engine_cs *engine = params->engine; 8131b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 8148621f407SFrançois Tigeot struct intel_ringbuffer *ringbuf = params->ctx->engine[engine->id].ringbuf; 815a05eeebfSFrançois Tigeot u64 exec_start; 8161b13d190SFrançois Tigeot int instp_mode; 8171b13d190SFrançois Tigeot u32 instp_mask; 8181b13d190SFrançois Tigeot int ret; 8191b13d190SFrançois Tigeot 8201b13d190SFrançois Tigeot instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK; 8211b13d190SFrançois Tigeot instp_mask = I915_EXEC_CONSTANTS_MASK; 8221b13d190SFrançois Tigeot switch (instp_mode) { 8231b13d190SFrançois Tigeot case I915_EXEC_CONSTANTS_REL_GENERAL: 8241b13d190SFrançois Tigeot case I915_EXEC_CONSTANTS_ABSOLUTE: 8251b13d190SFrançois Tigeot case I915_EXEC_CONSTANTS_REL_SURFACE: 8268621f407SFrançois Tigeot if (instp_mode != 0 && engine != &dev_priv->engine[RCS]) { 8271b13d190SFrançois Tigeot DRM_DEBUG("non-0 rel constants mode on non-RCS\n"); 8281b13d190SFrançois Tigeot return -EINVAL; 8291b13d190SFrançois Tigeot } 8301b13d190SFrançois Tigeot 8311b13d190SFrançois Tigeot if (instp_mode != dev_priv->relative_constants_mode) { 8321b13d190SFrançois Tigeot if (instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) { 8331b13d190SFrançois Tigeot DRM_DEBUG("rel surface constants mode invalid on gen5+\n"); 8341b13d190SFrançois Tigeot return -EINVAL; 8351b13d190SFrançois Tigeot } 8361b13d190SFrançois Tigeot 8371b13d190SFrançois Tigeot /* The HW changed the meaning on this bit on gen6 */ 8381b13d190SFrançois Tigeot instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE; 8391b13d190SFrançois Tigeot } 8401b13d190SFrançois Tigeot break; 8411b13d190SFrançois Tigeot default: 8421b13d190SFrançois Tigeot DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode); 8431b13d190SFrançois Tigeot return -EINVAL; 8441b13d190SFrançois Tigeot } 8451b13d190SFrançois Tigeot 8461b13d190SFrançois Tigeot if (args->flags & I915_EXEC_GEN7_SOL_RESET) { 8471b13d190SFrançois Tigeot DRM_DEBUG("sol reset is gen7 only\n"); 8481b13d190SFrançois Tigeot return -EINVAL; 8491b13d190SFrançois Tigeot } 8501b13d190SFrançois Tigeot 851a05eeebfSFrançois Tigeot ret = execlists_move_to_gpu(params->request, vmas); 8521b13d190SFrançois Tigeot if (ret) 8531b13d190SFrançois Tigeot return ret; 8541b13d190SFrançois Tigeot 8558621f407SFrançois Tigeot if (engine == &dev_priv->engine[RCS] && 8561b13d190SFrançois Tigeot instp_mode != dev_priv->relative_constants_mode) { 8578621f407SFrançois Tigeot ret = intel_ring_begin(params->request, 4); 8581b13d190SFrançois Tigeot if (ret) 8591b13d190SFrançois Tigeot return ret; 8601b13d190SFrançois Tigeot 8611b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_NOOP); 8621b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(1)); 863aee94f86SFrançois Tigeot intel_logical_ring_emit_reg(ringbuf, INSTPM); 8641b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, instp_mask << 16 | instp_mode); 8651b13d190SFrançois Tigeot intel_logical_ring_advance(ringbuf); 8661b13d190SFrançois Tigeot 8671b13d190SFrançois Tigeot dev_priv->relative_constants_mode = instp_mode; 8681b13d190SFrançois Tigeot } 8691b13d190SFrançois Tigeot 870a05eeebfSFrançois Tigeot exec_start = params->batch_obj_vm_offset + 871a05eeebfSFrançois Tigeot args->batch_start_offset; 872a05eeebfSFrançois Tigeot 8738621f407SFrançois Tigeot ret = engine->emit_bb_start(params->request, exec_start, params->dispatch_flags); 8741b13d190SFrançois Tigeot if (ret) 8751b13d190SFrançois Tigeot return ret; 8761b13d190SFrançois Tigeot 877a05eeebfSFrançois Tigeot trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); 878477eb7f9SFrançois Tigeot 879a05eeebfSFrançois Tigeot i915_gem_execbuffer_move_to_active(vmas, params->request); 8801b13d190SFrançois Tigeot 8811b13d190SFrançois Tigeot return 0; 8821b13d190SFrançois Tigeot } 8831b13d190SFrançois Tigeot 8848621f407SFrançois Tigeot void intel_execlists_retire_requests(struct intel_engine_cs *engine) 8852c9916cdSFrançois Tigeot { 8862c9916cdSFrançois Tigeot struct drm_i915_gem_request *req, *tmp; 8872c9916cdSFrançois Tigeot struct list_head retired_list; 8882c9916cdSFrançois Tigeot 8898621f407SFrançois Tigeot WARN_ON(!mutex_is_locked(&engine->dev->struct_mutex)); 8908621f407SFrançois Tigeot if (list_empty(&engine->execlist_retired_req_list)) 8912c9916cdSFrançois Tigeot return; 8922c9916cdSFrançois Tigeot 8932c9916cdSFrançois Tigeot INIT_LIST_HEAD(&retired_list); 8948621f407SFrançois Tigeot spin_lock_bh(&engine->execlist_lock); 8958621f407SFrançois Tigeot list_replace_init(&engine->execlist_retired_req_list, &retired_list); 8968621f407SFrançois Tigeot spin_unlock_bh(&engine->execlist_lock); 8972c9916cdSFrançois Tigeot 8982c9916cdSFrançois Tigeot list_for_each_entry_safe(req, tmp, &retired_list, execlist_link) { 8992c9916cdSFrançois Tigeot struct intel_context *ctx = req->ctx; 9002c9916cdSFrançois Tigeot struct drm_i915_gem_object *ctx_obj = 9018621f407SFrançois Tigeot ctx->engine[engine->id].state; 9022c9916cdSFrançois Tigeot 903c0e85e96SFrançois Tigeot if (ctx_obj && (ctx != req->i915->kernel_context)) 9048621f407SFrançois Tigeot intel_lr_context_unpin(ctx, engine); 905c0e85e96SFrançois Tigeot 9062c9916cdSFrançois Tigeot list_del(&req->execlist_link); 9072c9916cdSFrançois Tigeot i915_gem_request_unreference(req); 9082c9916cdSFrançois Tigeot } 9092c9916cdSFrançois Tigeot } 9102c9916cdSFrançois Tigeot 9118621f407SFrançois Tigeot void intel_logical_ring_stop(struct intel_engine_cs *engine) 9121b13d190SFrançois Tigeot { 9138621f407SFrançois Tigeot struct drm_i915_private *dev_priv = engine->dev->dev_private; 9141b13d190SFrançois Tigeot int ret; 9151b13d190SFrançois Tigeot 9168621f407SFrançois Tigeot if (!intel_engine_initialized(engine)) 9171b13d190SFrançois Tigeot return; 9181b13d190SFrançois Tigeot 9198621f407SFrançois Tigeot ret = intel_engine_idle(engine); 9208621f407SFrançois Tigeot if (ret) 9211b13d190SFrançois Tigeot DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n", 9228621f407SFrançois Tigeot engine->name, ret); 9231b13d190SFrançois Tigeot 9241b13d190SFrançois Tigeot /* TODO: Is this correct with Execlists enabled? */ 9258621f407SFrançois Tigeot I915_WRITE_MODE(engine, _MASKED_BIT_ENABLE(STOP_RING)); 9268621f407SFrançois Tigeot if (wait_for((I915_READ_MODE(engine) & MODE_IDLE) != 0, 1000)) { 9278621f407SFrançois Tigeot DRM_ERROR("%s :timed out trying to stop ring\n", engine->name); 9281b13d190SFrançois Tigeot return; 9291b13d190SFrançois Tigeot } 9308621f407SFrançois Tigeot I915_WRITE_MODE(engine, _MASKED_BIT_DISABLE(STOP_RING)); 9311b13d190SFrançois Tigeot } 9321b13d190SFrançois Tigeot 933a05eeebfSFrançois Tigeot int logical_ring_flush_all_caches(struct drm_i915_gem_request *req) 9341b13d190SFrançois Tigeot { 9358621f407SFrançois Tigeot struct intel_engine_cs *engine = req->engine; 9361b13d190SFrançois Tigeot int ret; 9371b13d190SFrançois Tigeot 9388621f407SFrançois Tigeot if (!engine->gpu_caches_dirty) 9391b13d190SFrançois Tigeot return 0; 9401b13d190SFrançois Tigeot 9418621f407SFrançois Tigeot ret = engine->emit_flush(req, 0, I915_GEM_GPU_DOMAINS); 9421b13d190SFrançois Tigeot if (ret) 9431b13d190SFrançois Tigeot return ret; 9441b13d190SFrançois Tigeot 9458621f407SFrançois Tigeot engine->gpu_caches_dirty = false; 9461b13d190SFrançois Tigeot return 0; 9471b13d190SFrançois Tigeot } 9481b13d190SFrançois Tigeot 949c0e85e96SFrançois Tigeot static int intel_lr_context_do_pin(struct intel_context *ctx, 9508621f407SFrançois Tigeot struct intel_engine_cs *engine) 9511b13d190SFrançois Tigeot { 9528621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 953352ff8bdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 9548621f407SFrançois Tigeot struct drm_i915_gem_object *ctx_obj = ctx->engine[engine->id].state; 9558621f407SFrançois Tigeot struct intel_ringbuffer *ringbuf = ctx->engine[engine->id].ringbuf; 9568621f407SFrançois Tigeot char *vaddr; 9578621f407SFrançois Tigeot u32 *lrc_reg_state; 958c0e85e96SFrançois Tigeot int ret; 9592c9916cdSFrançois Tigeot 9608621f407SFrançois Tigeot WARN_ON(!mutex_is_locked(&engine->dev->struct_mutex)); 961c0e85e96SFrançois Tigeot 962352ff8bdSFrançois Tigeot ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 963352ff8bdSFrançois Tigeot PIN_OFFSET_BIAS | GUC_WOPCM_TOP); 9642c9916cdSFrançois Tigeot if (ret) 965352ff8bdSFrançois Tigeot return ret; 9662c9916cdSFrançois Tigeot 9678621f407SFrançois Tigeot vaddr = i915_gem_object_pin_map(ctx_obj); 9688621f407SFrançois Tigeot if (IS_ERR(vaddr)) { 9698621f407SFrançois Tigeot ret = PTR_ERR(vaddr); 970c0e85e96SFrançois Tigeot goto unpin_ctx_obj; 971c0e85e96SFrançois Tigeot } 972c0e85e96SFrançois Tigeot 9738621f407SFrançois Tigeot lrc_reg_state = (u32 *)(vaddr + LRC_STATE_PN * PAGE_SIZE); 97419c468b4SFrançois Tigeot 9758621f407SFrançois Tigeot ret = intel_pin_and_map_ringbuffer_obj(engine->dev, ringbuf); 9768621f407SFrançois Tigeot if (ret) 9778621f407SFrançois Tigeot goto unpin_map; 9788621f407SFrançois Tigeot 9798621f407SFrançois Tigeot ctx->engine[engine->id].lrc_vma = i915_gem_obj_to_ggtt(ctx_obj); 9808621f407SFrançois Tigeot intel_lr_context_descriptor_update(ctx, engine); 981c0e85e96SFrançois Tigeot lrc_reg_state[CTX_RING_BUFFER_START+1] = ringbuf->vma->node.start; 9828621f407SFrançois Tigeot ctx->engine[engine->id].lrc_reg_state = lrc_reg_state; 98319c468b4SFrançois Tigeot ctx_obj->dirty = true; 984352ff8bdSFrançois Tigeot 985352ff8bdSFrançois Tigeot /* Invalidate GuC TLB. */ 986352ff8bdSFrançois Tigeot if (i915.enable_guc_submission) 987352ff8bdSFrançois Tigeot I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE); 9882c9916cdSFrançois Tigeot 9892c9916cdSFrançois Tigeot return ret; 9902c9916cdSFrançois Tigeot 9918621f407SFrançois Tigeot unpin_map: 9928621f407SFrançois Tigeot i915_gem_object_unpin_map(ctx_obj); 9932c9916cdSFrançois Tigeot unpin_ctx_obj: 9942c9916cdSFrançois Tigeot i915_gem_object_ggtt_unpin(ctx_obj); 995352ff8bdSFrançois Tigeot 996352ff8bdSFrançois Tigeot return ret; 997352ff8bdSFrançois Tigeot } 998352ff8bdSFrançois Tigeot 999c0e85e96SFrançois Tigeot static int intel_lr_context_pin(struct intel_context *ctx, 1000c0e85e96SFrançois Tigeot struct intel_engine_cs *engine) 1001352ff8bdSFrançois Tigeot { 1002352ff8bdSFrançois Tigeot int ret = 0; 1003352ff8bdSFrançois Tigeot 1004c0e85e96SFrançois Tigeot if (ctx->engine[engine->id].pin_count++ == 0) { 1005c0e85e96SFrançois Tigeot ret = intel_lr_context_do_pin(ctx, engine); 1006352ff8bdSFrançois Tigeot if (ret) 1007352ff8bdSFrançois Tigeot goto reset_pin_count; 1008c0e85e96SFrançois Tigeot 1009c0e85e96SFrançois Tigeot i915_gem_context_reference(ctx); 1010352ff8bdSFrançois Tigeot } 1011352ff8bdSFrançois Tigeot return ret; 1012352ff8bdSFrançois Tigeot 10132c9916cdSFrançois Tigeot reset_pin_count: 1014c0e85e96SFrançois Tigeot ctx->engine[engine->id].pin_count = 0; 10152c9916cdSFrançois Tigeot return ret; 10162c9916cdSFrançois Tigeot } 10172c9916cdSFrançois Tigeot 1018c0e85e96SFrançois Tigeot void intel_lr_context_unpin(struct intel_context *ctx, 1019c0e85e96SFrançois Tigeot struct intel_engine_cs *engine) 10202c9916cdSFrançois Tigeot { 1021c0e85e96SFrançois Tigeot struct drm_i915_gem_object *ctx_obj = ctx->engine[engine->id].state; 10222c9916cdSFrançois Tigeot 1023c0e85e96SFrançois Tigeot WARN_ON(!mutex_is_locked(&ctx->i915->dev->struct_mutex)); 1024c0e85e96SFrançois Tigeot if (--ctx->engine[engine->id].pin_count == 0) { 10258621f407SFrançois Tigeot i915_gem_object_unpin_map(ctx_obj); 1026c0e85e96SFrançois Tigeot intel_unpin_ringbuffer_obj(ctx->engine[engine->id].ringbuf); 10272c9916cdSFrançois Tigeot i915_gem_object_ggtt_unpin(ctx_obj); 1028c0e85e96SFrançois Tigeot ctx->engine[engine->id].lrc_vma = NULL; 1029c0e85e96SFrançois Tigeot ctx->engine[engine->id].lrc_desc = 0; 1030c0e85e96SFrançois Tigeot ctx->engine[engine->id].lrc_reg_state = NULL; 1031c0e85e96SFrançois Tigeot 1032c0e85e96SFrançois Tigeot i915_gem_context_unreference(ctx); 10332c9916cdSFrançois Tigeot } 10342c9916cdSFrançois Tigeot } 10352c9916cdSFrançois Tigeot 1036a05eeebfSFrançois Tigeot static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) 10372c9916cdSFrançois Tigeot { 10382c9916cdSFrançois Tigeot int ret, i; 10398621f407SFrançois Tigeot struct intel_engine_cs *engine = req->engine; 1040a05eeebfSFrançois Tigeot struct intel_ringbuffer *ringbuf = req->ringbuf; 10418621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 10422c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 10432c9916cdSFrançois Tigeot struct i915_workarounds *w = &dev_priv->workarounds; 10442c9916cdSFrançois Tigeot 1045c0e85e96SFrançois Tigeot if (w->count == 0) 10462c9916cdSFrançois Tigeot return 0; 10472c9916cdSFrançois Tigeot 10488621f407SFrançois Tigeot engine->gpu_caches_dirty = true; 1049a05eeebfSFrançois Tigeot ret = logical_ring_flush_all_caches(req); 10502c9916cdSFrançois Tigeot if (ret) 10512c9916cdSFrançois Tigeot return ret; 10522c9916cdSFrançois Tigeot 10538621f407SFrançois Tigeot ret = intel_ring_begin(req, w->count * 2 + 2); 10542c9916cdSFrançois Tigeot if (ret) 10552c9916cdSFrançois Tigeot return ret; 10562c9916cdSFrançois Tigeot 10572c9916cdSFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(w->count)); 10582c9916cdSFrançois Tigeot for (i = 0; i < w->count; i++) { 1059aee94f86SFrançois Tigeot intel_logical_ring_emit_reg(ringbuf, w->reg[i].addr); 10602c9916cdSFrançois Tigeot intel_logical_ring_emit(ringbuf, w->reg[i].value); 10612c9916cdSFrançois Tigeot } 10622c9916cdSFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_NOOP); 10632c9916cdSFrançois Tigeot 10642c9916cdSFrançois Tigeot intel_logical_ring_advance(ringbuf); 10652c9916cdSFrançois Tigeot 10668621f407SFrançois Tigeot engine->gpu_caches_dirty = true; 1067a05eeebfSFrançois Tigeot ret = logical_ring_flush_all_caches(req); 10682c9916cdSFrançois Tigeot if (ret) 10692c9916cdSFrançois Tigeot return ret; 10702c9916cdSFrançois Tigeot 10712c9916cdSFrançois Tigeot return 0; 10722c9916cdSFrançois Tigeot } 10732c9916cdSFrançois Tigeot 1074a05eeebfSFrançois Tigeot #define wa_ctx_emit(batch, index, cmd) \ 1075a05eeebfSFrançois Tigeot do { \ 1076a05eeebfSFrançois Tigeot int __index = (index)++; \ 1077a05eeebfSFrançois Tigeot if (WARN_ON(__index >= (PAGE_SIZE / sizeof(uint32_t)))) { \ 1078a05eeebfSFrançois Tigeot return -ENOSPC; \ 1079a05eeebfSFrançois Tigeot } \ 1080a05eeebfSFrançois Tigeot batch[__index] = (cmd); \ 1081a05eeebfSFrançois Tigeot } while (0) 1082a05eeebfSFrançois Tigeot 1083aee94f86SFrançois Tigeot #define wa_ctx_emit_reg(batch, index, reg) \ 1084aee94f86SFrançois Tigeot wa_ctx_emit((batch), (index), i915_mmio_reg_offset(reg)) 1085a05eeebfSFrançois Tigeot 1086a05eeebfSFrançois Tigeot /* 1087a05eeebfSFrançois Tigeot * In this WA we need to set GEN8_L3SQCREG4[21:21] and reset it after 1088a05eeebfSFrançois Tigeot * PIPE_CONTROL instruction. This is required for the flush to happen correctly 1089a05eeebfSFrançois Tigeot * but there is a slight complication as this is applied in WA batch where the 1090a05eeebfSFrançois Tigeot * values are only initialized once so we cannot take register value at the 1091a05eeebfSFrançois Tigeot * beginning and reuse it further; hence we save its value to memory, upload a 1092a05eeebfSFrançois Tigeot * constant value with bit21 set and then we restore it back with the saved value. 1093a05eeebfSFrançois Tigeot * To simplify the WA, a constant value is formed by using the default value 1094a05eeebfSFrançois Tigeot * of this register. This shouldn't be a problem because we are only modifying 1095a05eeebfSFrançois Tigeot * it for a short period and this batch in non-premptible. We can ofcourse 1096a05eeebfSFrançois Tigeot * use additional instructions that read the actual value of the register 1097a05eeebfSFrançois Tigeot * at that time and set our bit of interest but it makes the WA complicated. 1098a05eeebfSFrançois Tigeot * 1099a05eeebfSFrançois Tigeot * This WA is also required for Gen9 so extracting as a function avoids 1100a05eeebfSFrançois Tigeot * code duplication. 1101a05eeebfSFrançois Tigeot */ 11028621f407SFrançois Tigeot static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine, 1103a05eeebfSFrançois Tigeot uint32_t *const batch, 1104a05eeebfSFrançois Tigeot uint32_t index) 1105a05eeebfSFrançois Tigeot { 11068621f407SFrançois Tigeot struct drm_i915_private *dev_priv = engine->dev->dev_private; 1107a05eeebfSFrançois Tigeot uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); 1108a05eeebfSFrançois Tigeot 1109a05eeebfSFrançois Tigeot /* 11108621f407SFrançois Tigeot * WaDisableLSQCROPERFforOCL:skl,kbl 1111a05eeebfSFrançois Tigeot * This WA is implemented in skl_init_clock_gating() but since 1112a05eeebfSFrançois Tigeot * this batch updates GEN8_L3SQCREG4 with default value we need to 1113a05eeebfSFrançois Tigeot * set this bit here to retain the WA during flush. 1114a05eeebfSFrançois Tigeot */ 11158621f407SFrançois Tigeot if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0) || 11168621f407SFrançois Tigeot IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) 1117a05eeebfSFrançois Tigeot l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS; 1118a05eeebfSFrançois Tigeot 1119352ff8bdSFrançois Tigeot wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 | 1120a05eeebfSFrançois Tigeot MI_SRM_LRM_GLOBAL_GTT)); 1121aee94f86SFrançois Tigeot wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4); 11228621f407SFrançois Tigeot wa_ctx_emit(batch, index, engine->scratch.gtt_offset + 256); 1123a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, 0); 1124a05eeebfSFrançois Tigeot 1125a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1)); 1126aee94f86SFrançois Tigeot wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4); 1127a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, l3sqc4_flush); 1128a05eeebfSFrançois Tigeot 1129a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6)); 1130a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, (PIPE_CONTROL_CS_STALL | 1131a05eeebfSFrançois Tigeot PIPE_CONTROL_DC_FLUSH_ENABLE)); 1132a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, 0); 1133a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, 0); 1134a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, 0); 1135a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, 0); 1136a05eeebfSFrançois Tigeot 1137352ff8bdSFrançois Tigeot wa_ctx_emit(batch, index, (MI_LOAD_REGISTER_MEM_GEN8 | 1138a05eeebfSFrançois Tigeot MI_SRM_LRM_GLOBAL_GTT)); 1139aee94f86SFrançois Tigeot wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4); 11408621f407SFrançois Tigeot wa_ctx_emit(batch, index, engine->scratch.gtt_offset + 256); 1141a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, 0); 1142a05eeebfSFrançois Tigeot 1143a05eeebfSFrançois Tigeot return index; 1144a05eeebfSFrançois Tigeot } 1145a05eeebfSFrançois Tigeot 1146a05eeebfSFrançois Tigeot static inline uint32_t wa_ctx_start(struct i915_wa_ctx_bb *wa_ctx, 1147a05eeebfSFrançois Tigeot uint32_t offset, 1148a05eeebfSFrançois Tigeot uint32_t start_alignment) 1149a05eeebfSFrançois Tigeot { 1150a05eeebfSFrançois Tigeot return wa_ctx->offset = ALIGN(offset, start_alignment); 1151a05eeebfSFrançois Tigeot } 1152a05eeebfSFrançois Tigeot 1153a05eeebfSFrançois Tigeot static inline int wa_ctx_end(struct i915_wa_ctx_bb *wa_ctx, 1154a05eeebfSFrançois Tigeot uint32_t offset, 1155a05eeebfSFrançois Tigeot uint32_t size_alignment) 1156a05eeebfSFrançois Tigeot { 1157a05eeebfSFrançois Tigeot wa_ctx->size = offset - wa_ctx->offset; 1158a05eeebfSFrançois Tigeot 1159a05eeebfSFrançois Tigeot WARN(wa_ctx->size % size_alignment, 1160a05eeebfSFrançois Tigeot "wa_ctx_bb failed sanity checks: size %d is not aligned to %d\n", 1161a05eeebfSFrançois Tigeot wa_ctx->size, size_alignment); 1162a05eeebfSFrançois Tigeot return 0; 1163a05eeebfSFrançois Tigeot } 1164a05eeebfSFrançois Tigeot 1165a05eeebfSFrançois Tigeot /** 1166a05eeebfSFrançois Tigeot * gen8_init_indirectctx_bb() - initialize indirect ctx batch with WA 1167a05eeebfSFrançois Tigeot * 1168a05eeebfSFrançois Tigeot * @ring: only applicable for RCS 1169a05eeebfSFrançois Tigeot * @wa_ctx: structure representing wa_ctx 1170a05eeebfSFrançois Tigeot * offset: specifies start of the batch, should be cache-aligned. This is updated 1171a05eeebfSFrançois Tigeot * with the offset value received as input. 1172a05eeebfSFrançois Tigeot * size: size of the batch in DWORDS but HW expects in terms of cachelines 1173a05eeebfSFrançois Tigeot * @batch: page in which WA are loaded 1174a05eeebfSFrançois Tigeot * @offset: This field specifies the start of the batch, it should be 1175a05eeebfSFrançois Tigeot * cache-aligned otherwise it is adjusted accordingly. 1176a05eeebfSFrançois Tigeot * Typically we only have one indirect_ctx and per_ctx batch buffer which are 1177a05eeebfSFrançois Tigeot * initialized at the beginning and shared across all contexts but this field 1178a05eeebfSFrançois Tigeot * helps us to have multiple batches at different offsets and select them based 1179a05eeebfSFrançois Tigeot * on a criteria. At the moment this batch always start at the beginning of the page 1180a05eeebfSFrançois Tigeot * and at this point we don't have multiple wa_ctx batch buffers. 1181a05eeebfSFrançois Tigeot * 1182a05eeebfSFrançois Tigeot * The number of WA applied are not known at the beginning; we use this field 1183a05eeebfSFrançois Tigeot * to return the no of DWORDS written. 1184a05eeebfSFrançois Tigeot * 1185a05eeebfSFrançois Tigeot * It is to be noted that this batch does not contain MI_BATCH_BUFFER_END 1186a05eeebfSFrançois Tigeot * so it adds NOOPs as padding to make it cacheline aligned. 1187a05eeebfSFrançois Tigeot * MI_BATCH_BUFFER_END will be added to perctx batch and both of them together 1188a05eeebfSFrançois Tigeot * makes a complete batch buffer. 1189a05eeebfSFrançois Tigeot * 1190a05eeebfSFrançois Tigeot * Return: non-zero if we exceed the PAGE_SIZE limit. 1191a05eeebfSFrançois Tigeot */ 1192a05eeebfSFrançois Tigeot 11938621f407SFrançois Tigeot static int gen8_init_indirectctx_bb(struct intel_engine_cs *engine, 1194a05eeebfSFrançois Tigeot struct i915_wa_ctx_bb *wa_ctx, 1195a05eeebfSFrançois Tigeot uint32_t *const batch, 1196a05eeebfSFrançois Tigeot uint32_t *offset) 1197a05eeebfSFrançois Tigeot { 1198a05eeebfSFrançois Tigeot uint32_t scratch_addr; 1199a05eeebfSFrançois Tigeot uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); 1200a05eeebfSFrançois Tigeot 1201a05eeebfSFrançois Tigeot /* WaDisableCtxRestoreArbitration:bdw,chv */ 1202a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); 1203a05eeebfSFrançois Tigeot 1204a05eeebfSFrançois Tigeot /* WaFlushCoherentL3CacheLinesAtContextSwitch:bdw */ 12058621f407SFrançois Tigeot if (IS_BROADWELL(engine->dev)) { 12068621f407SFrançois Tigeot int rc = gen8_emit_flush_coherentl3_wa(engine, batch, index); 1207352ff8bdSFrançois Tigeot if (rc < 0) 1208352ff8bdSFrançois Tigeot return rc; 1209352ff8bdSFrançois Tigeot index = rc; 1210a05eeebfSFrançois Tigeot } 1211a05eeebfSFrançois Tigeot 1212a05eeebfSFrançois Tigeot /* WaClearSlmSpaceAtContextSwitch:bdw,chv */ 1213a05eeebfSFrançois Tigeot /* Actual scratch location is at 128 bytes offset */ 12148621f407SFrançois Tigeot scratch_addr = engine->scratch.gtt_offset + 2*CACHELINE_BYTES; 1215a05eeebfSFrançois Tigeot 1216a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6)); 1217a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, (PIPE_CONTROL_FLUSH_L3 | 1218a05eeebfSFrançois Tigeot PIPE_CONTROL_GLOBAL_GTT_IVB | 1219a05eeebfSFrançois Tigeot PIPE_CONTROL_CS_STALL | 1220a05eeebfSFrançois Tigeot PIPE_CONTROL_QW_WRITE)); 1221a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, scratch_addr); 1222a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, 0); 1223a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, 0); 1224a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, 0); 1225a05eeebfSFrançois Tigeot 1226a05eeebfSFrançois Tigeot /* Pad to end of cacheline */ 1227a05eeebfSFrançois Tigeot while (index % CACHELINE_DWORDS) 1228a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_NOOP); 1229a05eeebfSFrançois Tigeot 1230a05eeebfSFrançois Tigeot /* 1231a05eeebfSFrançois Tigeot * MI_BATCH_BUFFER_END is not required in Indirect ctx BB because 1232a05eeebfSFrançois Tigeot * execution depends on the length specified in terms of cache lines 1233a05eeebfSFrançois Tigeot * in the register CTX_RCS_INDIRECT_CTX 1234a05eeebfSFrançois Tigeot */ 1235a05eeebfSFrançois Tigeot 1236a05eeebfSFrançois Tigeot return wa_ctx_end(wa_ctx, *offset = index, CACHELINE_DWORDS); 1237a05eeebfSFrançois Tigeot } 1238a05eeebfSFrançois Tigeot 1239a05eeebfSFrançois Tigeot /** 1240a05eeebfSFrançois Tigeot * gen8_init_perctx_bb() - initialize per ctx batch with WA 1241a05eeebfSFrançois Tigeot * 1242a05eeebfSFrançois Tigeot * @ring: only applicable for RCS 1243a05eeebfSFrançois Tigeot * @wa_ctx: structure representing wa_ctx 1244a05eeebfSFrançois Tigeot * offset: specifies start of the batch, should be cache-aligned. 1245a05eeebfSFrançois Tigeot * size: size of the batch in DWORDS but HW expects in terms of cachelines 1246a05eeebfSFrançois Tigeot * @batch: page in which WA are loaded 1247a05eeebfSFrançois Tigeot * @offset: This field specifies the start of this batch. 1248a05eeebfSFrançois Tigeot * This batch is started immediately after indirect_ctx batch. Since we ensure 1249a05eeebfSFrançois Tigeot * that indirect_ctx ends on a cacheline this batch is aligned automatically. 1250a05eeebfSFrançois Tigeot * 1251a05eeebfSFrançois Tigeot * The number of DWORDS written are returned using this field. 1252a05eeebfSFrançois Tigeot * 1253a05eeebfSFrançois Tigeot * This batch is terminated with MI_BATCH_BUFFER_END and so we need not add padding 1254a05eeebfSFrançois Tigeot * to align it with cacheline as padding after MI_BATCH_BUFFER_END is redundant. 1255a05eeebfSFrançois Tigeot */ 12568621f407SFrançois Tigeot static int gen8_init_perctx_bb(struct intel_engine_cs *engine, 1257a05eeebfSFrançois Tigeot struct i915_wa_ctx_bb *wa_ctx, 1258a05eeebfSFrançois Tigeot uint32_t *const batch, 1259a05eeebfSFrançois Tigeot uint32_t *offset) 1260a05eeebfSFrançois Tigeot { 1261a05eeebfSFrançois Tigeot uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); 1262a05eeebfSFrançois Tigeot 1263a05eeebfSFrançois Tigeot /* WaDisableCtxRestoreArbitration:bdw,chv */ 1264a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE); 1265a05eeebfSFrançois Tigeot 1266a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); 1267a05eeebfSFrançois Tigeot 1268a05eeebfSFrançois Tigeot return wa_ctx_end(wa_ctx, *offset = index, 1); 1269a05eeebfSFrançois Tigeot } 1270a05eeebfSFrançois Tigeot 12718621f407SFrançois Tigeot static int gen9_init_indirectctx_bb(struct intel_engine_cs *engine, 1272a05eeebfSFrançois Tigeot struct i915_wa_ctx_bb *wa_ctx, 1273a05eeebfSFrançois Tigeot uint32_t *const batch, 1274a05eeebfSFrançois Tigeot uint32_t *offset) 1275a05eeebfSFrançois Tigeot { 1276a05eeebfSFrançois Tigeot int ret; 12778621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 12788621f407SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1279a05eeebfSFrançois Tigeot uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); 1280a05eeebfSFrançois Tigeot 1281a05eeebfSFrançois Tigeot /* WaDisableCtxRestoreArbitration:skl,bxt */ 1282aee94f86SFrançois Tigeot if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) || 1283aee94f86SFrançois Tigeot IS_BXT_REVID(dev, 0, BXT_REVID_A1)) 1284a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); 1285a05eeebfSFrançois Tigeot 1286a05eeebfSFrançois Tigeot /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt */ 12878621f407SFrançois Tigeot ret = gen8_emit_flush_coherentl3_wa(engine, batch, index); 1288a05eeebfSFrançois Tigeot if (ret < 0) 1289a05eeebfSFrançois Tigeot return ret; 1290a05eeebfSFrançois Tigeot index = ret; 1291a05eeebfSFrançois Tigeot 12928621f407SFrançois Tigeot /* WaClearSlmSpaceAtContextSwitch:kbl */ 12938621f407SFrançois Tigeot /* Actual scratch location is at 128 bytes offset */ 12948621f407SFrançois Tigeot if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_A0)) { 12958621f407SFrançois Tigeot uint32_t scratch_addr 12968621f407SFrançois Tigeot = engine->scratch.gtt_offset + 2*CACHELINE_BYTES; 12978621f407SFrançois Tigeot 12988621f407SFrançois Tigeot wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6)); 12998621f407SFrançois Tigeot wa_ctx_emit(batch, index, (PIPE_CONTROL_FLUSH_L3 | 13008621f407SFrançois Tigeot PIPE_CONTROL_GLOBAL_GTT_IVB | 13018621f407SFrançois Tigeot PIPE_CONTROL_CS_STALL | 13028621f407SFrançois Tigeot PIPE_CONTROL_QW_WRITE)); 13038621f407SFrançois Tigeot wa_ctx_emit(batch, index, scratch_addr); 13048621f407SFrançois Tigeot wa_ctx_emit(batch, index, 0); 13058621f407SFrançois Tigeot wa_ctx_emit(batch, index, 0); 13068621f407SFrançois Tigeot wa_ctx_emit(batch, index, 0); 13078621f407SFrançois Tigeot } 1308a05eeebfSFrançois Tigeot /* Pad to end of cacheline */ 1309a05eeebfSFrançois Tigeot while (index % CACHELINE_DWORDS) 1310a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_NOOP); 1311a05eeebfSFrançois Tigeot 1312a05eeebfSFrançois Tigeot return wa_ctx_end(wa_ctx, *offset = index, CACHELINE_DWORDS); 1313a05eeebfSFrançois Tigeot } 1314a05eeebfSFrançois Tigeot 13158621f407SFrançois Tigeot static int gen9_init_perctx_bb(struct intel_engine_cs *engine, 1316a05eeebfSFrançois Tigeot struct i915_wa_ctx_bb *wa_ctx, 1317a05eeebfSFrançois Tigeot uint32_t *const batch, 1318a05eeebfSFrançois Tigeot uint32_t *offset) 1319a05eeebfSFrançois Tigeot { 13208621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 1321a05eeebfSFrançois Tigeot uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); 1322a05eeebfSFrançois Tigeot 1323a05eeebfSFrançois Tigeot /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ 1324aee94f86SFrançois Tigeot if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) || 1325aee94f86SFrançois Tigeot IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { 1326a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1)); 1327aee94f86SFrançois Tigeot wa_ctx_emit_reg(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0); 1328a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, 1329a05eeebfSFrançois Tigeot _MASKED_BIT_ENABLE(DISABLE_PIXEL_MASK_CAMMING)); 1330a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_NOOP); 1331a05eeebfSFrançois Tigeot } 1332a05eeebfSFrançois Tigeot 13338621f407SFrançois Tigeot /* WaClearTdlStateAckDirtyBits:bxt */ 13348621f407SFrançois Tigeot if (IS_BXT_REVID(dev, 0, BXT_REVID_B0)) { 13358621f407SFrançois Tigeot wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(4)); 13368621f407SFrançois Tigeot 13378621f407SFrançois Tigeot wa_ctx_emit_reg(batch, index, GEN8_STATE_ACK); 13388621f407SFrançois Tigeot wa_ctx_emit(batch, index, _MASKED_BIT_DISABLE(GEN9_SUBSLICE_TDL_ACK_BITS)); 13398621f407SFrançois Tigeot 13408621f407SFrançois Tigeot wa_ctx_emit_reg(batch, index, GEN9_STATE_ACK_SLICE1); 13418621f407SFrançois Tigeot wa_ctx_emit(batch, index, _MASKED_BIT_DISABLE(GEN9_SUBSLICE_TDL_ACK_BITS)); 13428621f407SFrançois Tigeot 13438621f407SFrançois Tigeot wa_ctx_emit_reg(batch, index, GEN9_STATE_ACK_SLICE2); 13448621f407SFrançois Tigeot wa_ctx_emit(batch, index, _MASKED_BIT_DISABLE(GEN9_SUBSLICE_TDL_ACK_BITS)); 13458621f407SFrançois Tigeot 13468621f407SFrançois Tigeot wa_ctx_emit_reg(batch, index, GEN7_ROW_CHICKEN2); 13478621f407SFrançois Tigeot /* dummy write to CS, mask bits are 0 to ensure the register is not modified */ 13488621f407SFrançois Tigeot wa_ctx_emit(batch, index, 0x0); 13498621f407SFrançois Tigeot wa_ctx_emit(batch, index, MI_NOOP); 13508621f407SFrançois Tigeot } 13518621f407SFrançois Tigeot 1352a05eeebfSFrançois Tigeot /* WaDisableCtxRestoreArbitration:skl,bxt */ 1353aee94f86SFrançois Tigeot if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) || 1354aee94f86SFrançois Tigeot IS_BXT_REVID(dev, 0, BXT_REVID_A1)) 1355a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE); 1356a05eeebfSFrançois Tigeot 1357a05eeebfSFrançois Tigeot wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); 1358a05eeebfSFrançois Tigeot 1359a05eeebfSFrançois Tigeot return wa_ctx_end(wa_ctx, *offset = index, 1); 1360a05eeebfSFrançois Tigeot } 1361a05eeebfSFrançois Tigeot 13628621f407SFrançois Tigeot static int lrc_setup_wa_ctx_obj(struct intel_engine_cs *engine, u32 size) 1363a05eeebfSFrançois Tigeot { 1364a05eeebfSFrançois Tigeot int ret; 1365a05eeebfSFrançois Tigeot 13668621f407SFrançois Tigeot engine->wa_ctx.obj = i915_gem_alloc_object(engine->dev, 13678621f407SFrançois Tigeot PAGE_ALIGN(size)); 13688621f407SFrançois Tigeot if (!engine->wa_ctx.obj) { 1369a05eeebfSFrançois Tigeot DRM_DEBUG_DRIVER("alloc LRC WA ctx backing obj failed.\n"); 1370a05eeebfSFrançois Tigeot return -ENOMEM; 1371a05eeebfSFrançois Tigeot } 1372a05eeebfSFrançois Tigeot 13738621f407SFrançois Tigeot ret = i915_gem_obj_ggtt_pin(engine->wa_ctx.obj, PAGE_SIZE, 0); 1374a05eeebfSFrançois Tigeot if (ret) { 1375a05eeebfSFrançois Tigeot DRM_DEBUG_DRIVER("pin LRC WA ctx backing obj failed: %d\n", 1376a05eeebfSFrançois Tigeot ret); 13778621f407SFrançois Tigeot drm_gem_object_unreference(&engine->wa_ctx.obj->base); 1378a05eeebfSFrançois Tigeot return ret; 1379a05eeebfSFrançois Tigeot } 1380a05eeebfSFrançois Tigeot 1381a05eeebfSFrançois Tigeot return 0; 1382a05eeebfSFrançois Tigeot } 1383a05eeebfSFrançois Tigeot 13848621f407SFrançois Tigeot static void lrc_destroy_wa_ctx_obj(struct intel_engine_cs *engine) 1385a05eeebfSFrançois Tigeot { 13868621f407SFrançois Tigeot if (engine->wa_ctx.obj) { 13878621f407SFrançois Tigeot i915_gem_object_ggtt_unpin(engine->wa_ctx.obj); 13888621f407SFrançois Tigeot drm_gem_object_unreference(&engine->wa_ctx.obj->base); 13898621f407SFrançois Tigeot engine->wa_ctx.obj = NULL; 1390a05eeebfSFrançois Tigeot } 1391a05eeebfSFrançois Tigeot } 1392a05eeebfSFrançois Tigeot 13938621f407SFrançois Tigeot static int intel_init_workaround_bb(struct intel_engine_cs *engine) 1394a05eeebfSFrançois Tigeot { 1395a05eeebfSFrançois Tigeot int ret; 1396a05eeebfSFrançois Tigeot uint32_t *batch; 1397a05eeebfSFrançois Tigeot uint32_t offset; 1398*f0bba3d1SFrançois Tigeot struct page *page; 13998621f407SFrançois Tigeot struct i915_ctx_workarounds *wa_ctx = &engine->wa_ctx; 1400a05eeebfSFrançois Tigeot 14018621f407SFrançois Tigeot WARN_ON(engine->id != RCS); 1402a05eeebfSFrançois Tigeot 1403a05eeebfSFrançois Tigeot /* update this when WA for higher Gen are added */ 14048621f407SFrançois Tigeot if (INTEL_INFO(engine->dev)->gen > 9) { 1405a05eeebfSFrançois Tigeot DRM_ERROR("WA batch buffer is not initialized for Gen%d\n", 14068621f407SFrançois Tigeot INTEL_INFO(engine->dev)->gen); 1407a05eeebfSFrançois Tigeot return 0; 1408a05eeebfSFrançois Tigeot } 1409a05eeebfSFrançois Tigeot 1410a05eeebfSFrançois Tigeot /* some WA perform writes to scratch page, ensure it is valid */ 14118621f407SFrançois Tigeot if (engine->scratch.obj == NULL) { 14128621f407SFrançois Tigeot DRM_ERROR("scratch page not allocated for %s\n", engine->name); 1413a05eeebfSFrançois Tigeot return -EINVAL; 1414a05eeebfSFrançois Tigeot } 1415a05eeebfSFrançois Tigeot 14168621f407SFrançois Tigeot ret = lrc_setup_wa_ctx_obj(engine, PAGE_SIZE); 1417a05eeebfSFrançois Tigeot if (ret) { 1418a05eeebfSFrançois Tigeot DRM_DEBUG_DRIVER("Failed to setup context WA page: %d\n", ret); 1419a05eeebfSFrançois Tigeot return ret; 1420a05eeebfSFrançois Tigeot } 1421a05eeebfSFrançois Tigeot 1422aee94f86SFrançois Tigeot page = i915_gem_object_get_dirty_page(wa_ctx->obj, 0); 1423a05eeebfSFrançois Tigeot batch = kmap_atomic(page); 1424a05eeebfSFrançois Tigeot offset = 0; 1425a05eeebfSFrançois Tigeot 14268621f407SFrançois Tigeot if (INTEL_INFO(engine->dev)->gen == 8) { 14278621f407SFrançois Tigeot ret = gen8_init_indirectctx_bb(engine, 1428a05eeebfSFrançois Tigeot &wa_ctx->indirect_ctx, 1429a05eeebfSFrançois Tigeot batch, 1430a05eeebfSFrançois Tigeot &offset); 1431a05eeebfSFrançois Tigeot if (ret) 1432a05eeebfSFrançois Tigeot goto out; 1433a05eeebfSFrançois Tigeot 14348621f407SFrançois Tigeot ret = gen8_init_perctx_bb(engine, 1435a05eeebfSFrançois Tigeot &wa_ctx->per_ctx, 1436a05eeebfSFrançois Tigeot batch, 1437a05eeebfSFrançois Tigeot &offset); 1438a05eeebfSFrançois Tigeot if (ret) 1439a05eeebfSFrançois Tigeot goto out; 14408621f407SFrançois Tigeot } else if (INTEL_INFO(engine->dev)->gen == 9) { 14418621f407SFrançois Tigeot ret = gen9_init_indirectctx_bb(engine, 1442a05eeebfSFrançois Tigeot &wa_ctx->indirect_ctx, 1443a05eeebfSFrançois Tigeot batch, 1444a05eeebfSFrançois Tigeot &offset); 1445a05eeebfSFrançois Tigeot if (ret) 1446a05eeebfSFrançois Tigeot goto out; 1447a05eeebfSFrançois Tigeot 14488621f407SFrançois Tigeot ret = gen9_init_perctx_bb(engine, 1449a05eeebfSFrançois Tigeot &wa_ctx->per_ctx, 1450a05eeebfSFrançois Tigeot batch, 1451a05eeebfSFrançois Tigeot &offset); 1452a05eeebfSFrançois Tigeot if (ret) 1453a05eeebfSFrançois Tigeot goto out; 1454a05eeebfSFrançois Tigeot } 1455a05eeebfSFrançois Tigeot 1456a05eeebfSFrançois Tigeot out: 1457a05eeebfSFrançois Tigeot kunmap_atomic(batch); 1458a05eeebfSFrançois Tigeot if (ret) 14598621f407SFrançois Tigeot lrc_destroy_wa_ctx_obj(engine); 1460a05eeebfSFrançois Tigeot 1461a05eeebfSFrançois Tigeot return ret; 1462a05eeebfSFrançois Tigeot } 1463a05eeebfSFrançois Tigeot 14648621f407SFrançois Tigeot static void lrc_init_hws(struct intel_engine_cs *engine) 14651b13d190SFrançois Tigeot { 14668621f407SFrançois Tigeot struct drm_i915_private *dev_priv = engine->dev->dev_private; 14678621f407SFrançois Tigeot 14688621f407SFrançois Tigeot I915_WRITE(RING_HWS_PGA(engine->mmio_base), 14698621f407SFrançois Tigeot (u32)engine->status_page.gfx_addr); 14708621f407SFrançois Tigeot POSTING_READ(RING_HWS_PGA(engine->mmio_base)); 14718621f407SFrançois Tigeot } 14728621f407SFrançois Tigeot 14738621f407SFrançois Tigeot static int gen8_init_common_ring(struct intel_engine_cs *engine) 14748621f407SFrançois Tigeot { 14758621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 14761b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 14778621f407SFrançois Tigeot unsigned int next_context_status_buffer_hw; 14781b13d190SFrançois Tigeot 14798621f407SFrançois Tigeot lrc_init_hws(engine); 1480352ff8bdSFrançois Tigeot 14818621f407SFrançois Tigeot I915_WRITE_IMR(engine, 14828621f407SFrançois Tigeot ~(engine->irq_enable_mask | engine->irq_keep_mask)); 14838621f407SFrançois Tigeot I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff); 14841b13d190SFrançois Tigeot 14858621f407SFrançois Tigeot I915_WRITE(RING_MODE_GEN7(engine), 14861b13d190SFrançois Tigeot _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | 14871b13d190SFrançois Tigeot _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); 14888621f407SFrançois Tigeot POSTING_READ(RING_MODE_GEN7(engine)); 1489a05eeebfSFrançois Tigeot 1490a05eeebfSFrançois Tigeot /* 1491a05eeebfSFrançois Tigeot * Instead of resetting the Context Status Buffer (CSB) read pointer to 1492a05eeebfSFrançois Tigeot * zero, we need to read the write pointer from hardware and use its 1493a05eeebfSFrançois Tigeot * value because "this register is power context save restored". 1494a05eeebfSFrançois Tigeot * Effectively, these states have been observed: 1495a05eeebfSFrançois Tigeot * 1496a05eeebfSFrançois Tigeot * | Suspend-to-idle (freeze) | Suspend-to-RAM (mem) | 1497a05eeebfSFrançois Tigeot * BDW | CSB regs not reset | CSB regs reset | 1498a05eeebfSFrançois Tigeot * CHT | CSB regs not reset | CSB regs not reset | 1499c0e85e96SFrançois Tigeot * SKL | ? | ? | 1500c0e85e96SFrançois Tigeot * BXT | ? | ? | 1501a05eeebfSFrançois Tigeot */ 1502c0e85e96SFrançois Tigeot next_context_status_buffer_hw = 15038621f407SFrançois Tigeot GEN8_CSB_WRITE_PTR(I915_READ(RING_CONTEXT_STATUS_PTR(engine))); 1504a05eeebfSFrançois Tigeot 1505a05eeebfSFrançois Tigeot /* 1506a05eeebfSFrançois Tigeot * When the CSB registers are reset (also after power-up / gpu reset), 1507a05eeebfSFrançois Tigeot * CSB write pointer is set to all 1's, which is not valid, use '5' in 1508a05eeebfSFrançois Tigeot * this special case, so the first element read is CSB[0]. 1509a05eeebfSFrançois Tigeot */ 1510a05eeebfSFrançois Tigeot if (next_context_status_buffer_hw == GEN8_CSB_PTR_MASK) 1511a05eeebfSFrançois Tigeot next_context_status_buffer_hw = (GEN8_CSB_ENTRIES - 1); 1512a05eeebfSFrançois Tigeot 15138621f407SFrançois Tigeot engine->next_context_status_buffer = next_context_status_buffer_hw; 15148621f407SFrançois Tigeot DRM_DEBUG_DRIVER("Execlists enabled for %s\n", engine->name); 15151b13d190SFrançois Tigeot 15168621f407SFrançois Tigeot intel_engine_init_hangcheck(engine); 15171b13d190SFrançois Tigeot 15188621f407SFrançois Tigeot return intel_mocs_init_engine(engine); 15191b13d190SFrançois Tigeot } 15201b13d190SFrançois Tigeot 15218621f407SFrançois Tigeot static int gen8_init_render_ring(struct intel_engine_cs *engine) 15221b13d190SFrançois Tigeot { 15238621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 15241b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 15251b13d190SFrançois Tigeot int ret; 15261b13d190SFrançois Tigeot 15278621f407SFrançois Tigeot ret = gen8_init_common_ring(engine); 15281b13d190SFrançois Tigeot if (ret) 15291b13d190SFrançois Tigeot return ret; 15301b13d190SFrançois Tigeot 15311b13d190SFrançois Tigeot /* We need to disable the AsyncFlip performance optimisations in order 15321b13d190SFrançois Tigeot * to use MI_WAIT_FOR_EVENT within the CS. It should already be 15331b13d190SFrançois Tigeot * programmed to '1' on all products. 15341b13d190SFrançois Tigeot * 15351b13d190SFrançois Tigeot * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv,bdw,chv 15361b13d190SFrançois Tigeot */ 15371b13d190SFrançois Tigeot I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); 15381b13d190SFrançois Tigeot 15391b13d190SFrançois Tigeot I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); 15401b13d190SFrançois Tigeot 15418621f407SFrançois Tigeot return init_workarounds_ring(engine); 15421b13d190SFrançois Tigeot } 15431b13d190SFrançois Tigeot 15448621f407SFrançois Tigeot static int gen9_init_render_ring(struct intel_engine_cs *engine) 1545477eb7f9SFrançois Tigeot { 1546477eb7f9SFrançois Tigeot int ret; 1547477eb7f9SFrançois Tigeot 15488621f407SFrançois Tigeot ret = gen8_init_common_ring(engine); 1549477eb7f9SFrançois Tigeot if (ret) 1550477eb7f9SFrançois Tigeot return ret; 1551477eb7f9SFrançois Tigeot 15528621f407SFrançois Tigeot return init_workarounds_ring(engine); 1553477eb7f9SFrançois Tigeot } 1554477eb7f9SFrançois Tigeot 1555a05eeebfSFrançois Tigeot static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req) 1556a05eeebfSFrançois Tigeot { 1557a05eeebfSFrançois Tigeot struct i915_hw_ppgtt *ppgtt = req->ctx->ppgtt; 15588621f407SFrançois Tigeot struct intel_engine_cs *engine = req->engine; 1559a05eeebfSFrançois Tigeot struct intel_ringbuffer *ringbuf = req->ringbuf; 1560a05eeebfSFrançois Tigeot const int num_lri_cmds = GEN8_LEGACY_PDPES * 2; 1561a05eeebfSFrançois Tigeot int i, ret; 1562a05eeebfSFrançois Tigeot 15638621f407SFrançois Tigeot ret = intel_ring_begin(req, num_lri_cmds * 2 + 2); 1564a05eeebfSFrançois Tigeot if (ret) 1565a05eeebfSFrançois Tigeot return ret; 1566a05eeebfSFrançois Tigeot 1567a05eeebfSFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(num_lri_cmds)); 1568a05eeebfSFrançois Tigeot for (i = GEN8_LEGACY_PDPES - 1; i >= 0; i--) { 1569a05eeebfSFrançois Tigeot const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i); 1570a05eeebfSFrançois Tigeot 15718621f407SFrançois Tigeot intel_logical_ring_emit_reg(ringbuf, 15728621f407SFrançois Tigeot GEN8_RING_PDP_UDW(engine, i)); 1573a05eeebfSFrançois Tigeot intel_logical_ring_emit(ringbuf, upper_32_bits(pd_daddr)); 15748621f407SFrançois Tigeot intel_logical_ring_emit_reg(ringbuf, 15758621f407SFrançois Tigeot GEN8_RING_PDP_LDW(engine, i)); 1576a05eeebfSFrançois Tigeot intel_logical_ring_emit(ringbuf, lower_32_bits(pd_daddr)); 1577a05eeebfSFrançois Tigeot } 1578a05eeebfSFrançois Tigeot 1579a05eeebfSFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_NOOP); 1580a05eeebfSFrançois Tigeot intel_logical_ring_advance(ringbuf); 1581a05eeebfSFrançois Tigeot 1582a05eeebfSFrançois Tigeot return 0; 1583a05eeebfSFrançois Tigeot } 1584a05eeebfSFrançois Tigeot 1585a05eeebfSFrançois Tigeot static int gen8_emit_bb_start(struct drm_i915_gem_request *req, 1586477eb7f9SFrançois Tigeot u64 offset, unsigned dispatch_flags) 15871b13d190SFrançois Tigeot { 1588a05eeebfSFrançois Tigeot struct intel_ringbuffer *ringbuf = req->ringbuf; 1589477eb7f9SFrançois Tigeot bool ppgtt = !(dispatch_flags & I915_DISPATCH_SECURE); 15901b13d190SFrançois Tigeot int ret; 15911b13d190SFrançois Tigeot 1592a05eeebfSFrançois Tigeot /* Don't rely in hw updating PDPs, specially in lite-restore. 1593a05eeebfSFrançois Tigeot * Ideally, we should set Force PD Restore in ctx descriptor, 1594a05eeebfSFrançois Tigeot * but we can't. Force Restore would be a second option, but 1595a05eeebfSFrançois Tigeot * it is unsafe in case of lite-restore (because the ctx is 1596352ff8bdSFrançois Tigeot * not idle). PML4 is allocated during ppgtt init so this is 1597352ff8bdSFrançois Tigeot * not needed in 48-bit.*/ 1598a05eeebfSFrançois Tigeot if (req->ctx->ppgtt && 15998621f407SFrançois Tigeot (intel_engine_flag(req->engine) & req->ctx->ppgtt->pd_dirty_rings)) { 1600352ff8bdSFrançois Tigeot if (!USES_FULL_48BIT_PPGTT(req->i915) && 1601352ff8bdSFrançois Tigeot !intel_vgpu_active(req->i915->dev)) { 1602a05eeebfSFrançois Tigeot ret = intel_logical_ring_emit_pdps(req); 1603a05eeebfSFrançois Tigeot if (ret) 1604a05eeebfSFrançois Tigeot return ret; 1605352ff8bdSFrançois Tigeot } 1606a05eeebfSFrançois Tigeot 16078621f407SFrançois Tigeot req->ctx->ppgtt->pd_dirty_rings &= ~intel_engine_flag(req->engine); 1608a05eeebfSFrançois Tigeot } 1609a05eeebfSFrançois Tigeot 16108621f407SFrançois Tigeot ret = intel_ring_begin(req, 4); 16111b13d190SFrançois Tigeot if (ret) 16121b13d190SFrançois Tigeot return ret; 16131b13d190SFrançois Tigeot 16141b13d190SFrançois Tigeot /* FIXME(BDW): Address space and security selectors. */ 1615a05eeebfSFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 | 1616a05eeebfSFrançois Tigeot (ppgtt<<8) | 1617a05eeebfSFrançois Tigeot (dispatch_flags & I915_DISPATCH_RS ? 1618a05eeebfSFrançois Tigeot MI_BATCH_RESOURCE_STREAMER : 0)); 16191b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, lower_32_bits(offset)); 16201b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, upper_32_bits(offset)); 16211b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_NOOP); 16221b13d190SFrançois Tigeot intel_logical_ring_advance(ringbuf); 16231b13d190SFrançois Tigeot 16241b13d190SFrançois Tigeot return 0; 16251b13d190SFrançois Tigeot } 16261b13d190SFrançois Tigeot 16278621f407SFrançois Tigeot static bool gen8_logical_ring_get_irq(struct intel_engine_cs *engine) 16281b13d190SFrançois Tigeot { 16298621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 16301b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 16315e269720SFrançois Tigeot unsigned long flags; 16321b13d190SFrançois Tigeot 16332c9916cdSFrançois Tigeot if (WARN_ON(!intel_irqs_enabled(dev_priv))) 16341b13d190SFrançois Tigeot return false; 16351b13d190SFrançois Tigeot 16365e269720SFrançois Tigeot spin_lock_irqsave(&dev_priv->irq_lock, flags); 16378621f407SFrançois Tigeot if (engine->irq_refcount++ == 0) { 16388621f407SFrançois Tigeot I915_WRITE_IMR(engine, 16398621f407SFrançois Tigeot ~(engine->irq_enable_mask | engine->irq_keep_mask)); 16408621f407SFrançois Tigeot POSTING_READ(RING_IMR(engine->mmio_base)); 16411b13d190SFrançois Tigeot } 16425e269720SFrançois Tigeot spin_unlock_irqrestore(&dev_priv->irq_lock, flags); 16431b13d190SFrançois Tigeot 16441b13d190SFrançois Tigeot return true; 16451b13d190SFrançois Tigeot } 16461b13d190SFrançois Tigeot 16478621f407SFrançois Tigeot static void gen8_logical_ring_put_irq(struct intel_engine_cs *engine) 16481b13d190SFrançois Tigeot { 16498621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 16501b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 16515e269720SFrançois Tigeot unsigned long flags; 16521b13d190SFrançois Tigeot 16535e269720SFrançois Tigeot spin_lock_irqsave(&dev_priv->irq_lock, flags); 16548621f407SFrançois Tigeot if (--engine->irq_refcount == 0) { 16558621f407SFrançois Tigeot I915_WRITE_IMR(engine, ~engine->irq_keep_mask); 16568621f407SFrançois Tigeot POSTING_READ(RING_IMR(engine->mmio_base)); 16571b13d190SFrançois Tigeot } 16585e269720SFrançois Tigeot spin_unlock_irqrestore(&dev_priv->irq_lock, flags); 16591b13d190SFrançois Tigeot } 16601b13d190SFrançois Tigeot 1661a05eeebfSFrançois Tigeot static int gen8_emit_flush(struct drm_i915_gem_request *request, 16621b13d190SFrançois Tigeot u32 invalidate_domains, 16631b13d190SFrançois Tigeot u32 unused) 16641b13d190SFrançois Tigeot { 1665a05eeebfSFrançois Tigeot struct intel_ringbuffer *ringbuf = request->ringbuf; 16668621f407SFrançois Tigeot struct intel_engine_cs *engine = ringbuf->engine; 16678621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 16681b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 16691b13d190SFrançois Tigeot uint32_t cmd; 16701b13d190SFrançois Tigeot int ret; 16711b13d190SFrançois Tigeot 16728621f407SFrançois Tigeot ret = intel_ring_begin(request, 4); 16731b13d190SFrançois Tigeot if (ret) 16741b13d190SFrançois Tigeot return ret; 16751b13d190SFrançois Tigeot 16761b13d190SFrançois Tigeot cmd = MI_FLUSH_DW + 1; 16771b13d190SFrançois Tigeot 16782c9916cdSFrançois Tigeot /* We always require a command barrier so that subsequent 16792c9916cdSFrançois Tigeot * commands, such as breadcrumb interrupts, are strictly ordered 16802c9916cdSFrançois Tigeot * wrt the contents of the write cache being flushed to memory 16812c9916cdSFrançois Tigeot * (and thus being coherent from the CPU). 16822c9916cdSFrançois Tigeot */ 16832c9916cdSFrançois Tigeot cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW; 16842c9916cdSFrançois Tigeot 16852c9916cdSFrançois Tigeot if (invalidate_domains & I915_GEM_GPU_DOMAINS) { 16862c9916cdSFrançois Tigeot cmd |= MI_INVALIDATE_TLB; 16878621f407SFrançois Tigeot if (engine == &dev_priv->engine[VCS]) 16882c9916cdSFrançois Tigeot cmd |= MI_INVALIDATE_BSD; 16891b13d190SFrançois Tigeot } 16901b13d190SFrançois Tigeot 16911b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, cmd); 16921b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, 16931b13d190SFrançois Tigeot I915_GEM_HWS_SCRATCH_ADDR | 16941b13d190SFrançois Tigeot MI_FLUSH_DW_USE_GTT); 16951b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); /* upper addr */ 16961b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); /* value */ 16971b13d190SFrançois Tigeot intel_logical_ring_advance(ringbuf); 16981b13d190SFrançois Tigeot 16991b13d190SFrançois Tigeot return 0; 17001b13d190SFrançois Tigeot } 17011b13d190SFrançois Tigeot 1702a05eeebfSFrançois Tigeot static int gen8_emit_flush_render(struct drm_i915_gem_request *request, 17031b13d190SFrançois Tigeot u32 invalidate_domains, 17041b13d190SFrançois Tigeot u32 flush_domains) 17051b13d190SFrançois Tigeot { 1706a05eeebfSFrançois Tigeot struct intel_ringbuffer *ringbuf = request->ringbuf; 17078621f407SFrançois Tigeot struct intel_engine_cs *engine = ringbuf->engine; 17088621f407SFrançois Tigeot u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES; 17098621f407SFrançois Tigeot bool vf_flush_wa = false, dc_flush_wa = false; 17101b13d190SFrançois Tigeot u32 flags = 0; 17111b13d190SFrançois Tigeot int ret; 17128621f407SFrançois Tigeot int len; 17131b13d190SFrançois Tigeot 17141b13d190SFrançois Tigeot flags |= PIPE_CONTROL_CS_STALL; 17151b13d190SFrançois Tigeot 17161b13d190SFrançois Tigeot if (flush_domains) { 17171b13d190SFrançois Tigeot flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH; 17181b13d190SFrançois Tigeot flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH; 1719aee94f86SFrançois Tigeot flags |= PIPE_CONTROL_DC_FLUSH_ENABLE; 1720b49c8cf9SFrançois Tigeot flags |= PIPE_CONTROL_FLUSH_ENABLE; 17211b13d190SFrançois Tigeot } 17221b13d190SFrançois Tigeot 17231b13d190SFrançois Tigeot if (invalidate_domains) { 17241b13d190SFrançois Tigeot flags |= PIPE_CONTROL_TLB_INVALIDATE; 17251b13d190SFrançois Tigeot flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE; 17261b13d190SFrançois Tigeot flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE; 17271b13d190SFrançois Tigeot flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE; 17281b13d190SFrançois Tigeot flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE; 17291b13d190SFrançois Tigeot flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE; 17301b13d190SFrançois Tigeot flags |= PIPE_CONTROL_QW_WRITE; 17311b13d190SFrançois Tigeot flags |= PIPE_CONTROL_GLOBAL_GTT_IVB; 17321b13d190SFrançois Tigeot 173319c468b4SFrançois Tigeot /* 1734c0e85e96SFrançois Tigeot * On GEN9: before VF_CACHE_INVALIDATE we need to emit a NULL 1735c0e85e96SFrançois Tigeot * pipe control. 173619c468b4SFrançois Tigeot */ 17378621f407SFrançois Tigeot if (IS_GEN9(engine->dev)) 1738c0e85e96SFrançois Tigeot vf_flush_wa = true; 17398621f407SFrançois Tigeot 17408621f407SFrançois Tigeot /* WaForGAMHang:kbl */ 17418621f407SFrançois Tigeot if (IS_KBL_REVID(request->i915, 0, KBL_REVID_B0)) 17428621f407SFrançois Tigeot dc_flush_wa = true; 1743c0e85e96SFrançois Tigeot } 174419c468b4SFrançois Tigeot 17458621f407SFrançois Tigeot len = 6; 17468621f407SFrançois Tigeot 17478621f407SFrançois Tigeot if (vf_flush_wa) 17488621f407SFrançois Tigeot len += 6; 17498621f407SFrançois Tigeot 17508621f407SFrançois Tigeot if (dc_flush_wa) 17518621f407SFrançois Tigeot len += 12; 17528621f407SFrançois Tigeot 17538621f407SFrançois Tigeot ret = intel_ring_begin(request, len); 17541b13d190SFrançois Tigeot if (ret) 17551b13d190SFrançois Tigeot return ret; 17561b13d190SFrançois Tigeot 175719c468b4SFrançois Tigeot if (vf_flush_wa) { 175819c468b4SFrançois Tigeot intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6)); 175919c468b4SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 176019c468b4SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 176119c468b4SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 176219c468b4SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 176319c468b4SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 176419c468b4SFrançois Tigeot } 176519c468b4SFrançois Tigeot 17668621f407SFrançois Tigeot if (dc_flush_wa) { 17678621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6)); 17688621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, PIPE_CONTROL_DC_FLUSH_ENABLE); 17698621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17708621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17718621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17728621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17738621f407SFrançois Tigeot } 17748621f407SFrançois Tigeot 17751b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6)); 17761b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, flags); 17771b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, scratch_addr); 17781b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17791b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17801b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17818621f407SFrançois Tigeot 17828621f407SFrançois Tigeot if (dc_flush_wa) { 17838621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6)); 17848621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, PIPE_CONTROL_CS_STALL); 17858621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17868621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17878621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17888621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 17898621f407SFrançois Tigeot } 17908621f407SFrançois Tigeot 17911b13d190SFrançois Tigeot intel_logical_ring_advance(ringbuf); 17921b13d190SFrançois Tigeot 17931b13d190SFrançois Tigeot return 0; 17941b13d190SFrançois Tigeot } 17951b13d190SFrançois Tigeot 17968621f407SFrançois Tigeot static u32 gen8_get_seqno(struct intel_engine_cs *engine) 17971b13d190SFrançois Tigeot { 17988621f407SFrançois Tigeot return intel_read_status_page(engine, I915_GEM_HWS_INDEX); 17991b13d190SFrançois Tigeot } 18001b13d190SFrançois Tigeot 18018621f407SFrançois Tigeot static void gen8_set_seqno(struct intel_engine_cs *engine, u32 seqno) 18021b13d190SFrançois Tigeot { 18038621f407SFrançois Tigeot intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno); 18041b13d190SFrançois Tigeot } 18051b13d190SFrançois Tigeot 18068621f407SFrançois Tigeot static void bxt_a_seqno_barrier(struct intel_engine_cs *engine) 1807352ff8bdSFrançois Tigeot { 1808352ff8bdSFrançois Tigeot /* 1809352ff8bdSFrançois Tigeot * On BXT A steppings there is a HW coherency issue whereby the 1810352ff8bdSFrançois Tigeot * MI_STORE_DATA_IMM storing the completed request's seqno 1811352ff8bdSFrançois Tigeot * occasionally doesn't invalidate the CPU cache. Work around this by 1812352ff8bdSFrançois Tigeot * clflushing the corresponding cacheline whenever the caller wants 1813352ff8bdSFrançois Tigeot * the coherency to be guaranteed. Note that this cacheline is known 1814352ff8bdSFrançois Tigeot * to be clean at this point, since we only write it in 1815352ff8bdSFrançois Tigeot * bxt_a_set_seqno(), where we also do a clflush after the write. So 1816352ff8bdSFrançois Tigeot * this clflush in practice becomes an invalidate operation. 1817352ff8bdSFrançois Tigeot */ 18188621f407SFrançois Tigeot intel_flush_status_page(engine, I915_GEM_HWS_INDEX); 1819352ff8bdSFrançois Tigeot } 1820352ff8bdSFrançois Tigeot 18218621f407SFrançois Tigeot static void bxt_a_set_seqno(struct intel_engine_cs *engine, u32 seqno) 1822352ff8bdSFrançois Tigeot { 18238621f407SFrançois Tigeot intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno); 1824352ff8bdSFrançois Tigeot 1825352ff8bdSFrançois Tigeot /* See bxt_a_get_seqno() explaining the reason for the clflush. */ 18268621f407SFrançois Tigeot intel_flush_status_page(engine, I915_GEM_HWS_INDEX); 1827352ff8bdSFrançois Tigeot } 1828352ff8bdSFrançois Tigeot 1829477eb7f9SFrançois Tigeot /* 1830477eb7f9SFrançois Tigeot * Reserve space for 2 NOOPs at the end of each request to be 1831477eb7f9SFrançois Tigeot * used as a workaround for not being allowed to do lite 1832477eb7f9SFrançois Tigeot * restore with HEAD==TAIL (WaIdleLiteRestore). 1833477eb7f9SFrançois Tigeot */ 1834c0e85e96SFrançois Tigeot #define WA_TAIL_DWORDS 2 1835c0e85e96SFrançois Tigeot 1836c0e85e96SFrançois Tigeot static inline u32 hws_seqno_address(struct intel_engine_cs *engine) 1837c0e85e96SFrançois Tigeot { 1838c0e85e96SFrançois Tigeot return engine->status_page.gfx_addr + I915_GEM_HWS_INDEX_ADDR; 1839c0e85e96SFrançois Tigeot } 1840c0e85e96SFrançois Tigeot 1841c0e85e96SFrançois Tigeot static int gen8_emit_request(struct drm_i915_gem_request *request) 1842c0e85e96SFrançois Tigeot { 1843c0e85e96SFrançois Tigeot struct intel_ringbuffer *ringbuf = request->ringbuf; 1844c0e85e96SFrançois Tigeot int ret; 1845c0e85e96SFrançois Tigeot 18468621f407SFrançois Tigeot ret = intel_ring_begin(request, 6 + WA_TAIL_DWORDS); 18471b13d190SFrançois Tigeot if (ret) 18481b13d190SFrançois Tigeot return ret; 18491b13d190SFrançois Tigeot 1850c0e85e96SFrançois Tigeot /* w/a: bit 5 needs to be zero for MI_FLUSH_DW address. */ 1851c0e85e96SFrançois Tigeot BUILD_BUG_ON(I915_GEM_HWS_INDEX_ADDR & (1 << 5)); 18521b13d190SFrançois Tigeot 18531b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, 1854c0e85e96SFrançois Tigeot (MI_FLUSH_DW + 1) | MI_FLUSH_DW_OP_STOREDW); 1855c0e85e96SFrançois Tigeot intel_logical_ring_emit(ringbuf, 18568621f407SFrançois Tigeot hws_seqno_address(request->engine) | 1857c0e85e96SFrançois Tigeot MI_FLUSH_DW_USE_GTT); 18581b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 1859a05eeebfSFrançois Tigeot intel_logical_ring_emit(ringbuf, i915_gem_request_get_seqno(request)); 18601b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT); 18611b13d190SFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_NOOP); 1862c0e85e96SFrançois Tigeot return intel_logical_ring_advance_and_submit(request); 1863c0e85e96SFrançois Tigeot } 18641b13d190SFrançois Tigeot 1865c0e85e96SFrançois Tigeot static int gen8_emit_request_render(struct drm_i915_gem_request *request) 1866c0e85e96SFrançois Tigeot { 1867c0e85e96SFrançois Tigeot struct intel_ringbuffer *ringbuf = request->ringbuf; 1868c0e85e96SFrançois Tigeot int ret; 1869c0e85e96SFrançois Tigeot 18708621f407SFrançois Tigeot ret = intel_ring_begin(request, 8 + WA_TAIL_DWORDS); 1871c0e85e96SFrançois Tigeot if (ret) 1872c0e85e96SFrançois Tigeot return ret; 1873c0e85e96SFrançois Tigeot 1874c0e85e96SFrançois Tigeot /* We're using qword write, seqno should be aligned to 8 bytes. */ 1875c0e85e96SFrançois Tigeot BUILD_BUG_ON(I915_GEM_HWS_INDEX & 1); 1876c0e85e96SFrançois Tigeot 1877c0e85e96SFrançois Tigeot /* w/a for post sync ops following a GPGPU operation we 1878c0e85e96SFrançois Tigeot * need a prior CS_STALL, which is emitted by the flush 1879c0e85e96SFrançois Tigeot * following the batch. 1880477eb7f9SFrançois Tigeot */ 1881c0e85e96SFrançois Tigeot intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6)); 1882c0e85e96SFrançois Tigeot intel_logical_ring_emit(ringbuf, 1883c0e85e96SFrançois Tigeot (PIPE_CONTROL_GLOBAL_GTT_IVB | 1884c0e85e96SFrançois Tigeot PIPE_CONTROL_CS_STALL | 1885c0e85e96SFrançois Tigeot PIPE_CONTROL_QW_WRITE)); 18868621f407SFrançois Tigeot intel_logical_ring_emit(ringbuf, hws_seqno_address(request->engine)); 1887c0e85e96SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 1888c0e85e96SFrançois Tigeot intel_logical_ring_emit(ringbuf, i915_gem_request_get_seqno(request)); 1889c0e85e96SFrançois Tigeot /* We're thrashing one dword of HWS. */ 1890c0e85e96SFrançois Tigeot intel_logical_ring_emit(ringbuf, 0); 1891c0e85e96SFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT); 1892477eb7f9SFrançois Tigeot intel_logical_ring_emit(ringbuf, MI_NOOP); 1893c0e85e96SFrançois Tigeot return intel_logical_ring_advance_and_submit(request); 18941b13d190SFrançois Tigeot } 18951b13d190SFrançois Tigeot 1896a05eeebfSFrançois Tigeot static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req) 1897477eb7f9SFrançois Tigeot { 1898477eb7f9SFrançois Tigeot struct render_state so; 1899477eb7f9SFrançois Tigeot int ret; 1900477eb7f9SFrançois Tigeot 19018621f407SFrançois Tigeot ret = i915_gem_render_state_prepare(req->engine, &so); 1902477eb7f9SFrançois Tigeot if (ret) 1903477eb7f9SFrançois Tigeot return ret; 1904477eb7f9SFrançois Tigeot 1905477eb7f9SFrançois Tigeot if (so.rodata == NULL) 1906477eb7f9SFrançois Tigeot return 0; 1907477eb7f9SFrançois Tigeot 19088621f407SFrançois Tigeot ret = req->engine->emit_bb_start(req, so.ggtt_offset, 1909477eb7f9SFrançois Tigeot I915_DISPATCH_SECURE); 1910477eb7f9SFrançois Tigeot if (ret) 1911477eb7f9SFrançois Tigeot goto out; 1912477eb7f9SFrançois Tigeot 19138621f407SFrançois Tigeot ret = req->engine->emit_bb_start(req, 1914a05eeebfSFrançois Tigeot (so.ggtt_offset + so.aux_batch_offset), 1915a05eeebfSFrançois Tigeot I915_DISPATCH_SECURE); 1916a05eeebfSFrançois Tigeot if (ret) 1917a05eeebfSFrançois Tigeot goto out; 1918477eb7f9SFrançois Tigeot 1919a05eeebfSFrançois Tigeot i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req); 1920a05eeebfSFrançois Tigeot 1921477eb7f9SFrançois Tigeot out: 1922477eb7f9SFrançois Tigeot i915_gem_render_state_fini(&so); 1923477eb7f9SFrançois Tigeot return ret; 1924477eb7f9SFrançois Tigeot } 1925477eb7f9SFrançois Tigeot 1926a05eeebfSFrançois Tigeot static int gen8_init_rcs_context(struct drm_i915_gem_request *req) 19272c9916cdSFrançois Tigeot { 19282c9916cdSFrançois Tigeot int ret; 19292c9916cdSFrançois Tigeot 1930a05eeebfSFrançois Tigeot ret = intel_logical_ring_workarounds_emit(req); 19312c9916cdSFrançois Tigeot if (ret) 19322c9916cdSFrançois Tigeot return ret; 19332c9916cdSFrançois Tigeot 1934a05eeebfSFrançois Tigeot ret = intel_rcs_context_init_mocs(req); 1935a05eeebfSFrançois Tigeot /* 1936a05eeebfSFrançois Tigeot * Failing to program the MOCS is non-fatal.The system will not 1937a05eeebfSFrançois Tigeot * run at peak performance. So generate an error and carry on. 1938a05eeebfSFrançois Tigeot */ 1939a05eeebfSFrançois Tigeot if (ret) 1940a05eeebfSFrançois Tigeot DRM_ERROR("MOCS failed to program: expect performance issues.\n"); 1941a05eeebfSFrançois Tigeot 1942a05eeebfSFrançois Tigeot return intel_lr_context_render_state_init(req); 19432c9916cdSFrançois Tigeot } 19442c9916cdSFrançois Tigeot 19451b13d190SFrançois Tigeot /** 19461b13d190SFrançois Tigeot * intel_logical_ring_cleanup() - deallocate the Engine Command Streamer 19471b13d190SFrançois Tigeot * 19481b13d190SFrançois Tigeot * @ring: Engine Command Streamer. 19491b13d190SFrançois Tigeot * 19501b13d190SFrançois Tigeot */ 19518621f407SFrançois Tigeot void intel_logical_ring_cleanup(struct intel_engine_cs *engine) 19521b13d190SFrançois Tigeot { 19532c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv; 19541b13d190SFrançois Tigeot 19558621f407SFrançois Tigeot if (!intel_engine_initialized(engine)) 19561b13d190SFrançois Tigeot return; 19571b13d190SFrançois Tigeot 19588621f407SFrançois Tigeot /* 19598621f407SFrançois Tigeot * Tasklet cannot be active at this point due intel_mark_active/idle 19608621f407SFrançois Tigeot * so this is just for documentation. 19618621f407SFrançois Tigeot */ 19628621f407SFrançois Tigeot if (WARN_ON(test_bit(TASKLET_STATE_SCHED, &engine->irq_tasklet.state))) 19638621f407SFrançois Tigeot tasklet_kill(&engine->irq_tasklet); 19642c9916cdSFrançois Tigeot 19658621f407SFrançois Tigeot dev_priv = engine->dev->dev_private; 19668621f407SFrançois Tigeot 19678621f407SFrançois Tigeot if (engine->buffer) { 19688621f407SFrançois Tigeot intel_logical_ring_stop(engine); 19698621f407SFrançois Tigeot WARN_ON((I915_READ_MODE(engine) & MODE_IDLE) == 0); 1970aee94f86SFrançois Tigeot } 19711b13d190SFrançois Tigeot 19728621f407SFrançois Tigeot if (engine->cleanup) 19738621f407SFrançois Tigeot engine->cleanup(engine); 19741b13d190SFrançois Tigeot 19758621f407SFrançois Tigeot i915_cmd_parser_fini_ring(engine); 19768621f407SFrançois Tigeot i915_gem_batch_pool_fini(&engine->batch_pool); 19771b13d190SFrançois Tigeot 19788621f407SFrançois Tigeot if (engine->status_page.obj) { 19798621f407SFrançois Tigeot i915_gem_object_unpin_map(engine->status_page.obj); 19808621f407SFrançois Tigeot engine->status_page.obj = NULL; 19811b13d190SFrançois Tigeot } 1982a05eeebfSFrançois Tigeot 19838621f407SFrançois Tigeot engine->idle_lite_restore_wa = 0; 19848621f407SFrançois Tigeot engine->disable_lite_restore_wa = false; 19858621f407SFrançois Tigeot engine->ctx_desc_template = 0; 1986c0e85e96SFrançois Tigeot 19878621f407SFrançois Tigeot lrc_destroy_wa_ctx_obj(engine); 19888621f407SFrançois Tigeot engine->dev = NULL; 19891b13d190SFrançois Tigeot } 19901b13d190SFrançois Tigeot 1991c0e85e96SFrançois Tigeot static void 1992c0e85e96SFrançois Tigeot logical_ring_default_vfuncs(struct drm_device *dev, 19938621f407SFrançois Tigeot struct intel_engine_cs *engine) 19941b13d190SFrançois Tigeot { 1995c0e85e96SFrançois Tigeot /* Default vfuncs which can be overriden by each engine. */ 19968621f407SFrançois Tigeot engine->init_hw = gen8_init_common_ring; 19978621f407SFrançois Tigeot engine->emit_request = gen8_emit_request; 19988621f407SFrançois Tigeot engine->emit_flush = gen8_emit_flush; 19998621f407SFrançois Tigeot engine->irq_get = gen8_logical_ring_get_irq; 20008621f407SFrançois Tigeot engine->irq_put = gen8_logical_ring_put_irq; 20018621f407SFrançois Tigeot engine->emit_bb_start = gen8_emit_bb_start; 20028621f407SFrançois Tigeot engine->get_seqno = gen8_get_seqno; 20038621f407SFrançois Tigeot engine->set_seqno = gen8_set_seqno; 2004c0e85e96SFrançois Tigeot if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { 20058621f407SFrançois Tigeot engine->irq_seqno_barrier = bxt_a_seqno_barrier; 20068621f407SFrançois Tigeot engine->set_seqno = bxt_a_set_seqno; 2007c0e85e96SFrançois Tigeot } 2008c0e85e96SFrançois Tigeot } 2009c0e85e96SFrançois Tigeot 2010c0e85e96SFrançois Tigeot static inline void 20118621f407SFrançois Tigeot logical_ring_default_irqs(struct intel_engine_cs *engine, unsigned shift) 2012c0e85e96SFrançois Tigeot { 20138621f407SFrançois Tigeot engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT << shift; 20148621f407SFrançois Tigeot engine->irq_keep_mask = GT_CONTEXT_SWITCH_INTERRUPT << shift; 2015c0e85e96SFrançois Tigeot } 2016c0e85e96SFrançois Tigeot 2017c0e85e96SFrançois Tigeot static int 20188621f407SFrançois Tigeot lrc_setup_hws(struct intel_engine_cs *engine, 20198621f407SFrançois Tigeot struct drm_i915_gem_object *dctx_obj) 2020c0e85e96SFrançois Tigeot { 20218621f407SFrançois Tigeot char *hws; 20228621f407SFrançois Tigeot 20238621f407SFrançois Tigeot /* The HWSP is part of the default context object in LRC mode. */ 20248621f407SFrançois Tigeot engine->status_page.gfx_addr = i915_gem_obj_ggtt_offset(dctx_obj) + 20258621f407SFrançois Tigeot LRC_PPHWSP_PN * PAGE_SIZE; 20268621f407SFrançois Tigeot hws = i915_gem_object_pin_map(dctx_obj); 20278621f407SFrançois Tigeot if (IS_ERR(hws)) 20288621f407SFrançois Tigeot return PTR_ERR(hws); 20298621f407SFrançois Tigeot engine->status_page.page_addr = (u32 *)(hws + LRC_PPHWSP_PN * PAGE_SIZE); 20308621f407SFrançois Tigeot engine->status_page.obj = dctx_obj; 20318621f407SFrançois Tigeot 20328621f407SFrançois Tigeot return 0; 20338621f407SFrançois Tigeot } 20348621f407SFrançois Tigeot 20358621f407SFrançois Tigeot static int 20368621f407SFrançois Tigeot logical_ring_init(struct drm_device *dev, struct intel_engine_cs *engine) 20378621f407SFrançois Tigeot { 20388621f407SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 20398621f407SFrançois Tigeot struct intel_context *dctx = dev_priv->kernel_context; 20408621f407SFrançois Tigeot enum forcewake_domains fw_domains; 20411b13d190SFrançois Tigeot int ret; 20421b13d190SFrançois Tigeot 20431b13d190SFrançois Tigeot /* Intentionally left blank. */ 20448621f407SFrançois Tigeot engine->buffer = NULL; 20451b13d190SFrançois Tigeot 20468621f407SFrançois Tigeot engine->dev = dev; 20478621f407SFrançois Tigeot INIT_LIST_HEAD(&engine->active_list); 20488621f407SFrançois Tigeot INIT_LIST_HEAD(&engine->request_list); 20498621f407SFrançois Tigeot i915_gem_batch_pool_init(dev, &engine->batch_pool); 20508621f407SFrançois Tigeot init_waitqueue_head(&engine->irq_queue); 20511b13d190SFrançois Tigeot 20528621f407SFrançois Tigeot INIT_LIST_HEAD(&engine->buffers); 20538621f407SFrançois Tigeot INIT_LIST_HEAD(&engine->execlist_queue); 20548621f407SFrançois Tigeot INIT_LIST_HEAD(&engine->execlist_retired_req_list); 20558621f407SFrançois Tigeot lockinit(&engine->execlist_lock, "i915el", 0, LK_CANRECURSE); 20561b13d190SFrançois Tigeot 20578621f407SFrançois Tigeot tasklet_init(&engine->irq_tasklet, 20588621f407SFrançois Tigeot intel_lrc_irq_handler, (unsigned long)engine); 2059c0e85e96SFrançois Tigeot 20608621f407SFrançois Tigeot logical_ring_init_platform_invariants(engine); 20618621f407SFrançois Tigeot 20628621f407SFrançois Tigeot fw_domains = intel_uncore_forcewake_for_reg(dev_priv, 20638621f407SFrançois Tigeot RING_ELSP(engine), 20648621f407SFrançois Tigeot FW_REG_WRITE); 20658621f407SFrançois Tigeot 20668621f407SFrançois Tigeot fw_domains |= intel_uncore_forcewake_for_reg(dev_priv, 20678621f407SFrançois Tigeot RING_CONTEXT_STATUS_PTR(engine), 20688621f407SFrançois Tigeot FW_REG_READ | FW_REG_WRITE); 20698621f407SFrançois Tigeot 20708621f407SFrançois Tigeot fw_domains |= intel_uncore_forcewake_for_reg(dev_priv, 20718621f407SFrançois Tigeot RING_CONTEXT_STATUS_BUF_BASE(engine), 20728621f407SFrançois Tigeot FW_REG_READ); 20738621f407SFrançois Tigeot 20748621f407SFrançois Tigeot engine->fw_domains = fw_domains; 20758621f407SFrançois Tigeot 20768621f407SFrançois Tigeot ret = i915_cmd_parser_init_ring(engine); 20771b13d190SFrançois Tigeot if (ret) 2078aee94f86SFrançois Tigeot goto error; 20791b13d190SFrançois Tigeot 20808621f407SFrançois Tigeot ret = intel_lr_context_deferred_alloc(dctx, engine); 2081352ff8bdSFrançois Tigeot if (ret) 2082aee94f86SFrançois Tigeot goto error; 2083352ff8bdSFrançois Tigeot 2084352ff8bdSFrançois Tigeot /* As this is the default context, always pin it */ 20858621f407SFrançois Tigeot ret = intel_lr_context_do_pin(dctx, engine); 2086352ff8bdSFrançois Tigeot if (ret) { 2087352ff8bdSFrançois Tigeot DRM_ERROR( 2088352ff8bdSFrançois Tigeot "Failed to pin and map ringbuffer %s: %d\n", 20898621f407SFrançois Tigeot engine->name, ret); 20908621f407SFrançois Tigeot goto error; 20918621f407SFrançois Tigeot } 20928621f407SFrançois Tigeot 20938621f407SFrançois Tigeot /* And setup the hardware status page. */ 20948621f407SFrançois Tigeot ret = lrc_setup_hws(engine, dctx->engine[engine->id].state); 20958621f407SFrançois Tigeot if (ret) { 20968621f407SFrançois Tigeot DRM_ERROR("Failed to set up hws %s: %d\n", engine->name, ret); 2097aee94f86SFrançois Tigeot goto error; 2098352ff8bdSFrançois Tigeot } 20991b13d190SFrançois Tigeot 2100aee94f86SFrançois Tigeot return 0; 2101aee94f86SFrançois Tigeot 2102aee94f86SFrançois Tigeot error: 21038621f407SFrançois Tigeot intel_logical_ring_cleanup(engine); 21041b13d190SFrançois Tigeot return ret; 21051b13d190SFrançois Tigeot } 21061b13d190SFrançois Tigeot 21071b13d190SFrançois Tigeot static int logical_render_ring_init(struct drm_device *dev) 21081b13d190SFrançois Tigeot { 21091b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 21108621f407SFrançois Tigeot struct intel_engine_cs *engine = &dev_priv->engine[RCS]; 21112c9916cdSFrançois Tigeot int ret; 21121b13d190SFrançois Tigeot 21138621f407SFrançois Tigeot engine->name = "render ring"; 21148621f407SFrançois Tigeot engine->id = RCS; 21158621f407SFrançois Tigeot engine->exec_id = I915_EXEC_RENDER; 21168621f407SFrançois Tigeot engine->guc_id = GUC_RENDER_ENGINE; 21178621f407SFrançois Tigeot engine->mmio_base = RENDER_RING_BASE; 2118c0e85e96SFrançois Tigeot 21198621f407SFrançois Tigeot logical_ring_default_irqs(engine, GEN8_RCS_IRQ_SHIFT); 21201b13d190SFrançois Tigeot if (HAS_L3_DPF(dev)) 21218621f407SFrançois Tigeot engine->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; 21221b13d190SFrançois Tigeot 21238621f407SFrançois Tigeot logical_ring_default_vfuncs(dev, engine); 2124c0e85e96SFrançois Tigeot 2125c0e85e96SFrançois Tigeot /* Override some for render ring. */ 2126477eb7f9SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 9) 21278621f407SFrançois Tigeot engine->init_hw = gen9_init_render_ring; 2128477eb7f9SFrançois Tigeot else 21298621f407SFrançois Tigeot engine->init_hw = gen8_init_render_ring; 21308621f407SFrançois Tigeot engine->init_context = gen8_init_rcs_context; 21318621f407SFrançois Tigeot engine->cleanup = intel_fini_pipe_control; 21328621f407SFrançois Tigeot engine->emit_flush = gen8_emit_flush_render; 21338621f407SFrançois Tigeot engine->emit_request = gen8_emit_request_render; 21341b13d190SFrançois Tigeot 21358621f407SFrançois Tigeot engine->dev = dev; 2136a05eeebfSFrançois Tigeot 21378621f407SFrançois Tigeot ret = intel_init_pipe_control(engine); 21382c9916cdSFrançois Tigeot if (ret) 21392c9916cdSFrançois Tigeot return ret; 21402c9916cdSFrançois Tigeot 21418621f407SFrançois Tigeot ret = intel_init_workaround_bb(engine); 2142a05eeebfSFrançois Tigeot if (ret) { 2143a05eeebfSFrançois Tigeot /* 2144a05eeebfSFrançois Tigeot * We continue even if we fail to initialize WA batch 2145a05eeebfSFrançois Tigeot * because we only expect rare glitches but nothing 2146a05eeebfSFrançois Tigeot * critical to prevent us from using GPU 2147a05eeebfSFrançois Tigeot */ 2148a05eeebfSFrançois Tigeot DRM_ERROR("WA batch buffer initialization failed: %d\n", 2149a05eeebfSFrançois Tigeot ret); 2150a05eeebfSFrançois Tigeot } 2151a05eeebfSFrançois Tigeot 21528621f407SFrançois Tigeot ret = logical_ring_init(dev, engine); 2153a05eeebfSFrançois Tigeot if (ret) { 21548621f407SFrançois Tigeot lrc_destroy_wa_ctx_obj(engine); 2155a05eeebfSFrançois Tigeot } 2156a05eeebfSFrançois Tigeot 2157a05eeebfSFrançois Tigeot return ret; 21581b13d190SFrançois Tigeot } 21591b13d190SFrançois Tigeot 21601b13d190SFrançois Tigeot static int logical_bsd_ring_init(struct drm_device *dev) 21611b13d190SFrançois Tigeot { 21621b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 21638621f407SFrançois Tigeot struct intel_engine_cs *engine = &dev_priv->engine[VCS]; 21641b13d190SFrançois Tigeot 21658621f407SFrançois Tigeot engine->name = "bsd ring"; 21668621f407SFrançois Tigeot engine->id = VCS; 21678621f407SFrançois Tigeot engine->exec_id = I915_EXEC_BSD; 21688621f407SFrançois Tigeot engine->guc_id = GUC_VIDEO_ENGINE; 21698621f407SFrançois Tigeot engine->mmio_base = GEN6_BSD_RING_BASE; 21701b13d190SFrançois Tigeot 21718621f407SFrançois Tigeot logical_ring_default_irqs(engine, GEN8_VCS1_IRQ_SHIFT); 21728621f407SFrançois Tigeot logical_ring_default_vfuncs(dev, engine); 21731b13d190SFrançois Tigeot 21748621f407SFrançois Tigeot return logical_ring_init(dev, engine); 21751b13d190SFrançois Tigeot } 21761b13d190SFrançois Tigeot 21771b13d190SFrançois Tigeot static int logical_bsd2_ring_init(struct drm_device *dev) 21781b13d190SFrançois Tigeot { 21791b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 21808621f407SFrançois Tigeot struct intel_engine_cs *engine = &dev_priv->engine[VCS2]; 21811b13d190SFrançois Tigeot 21828621f407SFrançois Tigeot engine->name = "bsd2 ring"; 21838621f407SFrançois Tigeot engine->id = VCS2; 21848621f407SFrançois Tigeot engine->exec_id = I915_EXEC_BSD; 21858621f407SFrançois Tigeot engine->guc_id = GUC_VIDEO_ENGINE2; 21868621f407SFrançois Tigeot engine->mmio_base = GEN8_BSD2_RING_BASE; 21871b13d190SFrançois Tigeot 21888621f407SFrançois Tigeot logical_ring_default_irqs(engine, GEN8_VCS2_IRQ_SHIFT); 21898621f407SFrançois Tigeot logical_ring_default_vfuncs(dev, engine); 21901b13d190SFrançois Tigeot 21918621f407SFrançois Tigeot return logical_ring_init(dev, engine); 21921b13d190SFrançois Tigeot } 21931b13d190SFrançois Tigeot 21941b13d190SFrançois Tigeot static int logical_blt_ring_init(struct drm_device *dev) 21951b13d190SFrançois Tigeot { 21961b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 21978621f407SFrançois Tigeot struct intel_engine_cs *engine = &dev_priv->engine[BCS]; 21981b13d190SFrançois Tigeot 21998621f407SFrançois Tigeot engine->name = "blitter ring"; 22008621f407SFrançois Tigeot engine->id = BCS; 22018621f407SFrançois Tigeot engine->exec_id = I915_EXEC_BLT; 22028621f407SFrançois Tigeot engine->guc_id = GUC_BLITTER_ENGINE; 22038621f407SFrançois Tigeot engine->mmio_base = BLT_RING_BASE; 22041b13d190SFrançois Tigeot 22058621f407SFrançois Tigeot logical_ring_default_irqs(engine, GEN8_BCS_IRQ_SHIFT); 22068621f407SFrançois Tigeot logical_ring_default_vfuncs(dev, engine); 22071b13d190SFrançois Tigeot 22088621f407SFrançois Tigeot return logical_ring_init(dev, engine); 22091b13d190SFrançois Tigeot } 22101b13d190SFrançois Tigeot 22111b13d190SFrançois Tigeot static int logical_vebox_ring_init(struct drm_device *dev) 22121b13d190SFrançois Tigeot { 22131b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 22148621f407SFrançois Tigeot struct intel_engine_cs *engine = &dev_priv->engine[VECS]; 22151b13d190SFrançois Tigeot 22168621f407SFrançois Tigeot engine->name = "video enhancement ring"; 22178621f407SFrançois Tigeot engine->id = VECS; 22188621f407SFrançois Tigeot engine->exec_id = I915_EXEC_VEBOX; 22198621f407SFrançois Tigeot engine->guc_id = GUC_VIDEOENHANCE_ENGINE; 22208621f407SFrançois Tigeot engine->mmio_base = VEBOX_RING_BASE; 22211b13d190SFrançois Tigeot 22228621f407SFrançois Tigeot logical_ring_default_irqs(engine, GEN8_VECS_IRQ_SHIFT); 22238621f407SFrançois Tigeot logical_ring_default_vfuncs(dev, engine); 22241b13d190SFrançois Tigeot 22258621f407SFrançois Tigeot return logical_ring_init(dev, engine); 22261b13d190SFrançois Tigeot } 22271b13d190SFrançois Tigeot 22281b13d190SFrançois Tigeot /** 22291b13d190SFrançois Tigeot * intel_logical_rings_init() - allocate, populate and init the Engine Command Streamers 22301b13d190SFrançois Tigeot * @dev: DRM device. 22311b13d190SFrançois Tigeot * 22321b13d190SFrançois Tigeot * This function inits the engines for an Execlists submission style (the equivalent in the 22338621f407SFrançois Tigeot * legacy ringbuffer submission world would be i915_gem_init_engines). It does it only for 22341b13d190SFrançois Tigeot * those engines that are present in the hardware. 22351b13d190SFrançois Tigeot * 22361b13d190SFrançois Tigeot * Return: non-zero if the initialization failed. 22371b13d190SFrançois Tigeot */ 22381b13d190SFrançois Tigeot int intel_logical_rings_init(struct drm_device *dev) 22391b13d190SFrançois Tigeot { 22401b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 22411b13d190SFrançois Tigeot int ret; 22421b13d190SFrançois Tigeot 22431b13d190SFrançois Tigeot ret = logical_render_ring_init(dev); 22441b13d190SFrançois Tigeot if (ret) 22451b13d190SFrançois Tigeot return ret; 22461b13d190SFrançois Tigeot 22471b13d190SFrançois Tigeot if (HAS_BSD(dev)) { 22481b13d190SFrançois Tigeot ret = logical_bsd_ring_init(dev); 22491b13d190SFrançois Tigeot if (ret) 22501b13d190SFrançois Tigeot goto cleanup_render_ring; 22511b13d190SFrançois Tigeot } 22521b13d190SFrançois Tigeot 22531b13d190SFrançois Tigeot if (HAS_BLT(dev)) { 22541b13d190SFrançois Tigeot ret = logical_blt_ring_init(dev); 22551b13d190SFrançois Tigeot if (ret) 22561b13d190SFrançois Tigeot goto cleanup_bsd_ring; 22571b13d190SFrançois Tigeot } 22581b13d190SFrançois Tigeot 22591b13d190SFrançois Tigeot if (HAS_VEBOX(dev)) { 22601b13d190SFrançois Tigeot ret = logical_vebox_ring_init(dev); 22611b13d190SFrançois Tigeot if (ret) 22621b13d190SFrançois Tigeot goto cleanup_blt_ring; 22631b13d190SFrançois Tigeot } 22641b13d190SFrançois Tigeot 22651b13d190SFrançois Tigeot if (HAS_BSD2(dev)) { 22661b13d190SFrançois Tigeot ret = logical_bsd2_ring_init(dev); 22671b13d190SFrançois Tigeot if (ret) 22681b13d190SFrançois Tigeot goto cleanup_vebox_ring; 22691b13d190SFrançois Tigeot } 22701b13d190SFrançois Tigeot 22711b13d190SFrançois Tigeot return 0; 22721b13d190SFrançois Tigeot 22731b13d190SFrançois Tigeot cleanup_vebox_ring: 22748621f407SFrançois Tigeot intel_logical_ring_cleanup(&dev_priv->engine[VECS]); 22751b13d190SFrançois Tigeot cleanup_blt_ring: 22768621f407SFrançois Tigeot intel_logical_ring_cleanup(&dev_priv->engine[BCS]); 22771b13d190SFrançois Tigeot cleanup_bsd_ring: 22788621f407SFrançois Tigeot intel_logical_ring_cleanup(&dev_priv->engine[VCS]); 22791b13d190SFrançois Tigeot cleanup_render_ring: 22808621f407SFrançois Tigeot intel_logical_ring_cleanup(&dev_priv->engine[RCS]); 22811b13d190SFrançois Tigeot 22821b13d190SFrançois Tigeot return ret; 22831b13d190SFrançois Tigeot } 22841b13d190SFrançois Tigeot 2285477eb7f9SFrançois Tigeot static u32 2286477eb7f9SFrançois Tigeot make_rpcs(struct drm_device *dev) 22871b13d190SFrançois Tigeot { 2288477eb7f9SFrançois Tigeot u32 rpcs = 0; 22891b13d190SFrançois Tigeot 2290477eb7f9SFrançois Tigeot /* 2291477eb7f9SFrançois Tigeot * No explicit RPCS request is needed to ensure full 2292477eb7f9SFrançois Tigeot * slice/subslice/EU enablement prior to Gen9. 2293477eb7f9SFrançois Tigeot */ 2294477eb7f9SFrançois Tigeot if (INTEL_INFO(dev)->gen < 9) 22951b13d190SFrançois Tigeot return 0; 22961b13d190SFrançois Tigeot 2297477eb7f9SFrançois Tigeot /* 2298477eb7f9SFrançois Tigeot * Starting in Gen9, render power gating can leave 2299477eb7f9SFrançois Tigeot * slice/subslice/EU in a partially enabled state. We 2300477eb7f9SFrançois Tigeot * must make an explicit request through RPCS for full 2301477eb7f9SFrançois Tigeot * enablement. 2302477eb7f9SFrançois Tigeot */ 2303477eb7f9SFrançois Tigeot if (INTEL_INFO(dev)->has_slice_pg) { 2304477eb7f9SFrançois Tigeot rpcs |= GEN8_RPCS_S_CNT_ENABLE; 2305477eb7f9SFrançois Tigeot rpcs |= INTEL_INFO(dev)->slice_total << 2306477eb7f9SFrançois Tigeot GEN8_RPCS_S_CNT_SHIFT; 2307477eb7f9SFrançois Tigeot rpcs |= GEN8_RPCS_ENABLE; 2308477eb7f9SFrançois Tigeot } 23091b13d190SFrançois Tigeot 2310477eb7f9SFrançois Tigeot if (INTEL_INFO(dev)->has_subslice_pg) { 2311477eb7f9SFrançois Tigeot rpcs |= GEN8_RPCS_SS_CNT_ENABLE; 2312477eb7f9SFrançois Tigeot rpcs |= INTEL_INFO(dev)->subslice_per_slice << 2313477eb7f9SFrançois Tigeot GEN8_RPCS_SS_CNT_SHIFT; 2314477eb7f9SFrançois Tigeot rpcs |= GEN8_RPCS_ENABLE; 2315477eb7f9SFrançois Tigeot } 23161b13d190SFrançois Tigeot 2317477eb7f9SFrançois Tigeot if (INTEL_INFO(dev)->has_eu_pg) { 2318477eb7f9SFrançois Tigeot rpcs |= INTEL_INFO(dev)->eu_per_subslice << 2319477eb7f9SFrançois Tigeot GEN8_RPCS_EU_MIN_SHIFT; 2320477eb7f9SFrançois Tigeot rpcs |= INTEL_INFO(dev)->eu_per_subslice << 2321477eb7f9SFrançois Tigeot GEN8_RPCS_EU_MAX_SHIFT; 2322477eb7f9SFrançois Tigeot rpcs |= GEN8_RPCS_ENABLE; 2323477eb7f9SFrançois Tigeot } 2324477eb7f9SFrançois Tigeot 2325477eb7f9SFrançois Tigeot return rpcs; 23261b13d190SFrançois Tigeot } 23271b13d190SFrançois Tigeot 23288621f407SFrançois Tigeot static u32 intel_lr_indirect_ctx_offset(struct intel_engine_cs *engine) 2329c0e85e96SFrançois Tigeot { 2330c0e85e96SFrançois Tigeot u32 indirect_ctx_offset; 2331c0e85e96SFrançois Tigeot 23328621f407SFrançois Tigeot switch (INTEL_INFO(engine->dev)->gen) { 2333c0e85e96SFrançois Tigeot default: 23348621f407SFrançois Tigeot MISSING_CASE(INTEL_INFO(engine->dev)->gen); 2335c0e85e96SFrançois Tigeot /* fall through */ 2336c0e85e96SFrançois Tigeot case 9: 2337c0e85e96SFrançois Tigeot indirect_ctx_offset = 2338c0e85e96SFrançois Tigeot GEN9_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT; 2339c0e85e96SFrançois Tigeot break; 2340c0e85e96SFrançois Tigeot case 8: 2341c0e85e96SFrançois Tigeot indirect_ctx_offset = 2342c0e85e96SFrançois Tigeot GEN8_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT; 2343c0e85e96SFrançois Tigeot break; 2344c0e85e96SFrançois Tigeot } 2345c0e85e96SFrançois Tigeot 2346c0e85e96SFrançois Tigeot return indirect_ctx_offset; 2347c0e85e96SFrançois Tigeot } 2348c0e85e96SFrançois Tigeot 23491b13d190SFrançois Tigeot static int 23508621f407SFrançois Tigeot populate_lr_context(struct intel_context *ctx, 23518621f407SFrançois Tigeot struct drm_i915_gem_object *ctx_obj, 23528621f407SFrançois Tigeot struct intel_engine_cs *engine, 23538621f407SFrançois Tigeot struct intel_ringbuffer *ringbuf) 23541b13d190SFrançois Tigeot { 23558621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 23561b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 23571b13d190SFrançois Tigeot struct i915_hw_ppgtt *ppgtt = ctx->ppgtt; 23588621f407SFrançois Tigeot char *vaddr; 23598621f407SFrançois Tigeot u32 *reg_state; 23601b13d190SFrançois Tigeot int ret; 23611b13d190SFrançois Tigeot 23621b13d190SFrançois Tigeot if (!ppgtt) 23631b13d190SFrançois Tigeot ppgtt = dev_priv->mm.aliasing_ppgtt; 23641b13d190SFrançois Tigeot 23651b13d190SFrançois Tigeot ret = i915_gem_object_set_to_cpu_domain(ctx_obj, true); 23661b13d190SFrançois Tigeot if (ret) { 23671b13d190SFrançois Tigeot DRM_DEBUG_DRIVER("Could not set to CPU domain\n"); 23681b13d190SFrançois Tigeot return ret; 23691b13d190SFrançois Tigeot } 23701b13d190SFrançois Tigeot 23718621f407SFrançois Tigeot vaddr = i915_gem_object_pin_map(ctx_obj); 23728621f407SFrançois Tigeot if (IS_ERR(vaddr)) { 23738621f407SFrançois Tigeot ret = PTR_ERR(vaddr); 23748621f407SFrançois Tigeot DRM_DEBUG_DRIVER("Could not map object pages! (%d)\n", ret); 23751b13d190SFrançois Tigeot return ret; 23761b13d190SFrançois Tigeot } 23778621f407SFrançois Tigeot ctx_obj->dirty = true; 23781b13d190SFrançois Tigeot 23791b13d190SFrançois Tigeot /* The second page of the context object contains some fields which must 23801b13d190SFrançois Tigeot * be set up prior to the first execution. */ 23818621f407SFrançois Tigeot reg_state = (u32 *)(vaddr + LRC_STATE_PN * PAGE_SIZE); 23821b13d190SFrançois Tigeot 23831b13d190SFrançois Tigeot /* A context is actually a big batch buffer with several MI_LOAD_REGISTER_IMM 23841b13d190SFrançois Tigeot * commands followed by (reg, value) pairs. The values we are setting here are 23851b13d190SFrançois Tigeot * only for the first context restore: on a subsequent save, the GPU will 23861b13d190SFrançois Tigeot * recreate this batchbuffer with new values (including all the missing 23871b13d190SFrançois Tigeot * MI_LOAD_REGISTER_IMM commands that we are not initializing here). */ 2388aee94f86SFrançois Tigeot reg_state[CTX_LRI_HEADER_0] = 23898621f407SFrançois Tigeot MI_LOAD_REGISTER_IMM(engine->id == RCS ? 14 : 11) | MI_LRI_FORCE_POSTED; 23908621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_CONTEXT_CONTROL, 23918621f407SFrançois Tigeot RING_CONTEXT_CONTROL(engine), 2392477eb7f9SFrançois Tigeot _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH | 2393a05eeebfSFrançois Tigeot CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | 2394c0e85e96SFrançois Tigeot (HAS_RESOURCE_STREAMER(dev) ? 2395c0e85e96SFrançois Tigeot CTX_CTRL_RS_CTX_ENABLE : 0))); 23968621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_RING_HEAD, RING_HEAD(engine->mmio_base), 23978621f407SFrançois Tigeot 0); 23988621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_RING_TAIL, RING_TAIL(engine->mmio_base), 23998621f407SFrançois Tigeot 0); 24002c9916cdSFrançois Tigeot /* Ring buffer start address is not known until the buffer is pinned. 24012c9916cdSFrançois Tigeot * It is written to the context image in execlists_update_context() 24022c9916cdSFrançois Tigeot */ 24038621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_START, 24048621f407SFrançois Tigeot RING_START(engine->mmio_base), 0); 24058621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_CONTROL, 24068621f407SFrançois Tigeot RING_CTL(engine->mmio_base), 2407aee94f86SFrançois Tigeot ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID); 24088621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_U, 24098621f407SFrançois Tigeot RING_BBADDR_UDW(engine->mmio_base), 0); 24108621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_L, 24118621f407SFrançois Tigeot RING_BBADDR(engine->mmio_base), 0); 24128621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_BB_STATE, 24138621f407SFrançois Tigeot RING_BBSTATE(engine->mmio_base), 2414aee94f86SFrançois Tigeot RING_BB_PPGTT); 24158621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_HEAD_U, 24168621f407SFrançois Tigeot RING_SBBADDR_UDW(engine->mmio_base), 0); 24178621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_HEAD_L, 24188621f407SFrançois Tigeot RING_SBBADDR(engine->mmio_base), 0); 24198621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_STATE, 24208621f407SFrançois Tigeot RING_SBBSTATE(engine->mmio_base), 0); 24218621f407SFrançois Tigeot if (engine->id == RCS) { 24228621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_BB_PER_CTX_PTR, 24238621f407SFrançois Tigeot RING_BB_PER_CTX_PTR(engine->mmio_base), 0); 24248621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX, 24258621f407SFrançois Tigeot RING_INDIRECT_CTX(engine->mmio_base), 0); 24268621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX_OFFSET, 24278621f407SFrançois Tigeot RING_INDIRECT_CTX_OFFSET(engine->mmio_base), 0); 24288621f407SFrançois Tigeot if (engine->wa_ctx.obj) { 24298621f407SFrançois Tigeot struct i915_ctx_workarounds *wa_ctx = &engine->wa_ctx; 2430a05eeebfSFrançois Tigeot uint32_t ggtt_offset = i915_gem_obj_ggtt_offset(wa_ctx->obj); 2431a05eeebfSFrançois Tigeot 2432a05eeebfSFrançois Tigeot reg_state[CTX_RCS_INDIRECT_CTX+1] = 2433a05eeebfSFrançois Tigeot (ggtt_offset + wa_ctx->indirect_ctx.offset * sizeof(uint32_t)) | 2434a05eeebfSFrançois Tigeot (wa_ctx->indirect_ctx.size / CACHELINE_DWORDS); 2435a05eeebfSFrançois Tigeot 2436a05eeebfSFrançois Tigeot reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = 24378621f407SFrançois Tigeot intel_lr_indirect_ctx_offset(engine) << 6; 2438a05eeebfSFrançois Tigeot 2439a05eeebfSFrançois Tigeot reg_state[CTX_BB_PER_CTX_PTR+1] = 2440a05eeebfSFrançois Tigeot (ggtt_offset + wa_ctx->per_ctx.offset * sizeof(uint32_t)) | 2441a05eeebfSFrançois Tigeot 0x01; 2442a05eeebfSFrançois Tigeot } 24431b13d190SFrançois Tigeot } 2444aee94f86SFrançois Tigeot reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9) | MI_LRI_FORCE_POSTED; 24458621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_CTX_TIMESTAMP, 24468621f407SFrançois Tigeot RING_CTX_TIMESTAMP(engine->mmio_base), 0); 2447aee94f86SFrançois Tigeot /* PDP values well be assigned later if needed */ 24488621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_PDP3_UDW, GEN8_RING_PDP_UDW(engine, 3), 24498621f407SFrançois Tigeot 0); 24508621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_PDP3_LDW, GEN8_RING_PDP_LDW(engine, 3), 24518621f407SFrançois Tigeot 0); 24528621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_PDP2_UDW, GEN8_RING_PDP_UDW(engine, 2), 24538621f407SFrançois Tigeot 0); 24548621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_PDP2_LDW, GEN8_RING_PDP_LDW(engine, 2), 24558621f407SFrançois Tigeot 0); 24568621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_PDP1_UDW, GEN8_RING_PDP_UDW(engine, 1), 24578621f407SFrançois Tigeot 0); 24588621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_PDP1_LDW, GEN8_RING_PDP_LDW(engine, 1), 24598621f407SFrançois Tigeot 0); 24608621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_PDP0_UDW, GEN8_RING_PDP_UDW(engine, 0), 24618621f407SFrançois Tigeot 0); 24628621f407SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_PDP0_LDW, GEN8_RING_PDP_LDW(engine, 0), 24638621f407SFrançois Tigeot 0); 246419c468b4SFrançois Tigeot 2465352ff8bdSFrançois Tigeot if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) { 2466352ff8bdSFrançois Tigeot /* 64b PPGTT (48bit canonical) 2467352ff8bdSFrançois Tigeot * PDP0_DESCRIPTOR contains the base address to PML4 and 2468352ff8bdSFrançois Tigeot * other PDP Descriptors are ignored. 2469352ff8bdSFrançois Tigeot */ 2470352ff8bdSFrançois Tigeot ASSIGN_CTX_PML4(ppgtt, reg_state); 2471352ff8bdSFrançois Tigeot } else { 2472352ff8bdSFrançois Tigeot /* 32b PPGTT 2473352ff8bdSFrançois Tigeot * PDP*_DESCRIPTOR contains the base address of space supported. 2474352ff8bdSFrançois Tigeot * With dynamic page allocation, PDPs may not be allocated at 2475352ff8bdSFrançois Tigeot * this point. Point the unallocated PDPs to the scratch page 247619c468b4SFrançois Tigeot */ 24778621f407SFrançois Tigeot execlists_update_context_pdps(ppgtt, reg_state); 2478352ff8bdSFrançois Tigeot } 2479352ff8bdSFrançois Tigeot 24808621f407SFrançois Tigeot if (engine->id == RCS) { 24811b13d190SFrançois Tigeot reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1); 2482aee94f86SFrançois Tigeot ASSIGN_CTX_REG(reg_state, CTX_R_PWR_CLK_STATE, GEN8_R_PWR_CLK_STATE, 2483aee94f86SFrançois Tigeot make_rpcs(dev)); 24841b13d190SFrançois Tigeot } 24851b13d190SFrançois Tigeot 24868621f407SFrançois Tigeot i915_gem_object_unpin_map(ctx_obj); 24871b13d190SFrançois Tigeot 24881b13d190SFrançois Tigeot return 0; 24891b13d190SFrançois Tigeot } 24901b13d190SFrançois Tigeot 24911b13d190SFrançois Tigeot /** 24921b13d190SFrançois Tigeot * intel_lr_context_free() - free the LRC specific bits of a context 24931b13d190SFrançois Tigeot * @ctx: the LR context to free. 24941b13d190SFrançois Tigeot * 24951b13d190SFrançois Tigeot * The real context freeing is done in i915_gem_context_free: this only 24961b13d190SFrançois Tigeot * takes care of the bits that are LRC related: the per-engine backing 24971b13d190SFrançois Tigeot * objects and the logical ringbuffer. 24981b13d190SFrançois Tigeot */ 24991b13d190SFrançois Tigeot void intel_lr_context_free(struct intel_context *ctx) 25001b13d190SFrançois Tigeot { 25011b13d190SFrançois Tigeot int i; 25021b13d190SFrançois Tigeot 25038621f407SFrançois Tigeot for (i = I915_NUM_ENGINES; --i >= 0; ) { 2504c0e85e96SFrançois Tigeot struct intel_ringbuffer *ringbuf = ctx->engine[i].ringbuf; 25051b13d190SFrançois Tigeot struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state; 25061b13d190SFrançois Tigeot 2507c0e85e96SFrançois Tigeot if (!ctx_obj) 2508c0e85e96SFrançois Tigeot continue; 25092c9916cdSFrançois Tigeot 2510c0e85e96SFrançois Tigeot if (ctx == ctx->i915->kernel_context) { 25112c9916cdSFrançois Tigeot intel_unpin_ringbuffer_obj(ringbuf); 25122c9916cdSFrançois Tigeot i915_gem_object_ggtt_unpin(ctx_obj); 25138621f407SFrançois Tigeot i915_gem_object_unpin_map(ctx_obj); 25142c9916cdSFrançois Tigeot } 2515c0e85e96SFrançois Tigeot 2516c0e85e96SFrançois Tigeot WARN_ON(ctx->engine[i].pin_count); 2517352ff8bdSFrançois Tigeot intel_ringbuffer_free(ringbuf); 25181b13d190SFrançois Tigeot drm_gem_object_unreference(&ctx_obj->base); 25191b13d190SFrançois Tigeot } 25201b13d190SFrançois Tigeot } 25211b13d190SFrançois Tigeot 2522c0e85e96SFrançois Tigeot /** 2523c0e85e96SFrançois Tigeot * intel_lr_context_size() - return the size of the context for an engine 2524c0e85e96SFrançois Tigeot * @ring: which engine to find the context size for 2525c0e85e96SFrançois Tigeot * 2526c0e85e96SFrançois Tigeot * Each engine may require a different amount of space for a context image, 2527c0e85e96SFrançois Tigeot * so when allocating (or copying) an image, this function can be used to 2528c0e85e96SFrançois Tigeot * find the right size for the specific engine. 2529c0e85e96SFrançois Tigeot * 2530c0e85e96SFrançois Tigeot * Return: size (in bytes) of an engine-specific context image 2531c0e85e96SFrançois Tigeot * 2532c0e85e96SFrançois Tigeot * Note: this size includes the HWSP, which is part of the context image 2533c0e85e96SFrançois Tigeot * in LRC mode, but does not include the "shared data page" used with 2534c0e85e96SFrançois Tigeot * GuC submission. The caller should account for this if using the GuC. 2535c0e85e96SFrançois Tigeot */ 25368621f407SFrançois Tigeot uint32_t intel_lr_context_size(struct intel_engine_cs *engine) 25371b13d190SFrançois Tigeot { 25381b13d190SFrançois Tigeot int ret = 0; 25391b13d190SFrançois Tigeot 25408621f407SFrançois Tigeot WARN_ON(INTEL_INFO(engine->dev)->gen < 8); 25411b13d190SFrançois Tigeot 25428621f407SFrançois Tigeot switch (engine->id) { 25431b13d190SFrançois Tigeot case RCS: 25448621f407SFrançois Tigeot if (INTEL_INFO(engine->dev)->gen >= 9) 25452c9916cdSFrançois Tigeot ret = GEN9_LR_CONTEXT_RENDER_SIZE; 25462c9916cdSFrançois Tigeot else 25471b13d190SFrançois Tigeot ret = GEN8_LR_CONTEXT_RENDER_SIZE; 25481b13d190SFrançois Tigeot break; 25491b13d190SFrançois Tigeot case VCS: 25501b13d190SFrançois Tigeot case BCS: 25511b13d190SFrançois Tigeot case VECS: 25521b13d190SFrançois Tigeot case VCS2: 25531b13d190SFrançois Tigeot ret = GEN8_LR_CONTEXT_OTHER_SIZE; 25541b13d190SFrançois Tigeot break; 25551b13d190SFrançois Tigeot } 25561b13d190SFrançois Tigeot 25571b13d190SFrançois Tigeot return ret; 25581b13d190SFrançois Tigeot } 25591b13d190SFrançois Tigeot 25601b13d190SFrançois Tigeot /** 2561352ff8bdSFrançois Tigeot * intel_lr_context_deferred_alloc() - create the LRC specific bits of a context 25621b13d190SFrançois Tigeot * @ctx: LR context to create. 25631b13d190SFrançois Tigeot * @ring: engine to be used with the context. 25641b13d190SFrançois Tigeot * 25651b13d190SFrançois Tigeot * This function can be called more than once, with different engines, if we plan 25661b13d190SFrançois Tigeot * to use the context with them. The context backing objects and the ringbuffers 25671b13d190SFrançois Tigeot * (specially the ringbuffer backing objects) suck a lot of memory up, and that's why 25681b13d190SFrançois Tigeot * the creation is a deferred call: it's better to make sure first that we need to use 25691b13d190SFrançois Tigeot * a given ring with the context. 25701b13d190SFrançois Tigeot * 25712c9916cdSFrançois Tigeot * Return: non-zero on error. 25721b13d190SFrançois Tigeot */ 2573352ff8bdSFrançois Tigeot 2574352ff8bdSFrançois Tigeot int intel_lr_context_deferred_alloc(struct intel_context *ctx, 25758621f407SFrançois Tigeot struct intel_engine_cs *engine) 25761b13d190SFrançois Tigeot { 25778621f407SFrançois Tigeot struct drm_device *dev = engine->dev; 25781b13d190SFrançois Tigeot struct drm_i915_gem_object *ctx_obj; 25791b13d190SFrançois Tigeot uint32_t context_size; 25801b13d190SFrançois Tigeot struct intel_ringbuffer *ringbuf; 25811b13d190SFrançois Tigeot int ret; 25821b13d190SFrançois Tigeot 25831b13d190SFrançois Tigeot WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL); 25848621f407SFrançois Tigeot WARN_ON(ctx->engine[engine->id].state); 25851b13d190SFrançois Tigeot 25868621f407SFrançois Tigeot context_size = round_up(intel_lr_context_size(engine), 4096); 25871b13d190SFrançois Tigeot 2588352ff8bdSFrançois Tigeot /* One extra page as the sharing data between driver and GuC */ 2589352ff8bdSFrançois Tigeot context_size += PAGE_SIZE * LRC_PPHWSP_PN; 2590352ff8bdSFrançois Tigeot 259119c468b4SFrançois Tigeot ctx_obj = i915_gem_alloc_object(dev, context_size); 259219c468b4SFrançois Tigeot if (!ctx_obj) { 259319c468b4SFrançois Tigeot DRM_DEBUG_DRIVER("Alloc LRC backing obj failed.\n"); 259419c468b4SFrançois Tigeot return -ENOMEM; 25951b13d190SFrançois Tigeot } 25961b13d190SFrançois Tigeot 25978621f407SFrançois Tigeot ringbuf = intel_engine_create_ringbuffer(engine, 4 * PAGE_SIZE); 2598352ff8bdSFrançois Tigeot if (IS_ERR(ringbuf)) { 2599352ff8bdSFrançois Tigeot ret = PTR_ERR(ringbuf); 2600352ff8bdSFrançois Tigeot goto error_deref_obj; 26011b13d190SFrançois Tigeot } 26021b13d190SFrançois Tigeot 26038621f407SFrançois Tigeot ret = populate_lr_context(ctx, ctx_obj, engine, ringbuf); 26041b13d190SFrançois Tigeot if (ret) { 26051b13d190SFrançois Tigeot DRM_DEBUG_DRIVER("Failed to populate LRC: %d\n", ret); 2606352ff8bdSFrançois Tigeot goto error_ringbuf; 26071b13d190SFrançois Tigeot } 26081b13d190SFrançois Tigeot 26098621f407SFrançois Tigeot ctx->engine[engine->id].ringbuf = ringbuf; 26108621f407SFrançois Tigeot ctx->engine[engine->id].state = ctx_obj; 26111b13d190SFrançois Tigeot 26128621f407SFrançois Tigeot if (ctx != ctx->i915->kernel_context && engine->init_context) { 2613a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req; 2614a05eeebfSFrançois Tigeot 26158621f407SFrançois Tigeot req = i915_gem_request_alloc(engine, ctx); 2616c0e85e96SFrançois Tigeot if (IS_ERR(req)) { 2617c0e85e96SFrançois Tigeot ret = PTR_ERR(req); 2618c0e85e96SFrançois Tigeot DRM_ERROR("ring create req: %d\n", ret); 2619352ff8bdSFrançois Tigeot goto error_ringbuf; 2620352ff8bdSFrançois Tigeot } 2621a05eeebfSFrançois Tigeot 26228621f407SFrançois Tigeot ret = engine->init_context(req); 26238621f407SFrançois Tigeot i915_add_request_no_flush(req); 26241b13d190SFrançois Tigeot if (ret) { 2625352ff8bdSFrançois Tigeot DRM_ERROR("ring init context: %d\n", 2626352ff8bdSFrançois Tigeot ret); 2627352ff8bdSFrançois Tigeot goto error_ringbuf; 26281b13d190SFrançois Tigeot } 26292c9916cdSFrançois Tigeot } 26301b13d190SFrançois Tigeot return 0; 26311b13d190SFrançois Tigeot 2632352ff8bdSFrançois Tigeot error_ringbuf: 2633352ff8bdSFrançois Tigeot intel_ringbuffer_free(ringbuf); 2634352ff8bdSFrançois Tigeot error_deref_obj: 26351b13d190SFrançois Tigeot drm_gem_object_unreference(&ctx_obj->base); 26368621f407SFrançois Tigeot ctx->engine[engine->id].ringbuf = NULL; 26378621f407SFrançois Tigeot ctx->engine[engine->id].state = NULL; 26381b13d190SFrançois Tigeot return ret; 26391b13d190SFrançois Tigeot } 2640477eb7f9SFrançois Tigeot 26418621f407SFrançois Tigeot void intel_lr_context_reset(struct drm_i915_private *dev_priv, 2642477eb7f9SFrançois Tigeot struct intel_context *ctx) 2643477eb7f9SFrançois Tigeot { 26448621f407SFrançois Tigeot struct intel_engine_cs *engine; 2645477eb7f9SFrançois Tigeot 26468621f407SFrançois Tigeot for_each_engine(engine, dev_priv) { 2647477eb7f9SFrançois Tigeot struct drm_i915_gem_object *ctx_obj = 26488621f407SFrançois Tigeot ctx->engine[engine->id].state; 2649477eb7f9SFrançois Tigeot struct intel_ringbuffer *ringbuf = 26508621f407SFrançois Tigeot ctx->engine[engine->id].ringbuf; 26518621f407SFrançois Tigeot char *vaddr; 2652477eb7f9SFrançois Tigeot uint32_t *reg_state; 2653477eb7f9SFrançois Tigeot 2654477eb7f9SFrançois Tigeot if (!ctx_obj) 2655477eb7f9SFrançois Tigeot continue; 2656477eb7f9SFrançois Tigeot 26578621f407SFrançois Tigeot vaddr = i915_gem_object_pin_map(ctx_obj); 26588621f407SFrançois Tigeot if (WARN_ON(IS_ERR(vaddr))) 2659477eb7f9SFrançois Tigeot continue; 26608621f407SFrançois Tigeot 26618621f407SFrançois Tigeot reg_state = (uint32_t *)(vaddr + LRC_STATE_PN * PAGE_SIZE); 26628621f407SFrançois Tigeot ctx_obj->dirty = true; 2663477eb7f9SFrançois Tigeot 2664477eb7f9SFrançois Tigeot reg_state[CTX_RING_HEAD+1] = 0; 2665477eb7f9SFrançois Tigeot reg_state[CTX_RING_TAIL+1] = 0; 2666477eb7f9SFrançois Tigeot 26678621f407SFrançois Tigeot i915_gem_object_unpin_map(ctx_obj); 2668477eb7f9SFrançois Tigeot 2669477eb7f9SFrançois Tigeot ringbuf->head = 0; 2670477eb7f9SFrançois Tigeot ringbuf->tail = 0; 2671477eb7f9SFrançois Tigeot } 2672477eb7f9SFrançois Tigeot } 2673