xref: /dflybsd-src/sys/dev/drm/i915/i915_gem_context.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
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