1e555d299SFrançois Tigeot /*
2e555d299SFrançois Tigeot * Copyright © 2011-2012 Intel Corporation
3e555d299SFrançois Tigeot *
4e555d299SFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a
5e555d299SFrançois Tigeot * copy of this software and associated documentation files (the "Software"),
6e555d299SFrançois Tigeot * to deal in the Software without restriction, including without limitation
7e555d299SFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e555d299SFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the
9e555d299SFrançois Tigeot * Software is furnished to do so, subject to the following conditions:
10e555d299SFrançois Tigeot *
11e555d299SFrançois Tigeot * The above copyright notice and this permission notice (including the next
12e555d299SFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the
13e555d299SFrançois Tigeot * Software.
14e555d299SFrançois Tigeot *
15e555d299SFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16e555d299SFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17e555d299SFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18e555d299SFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19e555d299SFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20e555d299SFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21e555d299SFrançois Tigeot * IN THE SOFTWARE.
22e555d299SFrançois Tigeot *
23e555d299SFrançois Tigeot * Authors:
24e555d299SFrançois Tigeot * Ben Widawsky <ben@bwidawsk.net>
25e555d299SFrançois Tigeot *
26e555d299SFrançois Tigeot */
27e555d299SFrançois Tigeot
28e555d299SFrançois Tigeot /*
29e555d299SFrançois Tigeot * This file implements HW context support. On gen5+ a HW context consists of an
30e555d299SFrançois Tigeot * opaque GPU object which is referenced at times of context saves and restores.
31e555d299SFrançois Tigeot * With RC6 enabled, the context is also referenced as the GPU enters and exists
32e555d299SFrançois Tigeot * from RC6 (GPU has it's own internal power context, except on gen5). Though
33e555d299SFrançois Tigeot * something like a context does exist for the media ring, the code only
34e555d299SFrançois Tigeot * supports contexts for the render ring.
35e555d299SFrançois Tigeot *
36e555d299SFrançois Tigeot * In software, there is a distinction between contexts created by the user,
37e555d299SFrançois Tigeot * and the default HW context. The default HW context is used by GPU clients
38e555d299SFrançois Tigeot * that do not request setup of their own hardware context. The default
39e555d299SFrançois Tigeot * context's state is never restored to help prevent programming errors. This
40e555d299SFrançois Tigeot * would happen if a client ran and piggy-backed off another clients GPU state.
41e555d299SFrançois Tigeot * The default context only exists to give the GPU some offset to load as the
42e555d299SFrançois Tigeot * current to invoke a save of the context we actually care about. In fact, the
43e555d299SFrançois Tigeot * code could likely be constructed, albeit in a more complicated fashion, to
44e555d299SFrançois Tigeot * never use the default context, though that limits the driver's ability to
45e555d299SFrançois Tigeot * swap out, and/or destroy other contexts.
46e555d299SFrançois Tigeot *
47e555d299SFrançois Tigeot * All other contexts are created as a request by the GPU client. These contexts
48e555d299SFrançois Tigeot * store GPU state, and thus allow GPU clients to not re-emit state (and
49e555d299SFrançois Tigeot * potentially query certain state) at any time. The kernel driver makes
50e555d299SFrançois Tigeot * certain that the appropriate commands are inserted.
51e555d299SFrançois Tigeot *
52e555d299SFrançois Tigeot * The context life cycle is semi-complicated in that context BOs may live
53e555d299SFrançois Tigeot * longer than the context itself because of the way the hardware, and object
54e555d299SFrançois Tigeot * tracking works. Below is a very crude representation of the state machine
55e555d299SFrançois Tigeot * describing the context life.
56e555d299SFrançois Tigeot * refcount pincount active
57e555d299SFrançois Tigeot * S0: initial state 0 0 0
58e555d299SFrançois Tigeot * S1: context created 1 0 0
59e555d299SFrançois Tigeot * S2: context is currently running 2 1 X
60e555d299SFrançois Tigeot * S3: GPU referenced, but not current 2 0 1
61e555d299SFrançois Tigeot * S4: context is current, but destroyed 1 1 0
62e555d299SFrançois Tigeot * S5: like S3, but destroyed 1 0 1
63e555d299SFrançois Tigeot *
64e555d299SFrançois Tigeot * The most common (but not all) transitions:
65e555d299SFrançois Tigeot * S0->S1: client creates a context
66e555d299SFrançois Tigeot * S1->S2: client submits execbuf with context
67e555d299SFrançois Tigeot * S2->S3: other clients submits execbuf with context
68e555d299SFrançois Tigeot * S3->S1: context object was retired
69e555d299SFrançois Tigeot * S3->S2: clients submits another execbuf
70e555d299SFrançois Tigeot * S2->S4: context destroy called with current context
71e555d299SFrançois Tigeot * S3->S5->S0: destroy path
72e555d299SFrançois Tigeot * S4->S5->S0: destroy path on current context
73e555d299SFrançois Tigeot *
74e555d299SFrançois Tigeot * There are two confusing terms used above:
75e555d299SFrançois Tigeot * The "current context" means the context which is currently running on the
769edbd4a0SFrançois Tigeot * GPU. The GPU has loaded its state already and has stored away the gtt
77e555d299SFrançois Tigeot * offset of the BO. The GPU is not actively referencing the data at this
78e555d299SFrançois Tigeot * offset, but it will on the next context switch. The only way to avoid this
79e555d299SFrançois Tigeot * is to do a GPU reset.
80e555d299SFrançois Tigeot *
81e555d299SFrançois Tigeot * An "active context' is one which was previously the "current context" and is
82e555d299SFrançois Tigeot * on the active list waiting for the next context switch to occur. Until this
83e555d299SFrançois Tigeot * happens, the object must remain at the same gtt offset. It is therefore
84e555d299SFrançois Tigeot * possible to destroy a context, but it is still active.
85e555d299SFrançois Tigeot *
86e555d299SFrançois Tigeot */
87e555d299SFrançois Tigeot
88*3f2dd94aSFrançois Tigeot #include <linux/log2.h>
89e555d299SFrançois Tigeot #include <drm/drmP.h>
90e555d299SFrançois Tigeot #include <drm/i915_drm.h>
91e555d299SFrançois Tigeot #include "i915_drv.h"
922c9916cdSFrançois Tigeot #include "i915_trace.h"
93e555d299SFrançois Tigeot
941487f786SFrançois Tigeot #define ALL_L3_SLICES(dev) (1 << NUM_L3_SLICES(dev)) - 1
951487f786SFrançois Tigeot
lut_close(struct i915_gem_context * ctx)96*3f2dd94aSFrançois Tigeot static void lut_close(struct i915_gem_context *ctx)
97e555d299SFrançois Tigeot {
98*3f2dd94aSFrançois Tigeot struct i915_lut_handle *lut, *ln;
99*3f2dd94aSFrançois Tigeot struct radix_tree_iter iter;
100*3f2dd94aSFrançois Tigeot void __rcu **slot;
101e555d299SFrançois Tigeot
102*3f2dd94aSFrançois Tigeot list_for_each_entry_safe(lut, ln, &ctx->handles_list, ctx_link) {
103*3f2dd94aSFrançois Tigeot list_del(&lut->obj_link);
104*3f2dd94aSFrançois Tigeot kmem_cache_free(ctx->i915->luts, lut);
105e555d299SFrançois Tigeot }
106e555d299SFrançois Tigeot
107*3f2dd94aSFrançois Tigeot rcu_read_lock();
108*3f2dd94aSFrançois Tigeot radix_tree_for_each_slot(slot, &ctx->handles_vma, &iter, 0) {
109*3f2dd94aSFrançois Tigeot struct i915_vma *vma = rcu_dereference_raw(*slot);
110*3f2dd94aSFrançois Tigeot
111*3f2dd94aSFrançois Tigeot radix_tree_iter_delete(&ctx->handles_vma, &iter, slot);
112*3f2dd94aSFrançois Tigeot __i915_gem_object_release_unless_active(vma->obj);
113*3f2dd94aSFrançois Tigeot }
114*3f2dd94aSFrançois Tigeot rcu_read_unlock();
115e555d299SFrançois Tigeot }
116e555d299SFrançois Tigeot
i915_gem_context_free(struct i915_gem_context * ctx)117*3f2dd94aSFrançois Tigeot static void i915_gem_context_free(struct i915_gem_context *ctx)
118e555d299SFrançois Tigeot {
1191487f786SFrançois Tigeot int i;
120e555d299SFrançois Tigeot
121303bf270SFrançois Tigeot lockdep_assert_held(&ctx->i915->drm.struct_mutex);
122a85cb24fSFrançois Tigeot GEM_BUG_ON(!i915_gem_context_is_closed(ctx));
123352ff8bdSFrançois Tigeot
1241b13d190SFrançois Tigeot i915_ppgtt_put(ctx->ppgtt);
1251b13d190SFrançois Tigeot
1261487f786SFrançois Tigeot for (i = 0; i < I915_NUM_ENGINES; i++) {
1271487f786SFrançois Tigeot struct intel_context *ce = &ctx->engine[i];
1281487f786SFrançois Tigeot
1291487f786SFrançois Tigeot if (!ce->state)
1301487f786SFrançois Tigeot continue;
1311487f786SFrançois Tigeot
1321487f786SFrançois Tigeot WARN_ON(ce->pin_count);
13371f41f3eSFrançois Tigeot if (ce->ring)
13471f41f3eSFrançois Tigeot intel_ring_free(ce->ring);
1351487f786SFrançois Tigeot
1364be47400SFrançois Tigeot __i915_gem_object_release_unless_active(ce->state->obj);
1371487f786SFrançois Tigeot }
1381487f786SFrançois Tigeot
1394be47400SFrançois Tigeot kfree(ctx->name);
1401e12ee3bSFrançois Tigeot put_pid(ctx->pid);
141*3f2dd94aSFrançois Tigeot
142ba55f2f5SFrançois Tigeot list_del(&ctx->link);
1431487f786SFrançois Tigeot
144*3f2dd94aSFrançois Tigeot ida_simple_remove(&ctx->i915->contexts.hw_ida, ctx->hw_id);
145*3f2dd94aSFrançois Tigeot kfree_rcu(ctx, rcu);
146e555d299SFrançois Tigeot }
147e555d299SFrançois Tigeot
contexts_free(struct drm_i915_private * i915)148*3f2dd94aSFrançois Tigeot static void contexts_free(struct drm_i915_private *i915)
14924edb884SFrançois Tigeot {
150*3f2dd94aSFrançois Tigeot struct llist_node *freed = llist_del_all(&i915->contexts.free_list);
151*3f2dd94aSFrançois Tigeot struct i915_gem_context *ctx, *cn;
15224edb884SFrançois Tigeot
153*3f2dd94aSFrançois Tigeot lockdep_assert_held(&i915->drm.struct_mutex);
1541487f786SFrançois Tigeot
155*3f2dd94aSFrançois Tigeot llist_for_each_entry_safe(ctx, cn, freed, free_link)
156*3f2dd94aSFrançois Tigeot i915_gem_context_free(ctx);
15724edb884SFrançois Tigeot }
15824edb884SFrançois Tigeot
contexts_free_first(struct drm_i915_private * i915)159*3f2dd94aSFrançois Tigeot static void contexts_free_first(struct drm_i915_private *i915)
160*3f2dd94aSFrançois Tigeot {
161*3f2dd94aSFrançois Tigeot struct i915_gem_context *ctx;
162*3f2dd94aSFrançois Tigeot struct llist_node *freed;
163*3f2dd94aSFrançois Tigeot
164*3f2dd94aSFrançois Tigeot lockdep_assert_held(&i915->drm.struct_mutex);
165*3f2dd94aSFrançois Tigeot
166*3f2dd94aSFrançois Tigeot freed = llist_del_first(&i915->contexts.free_list);
167*3f2dd94aSFrançois Tigeot if (!freed)
168*3f2dd94aSFrançois Tigeot return;
169*3f2dd94aSFrançois Tigeot
170*3f2dd94aSFrançois Tigeot ctx = container_of(freed, typeof(*ctx), free_link);
171*3f2dd94aSFrançois Tigeot i915_gem_context_free(ctx);
172*3f2dd94aSFrançois Tigeot }
173*3f2dd94aSFrançois Tigeot
contexts_free_worker(struct work_struct * work)174*3f2dd94aSFrançois Tigeot static void contexts_free_worker(struct work_struct *work)
175*3f2dd94aSFrançois Tigeot {
176*3f2dd94aSFrançois Tigeot struct drm_i915_private *i915 =
177*3f2dd94aSFrançois Tigeot container_of(work, typeof(*i915), contexts.free_work);
178*3f2dd94aSFrançois Tigeot
179*3f2dd94aSFrançois Tigeot mutex_lock(&i915->drm.struct_mutex);
180*3f2dd94aSFrançois Tigeot contexts_free(i915);
181*3f2dd94aSFrançois Tigeot mutex_unlock(&i915->drm.struct_mutex);
182*3f2dd94aSFrançois Tigeot }
183*3f2dd94aSFrançois Tigeot
i915_gem_context_release(struct kref * ref)184*3f2dd94aSFrançois Tigeot void i915_gem_context_release(struct kref *ref)
185*3f2dd94aSFrançois Tigeot {
186*3f2dd94aSFrançois Tigeot struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
187*3f2dd94aSFrançois Tigeot struct drm_i915_private *i915 = ctx->i915;
188*3f2dd94aSFrançois Tigeot
189*3f2dd94aSFrançois Tigeot trace_i915_context_free(ctx);
190*3f2dd94aSFrançois Tigeot if (llist_add(&ctx->free_link, &i915->contexts.free_list))
191*3f2dd94aSFrançois Tigeot queue_work(i915->wq, &i915->contexts.free_work);
19224edb884SFrançois Tigeot }
19324edb884SFrançois Tigeot
context_close(struct i915_gem_context * ctx)19471f41f3eSFrançois Tigeot static void context_close(struct i915_gem_context *ctx)
19571f41f3eSFrançois Tigeot {
196a85cb24fSFrançois Tigeot i915_gem_context_set_closed(ctx);
197*3f2dd94aSFrançois Tigeot
198*3f2dd94aSFrançois Tigeot /*
199*3f2dd94aSFrançois Tigeot * The LUT uses the VMA as a backpointer to unref the object,
200*3f2dd94aSFrançois Tigeot * so we need to clear the LUT before we close all the VMA (inside
201*3f2dd94aSFrançois Tigeot * the ppgtt).
202*3f2dd94aSFrançois Tigeot */
203*3f2dd94aSFrançois Tigeot lut_close(ctx);
20471f41f3eSFrançois Tigeot if (ctx->ppgtt)
20571f41f3eSFrançois Tigeot i915_ppgtt_close(&ctx->ppgtt->base);
206*3f2dd94aSFrançois Tigeot
20771f41f3eSFrançois Tigeot ctx->file_priv = ERR_PTR(-EBADF);
20871f41f3eSFrançois Tigeot i915_gem_context_put(ctx);
20971f41f3eSFrançois Tigeot }
21071f41f3eSFrançois Tigeot
assign_hw_id(struct drm_i915_private * dev_priv,unsigned * out)2111487f786SFrançois Tigeot static int assign_hw_id(struct drm_i915_private *dev_priv, unsigned *out)
2121487f786SFrançois Tigeot {
2131487f786SFrançois Tigeot int ret;
2141487f786SFrançois Tigeot
215*3f2dd94aSFrançois Tigeot ret = ida_simple_get(&dev_priv->contexts.hw_ida,
2161487f786SFrançois Tigeot 0, MAX_CONTEXT_HW_ID, GFP_KERNEL);
2171487f786SFrançois Tigeot if (ret < 0) {
2181487f786SFrançois Tigeot /* Contexts are only released when no longer active.
2191487f786SFrançois Tigeot * Flush any pending retires to hopefully release some
2201487f786SFrançois Tigeot * stale contexts and try again.
2211487f786SFrançois Tigeot */
2221487f786SFrançois Tigeot i915_gem_retire_requests(dev_priv);
223*3f2dd94aSFrançois Tigeot ret = ida_simple_get(&dev_priv->contexts.hw_ida,
2241487f786SFrançois Tigeot 0, MAX_CONTEXT_HW_ID, GFP_KERNEL);
2251487f786SFrançois Tigeot if (ret < 0)
2261487f786SFrançois Tigeot return ret;
2271487f786SFrançois Tigeot }
2281487f786SFrançois Tigeot
2291487f786SFrançois Tigeot *out = ret;
2301487f786SFrançois Tigeot return 0;
2311487f786SFrançois Tigeot }
2321487f786SFrançois Tigeot
default_desc_template(const struct drm_i915_private * i915,const struct i915_hw_ppgtt * ppgtt)233a85cb24fSFrançois Tigeot static u32 default_desc_template(const struct drm_i915_private *i915,
234a85cb24fSFrançois Tigeot const struct i915_hw_ppgtt *ppgtt)
235a85cb24fSFrançois Tigeot {
236a85cb24fSFrançois Tigeot u32 address_mode;
237a85cb24fSFrançois Tigeot u32 desc;
238a85cb24fSFrançois Tigeot
239a85cb24fSFrançois Tigeot desc = GEN8_CTX_VALID | GEN8_CTX_PRIVILEGE;
240a85cb24fSFrançois Tigeot
241a85cb24fSFrançois Tigeot address_mode = INTEL_LEGACY_32B_CONTEXT;
242a85cb24fSFrançois Tigeot if (ppgtt && i915_vm_is_48bit(&ppgtt->base))
243a85cb24fSFrançois Tigeot address_mode = INTEL_LEGACY_64B_CONTEXT;
244a85cb24fSFrançois Tigeot desc |= address_mode << GEN8_CTX_ADDRESSING_MODE_SHIFT;
245a85cb24fSFrançois Tigeot
246a85cb24fSFrançois Tigeot if (IS_GEN8(i915))
247a85cb24fSFrançois Tigeot desc |= GEN8_CTX_L3LLC_COHERENT;
248a85cb24fSFrançois Tigeot
249a85cb24fSFrançois Tigeot /* TODO: WaDisableLiteRestore when we start using semaphore
250a85cb24fSFrançois Tigeot * signalling between Command Streamers
251a85cb24fSFrançois Tigeot * ring->ctx_desc_template |= GEN8_CTX_FORCE_RESTORE;
252a85cb24fSFrançois Tigeot */
253a85cb24fSFrançois Tigeot
254a85cb24fSFrançois Tigeot return desc;
255a85cb24fSFrançois Tigeot }
256a85cb24fSFrançois Tigeot
2571487f786SFrançois Tigeot static struct i915_gem_context *
__create_hw_context(struct drm_i915_private * dev_priv,struct drm_i915_file_private * file_priv)258a85cb24fSFrançois Tigeot __create_hw_context(struct drm_i915_private *dev_priv,
259e555d299SFrançois Tigeot struct drm_i915_file_private *file_priv)
260e555d299SFrançois Tigeot {
2611487f786SFrançois Tigeot struct i915_gem_context *ctx;
2629f0f5970SFrançois Tigeot int ret;
263e555d299SFrançois Tigeot
264159fc1d7SFrançois Tigeot ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
265e555d299SFrançois Tigeot if (ctx == NULL)
266e555d299SFrançois Tigeot return ERR_PTR(-ENOMEM);
267e555d299SFrançois Tigeot
2681487f786SFrançois Tigeot ret = assign_hw_id(dev_priv, &ctx->hw_id);
2691487f786SFrançois Tigeot if (ret) {
2701487f786SFrançois Tigeot kfree(ctx);
2711487f786SFrançois Tigeot return ERR_PTR(ret);
2721487f786SFrançois Tigeot }
2731487f786SFrançois Tigeot
2745d0b1887SFrançois Tigeot kref_init(&ctx->ref);
275*3f2dd94aSFrançois Tigeot list_add_tail(&ctx->link, &dev_priv->contexts.list);
27619c468b4SFrançois Tigeot ctx->i915 = dev_priv;
277*3f2dd94aSFrançois Tigeot ctx->priority = I915_PRIORITY_NORMAL;
278ba55f2f5SFrançois Tigeot
279*3f2dd94aSFrançois Tigeot INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
280*3f2dd94aSFrançois Tigeot INIT_LIST_HEAD(&ctx->handles_list);
281e555d299SFrançois Tigeot
282e555d299SFrançois Tigeot /* Default context will never have a file_priv */
2834be47400SFrançois Tigeot ret = DEFAULT_CONTEXT_HANDLE;
2844be47400SFrançois Tigeot if (file_priv) {
285ba55f2f5SFrançois Tigeot ret = idr_alloc(&file_priv->context_idr, ctx,
28624edb884SFrançois Tigeot DEFAULT_CONTEXT_HANDLE, 0, GFP_KERNEL);
2879f0f5970SFrançois Tigeot if (ret < 0)
288*3f2dd94aSFrançois Tigeot goto err_lut;
2894be47400SFrançois Tigeot }
2904be47400SFrançois Tigeot ctx->user_handle = ret;
2915d0b1887SFrançois Tigeot
2925d0b1887SFrançois Tigeot ctx->file_priv = file_priv;
2934be47400SFrançois Tigeot if (file_priv) {
2941e12ee3bSFrançois Tigeot ctx->pid = get_task_pid(current, PIDTYPE_PID);
295a85cb24fSFrançois Tigeot ctx->name = kasprintf(GFP_KERNEL, "%s[%d]/%x",
296a85cb24fSFrançois Tigeot current->comm,
297a85cb24fSFrançois Tigeot pid_nr(ctx->pid),
298a85cb24fSFrançois Tigeot ctx->user_handle);
2994be47400SFrançois Tigeot if (!ctx->name) {
3004be47400SFrançois Tigeot ret = -ENOMEM;
3014be47400SFrançois Tigeot goto err_pid;
3024be47400SFrançois Tigeot }
3034be47400SFrançois Tigeot }
3041e12ee3bSFrançois Tigeot
3059edbd4a0SFrançois Tigeot /* NB: Mark all slices as needing a remap so that when the context first
3069edbd4a0SFrançois Tigeot * loads it will restore whatever remap state already exists. If there
3079edbd4a0SFrançois Tigeot * is no remap info, it will be a NOP. */
3081487f786SFrançois Tigeot ctx->remap_slice = ALL_L3_SLICES(dev_priv);
309e555d299SFrançois Tigeot
310a85cb24fSFrançois Tigeot i915_gem_context_set_bannable(ctx);
3111487f786SFrançois Tigeot ctx->ring_size = 4 * PAGE_SIZE;
312a85cb24fSFrançois Tigeot ctx->desc_template =
313a85cb24fSFrançois Tigeot default_desc_template(dev_priv, dev_priv->mm.aliasing_ppgtt);
314a85cb24fSFrançois Tigeot
315a85cb24fSFrançois Tigeot /* GuC requires the ring to be placed above GUC_WOPCM_TOP. If GuC is not
316a85cb24fSFrançois Tigeot * present or not in use we still need a small bias as ring wraparound
317a85cb24fSFrançois Tigeot * at offset 0 sometimes hangs. No idea why.
318a85cb24fSFrançois Tigeot */
319*3f2dd94aSFrançois Tigeot if (HAS_GUC(dev_priv) && i915_modparams.enable_guc_loading)
320a85cb24fSFrançois Tigeot ctx->ggtt_offset_bias = GUC_WOPCM_TOP;
321a85cb24fSFrançois Tigeot else
322a85cb24fSFrançois Tigeot ctx->ggtt_offset_bias = I915_GTT_PAGE_SIZE;
3232c9916cdSFrançois Tigeot
324e555d299SFrançois Tigeot return ctx;
325e555d299SFrançois Tigeot
3264be47400SFrançois Tigeot err_pid:
3274be47400SFrançois Tigeot put_pid(ctx->pid);
3284be47400SFrançois Tigeot idr_remove(&file_priv->context_idr, ctx->user_handle);
329*3f2dd94aSFrançois Tigeot err_lut:
33071f41f3eSFrançois Tigeot context_close(ctx);
331e555d299SFrançois Tigeot return ERR_PTR(ret);
332e555d299SFrançois Tigeot }
333e555d299SFrançois Tigeot
__destroy_hw_context(struct i915_gem_context * ctx,struct drm_i915_file_private * file_priv)334a85cb24fSFrançois Tigeot static void __destroy_hw_context(struct i915_gem_context *ctx,
335a85cb24fSFrançois Tigeot struct drm_i915_file_private *file_priv)
336a85cb24fSFrançois Tigeot {
337a85cb24fSFrançois Tigeot idr_remove(&file_priv->context_idr, ctx->user_handle);
338a85cb24fSFrançois Tigeot context_close(ctx);
339a85cb24fSFrançois Tigeot }
340a85cb24fSFrançois Tigeot
341e555d299SFrançois Tigeot /**
342e555d299SFrançois Tigeot * The default context needs to exist per ring that uses contexts. It stores the
343e555d299SFrançois Tigeot * context state of the GPU for applications that don't utilize HW contexts, as
344e555d299SFrançois Tigeot * well as an idle case.
345e555d299SFrançois Tigeot */
3461487f786SFrançois Tigeot static struct i915_gem_context *
i915_gem_create_context(struct drm_i915_private * dev_priv,struct drm_i915_file_private * file_priv)347a85cb24fSFrançois Tigeot i915_gem_create_context(struct drm_i915_private *dev_priv,
3481b13d190SFrançois Tigeot struct drm_i915_file_private *file_priv)
349e555d299SFrançois Tigeot {
3501487f786SFrançois Tigeot struct i915_gem_context *ctx;
351e555d299SFrançois Tigeot
352a85cb24fSFrançois Tigeot lockdep_assert_held(&dev_priv->drm.struct_mutex);
353e555d299SFrançois Tigeot
354*3f2dd94aSFrançois Tigeot /* Reap the most stale context */
355*3f2dd94aSFrançois Tigeot contexts_free_first(dev_priv);
356*3f2dd94aSFrançois Tigeot
357a85cb24fSFrançois Tigeot ctx = __create_hw_context(dev_priv, file_priv);
358e555d299SFrançois Tigeot if (IS_ERR(ctx))
359ba55f2f5SFrançois Tigeot return ctx;
360e555d299SFrançois Tigeot
361a85cb24fSFrançois Tigeot if (USES_FULL_PPGTT(dev_priv)) {
3624be47400SFrançois Tigeot struct i915_hw_ppgtt *ppgtt;
363ba55f2f5SFrançois Tigeot
364a85cb24fSFrançois Tigeot ppgtt = i915_ppgtt_create(dev_priv, file_priv, ctx->name);
3651487f786SFrançois Tigeot if (IS_ERR(ppgtt)) {
366ba55f2f5SFrançois Tigeot DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n",
367ba55f2f5SFrançois Tigeot PTR_ERR(ppgtt));
368a85cb24fSFrançois Tigeot __destroy_hw_context(ctx, file_priv);
3691487f786SFrançois Tigeot return ERR_CAST(ppgtt);
3705d0b1887SFrançois Tigeot }
371e555d299SFrançois Tigeot
3721b13d190SFrançois Tigeot ctx->ppgtt = ppgtt;
373a85cb24fSFrançois Tigeot ctx->desc_template = default_desc_template(dev_priv, ppgtt);
374ba55f2f5SFrançois Tigeot }
3759edbd4a0SFrançois Tigeot
3762c9916cdSFrançois Tigeot trace_i915_context_create(ctx);
3772c9916cdSFrançois Tigeot
378ba55f2f5SFrançois Tigeot return ctx;
379ba55f2f5SFrançois Tigeot }
380ba55f2f5SFrançois Tigeot
3811487f786SFrançois Tigeot /**
3821487f786SFrançois Tigeot * i915_gem_context_create_gvt - create a GVT GEM context
3831487f786SFrançois Tigeot * @dev: drm device *
3841487f786SFrançois Tigeot *
3851487f786SFrançois Tigeot * This function is used to create a GVT specific GEM context.
3861487f786SFrançois Tigeot *
3871487f786SFrançois Tigeot * Returns:
3881487f786SFrançois Tigeot * pointer to i915_gem_context on success, error pointer if failed
3891487f786SFrançois Tigeot *
3901487f786SFrançois Tigeot */
3911487f786SFrançois Tigeot struct i915_gem_context *
i915_gem_context_create_gvt(struct drm_device * dev)3921487f786SFrançois Tigeot i915_gem_context_create_gvt(struct drm_device *dev)
3931487f786SFrançois Tigeot {
3941487f786SFrançois Tigeot struct i915_gem_context *ctx;
3951487f786SFrançois Tigeot int ret;
3961487f786SFrançois Tigeot
3971487f786SFrançois Tigeot if (!IS_ENABLED(CONFIG_DRM_I915_GVT))
3981487f786SFrançois Tigeot return ERR_PTR(-ENODEV);
3991487f786SFrançois Tigeot
4001487f786SFrançois Tigeot ret = i915_mutex_lock_interruptible(dev);
4011487f786SFrançois Tigeot if (ret)
4021487f786SFrançois Tigeot return ERR_PTR(ret);
4031487f786SFrançois Tigeot
404a85cb24fSFrançois Tigeot ctx = __create_hw_context(to_i915(dev), NULL);
4051487f786SFrançois Tigeot if (IS_ERR(ctx))
4061487f786SFrançois Tigeot goto out;
4071487f786SFrançois Tigeot
408a85cb24fSFrançois Tigeot ctx->file_priv = ERR_PTR(-EBADF);
409a85cb24fSFrançois Tigeot i915_gem_context_set_closed(ctx); /* not user accessible */
410a85cb24fSFrançois Tigeot i915_gem_context_clear_bannable(ctx);
411a85cb24fSFrançois Tigeot i915_gem_context_set_force_single_submission(ctx);
412*3f2dd94aSFrançois Tigeot if (!i915_modparams.enable_guc_submission)
4131487f786SFrançois Tigeot ctx->ring_size = 512 * PAGE_SIZE; /* Max ring buffer size */
414a85cb24fSFrançois Tigeot
415a85cb24fSFrançois Tigeot GEM_BUG_ON(i915_gem_context_is_kernel(ctx));
4161487f786SFrançois Tigeot out:
4171487f786SFrançois Tigeot mutex_unlock(&dev->struct_mutex);
4181487f786SFrançois Tigeot return ctx;
4191487f786SFrançois Tigeot }
4201487f786SFrançois Tigeot
421*3f2dd94aSFrançois Tigeot static struct i915_gem_context *
create_kernel_context(struct drm_i915_private * i915,int prio)422*3f2dd94aSFrançois Tigeot create_kernel_context(struct drm_i915_private *i915, int prio)
423c0e85e96SFrançois Tigeot {
4241487f786SFrançois Tigeot struct i915_gem_context *ctx;
425e555d299SFrançois Tigeot
426*3f2dd94aSFrançois Tigeot ctx = i915_gem_create_context(i915, NULL);
427*3f2dd94aSFrançois Tigeot if (IS_ERR(ctx))
428*3f2dd94aSFrançois Tigeot return ctx;
429*3f2dd94aSFrançois Tigeot
430*3f2dd94aSFrançois Tigeot i915_gem_context_clear_bannable(ctx);
431*3f2dd94aSFrançois Tigeot ctx->priority = prio;
432*3f2dd94aSFrançois Tigeot ctx->ring_size = PAGE_SIZE;
433*3f2dd94aSFrançois Tigeot
434*3f2dd94aSFrançois Tigeot GEM_BUG_ON(!i915_gem_context_is_kernel(ctx));
435*3f2dd94aSFrançois Tigeot
436*3f2dd94aSFrançois Tigeot return ctx;
437*3f2dd94aSFrançois Tigeot }
438*3f2dd94aSFrançois Tigeot
439*3f2dd94aSFrançois Tigeot static void
destroy_kernel_context(struct i915_gem_context ** ctxp)440*3f2dd94aSFrançois Tigeot destroy_kernel_context(struct i915_gem_context **ctxp)
441*3f2dd94aSFrançois Tigeot {
442*3f2dd94aSFrançois Tigeot struct i915_gem_context *ctx;
443*3f2dd94aSFrançois Tigeot
444*3f2dd94aSFrançois Tigeot /* Keep the context ref so that we can free it immediately ourselves */
445*3f2dd94aSFrançois Tigeot ctx = i915_gem_context_get(fetch_and_zero(ctxp));
446*3f2dd94aSFrançois Tigeot GEM_BUG_ON(!i915_gem_context_is_kernel(ctx));
447*3f2dd94aSFrançois Tigeot
448*3f2dd94aSFrançois Tigeot context_close(ctx);
449*3f2dd94aSFrançois Tigeot i915_gem_context_free(ctx);
450*3f2dd94aSFrançois Tigeot }
451*3f2dd94aSFrançois Tigeot
i915_gem_contexts_init(struct drm_i915_private * dev_priv)452*3f2dd94aSFrançois Tigeot int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
453*3f2dd94aSFrançois Tigeot {
454*3f2dd94aSFrançois Tigeot struct i915_gem_context *ctx;
455*3f2dd94aSFrançois Tigeot int err;
456*3f2dd94aSFrançois Tigeot
457*3f2dd94aSFrançois Tigeot GEM_BUG_ON(dev_priv->kernel_context);
458*3f2dd94aSFrançois Tigeot
459*3f2dd94aSFrançois Tigeot INIT_LIST_HEAD(&dev_priv->contexts.list);
460*3f2dd94aSFrançois Tigeot INIT_WORK(&dev_priv->contexts.free_work, contexts_free_worker);
461*3f2dd94aSFrançois Tigeot init_llist_head(&dev_priv->contexts.free_list);
462e555d299SFrançois Tigeot
4631487f786SFrançois Tigeot if (intel_vgpu_active(dev_priv) &&
4641487f786SFrançois Tigeot HAS_LOGICAL_RING_CONTEXTS(dev_priv)) {
465*3f2dd94aSFrançois Tigeot if (!i915_modparams.enable_execlists) {
466352ff8bdSFrançois Tigeot DRM_INFO("Only EXECLIST mode is supported in vgpu.\n");
467352ff8bdSFrançois Tigeot return -EINVAL;
468352ff8bdSFrançois Tigeot }
469352ff8bdSFrançois Tigeot }
470352ff8bdSFrançois Tigeot
4711487f786SFrançois Tigeot /* Using the simple ida interface, the max is limited by sizeof(int) */
4721487f786SFrançois Tigeot BUILD_BUG_ON(MAX_CONTEXT_HW_ID > INT_MAX);
473*3f2dd94aSFrançois Tigeot ida_init(&dev_priv->contexts.hw_ida);
4741487f786SFrançois Tigeot
475*3f2dd94aSFrançois Tigeot /* lowest priority; idle task */
476*3f2dd94aSFrançois Tigeot ctx = create_kernel_context(dev_priv, I915_PRIORITY_MIN);
477ba55f2f5SFrançois Tigeot if (IS_ERR(ctx)) {
478*3f2dd94aSFrançois Tigeot DRM_ERROR("Failed to create default global context\n");
479*3f2dd94aSFrançois Tigeot err = PTR_ERR(ctx);
480*3f2dd94aSFrançois Tigeot goto err;
481e555d299SFrançois Tigeot }
482*3f2dd94aSFrançois Tigeot /*
483*3f2dd94aSFrançois Tigeot * For easy recognisablity, we want the kernel context to be 0 and then
484a85cb24fSFrançois Tigeot * all user contexts will have non-zero hw_id.
485a85cb24fSFrançois Tigeot */
486a85cb24fSFrançois Tigeot GEM_BUG_ON(ctx->hw_id);
487c0e85e96SFrançois Tigeot dev_priv->kernel_context = ctx;
4881b13d190SFrançois Tigeot
489*3f2dd94aSFrançois Tigeot /* highest priority; preempting task */
490*3f2dd94aSFrançois Tigeot ctx = create_kernel_context(dev_priv, INT_MAX);
491*3f2dd94aSFrançois Tigeot if (IS_ERR(ctx)) {
492*3f2dd94aSFrançois Tigeot DRM_ERROR("Failed to create default preempt context\n");
493*3f2dd94aSFrançois Tigeot err = PTR_ERR(ctx);
494*3f2dd94aSFrançois Tigeot goto err_kernel_context;
495*3f2dd94aSFrançois Tigeot }
496*3f2dd94aSFrançois Tigeot dev_priv->preempt_context = ctx;
497a85cb24fSFrançois Tigeot
4981b13d190SFrançois Tigeot DRM_DEBUG_DRIVER("%s context support initialized\n",
499*3f2dd94aSFrançois Tigeot dev_priv->engine[RCS]->context_size ? "logical" :
500*3f2dd94aSFrançois Tigeot "fake");
5019edbd4a0SFrançois Tigeot return 0;
502*3f2dd94aSFrançois Tigeot
503*3f2dd94aSFrançois Tigeot err_kernel_context:
504*3f2dd94aSFrançois Tigeot destroy_kernel_context(&dev_priv->kernel_context);
505*3f2dd94aSFrançois Tigeot err:
506*3f2dd94aSFrançois Tigeot return err;
507e555d299SFrançois Tigeot }
508e555d299SFrançois Tigeot
i915_gem_contexts_lost(struct drm_i915_private * dev_priv)509*3f2dd94aSFrançois Tigeot void i915_gem_contexts_lost(struct drm_i915_private *dev_priv)
510e555d299SFrançois Tigeot {
5111487f786SFrançois Tigeot struct intel_engine_cs *engine;
5121e12ee3bSFrançois Tigeot enum intel_engine_id id;
513e555d299SFrançois Tigeot
514303bf270SFrançois Tigeot lockdep_assert_held(&dev_priv->drm.struct_mutex);
515e555d299SFrançois Tigeot
5161e12ee3bSFrançois Tigeot for_each_engine(engine, dev_priv, id) {
517a85cb24fSFrançois Tigeot engine->legacy_active_context = NULL;
518a85cb24fSFrançois Tigeot
519a85cb24fSFrançois Tigeot if (!engine->last_retired_context)
520a85cb24fSFrançois Tigeot continue;
521a85cb24fSFrançois Tigeot
522a85cb24fSFrançois Tigeot engine->context_unpin(engine, engine->last_retired_context);
523a85cb24fSFrançois Tigeot engine->last_retired_context = NULL;
524c0e85e96SFrançois Tigeot }
525ba55f2f5SFrançois Tigeot
5261487f786SFrançois Tigeot /* Force the GPU state to be restored on enabling */
527*3f2dd94aSFrançois Tigeot if (!i915_modparams.enable_execlists) {
5281487f786SFrançois Tigeot struct i915_gem_context *ctx;
5291487f786SFrançois Tigeot
530*3f2dd94aSFrançois Tigeot list_for_each_entry(ctx, &dev_priv->contexts.list, link) {
5311487f786SFrançois Tigeot if (!i915_gem_context_is_default(ctx))
5321487f786SFrançois Tigeot continue;
5331487f786SFrançois Tigeot
5341e12ee3bSFrançois Tigeot for_each_engine(engine, dev_priv, id)
5351487f786SFrançois Tigeot ctx->engine[engine->id].initialised = false;
5361487f786SFrançois Tigeot
5371487f786SFrançois Tigeot ctx->remap_slice = ALL_L3_SLICES(dev_priv);
5381487f786SFrançois Tigeot }
5391487f786SFrançois Tigeot
5401e12ee3bSFrançois Tigeot for_each_engine(engine, dev_priv, id) {
5411487f786SFrançois Tigeot struct intel_context *kce =
5421487f786SFrançois Tigeot &dev_priv->kernel_context->engine[engine->id];
5431487f786SFrançois Tigeot
5441487f786SFrançois Tigeot kce->initialised = true;
5451487f786SFrançois Tigeot }
5461487f786SFrançois Tigeot }
5471487f786SFrançois Tigeot }
5481487f786SFrançois Tigeot
i915_gem_contexts_fini(struct drm_i915_private * i915)549*3f2dd94aSFrançois Tigeot void i915_gem_contexts_fini(struct drm_i915_private *i915)
5501487f786SFrançois Tigeot {
551*3f2dd94aSFrançois Tigeot lockdep_assert_held(&i915->drm.struct_mutex);
5521487f786SFrançois Tigeot
553*3f2dd94aSFrançois Tigeot destroy_kernel_context(&i915->preempt_context);
554*3f2dd94aSFrançois Tigeot destroy_kernel_context(&i915->kernel_context);
555a85cb24fSFrançois Tigeot
556*3f2dd94aSFrançois Tigeot /* Must free all deferred contexts (via flush_workqueue) first */
557*3f2dd94aSFrançois Tigeot ida_destroy(&i915->contexts.hw_ida);
5589edbd4a0SFrançois Tigeot }
5599edbd4a0SFrançois Tigeot
context_idr_cleanup(int id,void * p,void * data)560e555d299SFrançois Tigeot static int context_idr_cleanup(int id, void *p, void *data)
561e555d299SFrançois Tigeot {
5621487f786SFrançois Tigeot struct i915_gem_context *ctx = p;
563e555d299SFrançois Tigeot
56471f41f3eSFrançois Tigeot context_close(ctx);
565e555d299SFrançois Tigeot return 0;
566e555d299SFrançois Tigeot }
567e555d299SFrançois Tigeot
i915_gem_context_open(struct drm_i915_private * i915,struct drm_file * file)568*3f2dd94aSFrançois Tigeot int i915_gem_context_open(struct drm_i915_private *i915,
569*3f2dd94aSFrançois Tigeot struct drm_file *file)
5705d0b1887SFrançois Tigeot {
5715d0b1887SFrançois Tigeot struct drm_i915_file_private *file_priv = file->driver_priv;
5721487f786SFrançois Tigeot struct i915_gem_context *ctx;
5735d0b1887SFrançois Tigeot
574ba55f2f5SFrançois Tigeot idr_init(&file_priv->context_idr);
5755d0b1887SFrançois Tigeot
576*3f2dd94aSFrançois Tigeot mutex_lock(&i915->drm.struct_mutex);
577*3f2dd94aSFrançois Tigeot ctx = i915_gem_create_context(i915, file_priv);
578*3f2dd94aSFrançois Tigeot mutex_unlock(&i915->drm.struct_mutex);
579ba55f2f5SFrançois Tigeot if (IS_ERR(ctx)) {
580ba55f2f5SFrançois Tigeot idr_destroy(&file_priv->context_idr);
581ba55f2f5SFrançois Tigeot return PTR_ERR(ctx);
582ba55f2f5SFrançois Tigeot }
5839edbd4a0SFrançois Tigeot
584*3f2dd94aSFrançois Tigeot GEM_BUG_ON(i915_gem_context_is_kernel(ctx));
585*3f2dd94aSFrançois Tigeot
586ba55f2f5SFrançois Tigeot return 0;
5875d0b1887SFrançois Tigeot }
5885d0b1887SFrançois Tigeot
i915_gem_context_close(struct drm_file * file)589*3f2dd94aSFrançois Tigeot void i915_gem_context_close(struct drm_file *file)
590e555d299SFrançois Tigeot {
591e555d299SFrançois Tigeot struct drm_i915_file_private *file_priv = file->driver_priv;
592e555d299SFrançois Tigeot
593*3f2dd94aSFrançois Tigeot lockdep_assert_held(&file_priv->dev_priv->drm.struct_mutex);
5941487f786SFrançois Tigeot
595e555d299SFrançois Tigeot idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL);
596e555d299SFrançois Tigeot idr_destroy(&file_priv->context_idr);
597e555d299SFrançois Tigeot }
598e555d299SFrançois Tigeot
599e555d299SFrançois Tigeot static inline int
mi_set_context(struct drm_i915_gem_request * req,u32 flags)600a85cb24fSFrançois Tigeot mi_set_context(struct drm_i915_gem_request *req, u32 flags)
601e555d299SFrançois Tigeot {
6021487f786SFrançois Tigeot struct drm_i915_private *dev_priv = req->i915;
6038621f407SFrançois Tigeot struct intel_engine_cs *engine = req->engine;
6041e12ee3bSFrançois Tigeot enum intel_engine_id id;
6050dbf0ea8SMatthew Dillon const int num_rings =
606a85cb24fSFrançois Tigeot /* Use an extended w/a on gen7 if signalling from other rings */
607*3f2dd94aSFrançois Tigeot (i915_modparams.semaphores && INTEL_GEN(dev_priv) == 7) ?
6081e12ee3bSFrançois Tigeot INTEL_INFO(dev_priv)->num_rings - 1 :
6090dbf0ea8SMatthew Dillon 0;
610a85cb24fSFrançois Tigeot int len;
611a85cb24fSFrançois Tigeot u32 *cs;
612e555d299SFrançois Tigeot
613a85cb24fSFrançois Tigeot flags |= MI_MM_SPACE_GTT;
6141487f786SFrançois Tigeot if (IS_HASWELL(dev_priv) || INTEL_GEN(dev_priv) >= 8)
615a85cb24fSFrançois Tigeot /* These flags are for resource streamer on HSW+ */
616a85cb24fSFrançois Tigeot flags |= HSW_MI_RS_SAVE_STATE_EN | HSW_MI_RS_RESTORE_STATE_EN;
617a85cb24fSFrançois Tigeot else
618a85cb24fSFrançois Tigeot flags |= MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN;
6192c9916cdSFrançois Tigeot
6200dbf0ea8SMatthew Dillon len = 4;
6211487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 7)
6228621f407SFrançois Tigeot len += 2 + (num_rings ? 4*num_rings + 6 : 0);
6230dbf0ea8SMatthew Dillon
624a85cb24fSFrançois Tigeot cs = intel_ring_begin(req, len);
625a85cb24fSFrançois Tigeot if (IS_ERR(cs))
626a85cb24fSFrançois Tigeot return PTR_ERR(cs);
627e555d299SFrançois Tigeot
628ba55f2f5SFrançois Tigeot /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */
6291487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 7) {
630a85cb24fSFrançois Tigeot *cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
6310dbf0ea8SMatthew Dillon if (num_rings) {
6320dbf0ea8SMatthew Dillon struct intel_engine_cs *signaller;
6330dbf0ea8SMatthew Dillon
634a85cb24fSFrançois Tigeot *cs++ = MI_LOAD_REGISTER_IMM(num_rings);
6351e12ee3bSFrançois Tigeot for_each_engine(signaller, dev_priv, id) {
6368621f407SFrançois Tigeot if (signaller == engine)
6370dbf0ea8SMatthew Dillon continue;
6380dbf0ea8SMatthew Dillon
639a85cb24fSFrançois Tigeot *cs++ = i915_mmio_reg_offset(
6408621f407SFrançois Tigeot RING_PSMI_CTL(signaller->mmio_base));
641a85cb24fSFrançois Tigeot *cs++ = _MASKED_BIT_ENABLE(
642a85cb24fSFrançois Tigeot GEN6_PSMI_SLEEP_MSG_DISABLE);
6430dbf0ea8SMatthew Dillon }
6440dbf0ea8SMatthew Dillon }
6450dbf0ea8SMatthew Dillon }
646e555d299SFrançois Tigeot
647a85cb24fSFrançois Tigeot *cs++ = MI_NOOP;
648a85cb24fSFrançois Tigeot *cs++ = MI_SET_CONTEXT;
649a85cb24fSFrançois Tigeot *cs++ = i915_ggtt_offset(req->ctx->engine[RCS].state) | flags;
650ba55f2f5SFrançois Tigeot /*
651ba55f2f5SFrançois Tigeot * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
652ba55f2f5SFrançois Tigeot * WaMiSetContext_Hang:snb,ivb,vlv
653ba55f2f5SFrançois Tigeot */
654a85cb24fSFrançois Tigeot *cs++ = MI_NOOP;
655e555d299SFrançois Tigeot
6561487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 7) {
6570dbf0ea8SMatthew Dillon if (num_rings) {
6580dbf0ea8SMatthew Dillon struct intel_engine_cs *signaller;
6598621f407SFrançois Tigeot i915_reg_t last_reg = {}; /* keep gcc quiet */
6600dbf0ea8SMatthew Dillon
661a85cb24fSFrançois Tigeot *cs++ = MI_LOAD_REGISTER_IMM(num_rings);
6621e12ee3bSFrançois Tigeot for_each_engine(signaller, dev_priv, id) {
6638621f407SFrançois Tigeot if (signaller == engine)
6640dbf0ea8SMatthew Dillon continue;
6650dbf0ea8SMatthew Dillon
6668621f407SFrançois Tigeot last_reg = RING_PSMI_CTL(signaller->mmio_base);
667a85cb24fSFrançois Tigeot *cs++ = i915_mmio_reg_offset(last_reg);
668a85cb24fSFrançois Tigeot *cs++ = _MASKED_BIT_DISABLE(
669a85cb24fSFrançois Tigeot GEN6_PSMI_SLEEP_MSG_DISABLE);
6700dbf0ea8SMatthew Dillon }
671e555d299SFrançois Tigeot
6728621f407SFrançois Tigeot /* Insert a delay before the next switch! */
673a85cb24fSFrançois Tigeot *cs++ = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT;
674a85cb24fSFrançois Tigeot *cs++ = i915_mmio_reg_offset(last_reg);
675a85cb24fSFrançois Tigeot *cs++ = i915_ggtt_offset(engine->scratch);
676a85cb24fSFrançois Tigeot *cs++ = MI_NOOP;
6778621f407SFrançois Tigeot }
678a85cb24fSFrançois Tigeot *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
6798621f407SFrançois Tigeot }
6808621f407SFrançois Tigeot
681a85cb24fSFrançois Tigeot intel_ring_advance(req, cs);
682e555d299SFrançois Tigeot
683a85cb24fSFrançois Tigeot return 0;
684e555d299SFrançois Tigeot }
685e555d299SFrançois Tigeot
remap_l3(struct drm_i915_gem_request * req,int slice)6861487f786SFrançois Tigeot static int remap_l3(struct drm_i915_gem_request *req, int slice)
6871487f786SFrançois Tigeot {
688a85cb24fSFrançois Tigeot u32 *cs, *remap_info = req->i915->l3_parity.remap_info[slice];
689a85cb24fSFrançois Tigeot int i;
6901487f786SFrançois Tigeot
6911487f786SFrançois Tigeot if (!remap_info)
6921487f786SFrançois Tigeot return 0;
6931487f786SFrançois Tigeot
694a85cb24fSFrançois Tigeot cs = intel_ring_begin(req, GEN7_L3LOG_SIZE/4 * 2 + 2);
695a85cb24fSFrançois Tigeot if (IS_ERR(cs))
696a85cb24fSFrançois Tigeot return PTR_ERR(cs);
6971487f786SFrançois Tigeot
6981487f786SFrançois Tigeot /*
6991487f786SFrançois Tigeot * Note: We do not worry about the concurrent register cacheline hang
7001487f786SFrançois Tigeot * here because no other code should access these registers other than
7011487f786SFrançois Tigeot * at initialization time.
7021487f786SFrançois Tigeot */
703a85cb24fSFrançois Tigeot *cs++ = MI_LOAD_REGISTER_IMM(GEN7_L3LOG_SIZE/4);
7041487f786SFrançois Tigeot for (i = 0; i < GEN7_L3LOG_SIZE/4; i++) {
705a85cb24fSFrançois Tigeot *cs++ = i915_mmio_reg_offset(GEN7_L3LOG(slice, i));
706a85cb24fSFrançois Tigeot *cs++ = remap_info[i];
7071487f786SFrançois Tigeot }
708a85cb24fSFrançois Tigeot *cs++ = MI_NOOP;
709a85cb24fSFrançois Tigeot intel_ring_advance(req, cs);
7101487f786SFrançois Tigeot
7111487f786SFrançois Tigeot return 0;
7121487f786SFrançois Tigeot }
7131487f786SFrançois Tigeot
skip_rcs_switch(struct i915_hw_ppgtt * ppgtt,struct intel_engine_cs * engine,struct i915_gem_context * to)7141487f786SFrançois Tigeot static inline bool skip_rcs_switch(struct i915_hw_ppgtt *ppgtt,
7151487f786SFrançois Tigeot struct intel_engine_cs *engine,
7161487f786SFrançois Tigeot struct i915_gem_context *to)
717477eb7f9SFrançois Tigeot {
718477eb7f9SFrançois Tigeot if (to->remap_slice)
719477eb7f9SFrançois Tigeot return false;
720477eb7f9SFrançois Tigeot
7211487f786SFrançois Tigeot if (!to->engine[RCS].initialised)
7228621f407SFrançois Tigeot return false;
7238621f407SFrançois Tigeot
7241487f786SFrançois Tigeot if (ppgtt && (intel_engine_flag(engine) & ppgtt->pd_dirty_rings))
7258621f407SFrançois Tigeot return false;
7268621f407SFrançois Tigeot
727a85cb24fSFrançois Tigeot return to == engine->legacy_active_context;
7288621f407SFrançois Tigeot }
7298621f407SFrançois Tigeot
7308621f407SFrançois Tigeot static bool
needs_pd_load_pre(struct i915_hw_ppgtt * ppgtt,struct intel_engine_cs * engine)731*3f2dd94aSFrançois Tigeot needs_pd_load_pre(struct i915_hw_ppgtt *ppgtt, struct intel_engine_cs *engine)
7328621f407SFrançois Tigeot {
733*3f2dd94aSFrançois Tigeot struct i915_gem_context *from = engine->legacy_active_context;
734*3f2dd94aSFrançois Tigeot
7351487f786SFrançois Tigeot if (!ppgtt)
7368621f407SFrançois Tigeot return false;
7378621f407SFrançois Tigeot
7381487f786SFrançois Tigeot /* Always load the ppgtt on first use */
739*3f2dd94aSFrançois Tigeot if (!from)
7401487f786SFrançois Tigeot return true;
7411487f786SFrançois Tigeot
7421487f786SFrançois Tigeot /* Same context without new entries, skip */
743*3f2dd94aSFrançois Tigeot if ((!from->ppgtt || from->ppgtt == ppgtt) &&
7441487f786SFrançois Tigeot !(intel_engine_flag(engine) & ppgtt->pd_dirty_rings))
7458621f407SFrançois Tigeot return false;
7468621f407SFrançois Tigeot
7478621f407SFrançois Tigeot if (engine->id != RCS)
7488621f407SFrançois Tigeot return true;
7498621f407SFrançois Tigeot
7501487f786SFrançois Tigeot if (INTEL_GEN(engine->i915) < 8)
751477eb7f9SFrançois Tigeot return true;
752477eb7f9SFrançois Tigeot
753477eb7f9SFrançois Tigeot return false;
754477eb7f9SFrançois Tigeot }
755477eb7f9SFrançois Tigeot
756477eb7f9SFrançois Tigeot static bool
needs_pd_load_post(struct i915_hw_ppgtt * ppgtt,struct i915_gem_context * to,u32 hw_flags)7571487f786SFrançois Tigeot needs_pd_load_post(struct i915_hw_ppgtt *ppgtt,
7581487f786SFrançois Tigeot struct i915_gem_context *to,
7591487f786SFrançois Tigeot u32 hw_flags)
760477eb7f9SFrançois Tigeot {
7611487f786SFrançois Tigeot if (!ppgtt)
762477eb7f9SFrançois Tigeot return false;
763477eb7f9SFrançois Tigeot
7648621f407SFrançois Tigeot if (!IS_GEN8(to->i915))
765477eb7f9SFrançois Tigeot return false;
766477eb7f9SFrançois Tigeot
767477eb7f9SFrançois Tigeot if (hw_flags & MI_RESTORE_INHIBIT)
768477eb7f9SFrançois Tigeot return true;
769477eb7f9SFrançois Tigeot
770477eb7f9SFrançois Tigeot return false;
771477eb7f9SFrançois Tigeot }
772477eb7f9SFrançois Tigeot
do_rcs_switch(struct drm_i915_gem_request * req)7738621f407SFrançois Tigeot static int do_rcs_switch(struct drm_i915_gem_request *req)
774e555d299SFrançois Tigeot {
7751487f786SFrançois Tigeot struct i915_gem_context *to = req->ctx;
7768621f407SFrançois Tigeot struct intel_engine_cs *engine = req->engine;
7771487f786SFrançois Tigeot struct i915_hw_ppgtt *ppgtt = to->ppgtt ?: req->i915->mm.aliasing_ppgtt;
778a85cb24fSFrançois Tigeot struct i915_gem_context *from = engine->legacy_active_context;
7798621f407SFrançois Tigeot u32 hw_flags;
7809edbd4a0SFrançois Tigeot int ret, i;
781e555d299SFrançois Tigeot
782a85cb24fSFrançois Tigeot GEM_BUG_ON(engine->id != RCS);
783a85cb24fSFrançois Tigeot
7841487f786SFrançois Tigeot if (skip_rcs_switch(ppgtt, engine, to))
785e555d299SFrançois Tigeot return 0;
786e555d299SFrançois Tigeot
787*3f2dd94aSFrançois Tigeot if (needs_pd_load_pre(ppgtt, engine)) {
7888621f407SFrançois Tigeot /* Older GENs and non render rings still want the load first,
7898621f407SFrançois Tigeot * "PP_DCLV followed by PP_DIR_BASE register through Load
7908621f407SFrançois Tigeot * Register Immediate commands in Ring Buffer before submitting
7918621f407SFrançois Tigeot * a context."*/
7928621f407SFrançois Tigeot trace_switch_mm(engine, to);
7931487f786SFrançois Tigeot ret = ppgtt->switch_mm(ppgtt, req);
7948621f407SFrançois Tigeot if (ret)
795a85cb24fSFrançois Tigeot return ret;
7968621f407SFrançois Tigeot }
7978621f407SFrançois Tigeot
7981487f786SFrançois Tigeot if (!to->engine[RCS].initialised || i915_gem_context_is_default(to))
799477eb7f9SFrançois Tigeot /* NB: If we inhibit the restore, the context is not allowed to
800477eb7f9SFrançois Tigeot * die because future work may end up depending on valid address
801477eb7f9SFrançois Tigeot * space. This means we must enforce that a page table load
802477eb7f9SFrançois Tigeot * occur when this occurs. */
8038621f407SFrançois Tigeot hw_flags = MI_RESTORE_INHIBIT;
8041487f786SFrançois Tigeot else if (ppgtt && intel_engine_flag(engine) & ppgtt->pd_dirty_rings)
8058621f407SFrançois Tigeot hw_flags = MI_FORCE_RESTORE;
8068621f407SFrançois Tigeot else
8078621f407SFrançois Tigeot hw_flags = 0;
808477eb7f9SFrançois Tigeot
8098621f407SFrançois Tigeot if (to != from || (hw_flags & MI_FORCE_RESTORE)) {
810a05eeebfSFrançois Tigeot ret = mi_set_context(req, hw_flags);
811ba55f2f5SFrançois Tigeot if (ret)
812a85cb24fSFrançois Tigeot return ret;
8139edbd4a0SFrançois Tigeot
814a85cb24fSFrançois Tigeot engine->legacy_active_context = to;
8155d0b1887SFrançois Tigeot }
816ba55f2f5SFrançois Tigeot
8178621f407SFrançois Tigeot /* GEN8 does *not* require an explicit reload if the PDPs have been
8188621f407SFrançois Tigeot * setup, and we do not wish to move them.
8198621f407SFrançois Tigeot */
8201487f786SFrançois Tigeot if (needs_pd_load_post(ppgtt, to, hw_flags)) {
8218621f407SFrançois Tigeot trace_switch_mm(engine, to);
8221487f786SFrançois Tigeot ret = ppgtt->switch_mm(ppgtt, req);
8238621f407SFrançois Tigeot /* The hardware context switch is emitted, but we haven't
8248621f407SFrançois Tigeot * actually changed the state - so it's probably safe to bail
8258621f407SFrançois Tigeot * here. Still, let the user know something dangerous has
8268621f407SFrançois Tigeot * happened.
8278621f407SFrançois Tigeot */
8281b13d190SFrançois Tigeot if (ret)
8298621f407SFrançois Tigeot return ret;
8301b13d190SFrançois Tigeot }
8318621f407SFrançois Tigeot
8321487f786SFrançois Tigeot if (ppgtt)
8331487f786SFrançois Tigeot ppgtt->pd_dirty_rings &= ~intel_engine_flag(engine);
8348621f407SFrançois Tigeot
8358621f407SFrançois Tigeot for (i = 0; i < MAX_L3_SLICES; i++) {
8368621f407SFrançois Tigeot if (!(to->remap_slice & (1<<i)))
8378621f407SFrançois Tigeot continue;
8388621f407SFrançois Tigeot
8391487f786SFrançois Tigeot ret = remap_l3(req, i);
8408621f407SFrançois Tigeot if (ret)
8418621f407SFrançois Tigeot return ret;
8428621f407SFrançois Tigeot
8438621f407SFrançois Tigeot to->remap_slice &= ~(1<<i);
8448621f407SFrançois Tigeot }
8458621f407SFrançois Tigeot
8461487f786SFrançois Tigeot if (!to->engine[RCS].initialised) {
8478621f407SFrançois Tigeot if (engine->init_context) {
8488621f407SFrançois Tigeot ret = engine->init_context(req);
8498621f407SFrançois Tigeot if (ret)
8508621f407SFrançois Tigeot return ret;
8518621f407SFrançois Tigeot }
8521487f786SFrançois Tigeot to->engine[RCS].initialised = true;
853ba55f2f5SFrançois Tigeot }
854ba55f2f5SFrançois Tigeot
855e555d299SFrançois Tigeot return 0;
856e555d299SFrançois Tigeot }
857e555d299SFrançois Tigeot
858e555d299SFrançois Tigeot /**
859e555d299SFrançois Tigeot * i915_switch_context() - perform a GPU context switch.
860a05eeebfSFrançois Tigeot * @req: request for which we'll execute the context switch
861e555d299SFrançois Tigeot *
862e555d299SFrançois Tigeot * The context life cycle is simple. The context refcount is incremented and
863e555d299SFrançois Tigeot * decremented by 1 and create and destroy. If the context is in use by the GPU,
8641b13d190SFrançois Tigeot * it will have a refcount > 1. This allows us to destroy the context abstract
865e555d299SFrançois Tigeot * object while letting the normal object tracking destroy the backing BO.
8661b13d190SFrançois Tigeot *
8671b13d190SFrançois Tigeot * This function should not be used in execlists mode. Instead the context is
8681b13d190SFrançois Tigeot * switched by writing to the ELSP and requests keep a reference to their
8691b13d190SFrançois Tigeot * context.
870e555d299SFrançois Tigeot */
i915_switch_context(struct drm_i915_gem_request * req)871a05eeebfSFrançois Tigeot int i915_switch_context(struct drm_i915_gem_request *req)
872e555d299SFrançois Tigeot {
8738621f407SFrançois Tigeot struct intel_engine_cs *engine = req->engine;
874e555d299SFrançois Tigeot
875303bf270SFrançois Tigeot lockdep_assert_held(&req->i915->drm.struct_mutex);
876*3f2dd94aSFrançois Tigeot if (i915_modparams.enable_execlists)
87771f41f3eSFrançois Tigeot return 0;
8785d0b1887SFrançois Tigeot
8791487f786SFrançois Tigeot if (!req->ctx->engine[engine->id].state) {
8801487f786SFrançois Tigeot struct i915_gem_context *to = req->ctx;
8811487f786SFrançois Tigeot struct i915_hw_ppgtt *ppgtt =
8821487f786SFrançois Tigeot to->ppgtt ?: req->i915->mm.aliasing_ppgtt;
8838621f407SFrançois Tigeot
884*3f2dd94aSFrançois Tigeot if (needs_pd_load_pre(ppgtt, engine)) {
8858621f407SFrançois Tigeot int ret;
8868621f407SFrançois Tigeot
8878621f407SFrançois Tigeot trace_switch_mm(engine, to);
8881487f786SFrançois Tigeot ret = ppgtt->switch_mm(ppgtt, req);
8898621f407SFrançois Tigeot if (ret)
8908621f407SFrançois Tigeot return ret;
8918621f407SFrançois Tigeot
8921487f786SFrançois Tigeot ppgtt->pd_dirty_rings &= ~intel_engine_flag(engine);
893ba55f2f5SFrançois Tigeot }
8948621f407SFrançois Tigeot
895*3f2dd94aSFrançois Tigeot engine->legacy_active_context = to;
896e555d299SFrançois Tigeot return 0;
897e555d299SFrançois Tigeot }
898e555d299SFrançois Tigeot
8998621f407SFrançois Tigeot return do_rcs_switch(req);
900ba55f2f5SFrançois Tigeot }
901ba55f2f5SFrançois Tigeot
engine_has_kernel_context(struct intel_engine_cs * engine)902a85cb24fSFrançois Tigeot static bool engine_has_kernel_context(struct intel_engine_cs *engine)
903a85cb24fSFrançois Tigeot {
904a85cb24fSFrançois Tigeot struct i915_gem_timeline *timeline;
905a85cb24fSFrançois Tigeot
906a85cb24fSFrançois Tigeot list_for_each_entry(timeline, &engine->i915->gt.timelines, link) {
907a85cb24fSFrançois Tigeot struct intel_timeline *tl;
908a85cb24fSFrançois Tigeot
909a85cb24fSFrançois Tigeot if (timeline == &engine->i915->gt.global_timeline)
910a85cb24fSFrançois Tigeot continue;
911a85cb24fSFrançois Tigeot
912a85cb24fSFrançois Tigeot tl = &timeline->engine[engine->id];
913a85cb24fSFrançois Tigeot if (i915_gem_active_peek(&tl->last_request,
914a85cb24fSFrançois Tigeot &engine->i915->drm.struct_mutex))
915a85cb24fSFrançois Tigeot return false;
916a85cb24fSFrançois Tigeot }
917a85cb24fSFrançois Tigeot
918a85cb24fSFrançois Tigeot return (!engine->last_retired_context ||
919a85cb24fSFrançois Tigeot i915_gem_context_is_kernel(engine->last_retired_context));
920a85cb24fSFrançois Tigeot }
921a85cb24fSFrançois Tigeot
i915_gem_switch_to_kernel_context(struct drm_i915_private * dev_priv)92287df8fc6SFrançois Tigeot int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
92387df8fc6SFrançois Tigeot {
92487df8fc6SFrançois Tigeot struct intel_engine_cs *engine;
9254be47400SFrançois Tigeot struct i915_gem_timeline *timeline;
9261e12ee3bSFrançois Tigeot enum intel_engine_id id;
92787df8fc6SFrançois Tigeot
9284be47400SFrançois Tigeot lockdep_assert_held(&dev_priv->drm.struct_mutex);
9294be47400SFrançois Tigeot
930a85cb24fSFrançois Tigeot i915_gem_retire_requests(dev_priv);
931a85cb24fSFrançois Tigeot
9321e12ee3bSFrançois Tigeot for_each_engine(engine, dev_priv, id) {
93387df8fc6SFrançois Tigeot struct drm_i915_gem_request *req;
93487df8fc6SFrançois Tigeot int ret;
93587df8fc6SFrançois Tigeot
936a85cb24fSFrançois Tigeot if (engine_has_kernel_context(engine))
937a85cb24fSFrançois Tigeot continue;
938a85cb24fSFrançois Tigeot
93987df8fc6SFrançois Tigeot req = i915_gem_request_alloc(engine, dev_priv->kernel_context);
94087df8fc6SFrançois Tigeot if (IS_ERR(req))
94187df8fc6SFrançois Tigeot return PTR_ERR(req);
94287df8fc6SFrançois Tigeot
9434be47400SFrançois Tigeot /* Queue this switch after all other activity */
9444be47400SFrançois Tigeot list_for_each_entry(timeline, &dev_priv->gt.timelines, link) {
9454be47400SFrançois Tigeot struct drm_i915_gem_request *prev;
9464be47400SFrançois Tigeot struct intel_timeline *tl;
9474be47400SFrançois Tigeot
9484be47400SFrançois Tigeot tl = &timeline->engine[engine->id];
9494be47400SFrançois Tigeot prev = i915_gem_active_raw(&tl->last_request,
9504be47400SFrançois Tigeot &dev_priv->drm.struct_mutex);
9514be47400SFrançois Tigeot if (prev)
9524be47400SFrançois Tigeot i915_sw_fence_await_sw_fence_gfp(&req->submit,
9534be47400SFrançois Tigeot &prev->submit,
9544be47400SFrançois Tigeot GFP_KERNEL);
9554be47400SFrançois Tigeot }
9564be47400SFrançois Tigeot
95787df8fc6SFrançois Tigeot ret = i915_switch_context(req);
958a85cb24fSFrançois Tigeot i915_add_request(req);
95987df8fc6SFrançois Tigeot if (ret)
96087df8fc6SFrançois Tigeot return ret;
96187df8fc6SFrançois Tigeot }
96287df8fc6SFrançois Tigeot
96387df8fc6SFrançois Tigeot return 0;
96487df8fc6SFrançois Tigeot }
96587df8fc6SFrançois Tigeot
client_is_banned(struct drm_i915_file_private * file_priv)966a85cb24fSFrançois Tigeot static bool client_is_banned(struct drm_i915_file_private *file_priv)
967a85cb24fSFrançois Tigeot {
968*3f2dd94aSFrançois Tigeot return atomic_read(&file_priv->context_bans) > I915_MAX_CLIENT_CONTEXT_BANS;
969a85cb24fSFrançois Tigeot }
970a85cb24fSFrançois Tigeot
i915_gem_context_create_ioctl(struct drm_device * dev,void * data,struct drm_file * file)971e555d299SFrançois Tigeot int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
972e555d299SFrançois Tigeot struct drm_file *file)
973e555d299SFrançois Tigeot {
974*3f2dd94aSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
975e555d299SFrançois Tigeot struct drm_i915_gem_context_create *args = data;
976e555d299SFrançois Tigeot struct drm_i915_file_private *file_priv = file->driver_priv;
9771487f786SFrançois Tigeot struct i915_gem_context *ctx;
978e555d299SFrançois Tigeot int ret;
979e555d299SFrançois Tigeot
980*3f2dd94aSFrançois Tigeot if (!dev_priv->engine[RCS]->context_size)
981e555d299SFrançois Tigeot return -ENODEV;
982e555d299SFrançois Tigeot
983c0e85e96SFrançois Tigeot if (args->pad != 0)
984c0e85e96SFrançois Tigeot return -EINVAL;
985c0e85e96SFrançois Tigeot
986a85cb24fSFrançois Tigeot if (client_is_banned(file_priv)) {
987a85cb24fSFrançois Tigeot DRM_DEBUG("client %s[%d] banned from creating ctx\n",
988a85cb24fSFrançois Tigeot current->comm,
989a85cb24fSFrançois Tigeot pid_nr(get_task_pid(current, PIDTYPE_PID)));
990a85cb24fSFrançois Tigeot
991a85cb24fSFrançois Tigeot return -EIO;
992a85cb24fSFrançois Tigeot }
993a85cb24fSFrançois Tigeot
994e555d299SFrançois Tigeot ret = i915_mutex_lock_interruptible(dev);
995e555d299SFrançois Tigeot if (ret)
996e555d299SFrançois Tigeot return ret;
997e555d299SFrançois Tigeot
998*3f2dd94aSFrançois Tigeot ctx = i915_gem_create_context(dev_priv, file_priv);
999a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex);
1000e555d299SFrançois Tigeot if (IS_ERR(ctx))
1001e555d299SFrançois Tigeot return PTR_ERR(ctx);
1002e555d299SFrançois Tigeot
1003a85cb24fSFrançois Tigeot GEM_BUG_ON(i915_gem_context_is_kernel(ctx));
1004a85cb24fSFrançois Tigeot
100524edb884SFrançois Tigeot args->ctx_id = ctx->user_handle;
1006a85cb24fSFrançois Tigeot DRM_DEBUG("HW context %d created\n", args->ctx_id);
1007e555d299SFrançois Tigeot
1008e555d299SFrançois Tigeot return 0;
1009e555d299SFrançois Tigeot }
1010e555d299SFrançois Tigeot
i915_gem_context_destroy_ioctl(struct drm_device * dev,void * data,struct drm_file * file)1011e555d299SFrançois Tigeot int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
1012e555d299SFrançois Tigeot struct drm_file *file)
1013e555d299SFrançois Tigeot {
1014e555d299SFrançois Tigeot struct drm_i915_gem_context_destroy *args = data;
1015e555d299SFrançois Tigeot struct drm_i915_file_private *file_priv = file->driver_priv;
10161487f786SFrançois Tigeot struct i915_gem_context *ctx;
1017e555d299SFrançois Tigeot int ret;
1018e555d299SFrançois Tigeot
1019c0e85e96SFrançois Tigeot if (args->pad != 0)
1020c0e85e96SFrançois Tigeot return -EINVAL;
1021c0e85e96SFrançois Tigeot
102224edb884SFrançois Tigeot if (args->ctx_id == DEFAULT_CONTEXT_HANDLE)
1023ba55f2f5SFrançois Tigeot return -ENOENT;
1024e555d299SFrançois Tigeot
10251487f786SFrançois Tigeot ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
1026*3f2dd94aSFrançois Tigeot if (!ctx)
1027*3f2dd94aSFrançois Tigeot return -ENOENT;
1028*3f2dd94aSFrançois Tigeot
1029*3f2dd94aSFrançois Tigeot ret = mutex_lock_interruptible(&dev->struct_mutex);
1030*3f2dd94aSFrançois Tigeot if (ret)
1031*3f2dd94aSFrançois Tigeot goto out;
1032e555d299SFrançois Tigeot
1033a85cb24fSFrançois Tigeot __destroy_hw_context(ctx, file_priv);
1034a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex);
1035e555d299SFrançois Tigeot
1036*3f2dd94aSFrançois Tigeot out:
1037*3f2dd94aSFrançois Tigeot i915_gem_context_put(ctx);
1038e555d299SFrançois Tigeot return 0;
1039e555d299SFrançois Tigeot }
10402c9916cdSFrançois Tigeot
i915_gem_context_getparam_ioctl(struct drm_device * dev,void * data,struct drm_file * file)10412c9916cdSFrançois Tigeot int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
10422c9916cdSFrançois Tigeot struct drm_file *file)
10432c9916cdSFrançois Tigeot {
10442c9916cdSFrançois Tigeot struct drm_i915_file_private *file_priv = file->driver_priv;
10452c9916cdSFrançois Tigeot struct drm_i915_gem_context_param *args = data;
10461487f786SFrançois Tigeot struct i915_gem_context *ctx;
1047*3f2dd94aSFrançois Tigeot int ret = 0;
10482c9916cdSFrançois Tigeot
10491487f786SFrançois Tigeot ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
1050*3f2dd94aSFrançois Tigeot if (!ctx)
1051*3f2dd94aSFrançois Tigeot return -ENOENT;
10522c9916cdSFrançois Tigeot
10532c9916cdSFrançois Tigeot args->size = 0;
10542c9916cdSFrançois Tigeot switch (args->param) {
10552c9916cdSFrançois Tigeot case I915_CONTEXT_PARAM_BAN_PERIOD:
1056a85cb24fSFrançois Tigeot ret = -EINVAL;
10572c9916cdSFrançois Tigeot break;
1058a05eeebfSFrançois Tigeot case I915_CONTEXT_PARAM_NO_ZEROMAP:
1059a05eeebfSFrançois Tigeot args->value = ctx->flags & CONTEXT_NO_ZEROMAP;
1060a05eeebfSFrançois Tigeot break;
1061aee94f86SFrançois Tigeot case I915_CONTEXT_PARAM_GTT_SIZE:
1062aee94f86SFrançois Tigeot if (ctx->ppgtt)
1063aee94f86SFrançois Tigeot args->value = ctx->ppgtt->base.total;
1064aee94f86SFrançois Tigeot else if (to_i915(dev)->mm.aliasing_ppgtt)
1065aee94f86SFrançois Tigeot args->value = to_i915(dev)->mm.aliasing_ppgtt->base.total;
1066aee94f86SFrançois Tigeot else
10678621f407SFrançois Tigeot args->value = to_i915(dev)->ggtt.base.total;
1068aee94f86SFrançois Tigeot break;
1069303bf270SFrançois Tigeot case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
1070a85cb24fSFrançois Tigeot args->value = i915_gem_context_no_error_capture(ctx);
1071a85cb24fSFrançois Tigeot break;
1072a85cb24fSFrançois Tigeot case I915_CONTEXT_PARAM_BANNABLE:
1073a85cb24fSFrançois Tigeot args->value = i915_gem_context_is_bannable(ctx);
1074303bf270SFrançois Tigeot break;
1075*3f2dd94aSFrançois Tigeot case I915_CONTEXT_PARAM_PRIORITY:
1076*3f2dd94aSFrançois Tigeot args->value = ctx->priority;
1077*3f2dd94aSFrançois Tigeot break;
10782c9916cdSFrançois Tigeot default:
10792c9916cdSFrançois Tigeot ret = -EINVAL;
10802c9916cdSFrançois Tigeot break;
10812c9916cdSFrançois Tigeot }
10822c9916cdSFrançois Tigeot
1083*3f2dd94aSFrançois Tigeot i915_gem_context_put(ctx);
10842c9916cdSFrançois Tigeot return ret;
10852c9916cdSFrançois Tigeot }
10862c9916cdSFrançois Tigeot
i915_gem_context_setparam_ioctl(struct drm_device * dev,void * data,struct drm_file * file)10872c9916cdSFrançois Tigeot int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
10882c9916cdSFrançois Tigeot struct drm_file *file)
10892c9916cdSFrançois Tigeot {
10902c9916cdSFrançois Tigeot struct drm_i915_file_private *file_priv = file->driver_priv;
10912c9916cdSFrançois Tigeot struct drm_i915_gem_context_param *args = data;
10921487f786SFrançois Tigeot struct i915_gem_context *ctx;
10932c9916cdSFrançois Tigeot int ret;
10942c9916cdSFrançois Tigeot
1095*3f2dd94aSFrançois Tigeot ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
1096*3f2dd94aSFrançois Tigeot if (!ctx)
1097*3f2dd94aSFrançois Tigeot return -ENOENT;
1098*3f2dd94aSFrançois Tigeot
10992c9916cdSFrançois Tigeot ret = i915_mutex_lock_interruptible(dev);
11002c9916cdSFrançois Tigeot if (ret)
1101*3f2dd94aSFrançois Tigeot goto out;
11022c9916cdSFrançois Tigeot
11032c9916cdSFrançois Tigeot switch (args->param) {
11042c9916cdSFrançois Tigeot case I915_CONTEXT_PARAM_BAN_PERIOD:
11052c9916cdSFrançois Tigeot ret = -EINVAL;
11062c9916cdSFrançois Tigeot break;
1107a05eeebfSFrançois Tigeot case I915_CONTEXT_PARAM_NO_ZEROMAP:
1108a05eeebfSFrançois Tigeot if (args->size) {
1109a05eeebfSFrançois Tigeot ret = -EINVAL;
1110a05eeebfSFrançois Tigeot } else {
1111a05eeebfSFrançois Tigeot ctx->flags &= ~CONTEXT_NO_ZEROMAP;
1112a05eeebfSFrançois Tigeot ctx->flags |= args->value ? CONTEXT_NO_ZEROMAP : 0;
1113a05eeebfSFrançois Tigeot }
1114a05eeebfSFrançois Tigeot break;
1115303bf270SFrançois Tigeot case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
1116a85cb24fSFrançois Tigeot if (args->size)
1117303bf270SFrançois Tigeot ret = -EINVAL;
1118a85cb24fSFrançois Tigeot else if (args->value)
1119a85cb24fSFrançois Tigeot i915_gem_context_set_no_error_capture(ctx);
1120303bf270SFrançois Tigeot else
1121a85cb24fSFrançois Tigeot i915_gem_context_clear_no_error_capture(ctx);
1122a85cb24fSFrançois Tigeot break;
1123a85cb24fSFrançois Tigeot case I915_CONTEXT_PARAM_BANNABLE:
1124a85cb24fSFrançois Tigeot if (args->size)
1125a85cb24fSFrançois Tigeot ret = -EINVAL;
1126a85cb24fSFrançois Tigeot else if (!capable(CAP_SYS_ADMIN) && !args->value)
1127a85cb24fSFrançois Tigeot ret = -EPERM;
1128a85cb24fSFrançois Tigeot else if (args->value)
1129a85cb24fSFrançois Tigeot i915_gem_context_set_bannable(ctx);
1130a85cb24fSFrançois Tigeot else
1131a85cb24fSFrançois Tigeot i915_gem_context_clear_bannable(ctx);
1132303bf270SFrançois Tigeot break;
1133*3f2dd94aSFrançois Tigeot
1134*3f2dd94aSFrançois Tigeot case I915_CONTEXT_PARAM_PRIORITY:
1135*3f2dd94aSFrançois Tigeot {
1136*3f2dd94aSFrançois Tigeot int priority = args->value;
1137*3f2dd94aSFrançois Tigeot
1138*3f2dd94aSFrançois Tigeot if (args->size)
1139*3f2dd94aSFrançois Tigeot ret = -EINVAL;
1140*3f2dd94aSFrançois Tigeot else if (!to_i915(dev)->engine[RCS]->schedule)
1141*3f2dd94aSFrançois Tigeot ret = -ENODEV;
1142*3f2dd94aSFrançois Tigeot else if (priority > I915_CONTEXT_MAX_USER_PRIORITY ||
1143*3f2dd94aSFrançois Tigeot priority < I915_CONTEXT_MIN_USER_PRIORITY)
1144*3f2dd94aSFrançois Tigeot ret = -EINVAL;
1145*3f2dd94aSFrançois Tigeot #if 0
1146*3f2dd94aSFrançois Tigeot else if (priority > I915_CONTEXT_DEFAULT_PRIORITY &&
1147*3f2dd94aSFrançois Tigeot !capable(CAP_SYS_NICE))
1148*3f2dd94aSFrançois Tigeot #else
1149*3f2dd94aSFrançois Tigeot else if (priority > I915_CONTEXT_DEFAULT_PRIORITY)
1150*3f2dd94aSFrançois Tigeot #endif
1151*3f2dd94aSFrançois Tigeot ret = -EPERM;
1152*3f2dd94aSFrançois Tigeot else
1153*3f2dd94aSFrançois Tigeot ctx->priority = priority;
1154*3f2dd94aSFrançois Tigeot }
1155*3f2dd94aSFrançois Tigeot break;
1156*3f2dd94aSFrançois Tigeot
11572c9916cdSFrançois Tigeot default:
11582c9916cdSFrançois Tigeot ret = -EINVAL;
11592c9916cdSFrançois Tigeot break;
11602c9916cdSFrançois Tigeot }
11612c9916cdSFrançois Tigeot mutex_unlock(&dev->struct_mutex);
11622c9916cdSFrançois Tigeot
1163*3f2dd94aSFrançois Tigeot out:
1164*3f2dd94aSFrançois Tigeot i915_gem_context_put(ctx);
11652c9916cdSFrançois Tigeot return ret;
11662c9916cdSFrançois Tigeot }
11671487f786SFrançois Tigeot
i915_gem_context_reset_stats_ioctl(struct drm_device * dev,void * data,struct drm_file * file)11681487f786SFrançois Tigeot int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
11691487f786SFrançois Tigeot void *data, struct drm_file *file)
11701487f786SFrançois Tigeot {
1171303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
11721487f786SFrançois Tigeot struct drm_i915_reset_stats *args = data;
11731487f786SFrançois Tigeot struct i915_gem_context *ctx;
11741487f786SFrançois Tigeot int ret;
11751487f786SFrançois Tigeot
11761487f786SFrançois Tigeot if (args->flags || args->pad)
11771487f786SFrançois Tigeot return -EINVAL;
11781487f786SFrançois Tigeot
1179*3f2dd94aSFrançois Tigeot ret = -ENOENT;
1180*3f2dd94aSFrançois Tigeot rcu_read_lock();
1181*3f2dd94aSFrançois Tigeot ctx = __i915_gem_context_lookup_rcu(file->driver_priv, args->ctx_id);
1182*3f2dd94aSFrançois Tigeot if (!ctx)
1183*3f2dd94aSFrançois Tigeot goto out;
11841487f786SFrançois Tigeot
1185*3f2dd94aSFrançois Tigeot /*
1186*3f2dd94aSFrançois Tigeot * We opt for unserialised reads here. This may result in tearing
1187*3f2dd94aSFrançois Tigeot * in the extremely unlikely event of a GPU hang on this context
1188*3f2dd94aSFrançois Tigeot * as we are querying them. If we need that extra layer of protection,
1189*3f2dd94aSFrançois Tigeot * we should wrap the hangstats with a seqlock.
1190*3f2dd94aSFrançois Tigeot */
11911487f786SFrançois Tigeot
11921487f786SFrançois Tigeot if (capable(CAP_SYS_ADMIN))
11931487f786SFrançois Tigeot args->reset_count = i915_reset_count(&dev_priv->gpu_error);
11941487f786SFrançois Tigeot else
11951487f786SFrançois Tigeot args->reset_count = 0;
11961487f786SFrançois Tigeot
1197*3f2dd94aSFrançois Tigeot args->batch_active = atomic_read(&ctx->guilty_count);
1198*3f2dd94aSFrançois Tigeot args->batch_pending = atomic_read(&ctx->active_count);
11991487f786SFrançois Tigeot
1200*3f2dd94aSFrançois Tigeot ret = 0;
1201*3f2dd94aSFrançois Tigeot out:
1202*3f2dd94aSFrançois Tigeot rcu_read_unlock();
1203*3f2dd94aSFrançois Tigeot return ret;
12041487f786SFrançois Tigeot }
1205a85cb24fSFrançois Tigeot
1206a85cb24fSFrançois Tigeot #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
1207a85cb24fSFrançois Tigeot #include "selftests/mock_context.c"
1208a85cb24fSFrançois Tigeot #include "selftests/i915_gem_context.c"
1209a85cb24fSFrançois Tigeot #endif
1210