1352ff8bdSFrançois Tigeot /*
2352ff8bdSFrançois Tigeot  * Copyright © 2014 Intel Corporation
3352ff8bdSFrançois Tigeot  *
4352ff8bdSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5352ff8bdSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6352ff8bdSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7352ff8bdSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8352ff8bdSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9352ff8bdSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
10352ff8bdSFrançois Tigeot  *
11352ff8bdSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
12352ff8bdSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
13352ff8bdSFrançois Tigeot  * Software.
14352ff8bdSFrançois Tigeot  *
15352ff8bdSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16352ff8bdSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17352ff8bdSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18352ff8bdSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19352ff8bdSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20352ff8bdSFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21352ff8bdSFrançois Tigeot  * IN THE SOFTWARE.
22352ff8bdSFrançois Tigeot  *
23352ff8bdSFrançois Tigeot  */
24352ff8bdSFrançois Tigeot #include <linux/firmware.h>
258cd49a21SFrançois Tigeot #include <linux/circ_buf.h>
26352ff8bdSFrançois Tigeot #include "i915_drv.h"
27352ff8bdSFrançois Tigeot #include "intel_guc.h"
28352ff8bdSFrançois Tigeot 
29352ff8bdSFrançois Tigeot /**
30aee94f86SFrançois Tigeot  * DOC: GuC-based command submission
31352ff8bdSFrançois Tigeot  *
32352ff8bdSFrançois Tigeot  * i915_guc_client:
33352ff8bdSFrançois Tigeot  * We use the term client to avoid confusion with contexts. A i915_guc_client is
34352ff8bdSFrançois Tigeot  * equivalent to GuC object guc_context_desc. This context descriptor is
35352ff8bdSFrançois Tigeot  * allocated from a pool of 1024 entries. Kernel driver will allocate doorbell
36352ff8bdSFrançois Tigeot  * and workqueue for it. Also the process descriptor (guc_process_desc), which
37352ff8bdSFrançois Tigeot  * is mapped to client space. So the client can write Work Item then ring the
38352ff8bdSFrançois Tigeot  * doorbell.
39352ff8bdSFrançois Tigeot  *
40352ff8bdSFrançois Tigeot  * To simplify the implementation, we allocate one gem object that contains all
41352ff8bdSFrançois Tigeot  * pages for doorbell, process descriptor and workqueue.
42352ff8bdSFrançois Tigeot  *
43352ff8bdSFrançois Tigeot  * The Scratch registers:
44352ff8bdSFrançois Tigeot  * There are 16 MMIO-based registers start from 0xC180. The kernel driver writes
45352ff8bdSFrançois Tigeot  * a value to the action register (SOFT_SCRATCH_0) along with any data. It then
46352ff8bdSFrançois Tigeot  * triggers an interrupt on the GuC via another register write (0xC4C8).
47352ff8bdSFrançois Tigeot  * Firmware writes a success/fail code back to the action register after
48352ff8bdSFrançois Tigeot  * processes the request. The kernel driver polls waiting for this update and
49352ff8bdSFrançois Tigeot  * then proceeds.
50352ff8bdSFrançois Tigeot  * See host2guc_action()
51352ff8bdSFrançois Tigeot  *
52352ff8bdSFrançois Tigeot  * Doorbells:
53352ff8bdSFrançois Tigeot  * Doorbells are interrupts to uKernel. A doorbell is a single cache line (QW)
54352ff8bdSFrançois Tigeot  * mapped into process space.
55352ff8bdSFrançois Tigeot  *
56352ff8bdSFrançois Tigeot  * Work Items:
57352ff8bdSFrançois Tigeot  * There are several types of work items that the host may place into a
58352ff8bdSFrançois Tigeot  * workqueue, each with its own requirements and limitations. Currently only
59352ff8bdSFrançois Tigeot  * WQ_TYPE_INORDER is needed to support legacy submission via GuC, which
60352ff8bdSFrançois Tigeot  * represents in-order queue. The kernel driver packs ring tail pointer and an
61352ff8bdSFrançois Tigeot  * ELSP context descriptor dword into Work Item.
62352ff8bdSFrançois Tigeot  * See guc_add_workqueue_item()
63352ff8bdSFrançois Tigeot  *
64352ff8bdSFrançois Tigeot  */
65352ff8bdSFrançois Tigeot 
66352ff8bdSFrançois Tigeot /*
67352ff8bdSFrançois Tigeot  * Read GuC command/status register (SOFT_SCRATCH_0)
68352ff8bdSFrançois Tigeot  * Return true if it contains a response rather than a command
69352ff8bdSFrançois Tigeot  */
70352ff8bdSFrançois Tigeot static inline bool host2guc_action_response(struct drm_i915_private *dev_priv,
71352ff8bdSFrançois Tigeot 					    u32 *status)
72352ff8bdSFrançois Tigeot {
73352ff8bdSFrançois Tigeot 	u32 val = I915_READ(SOFT_SCRATCH(0));
74352ff8bdSFrançois Tigeot 	*status = val;
75352ff8bdSFrançois Tigeot 	return GUC2HOST_IS_RESPONSE(val);
76352ff8bdSFrançois Tigeot }
77352ff8bdSFrançois Tigeot 
78352ff8bdSFrançois Tigeot static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
79352ff8bdSFrançois Tigeot {
80352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
81352ff8bdSFrançois Tigeot 	u32 status;
82352ff8bdSFrançois Tigeot 	int i;
83352ff8bdSFrançois Tigeot 	int ret;
84352ff8bdSFrançois Tigeot 
85352ff8bdSFrançois Tigeot 	if (WARN_ON(len < 1 || len > 15))
86352ff8bdSFrançois Tigeot 		return -EINVAL;
87352ff8bdSFrançois Tigeot 
88352ff8bdSFrançois Tigeot 	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
89352ff8bdSFrançois Tigeot 
90352ff8bdSFrançois Tigeot 	dev_priv->guc.action_count += 1;
91352ff8bdSFrançois Tigeot 	dev_priv->guc.action_cmd = data[0];
92352ff8bdSFrançois Tigeot 
93352ff8bdSFrançois Tigeot 	for (i = 0; i < len; i++)
94352ff8bdSFrançois Tigeot 		I915_WRITE(SOFT_SCRATCH(i), data[i]);
95352ff8bdSFrançois Tigeot 
96352ff8bdSFrançois Tigeot 	POSTING_READ(SOFT_SCRATCH(i - 1));
97352ff8bdSFrançois Tigeot 
98352ff8bdSFrançois Tigeot 	I915_WRITE(HOST2GUC_INTERRUPT, HOST2GUC_TRIGGER);
99352ff8bdSFrançois Tigeot 
100*303bf270SFrançois Tigeot 	/*
101*303bf270SFrançois Tigeot 	 * Fast commands should complete in less than 10us, so sample quickly
102*303bf270SFrançois Tigeot 	 * up to that length of time, then switch to a slower sleep-wait loop.
103*303bf270SFrançois Tigeot 	 * No HOST2GUC command should ever take longer than 10ms.
104*303bf270SFrançois Tigeot 	 */
105*303bf270SFrançois Tigeot 	ret = wait_for_us(host2guc_action_response(dev_priv, &status), 10);
106*303bf270SFrançois Tigeot 	if (ret)
107*303bf270SFrançois Tigeot 		ret = wait_for(host2guc_action_response(dev_priv, &status), 10);
108352ff8bdSFrançois Tigeot 	if (status != GUC2HOST_STATUS_SUCCESS) {
109352ff8bdSFrançois Tigeot 		/*
110352ff8bdSFrançois Tigeot 		 * Either the GuC explicitly returned an error (which
111352ff8bdSFrançois Tigeot 		 * we convert to -EIO here) or no response at all was
112352ff8bdSFrançois Tigeot 		 * received within the timeout limit (-ETIMEDOUT)
113352ff8bdSFrançois Tigeot 		 */
114352ff8bdSFrançois Tigeot 		if (ret != -ETIMEDOUT)
115352ff8bdSFrançois Tigeot 			ret = -EIO;
116352ff8bdSFrançois Tigeot 
117352ff8bdSFrançois Tigeot 		DRM_ERROR("GUC: host2guc action 0x%X failed. ret=%d "
118352ff8bdSFrançois Tigeot 				"status=0x%08X response=0x%08X\n",
119352ff8bdSFrançois Tigeot 				data[0], ret, status,
120352ff8bdSFrançois Tigeot 				I915_READ(SOFT_SCRATCH(15)));
121352ff8bdSFrançois Tigeot 
122352ff8bdSFrançois Tigeot 		dev_priv->guc.action_fail += 1;
123352ff8bdSFrançois Tigeot 		dev_priv->guc.action_err = ret;
124352ff8bdSFrançois Tigeot 	}
125352ff8bdSFrançois Tigeot 	dev_priv->guc.action_status = status;
126352ff8bdSFrançois Tigeot 
127352ff8bdSFrançois Tigeot 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
128352ff8bdSFrançois Tigeot 
129352ff8bdSFrançois Tigeot 	return ret;
130352ff8bdSFrançois Tigeot }
131352ff8bdSFrançois Tigeot 
132352ff8bdSFrançois Tigeot /*
133352ff8bdSFrançois Tigeot  * Tell the GuC to allocate or deallocate a specific doorbell
134352ff8bdSFrançois Tigeot  */
135352ff8bdSFrançois Tigeot 
136352ff8bdSFrançois Tigeot static int host2guc_allocate_doorbell(struct intel_guc *guc,
137352ff8bdSFrançois Tigeot 				      struct i915_guc_client *client)
138352ff8bdSFrançois Tigeot {
139352ff8bdSFrançois Tigeot 	u32 data[2];
140352ff8bdSFrançois Tigeot 
141352ff8bdSFrançois Tigeot 	data[0] = HOST2GUC_ACTION_ALLOCATE_DOORBELL;
142352ff8bdSFrançois Tigeot 	data[1] = client->ctx_index;
143352ff8bdSFrançois Tigeot 
144352ff8bdSFrançois Tigeot 	return host2guc_action(guc, data, 2);
145352ff8bdSFrançois Tigeot }
146352ff8bdSFrançois Tigeot 
147352ff8bdSFrançois Tigeot static int host2guc_release_doorbell(struct intel_guc *guc,
148352ff8bdSFrançois Tigeot 				     struct i915_guc_client *client)
149352ff8bdSFrançois Tigeot {
150352ff8bdSFrançois Tigeot 	u32 data[2];
151352ff8bdSFrançois Tigeot 
152352ff8bdSFrançois Tigeot 	data[0] = HOST2GUC_ACTION_DEALLOCATE_DOORBELL;
153352ff8bdSFrançois Tigeot 	data[1] = client->ctx_index;
154352ff8bdSFrançois Tigeot 
155352ff8bdSFrançois Tigeot 	return host2guc_action(guc, data, 2);
156352ff8bdSFrançois Tigeot }
157352ff8bdSFrançois Tigeot 
158352ff8bdSFrançois Tigeot static int host2guc_sample_forcewake(struct intel_guc *guc,
159352ff8bdSFrançois Tigeot 				     struct i915_guc_client *client)
160352ff8bdSFrançois Tigeot {
161352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
162352ff8bdSFrançois Tigeot 	u32 data[2];
163352ff8bdSFrançois Tigeot 
164352ff8bdSFrançois Tigeot 	data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE;
165352ff8bdSFrançois Tigeot 	/* WaRsDisableCoarsePowerGating:skl,bxt */
1661487f786SFrançois Tigeot 	if (!intel_enable_rc6() || NEEDS_WaRsDisableCoarsePowerGating(dev_priv))
167352ff8bdSFrançois Tigeot 		data[1] = 0;
168352ff8bdSFrançois Tigeot 	else
169352ff8bdSFrançois Tigeot 		/* bit 0 and 1 are for Render and Media domain separately */
170352ff8bdSFrançois Tigeot 		data[1] = GUC_FORCEWAKE_RENDER | GUC_FORCEWAKE_MEDIA;
171352ff8bdSFrançois Tigeot 
172352ff8bdSFrançois Tigeot 	return host2guc_action(guc, data, ARRAY_SIZE(data));
173352ff8bdSFrançois Tigeot }
174352ff8bdSFrançois Tigeot 
175352ff8bdSFrançois Tigeot /*
176352ff8bdSFrançois Tigeot  * Initialise, update, or clear doorbell data shared with the GuC
177352ff8bdSFrançois Tigeot  *
178352ff8bdSFrançois Tigeot  * These functions modify shared data and so need access to the mapped
179352ff8bdSFrançois Tigeot  * client object which contains the page being used for the doorbell
180352ff8bdSFrançois Tigeot  */
181352ff8bdSFrançois Tigeot 
1821487f786SFrançois Tigeot static int guc_update_doorbell_id(struct intel_guc *guc,
1831487f786SFrançois Tigeot 				  struct i915_guc_client *client,
1841487f786SFrançois Tigeot 				  u16 new_id)
185352ff8bdSFrançois Tigeot {
1861487f786SFrançois Tigeot 	struct sg_table *sg = guc->ctx_pool_obj->pages;
1871487f786SFrançois Tigeot 	void *doorbell_bitmap = guc->doorbell_bitmap;
188352ff8bdSFrançois Tigeot 	struct guc_doorbell_info *doorbell;
1891487f786SFrançois Tigeot 	struct guc_context_desc desc;
1901487f786SFrançois Tigeot 	size_t len;
191352ff8bdSFrançois Tigeot 
1921487f786SFrançois Tigeot 	doorbell = client->client_base + client->doorbell_offset;
193352ff8bdSFrançois Tigeot 
1941487f786SFrançois Tigeot 	if (client->doorbell_id != GUC_INVALID_DOORBELL_ID &&
1951487f786SFrançois Tigeot 	    test_bit(client->doorbell_id, doorbell_bitmap)) {
1961487f786SFrançois Tigeot 		/* Deactivate the old doorbell */
1971487f786SFrançois Tigeot 		doorbell->db_status = GUC_DOORBELL_DISABLED;
1981487f786SFrançois Tigeot 		(void)host2guc_release_doorbell(guc, client);
1991487f786SFrançois Tigeot 		__clear_bit(client->doorbell_id, doorbell_bitmap);
2001487f786SFrançois Tigeot 	}
2011487f786SFrançois Tigeot 
2021487f786SFrançois Tigeot 	/* Update the GuC's idea of the doorbell ID */
2031487f786SFrançois Tigeot 	len = sg_pcopy_to_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
2041487f786SFrançois Tigeot 			     sizeof(desc) * client->ctx_index);
2051487f786SFrançois Tigeot 	if (len != sizeof(desc))
2061487f786SFrançois Tigeot 		return -EFAULT;
2071487f786SFrançois Tigeot 	desc.db_id = new_id;
2081487f786SFrançois Tigeot 	len = sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
2091487f786SFrançois Tigeot 			     sizeof(desc) * client->ctx_index);
2101487f786SFrançois Tigeot 	if (len != sizeof(desc))
2111487f786SFrançois Tigeot 		return -EFAULT;
2121487f786SFrançois Tigeot 
2131487f786SFrançois Tigeot 	client->doorbell_id = new_id;
2141487f786SFrançois Tigeot 	if (new_id == GUC_INVALID_DOORBELL_ID)
2151487f786SFrançois Tigeot 		return 0;
2161487f786SFrançois Tigeot 
2171487f786SFrançois Tigeot 	/* Activate the new doorbell */
2181487f786SFrançois Tigeot 	__set_bit(new_id, doorbell_bitmap);
219352ff8bdSFrançois Tigeot 	doorbell->cookie = 0;
2201487f786SFrançois Tigeot 	doorbell->db_status = GUC_DOORBELL_ENABLED;
2211487f786SFrançois Tigeot 	return host2guc_allocate_doorbell(guc, client);
222352ff8bdSFrançois Tigeot }
223352ff8bdSFrançois Tigeot 
2241487f786SFrançois Tigeot static int guc_init_doorbell(struct intel_guc *guc,
2251487f786SFrançois Tigeot 			      struct i915_guc_client *client,
2261487f786SFrançois Tigeot 			      uint16_t db_id)
227352ff8bdSFrançois Tigeot {
2281487f786SFrançois Tigeot 	return guc_update_doorbell_id(guc, client, db_id);
229352ff8bdSFrançois Tigeot }
230352ff8bdSFrançois Tigeot 
231352ff8bdSFrançois Tigeot static void guc_disable_doorbell(struct intel_guc *guc,
232352ff8bdSFrançois Tigeot 				 struct i915_guc_client *client)
233352ff8bdSFrançois Tigeot {
2341487f786SFrançois Tigeot 	(void)guc_update_doorbell_id(guc, client, GUC_INVALID_DOORBELL_ID);
235352ff8bdSFrançois Tigeot 
236352ff8bdSFrançois Tigeot 	/* XXX: wait for any interrupts */
237352ff8bdSFrançois Tigeot 	/* XXX: wait for workqueue to drain */
238352ff8bdSFrançois Tigeot }
239352ff8bdSFrançois Tigeot 
2401487f786SFrançois Tigeot static uint16_t
2411487f786SFrançois Tigeot select_doorbell_register(struct intel_guc *guc, uint32_t priority)
2421487f786SFrançois Tigeot {
2431487f786SFrançois Tigeot 	/*
2441487f786SFrançois Tigeot 	 * The bitmap tracks which doorbell registers are currently in use.
2451487f786SFrançois Tigeot 	 * It is split into two halves; the first half is used for normal
2461487f786SFrançois Tigeot 	 * priority contexts, the second half for high-priority ones.
2471487f786SFrançois Tigeot 	 * Note that logically higher priorities are numerically less than
2481487f786SFrançois Tigeot 	 * normal ones, so the test below means "is it high-priority?"
2491487f786SFrançois Tigeot 	 */
2501487f786SFrançois Tigeot 	const bool hi_pri = (priority <= GUC_CTX_PRIORITY_HIGH);
2511487f786SFrançois Tigeot 	const uint16_t half = GUC_MAX_DOORBELLS / 2;
2521487f786SFrançois Tigeot 	const uint16_t start = hi_pri ? half : 0;
2531487f786SFrançois Tigeot 	const uint16_t end = start + half;
2541487f786SFrançois Tigeot 	uint16_t id;
2551487f786SFrançois Tigeot 
2561487f786SFrançois Tigeot 	id = find_next_zero_bit(guc->doorbell_bitmap, end, start);
2571487f786SFrançois Tigeot 	if (id == end)
2581487f786SFrançois Tigeot 		id = GUC_INVALID_DOORBELL_ID;
2591487f786SFrançois Tigeot 
2601487f786SFrançois Tigeot 	DRM_DEBUG_DRIVER("assigned %s priority doorbell id 0x%x\n",
2611487f786SFrançois Tigeot 			hi_pri ? "high" : "normal", id);
2621487f786SFrançois Tigeot 
2631487f786SFrançois Tigeot 	return id;
2641487f786SFrançois Tigeot }
2651487f786SFrançois Tigeot 
266352ff8bdSFrançois Tigeot /*
267352ff8bdSFrançois Tigeot  * Select, assign and relase doorbell cachelines
268352ff8bdSFrançois Tigeot  *
269352ff8bdSFrançois Tigeot  * These functions track which doorbell cachelines are in use.
270352ff8bdSFrançois Tigeot  * The data they manipulate is protected by the host2guc lock.
271352ff8bdSFrançois Tigeot  */
272352ff8bdSFrançois Tigeot 
273352ff8bdSFrançois Tigeot static uint32_t select_doorbell_cacheline(struct intel_guc *guc)
274352ff8bdSFrançois Tigeot {
275352ff8bdSFrançois Tigeot 	const uint32_t cacheline_size = cache_line_size();
276352ff8bdSFrançois Tigeot 	uint32_t offset;
277352ff8bdSFrançois Tigeot 
278352ff8bdSFrançois Tigeot 	/* Doorbell uses a single cache line within a page */
279352ff8bdSFrançois Tigeot 	offset = offset_in_page(guc->db_cacheline);
280352ff8bdSFrançois Tigeot 
281352ff8bdSFrançois Tigeot 	/* Moving to next cache line to reduce contention */
282352ff8bdSFrançois Tigeot 	guc->db_cacheline += cacheline_size;
283352ff8bdSFrançois Tigeot 
284352ff8bdSFrançois Tigeot 	DRM_DEBUG_DRIVER("selected doorbell cacheline 0x%x, next 0x%x, linesize %u\n",
285352ff8bdSFrançois Tigeot 			offset, guc->db_cacheline, cacheline_size);
286352ff8bdSFrançois Tigeot 
287352ff8bdSFrançois Tigeot 	return offset;
288352ff8bdSFrançois Tigeot }
289352ff8bdSFrançois Tigeot 
290352ff8bdSFrançois Tigeot /*
291352ff8bdSFrançois Tigeot  * Initialise the process descriptor shared with the GuC firmware.
292352ff8bdSFrançois Tigeot  */
293352ff8bdSFrançois Tigeot static void guc_init_proc_desc(struct intel_guc *guc,
294352ff8bdSFrançois Tigeot 			       struct i915_guc_client *client)
295352ff8bdSFrançois Tigeot {
296352ff8bdSFrançois Tigeot 	struct guc_process_desc *desc;
297352ff8bdSFrançois Tigeot 
2981487f786SFrançois Tigeot 	desc = client->client_base + client->proc_desc_offset;
299352ff8bdSFrançois Tigeot 
300352ff8bdSFrançois Tigeot 	memset(desc, 0, sizeof(*desc));
301352ff8bdSFrançois Tigeot 
302352ff8bdSFrançois Tigeot 	/*
303352ff8bdSFrançois Tigeot 	 * XXX: pDoorbell and WQVBaseAddress are pointers in process address
304352ff8bdSFrançois Tigeot 	 * space for ring3 clients (set them as in mmap_ioctl) or kernel
305352ff8bdSFrançois Tigeot 	 * space for kernel clients (map on demand instead? May make debug
306352ff8bdSFrançois Tigeot 	 * easier to have it mapped).
307352ff8bdSFrançois Tigeot 	 */
308352ff8bdSFrançois Tigeot 	desc->wq_base_addr = 0;
309352ff8bdSFrançois Tigeot 	desc->db_base_addr = 0;
310352ff8bdSFrançois Tigeot 
311352ff8bdSFrançois Tigeot 	desc->context_id = client->ctx_index;
312352ff8bdSFrançois Tigeot 	desc->wq_size_bytes = client->wq_size;
313352ff8bdSFrançois Tigeot 	desc->wq_status = WQ_STATUS_ACTIVE;
314352ff8bdSFrançois Tigeot 	desc->priority = client->priority;
315352ff8bdSFrançois Tigeot }
316352ff8bdSFrançois Tigeot 
317352ff8bdSFrançois Tigeot /*
318352ff8bdSFrançois Tigeot  * Initialise/clear the context descriptor shared with the GuC firmware.
319352ff8bdSFrançois Tigeot  *
320352ff8bdSFrançois Tigeot  * This descriptor tells the GuC where (in GGTT space) to find the important
321352ff8bdSFrançois Tigeot  * data structures relating to this client (doorbell, process descriptor,
322352ff8bdSFrançois Tigeot  * write queue, etc).
323352ff8bdSFrançois Tigeot  */
324352ff8bdSFrançois Tigeot 
325352ff8bdSFrançois Tigeot static void guc_init_ctx_desc(struct intel_guc *guc,
326352ff8bdSFrançois Tigeot 			      struct i915_guc_client *client)
327352ff8bdSFrançois Tigeot {
3288621f407SFrançois Tigeot 	struct drm_i915_gem_object *client_obj = client->client_obj;
329c0e85e96SFrançois Tigeot 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
3308621f407SFrançois Tigeot 	struct intel_engine_cs *engine;
3311487f786SFrançois Tigeot 	struct i915_gem_context *ctx = client->owner;
332352ff8bdSFrançois Tigeot 	struct guc_context_desc desc;
333352ff8bdSFrançois Tigeot 	struct sg_table *sg;
3348621f407SFrançois Tigeot 	u32 gfx_addr;
335352ff8bdSFrançois Tigeot 
336352ff8bdSFrançois Tigeot 	memset(&desc, 0, sizeof(desc));
337352ff8bdSFrançois Tigeot 
338352ff8bdSFrançois Tigeot 	desc.attribute = GUC_CTX_DESC_ATTR_ACTIVE | GUC_CTX_DESC_ATTR_KERNEL;
339352ff8bdSFrançois Tigeot 	desc.context_id = client->ctx_index;
340352ff8bdSFrançois Tigeot 	desc.priority = client->priority;
341352ff8bdSFrançois Tigeot 	desc.db_id = client->doorbell_id;
342352ff8bdSFrançois Tigeot 
3431487f786SFrançois Tigeot 	for_each_engine(engine, dev_priv) {
3441487f786SFrançois Tigeot 		struct intel_context *ce = &ctx->engine[engine->id];
3458621f407SFrançois Tigeot 		struct guc_execlist_context *lrc = &desc.lrc[engine->guc_id];
346352ff8bdSFrançois Tigeot 		struct drm_i915_gem_object *obj;
347352ff8bdSFrançois Tigeot 
348352ff8bdSFrançois Tigeot 		/* TODO: We have a design issue to be solved here. Only when we
349352ff8bdSFrançois Tigeot 		 * receive the first batch, we know which engine is used by the
350352ff8bdSFrançois Tigeot 		 * user. But here GuC expects the lrc and ring to be pinned. It
351352ff8bdSFrançois Tigeot 		 * is not an issue for default context, which is the only one
352352ff8bdSFrançois Tigeot 		 * for now who owns a GuC client. But for future owner of GuC
353352ff8bdSFrançois Tigeot 		 * client, need to make sure lrc is pinned prior to enter here.
354352ff8bdSFrançois Tigeot 		 */
3551487f786SFrançois Tigeot 		if (!ce->state)
356352ff8bdSFrançois Tigeot 			break;	/* XXX: continue? */
357352ff8bdSFrançois Tigeot 
3581487f786SFrançois Tigeot 		lrc->context_desc = lower_32_bits(ce->lrc_desc);
359352ff8bdSFrançois Tigeot 
360352ff8bdSFrançois Tigeot 		/* The state page is after PPHWSP */
3611487f786SFrançois Tigeot 		gfx_addr = i915_gem_obj_ggtt_offset(ce->state);
3628621f407SFrançois Tigeot 		lrc->ring_lcra = gfx_addr + LRC_STATE_PN * PAGE_SIZE;
363352ff8bdSFrançois Tigeot 		lrc->context_id = (client->ctx_index << GUC_ELC_CTXID_OFFSET) |
3648621f407SFrançois Tigeot 				(engine->guc_id << GUC_ELC_ENGINE_OFFSET);
365352ff8bdSFrançois Tigeot 
3661487f786SFrançois Tigeot 		obj = ce->ringbuf->obj;
3678621f407SFrançois Tigeot 		gfx_addr = i915_gem_obj_ggtt_offset(obj);
368352ff8bdSFrançois Tigeot 
3698621f407SFrançois Tigeot 		lrc->ring_begin = gfx_addr;
3708621f407SFrançois Tigeot 		lrc->ring_end = gfx_addr + obj->base.size - 1;
3718621f407SFrançois Tigeot 		lrc->ring_next_free_location = gfx_addr;
372352ff8bdSFrançois Tigeot 		lrc->ring_current_tail_pointer_value = 0;
373352ff8bdSFrançois Tigeot 
3748621f407SFrançois Tigeot 		desc.engines_used |= (1 << engine->guc_id);
375352ff8bdSFrançois Tigeot 	}
376352ff8bdSFrançois Tigeot 
377352ff8bdSFrançois Tigeot 	WARN_ON(desc.engines_used == 0);
378352ff8bdSFrançois Tigeot 
379352ff8bdSFrançois Tigeot 	/*
3808621f407SFrançois Tigeot 	 * The doorbell, process descriptor, and workqueue are all parts
3818621f407SFrançois Tigeot 	 * of the client object, which the GuC will reference via the GGTT
382352ff8bdSFrançois Tigeot 	 */
3838621f407SFrançois Tigeot 	gfx_addr = i915_gem_obj_ggtt_offset(client_obj);
3848621f407SFrançois Tigeot 	desc.db_trigger_phy = sg_dma_address(client_obj->pages->sgl) +
3858621f407SFrançois Tigeot 				client->doorbell_offset;
3868621f407SFrançois Tigeot 	desc.db_trigger_cpu = (uintptr_t)client->client_base +
3878621f407SFrançois Tigeot 				client->doorbell_offset;
3888621f407SFrançois Tigeot 	desc.db_trigger_uk = gfx_addr + client->doorbell_offset;
3898621f407SFrançois Tigeot 	desc.process_desc = gfx_addr + client->proc_desc_offset;
3908621f407SFrançois Tigeot 	desc.wq_addr = gfx_addr + client->wq_offset;
391352ff8bdSFrançois Tigeot 	desc.wq_size = client->wq_size;
392352ff8bdSFrançois Tigeot 
393352ff8bdSFrançois Tigeot 	/*
3941487f786SFrançois Tigeot 	 * XXX: Take LRCs from an existing context if this is not an
395352ff8bdSFrançois Tigeot 	 * IsKMDCreatedContext client
396352ff8bdSFrançois Tigeot 	 */
397352ff8bdSFrançois Tigeot 	desc.desc_private = (uintptr_t)client;
398352ff8bdSFrançois Tigeot 
399352ff8bdSFrançois Tigeot 	/* Pool context is pinned already */
400352ff8bdSFrançois Tigeot 	sg = guc->ctx_pool_obj->pages;
401352ff8bdSFrançois Tigeot 	sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
402352ff8bdSFrançois Tigeot 			     sizeof(desc) * client->ctx_index);
403352ff8bdSFrançois Tigeot }
404352ff8bdSFrançois Tigeot 
405352ff8bdSFrançois Tigeot static void guc_fini_ctx_desc(struct intel_guc *guc,
406352ff8bdSFrançois Tigeot 			      struct i915_guc_client *client)
407352ff8bdSFrançois Tigeot {
408352ff8bdSFrançois Tigeot 	struct guc_context_desc desc;
409352ff8bdSFrançois Tigeot 	struct sg_table *sg;
410352ff8bdSFrançois Tigeot 
411352ff8bdSFrançois Tigeot 	memset(&desc, 0, sizeof(desc));
412352ff8bdSFrançois Tigeot 
413352ff8bdSFrançois Tigeot 	sg = guc->ctx_pool_obj->pages;
414352ff8bdSFrançois Tigeot 	sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
415352ff8bdSFrançois Tigeot 			     sizeof(desc) * client->ctx_index);
416352ff8bdSFrançois Tigeot }
417352ff8bdSFrançois Tigeot 
4181487f786SFrançois Tigeot /**
4191487f786SFrançois Tigeot  * i915_guc_wq_check_space() - check that the GuC can accept a request
4201487f786SFrançois Tigeot  * @request:	request associated with the commands
4211487f786SFrançois Tigeot  *
4221487f786SFrançois Tigeot  * Return:	0 if space is available
4231487f786SFrançois Tigeot  *		-EAGAIN if space is not currently available
4241487f786SFrançois Tigeot  *
4251487f786SFrançois Tigeot  * This function must be called (and must return 0) before a request
4261487f786SFrançois Tigeot  * is submitted to the GuC via i915_guc_submit() below. Once a result
4271487f786SFrançois Tigeot  * of 0 has been returned, it remains valid until (but only until)
4281487f786SFrançois Tigeot  * the next call to submit().
4291487f786SFrançois Tigeot  *
4301487f786SFrançois Tigeot  * This precheck allows the caller to determine in advance that space
4311487f786SFrançois Tigeot  * will be available for the next submission before committing resources
4321487f786SFrançois Tigeot  * to it, and helps avoid late failures with complicated recovery paths.
4331487f786SFrançois Tigeot  */
4341487f786SFrançois Tigeot int i915_guc_wq_check_space(struct drm_i915_gem_request *request)
435352ff8bdSFrançois Tigeot {
4361487f786SFrançois Tigeot 	const size_t wqi_size = sizeof(struct guc_wq_item);
4371487f786SFrançois Tigeot 	struct i915_guc_client *gc = request->i915->guc.execbuf_client;
438352ff8bdSFrançois Tigeot 	struct guc_process_desc *desc;
4391487f786SFrançois Tigeot 	u32 freespace;
440352ff8bdSFrançois Tigeot 
4411487f786SFrançois Tigeot 	GEM_BUG_ON(gc == NULL);
4421487f786SFrançois Tigeot 
4431487f786SFrançois Tigeot 	desc = gc->client_base + gc->proc_desc_offset;
4441487f786SFrançois Tigeot 
4451487f786SFrançois Tigeot 	freespace = CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size);
4461487f786SFrançois Tigeot 	if (likely(freespace >= wqi_size))
447c0e85e96SFrançois Tigeot 		return 0;
448c0e85e96SFrançois Tigeot 
4491487f786SFrançois Tigeot 	gc->no_wq_space += 1;
450352ff8bdSFrançois Tigeot 
4511487f786SFrançois Tigeot 	return -EAGAIN;
452352ff8bdSFrançois Tigeot }
453aee94f86SFrançois Tigeot 
4541487f786SFrançois Tigeot static void guc_add_workqueue_item(struct i915_guc_client *gc,
455352ff8bdSFrançois Tigeot 				   struct drm_i915_gem_request *rq)
456352ff8bdSFrançois Tigeot {
4571487f786SFrançois Tigeot 	/* wqi_len is in DWords, and does not include the one-word header */
4581487f786SFrançois Tigeot 	const size_t wqi_size = sizeof(struct guc_wq_item);
4591487f786SFrançois Tigeot 	const u32 wqi_len = wqi_size/sizeof(u32) - 1;
4608621f407SFrançois Tigeot 	struct guc_process_desc *desc;
461352ff8bdSFrançois Tigeot 	struct guc_wq_item *wqi;
462352ff8bdSFrançois Tigeot 	void *base;
4631487f786SFrançois Tigeot 	u32 freespace, tail, wq_off, wq_page;
464352ff8bdSFrançois Tigeot 
4651487f786SFrançois Tigeot 	desc = gc->client_base + gc->proc_desc_offset;
466c0e85e96SFrançois Tigeot 
4671487f786SFrançois Tigeot 	/* Free space is guaranteed, see i915_guc_wq_check_space() above */
4681487f786SFrançois Tigeot 	freespace = CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size);
4691487f786SFrançois Tigeot 	GEM_BUG_ON(freespace < wqi_size);
4701487f786SFrançois Tigeot 
4711487f786SFrançois Tigeot 	/* The GuC firmware wants the tail index in QWords, not bytes */
4721487f786SFrançois Tigeot 	tail = rq->tail;
4731487f786SFrançois Tigeot 	GEM_BUG_ON(tail & 7);
4741487f786SFrançois Tigeot 	tail >>= 3;
4751487f786SFrançois Tigeot 	GEM_BUG_ON(tail > WQ_RING_TAIL_MAX);
476352ff8bdSFrançois Tigeot 
477352ff8bdSFrançois Tigeot 	/* For now workqueue item is 4 DWs; workqueue buffer is 2 pages. So we
478352ff8bdSFrançois Tigeot 	 * should not have the case where structure wqi is across page, neither
479352ff8bdSFrançois Tigeot 	 * wrapped to the beginning. This simplifies the implementation below.
480352ff8bdSFrançois Tigeot 	 *
481352ff8bdSFrançois Tigeot 	 * XXX: if not the case, we need save data to a temp wqi and copy it to
482352ff8bdSFrançois Tigeot 	 * workqueue buffer dw by dw.
483352ff8bdSFrançois Tigeot 	 */
4841487f786SFrançois Tigeot 	BUILD_BUG_ON(wqi_size != 16);
485352ff8bdSFrançois Tigeot 
4861487f786SFrançois Tigeot 	/* postincrement WQ tail for next time */
4871487f786SFrançois Tigeot 	wq_off = gc->wq_tail;
4881487f786SFrançois Tigeot 	gc->wq_tail += wqi_size;
4891487f786SFrançois Tigeot 	gc->wq_tail &= gc->wq_size - 1;
4901487f786SFrançois Tigeot 	GEM_BUG_ON(wq_off & (wqi_size - 1));
4911487f786SFrançois Tigeot 
4921487f786SFrançois Tigeot 	/* WQ starts from the page after doorbell / process_desc */
4931487f786SFrançois Tigeot 	wq_page = (wq_off + GUC_DB_SIZE) >> PAGE_SHIFT;
494352ff8bdSFrançois Tigeot 	wq_off &= PAGE_SIZE - 1;
4951487f786SFrançois Tigeot 	base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, wq_page));
496352ff8bdSFrançois Tigeot 	wqi = (struct guc_wq_item *)((char *)base + wq_off);
497352ff8bdSFrançois Tigeot 
4981487f786SFrançois Tigeot 	/* Now fill in the 4-word work queue item */
499352ff8bdSFrançois Tigeot 	wqi->header = WQ_TYPE_INORDER |
5001487f786SFrançois Tigeot 			(wqi_len << WQ_LEN_SHIFT) |
5018621f407SFrançois Tigeot 			(rq->engine->guc_id << WQ_TARGET_SHIFT) |
502352ff8bdSFrançois Tigeot 			WQ_NO_WCFLUSH_WAIT;
503352ff8bdSFrançois Tigeot 
504352ff8bdSFrançois Tigeot 	/* The GuC wants only the low-order word of the context descriptor */
5058621f407SFrançois Tigeot 	wqi->context_desc = (u32)intel_lr_context_descriptor(rq->ctx,
5068621f407SFrançois Tigeot 							     rq->engine);
507352ff8bdSFrançois Tigeot 
508352ff8bdSFrançois Tigeot 	wqi->ring_tail = tail << WQ_RING_TAIL_SHIFT;
5091487f786SFrançois Tigeot 	wqi->fence_id = rq->seqno;
510352ff8bdSFrançois Tigeot 
511352ff8bdSFrançois Tigeot 	kunmap_atomic(base);
5121487f786SFrançois Tigeot }
513352ff8bdSFrançois Tigeot 
5141487f786SFrançois Tigeot static int guc_ring_doorbell(struct i915_guc_client *gc)
5151487f786SFrançois Tigeot {
5161487f786SFrançois Tigeot 	struct guc_process_desc *desc;
5171487f786SFrançois Tigeot 	union guc_doorbell_qw db_cmp, db_exc, db_ret;
5181487f786SFrançois Tigeot 	union guc_doorbell_qw *db;
5191487f786SFrançois Tigeot 	int attempt = 2, ret = -EAGAIN;
5201487f786SFrançois Tigeot 
5211487f786SFrançois Tigeot 	desc = gc->client_base + gc->proc_desc_offset;
5221487f786SFrançois Tigeot 
5231487f786SFrançois Tigeot 	/* Update the tail so it is visible to GuC */
5241487f786SFrançois Tigeot 	desc->tail = gc->wq_tail;
5251487f786SFrançois Tigeot 
5261487f786SFrançois Tigeot 	/* current cookie */
5271487f786SFrançois Tigeot 	db_cmp.db_status = GUC_DOORBELL_ENABLED;
5281487f786SFrançois Tigeot 	db_cmp.cookie = gc->cookie;
5291487f786SFrançois Tigeot 
5301487f786SFrançois Tigeot 	/* cookie to be updated */
5311487f786SFrançois Tigeot 	db_exc.db_status = GUC_DOORBELL_ENABLED;
5321487f786SFrançois Tigeot 	db_exc.cookie = gc->cookie + 1;
5331487f786SFrançois Tigeot 	if (db_exc.cookie == 0)
5341487f786SFrançois Tigeot 		db_exc.cookie = 1;
5351487f786SFrançois Tigeot 
5361487f786SFrançois Tigeot 	/* pointer of current doorbell cacheline */
5371487f786SFrançois Tigeot 	db = gc->client_base + gc->doorbell_offset;
5381487f786SFrançois Tigeot 
5391487f786SFrançois Tigeot 	while (attempt--) {
5401487f786SFrançois Tigeot 		/* lets ring the doorbell */
5411487f786SFrançois Tigeot 		db_ret.value_qw = atomic64_cmpxchg((atomic64_t *)db,
5421487f786SFrançois Tigeot 			db_cmp.value_qw, db_exc.value_qw);
5431487f786SFrançois Tigeot 
5441487f786SFrançois Tigeot 		/* if the exchange was successfully executed */
5451487f786SFrançois Tigeot 		if (db_ret.value_qw == db_cmp.value_qw) {
5461487f786SFrançois Tigeot 			/* db was successfully rung */
5471487f786SFrançois Tigeot 			gc->cookie = db_exc.cookie;
5481487f786SFrançois Tigeot 			ret = 0;
5491487f786SFrançois Tigeot 			break;
5501487f786SFrançois Tigeot 		}
5511487f786SFrançois Tigeot 
5521487f786SFrançois Tigeot 		/* XXX: doorbell was lost and need to acquire it again */
5531487f786SFrançois Tigeot 		if (db_ret.db_status == GUC_DOORBELL_DISABLED)
5541487f786SFrançois Tigeot 			break;
5551487f786SFrançois Tigeot 
5561487f786SFrançois Tigeot 		DRM_ERROR("Cookie mismatch. Expected %d, returned %d\n",
5571487f786SFrançois Tigeot 			  db_cmp.cookie, db_ret.cookie);
5581487f786SFrançois Tigeot 
5591487f786SFrançois Tigeot 		/* update the cookie to newly read cookie from GuC */
5601487f786SFrançois Tigeot 		db_cmp.cookie = db_ret.cookie;
5611487f786SFrançois Tigeot 		db_exc.cookie = db_ret.cookie + 1;
5621487f786SFrançois Tigeot 		if (db_exc.cookie == 0)
5631487f786SFrançois Tigeot 			db_exc.cookie = 1;
5641487f786SFrançois Tigeot 	}
5651487f786SFrançois Tigeot 
5661487f786SFrançois Tigeot 	return ret;
567352ff8bdSFrançois Tigeot }
568352ff8bdSFrançois Tigeot 
569352ff8bdSFrançois Tigeot /**
570352ff8bdSFrançois Tigeot  * i915_guc_submit() - Submit commands through GuC
571aee94f86SFrançois Tigeot  * @rq:		request associated with the commands
572352ff8bdSFrançois Tigeot  *
5731487f786SFrançois Tigeot  * Return:	0 on success, otherwise an errno.
5741487f786SFrançois Tigeot  * 		(Note: nonzero really shouldn't happen!)
5751487f786SFrançois Tigeot  *
5761487f786SFrançois Tigeot  * The caller must have already called i915_guc_wq_check_space() above
5771487f786SFrançois Tigeot  * with a result of 0 (success) since the last request submission. This
5781487f786SFrançois Tigeot  * guarantees that there is space in the work queue for the new request,
5791487f786SFrançois Tigeot  * so enqueuing the item cannot fail.
5801487f786SFrançois Tigeot  *
5811487f786SFrançois Tigeot  * Bad Things Will Happen if the caller violates this protocol e.g. calls
5821487f786SFrançois Tigeot  * submit() when check() says there's no space, or calls submit() multiple
5831487f786SFrançois Tigeot  * times with no intervening check().
5841487f786SFrançois Tigeot  *
5851487f786SFrançois Tigeot  * The only error here arises if the doorbell hardware isn't functioning
5861487f786SFrançois Tigeot  * as expected, which really shouln't happen.
587352ff8bdSFrançois Tigeot  */
5881487f786SFrançois Tigeot int i915_guc_submit(struct drm_i915_gem_request *rq)
589352ff8bdSFrançois Tigeot {
5901487f786SFrançois Tigeot 	unsigned int engine_id = rq->engine->id;
5911487f786SFrançois Tigeot 	struct intel_guc *guc = &rq->i915->guc;
5921487f786SFrançois Tigeot 	struct i915_guc_client *client = guc->execbuf_client;
5931487f786SFrançois Tigeot 	int b_ret;
594352ff8bdSFrançois Tigeot 
5951487f786SFrançois Tigeot 	guc_add_workqueue_item(client, rq);
596352ff8bdSFrançois Tigeot 	b_ret = guc_ring_doorbell(client);
597352ff8bdSFrançois Tigeot 
598c0e85e96SFrançois Tigeot 	client->submissions[engine_id] += 1;
5991487f786SFrançois Tigeot 	client->retcode = b_ret;
6001487f786SFrançois Tigeot 	if (b_ret)
601352ff8bdSFrançois Tigeot 		client->b_fail += 1;
6021487f786SFrançois Tigeot 
603c0e85e96SFrançois Tigeot 	guc->submissions[engine_id] += 1;
604c0e85e96SFrançois Tigeot 	guc->last_seqno[engine_id] = rq->seqno;
605352ff8bdSFrançois Tigeot 
6061487f786SFrançois Tigeot 	return b_ret;
607352ff8bdSFrançois Tigeot }
608352ff8bdSFrançois Tigeot 
609352ff8bdSFrançois Tigeot /*
610352ff8bdSFrançois Tigeot  * Everything below here is concerned with setup & teardown, and is
611352ff8bdSFrançois Tigeot  * therefore not part of the somewhat time-critical batch-submission
612352ff8bdSFrançois Tigeot  * path of i915_guc_submit() above.
613352ff8bdSFrançois Tigeot  */
614352ff8bdSFrançois Tigeot 
615352ff8bdSFrançois Tigeot /**
616352ff8bdSFrançois Tigeot  * gem_allocate_guc_obj() - Allocate gem object for GuC usage
6171487f786SFrançois Tigeot  * @dev_priv:	driver private data structure
618352ff8bdSFrançois Tigeot  * @size:	size of object
619352ff8bdSFrançois Tigeot  *
620352ff8bdSFrançois Tigeot  * This is a wrapper to create a gem obj. In order to use it inside GuC, the
621352ff8bdSFrançois Tigeot  * object needs to be pinned lifetime. Also we must pin it to gtt space other
622352ff8bdSFrançois Tigeot  * than [0, GUC_WOPCM_TOP) because this range is reserved inside GuC.
623352ff8bdSFrançois Tigeot  *
624352ff8bdSFrançois Tigeot  * Return:	A drm_i915_gem_object if successful, otherwise NULL.
625352ff8bdSFrançois Tigeot  */
6261487f786SFrançois Tigeot static struct drm_i915_gem_object *
6271487f786SFrançois Tigeot gem_allocate_guc_obj(struct drm_i915_private *dev_priv, u32 size)
628352ff8bdSFrançois Tigeot {
629352ff8bdSFrançois Tigeot 	struct drm_i915_gem_object *obj;
630352ff8bdSFrançois Tigeot 
631*303bf270SFrançois Tigeot 	obj = i915_gem_object_create(&dev_priv->drm, size);
6321487f786SFrançois Tigeot 	if (IS_ERR(obj))
633352ff8bdSFrançois Tigeot 		return NULL;
634352ff8bdSFrançois Tigeot 
635352ff8bdSFrançois Tigeot 	if (i915_gem_object_get_pages(obj)) {
636352ff8bdSFrançois Tigeot 		drm_gem_object_unreference(&obj->base);
637352ff8bdSFrançois Tigeot 		return NULL;
638352ff8bdSFrançois Tigeot 	}
639352ff8bdSFrançois Tigeot 
640352ff8bdSFrançois Tigeot 	if (i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
641352ff8bdSFrançois Tigeot 			PIN_OFFSET_BIAS | GUC_WOPCM_TOP)) {
642352ff8bdSFrançois Tigeot 		drm_gem_object_unreference(&obj->base);
643352ff8bdSFrançois Tigeot 		return NULL;
644352ff8bdSFrançois Tigeot 	}
645352ff8bdSFrançois Tigeot 
646352ff8bdSFrançois Tigeot 	/* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
647352ff8bdSFrançois Tigeot 	I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
648352ff8bdSFrançois Tigeot 
649352ff8bdSFrançois Tigeot 	return obj;
650352ff8bdSFrançois Tigeot }
651352ff8bdSFrançois Tigeot 
652352ff8bdSFrançois Tigeot /**
653352ff8bdSFrançois Tigeot  * gem_release_guc_obj() - Release gem object allocated for GuC usage
654352ff8bdSFrançois Tigeot  * @obj:	gem obj to be released
655352ff8bdSFrançois Tigeot  */
656352ff8bdSFrançois Tigeot static void gem_release_guc_obj(struct drm_i915_gem_object *obj)
657352ff8bdSFrançois Tigeot {
658352ff8bdSFrançois Tigeot 	if (!obj)
659352ff8bdSFrançois Tigeot 		return;
660352ff8bdSFrançois Tigeot 
661352ff8bdSFrançois Tigeot 	if (i915_gem_obj_is_pinned(obj))
662352ff8bdSFrançois Tigeot 		i915_gem_object_ggtt_unpin(obj);
663352ff8bdSFrançois Tigeot 
664352ff8bdSFrançois Tigeot 	drm_gem_object_unreference(&obj->base);
665352ff8bdSFrançois Tigeot }
666352ff8bdSFrançois Tigeot 
6671487f786SFrançois Tigeot static void
6681487f786SFrançois Tigeot guc_client_free(struct drm_i915_private *dev_priv,
669352ff8bdSFrançois Tigeot 		struct i915_guc_client *client)
670352ff8bdSFrançois Tigeot {
671352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
672352ff8bdSFrançois Tigeot 
673352ff8bdSFrançois Tigeot 	if (!client)
674352ff8bdSFrançois Tigeot 		return;
675352ff8bdSFrançois Tigeot 
676352ff8bdSFrançois Tigeot 	/*
6778621f407SFrançois Tigeot 	 * XXX: wait for any outstanding submissions before freeing memory.
6788621f407SFrançois Tigeot 	 * Be sure to drop any locks
679352ff8bdSFrançois Tigeot 	 */
6808621f407SFrançois Tigeot 
6818621f407SFrançois Tigeot 	if (client->client_base) {
6828621f407SFrançois Tigeot 		/*
6831487f786SFrançois Tigeot 		 * If we got as far as setting up a doorbell, make sure we
6841487f786SFrançois Tigeot 		 * shut it down before unmapping & deallocating the memory.
6858621f407SFrançois Tigeot 		 */
686352ff8bdSFrançois Tigeot 		guc_disable_doorbell(guc, client);
687352ff8bdSFrançois Tigeot 
6888621f407SFrançois Tigeot 		kunmap(kmap_to_page(client->client_base));
6898621f407SFrançois Tigeot 	}
690352ff8bdSFrançois Tigeot 
691352ff8bdSFrançois Tigeot 	gem_release_guc_obj(client->client_obj);
692352ff8bdSFrançois Tigeot 
693352ff8bdSFrançois Tigeot 	if (client->ctx_index != GUC_INVALID_CTX_ID) {
694352ff8bdSFrançois Tigeot 		guc_fini_ctx_desc(guc, client);
695352ff8bdSFrançois Tigeot 		ida_simple_remove(&guc->ctx_ids, client->ctx_index);
696352ff8bdSFrançois Tigeot 	}
697352ff8bdSFrançois Tigeot 
698352ff8bdSFrançois Tigeot 	kfree(client);
699352ff8bdSFrançois Tigeot }
700352ff8bdSFrançois Tigeot 
7011487f786SFrançois Tigeot /*
7021487f786SFrançois Tigeot  * Borrow the first client to set up & tear down every doorbell
7031487f786SFrançois Tigeot  * in turn, to ensure that all doorbell h/w is (re)initialised.
7041487f786SFrançois Tigeot  */
7051487f786SFrançois Tigeot static void guc_init_doorbell_hw(struct intel_guc *guc)
7061487f786SFrançois Tigeot {
7071487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
7081487f786SFrançois Tigeot 	struct i915_guc_client *client = guc->execbuf_client;
7091487f786SFrançois Tigeot 	uint16_t db_id, i;
7101487f786SFrançois Tigeot 	int err;
7111487f786SFrançois Tigeot 
7121487f786SFrançois Tigeot 	db_id = client->doorbell_id;
7131487f786SFrançois Tigeot 
7141487f786SFrançois Tigeot 	for (i = 0; i < GUC_MAX_DOORBELLS; ++i) {
7151487f786SFrançois Tigeot 		i915_reg_t drbreg = GEN8_DRBREGL(i);
7161487f786SFrançois Tigeot 		u32 value = I915_READ(drbreg);
7171487f786SFrançois Tigeot 
7181487f786SFrançois Tigeot 		err = guc_update_doorbell_id(guc, client, i);
7191487f786SFrançois Tigeot 
7201487f786SFrançois Tigeot 		/* Report update failure or unexpectedly active doorbell */
7211487f786SFrançois Tigeot 		if (err || (i != db_id && (value & GUC_DOORBELL_ENABLED)))
7221487f786SFrançois Tigeot 			DRM_DEBUG_DRIVER("Doorbell %d (reg 0x%x) was 0x%x, err %d\n",
7231487f786SFrançois Tigeot 					  i, drbreg.reg, value, err);
7241487f786SFrançois Tigeot 	}
7251487f786SFrançois Tigeot 
7261487f786SFrançois Tigeot 	/* Restore to original value */
7271487f786SFrançois Tigeot 	err = guc_update_doorbell_id(guc, client, db_id);
7281487f786SFrançois Tigeot 	if (err)
7291487f786SFrançois Tigeot 		DRM_ERROR("Failed to restore doorbell to %d, err %d\n",
7301487f786SFrançois Tigeot 			db_id, err);
7311487f786SFrançois Tigeot 
7321487f786SFrançois Tigeot 	for (i = 0; i < GUC_MAX_DOORBELLS; ++i) {
7331487f786SFrançois Tigeot 		i915_reg_t drbreg = GEN8_DRBREGL(i);
7341487f786SFrançois Tigeot 		u32 value = I915_READ(drbreg);
7351487f786SFrançois Tigeot 
7361487f786SFrançois Tigeot 		if (i != db_id && (value & GUC_DOORBELL_ENABLED))
7371487f786SFrançois Tigeot 			DRM_DEBUG_DRIVER("Doorbell %d (reg 0x%x) finally 0x%x\n",
7381487f786SFrançois Tigeot 					  i, drbreg.reg, value);
7391487f786SFrançois Tigeot 
7401487f786SFrançois Tigeot 	}
7411487f786SFrançois Tigeot }
7421487f786SFrançois Tigeot 
743352ff8bdSFrançois Tigeot /**
744352ff8bdSFrançois Tigeot  * guc_client_alloc() - Allocate an i915_guc_client
7451487f786SFrançois Tigeot  * @dev_priv:	driver private data structure
746352ff8bdSFrançois Tigeot  * @priority:	four levels priority _CRITICAL, _HIGH, _NORMAL and _LOW
747352ff8bdSFrançois Tigeot  * 		The kernel client to replace ExecList submission is created with
748352ff8bdSFrançois Tigeot  * 		NORMAL priority. Priority of a client for scheduler can be HIGH,
749352ff8bdSFrançois Tigeot  * 		while a preemption context can use CRITICAL.
750aee94f86SFrançois Tigeot  * @ctx:	the context that owns the client (we use the default render
751aee94f86SFrançois Tigeot  * 		context)
752352ff8bdSFrançois Tigeot  *
7538621f407SFrançois Tigeot  * Return:	An i915_guc_client object if success, else NULL.
754352ff8bdSFrançois Tigeot  */
7551487f786SFrançois Tigeot static struct i915_guc_client *
7561487f786SFrançois Tigeot guc_client_alloc(struct drm_i915_private *dev_priv,
757352ff8bdSFrançois Tigeot 		 uint32_t priority,
7581487f786SFrançois Tigeot 		 struct i915_gem_context *ctx)
759352ff8bdSFrançois Tigeot {
760352ff8bdSFrançois Tigeot 	struct i915_guc_client *client;
761352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
762352ff8bdSFrançois Tigeot 	struct drm_i915_gem_object *obj;
7631487f786SFrançois Tigeot 	uint16_t db_id;
764352ff8bdSFrançois Tigeot 
765352ff8bdSFrançois Tigeot 	client = kzalloc(sizeof(*client), GFP_KERNEL);
766352ff8bdSFrançois Tigeot 	if (!client)
767352ff8bdSFrançois Tigeot 		return NULL;
768352ff8bdSFrançois Tigeot 
769352ff8bdSFrançois Tigeot 	client->doorbell_id = GUC_INVALID_DOORBELL_ID;
770352ff8bdSFrançois Tigeot 	client->priority = priority;
771352ff8bdSFrançois Tigeot 	client->owner = ctx;
772352ff8bdSFrançois Tigeot 	client->guc = guc;
773352ff8bdSFrançois Tigeot 
774352ff8bdSFrançois Tigeot 	client->ctx_index = (uint32_t)ida_simple_get(&guc->ctx_ids, 0,
775352ff8bdSFrançois Tigeot 			GUC_MAX_GPU_CONTEXTS, GFP_KERNEL);
776352ff8bdSFrançois Tigeot 	if (client->ctx_index >= GUC_MAX_GPU_CONTEXTS) {
777352ff8bdSFrançois Tigeot 		client->ctx_index = GUC_INVALID_CTX_ID;
778352ff8bdSFrançois Tigeot 		goto err;
779352ff8bdSFrançois Tigeot 	}
780352ff8bdSFrançois Tigeot 
781352ff8bdSFrançois Tigeot 	/* The first page is doorbell/proc_desc. Two followed pages are wq. */
7821487f786SFrançois Tigeot 	obj = gem_allocate_guc_obj(dev_priv, GUC_DB_SIZE + GUC_WQ_SIZE);
783352ff8bdSFrançois Tigeot 	if (!obj)
784352ff8bdSFrançois Tigeot 		goto err;
785352ff8bdSFrançois Tigeot 
7868621f407SFrançois Tigeot 	/* We'll keep just the first (doorbell/proc) page permanently kmap'd. */
787352ff8bdSFrançois Tigeot 	client->client_obj = obj;
7888621f407SFrançois Tigeot 	client->client_base = kmap(i915_gem_object_get_page(obj, 0));
789352ff8bdSFrançois Tigeot 	client->wq_offset = GUC_DB_SIZE;
790352ff8bdSFrançois Tigeot 	client->wq_size = GUC_WQ_SIZE;
791352ff8bdSFrançois Tigeot 
7921487f786SFrançois Tigeot 	db_id = select_doorbell_register(guc, client->priority);
7931487f786SFrançois Tigeot 	if (db_id == GUC_INVALID_DOORBELL_ID)
7941487f786SFrançois Tigeot 		/* XXX: evict a doorbell instead? */
7951487f786SFrançois Tigeot 		goto err;
7961487f786SFrançois Tigeot 
797352ff8bdSFrançois Tigeot 	client->doorbell_offset = select_doorbell_cacheline(guc);
798352ff8bdSFrançois Tigeot 
799352ff8bdSFrançois Tigeot 	/*
800352ff8bdSFrançois Tigeot 	 * Since the doorbell only requires a single cacheline, we can save
801352ff8bdSFrançois Tigeot 	 * space by putting the application process descriptor in the same
802352ff8bdSFrançois Tigeot 	 * page. Use the half of the page that doesn't include the doorbell.
803352ff8bdSFrançois Tigeot 	 */
804352ff8bdSFrançois Tigeot 	if (client->doorbell_offset >= (GUC_DB_SIZE / 2))
805352ff8bdSFrançois Tigeot 		client->proc_desc_offset = 0;
806352ff8bdSFrançois Tigeot 	else
807352ff8bdSFrançois Tigeot 		client->proc_desc_offset = (GUC_DB_SIZE / 2);
808352ff8bdSFrançois Tigeot 
809352ff8bdSFrançois Tigeot 	guc_init_proc_desc(guc, client);
810352ff8bdSFrançois Tigeot 	guc_init_ctx_desc(guc, client);
8111487f786SFrançois Tigeot 	if (guc_init_doorbell(guc, client, db_id))
812352ff8bdSFrançois Tigeot 		goto err;
813352ff8bdSFrançois Tigeot 
8141487f786SFrançois Tigeot 	DRM_DEBUG_DRIVER("new priority %u client %p: ctx_index %u\n",
8151487f786SFrançois Tigeot 		priority, client, client->ctx_index);
8161487f786SFrançois Tigeot 	DRM_DEBUG_DRIVER("doorbell id %u, cacheline offset 0x%x\n",
8171487f786SFrançois Tigeot 		client->doorbell_id, client->doorbell_offset);
818352ff8bdSFrançois Tigeot 
819352ff8bdSFrançois Tigeot 	return client;
820352ff8bdSFrançois Tigeot 
821352ff8bdSFrançois Tigeot err:
822352ff8bdSFrançois Tigeot 	DRM_ERROR("FAILED to create priority %u GuC client!\n", priority);
823352ff8bdSFrançois Tigeot 
8241487f786SFrançois Tigeot 	guc_client_free(dev_priv, client);
825352ff8bdSFrançois Tigeot 	return NULL;
826352ff8bdSFrançois Tigeot }
827352ff8bdSFrançois Tigeot 
828352ff8bdSFrançois Tigeot static void guc_create_log(struct intel_guc *guc)
829352ff8bdSFrançois Tigeot {
830352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
831352ff8bdSFrançois Tigeot 	struct drm_i915_gem_object *obj;
832352ff8bdSFrançois Tigeot 	unsigned long offset;
833352ff8bdSFrançois Tigeot 	uint32_t size, flags;
834352ff8bdSFrançois Tigeot 
835352ff8bdSFrançois Tigeot 	if (i915.guc_log_level < GUC_LOG_VERBOSITY_MIN)
836352ff8bdSFrançois Tigeot 		return;
837352ff8bdSFrançois Tigeot 
838352ff8bdSFrançois Tigeot 	if (i915.guc_log_level > GUC_LOG_VERBOSITY_MAX)
839352ff8bdSFrançois Tigeot 		i915.guc_log_level = GUC_LOG_VERBOSITY_MAX;
840352ff8bdSFrançois Tigeot 
841352ff8bdSFrançois Tigeot 	/* The first page is to save log buffer state. Allocate one
842352ff8bdSFrançois Tigeot 	 * extra page for others in case for overlap */
843352ff8bdSFrançois Tigeot 	size = (1 + GUC_LOG_DPC_PAGES + 1 +
844352ff8bdSFrançois Tigeot 		GUC_LOG_ISR_PAGES + 1 +
845352ff8bdSFrançois Tigeot 		GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT;
846352ff8bdSFrançois Tigeot 
847352ff8bdSFrançois Tigeot 	obj = guc->log_obj;
848352ff8bdSFrançois Tigeot 	if (!obj) {
8491487f786SFrançois Tigeot 		obj = gem_allocate_guc_obj(dev_priv, size);
850352ff8bdSFrançois Tigeot 		if (!obj) {
851352ff8bdSFrançois Tigeot 			/* logging will be off */
852352ff8bdSFrançois Tigeot 			i915.guc_log_level = -1;
853352ff8bdSFrançois Tigeot 			return;
854352ff8bdSFrançois Tigeot 		}
855352ff8bdSFrançois Tigeot 
856352ff8bdSFrançois Tigeot 		guc->log_obj = obj;
857352ff8bdSFrançois Tigeot 	}
858352ff8bdSFrançois Tigeot 
859352ff8bdSFrançois Tigeot 	/* each allocated unit is a page */
860352ff8bdSFrançois Tigeot 	flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL |
861352ff8bdSFrançois Tigeot 		(GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) |
862352ff8bdSFrançois Tigeot 		(GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) |
863352ff8bdSFrançois Tigeot 		(GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT);
864352ff8bdSFrançois Tigeot 
865352ff8bdSFrançois Tigeot 	offset = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; /* in pages */
866352ff8bdSFrançois Tigeot 	guc->log_flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
867352ff8bdSFrançois Tigeot }
868352ff8bdSFrançois Tigeot 
869c0e85e96SFrançois Tigeot static void init_guc_policies(struct guc_policies *policies)
870c0e85e96SFrançois Tigeot {
871c0e85e96SFrançois Tigeot 	struct guc_policy *policy;
872c0e85e96SFrançois Tigeot 	u32 p, i;
873c0e85e96SFrançois Tigeot 
874c0e85e96SFrançois Tigeot 	policies->dpc_promote_time = 500000;
875c0e85e96SFrançois Tigeot 	policies->max_num_work_items = POLICY_MAX_NUM_WI;
876c0e85e96SFrançois Tigeot 
877c0e85e96SFrançois Tigeot 	for (p = 0; p < GUC_CTX_PRIORITY_NUM; p++) {
878c0e85e96SFrançois Tigeot 		for (i = GUC_RENDER_ENGINE; i < GUC_MAX_ENGINES_NUM; i++) {
879c0e85e96SFrançois Tigeot 			policy = &policies->policy[p][i];
880c0e85e96SFrançois Tigeot 
881c0e85e96SFrançois Tigeot 			policy->execution_quantum = 1000000;
882c0e85e96SFrançois Tigeot 			policy->preemption_time = 500000;
883c0e85e96SFrançois Tigeot 			policy->fault_time = 250000;
884c0e85e96SFrançois Tigeot 			policy->policy_flags = 0;
885c0e85e96SFrançois Tigeot 		}
886c0e85e96SFrançois Tigeot 	}
887c0e85e96SFrançois Tigeot 
888c0e85e96SFrançois Tigeot 	policies->is_valid = 1;
889c0e85e96SFrançois Tigeot }
890c0e85e96SFrançois Tigeot 
891c0e85e96SFrançois Tigeot static void guc_create_ads(struct intel_guc *guc)
892c0e85e96SFrançois Tigeot {
893c0e85e96SFrançois Tigeot 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
894c0e85e96SFrançois Tigeot 	struct drm_i915_gem_object *obj;
895c0e85e96SFrançois Tigeot 	struct guc_ads *ads;
896c0e85e96SFrançois Tigeot 	struct guc_policies *policies;
897c0e85e96SFrançois Tigeot 	struct guc_mmio_reg_state *reg_state;
8988621f407SFrançois Tigeot 	struct intel_engine_cs *engine;
899f0bba3d1SFrançois Tigeot 	struct page *page;
9008621f407SFrançois Tigeot 	u32 size;
901c0e85e96SFrançois Tigeot 
902c0e85e96SFrançois Tigeot 	/* The ads obj includes the struct itself and buffers passed to GuC */
903c0e85e96SFrançois Tigeot 	size = sizeof(struct guc_ads) + sizeof(struct guc_policies) +
904c0e85e96SFrançois Tigeot 			sizeof(struct guc_mmio_reg_state) +
905c0e85e96SFrançois Tigeot 			GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE;
906c0e85e96SFrançois Tigeot 
907c0e85e96SFrançois Tigeot 	obj = guc->ads_obj;
908c0e85e96SFrançois Tigeot 	if (!obj) {
9091487f786SFrançois Tigeot 		obj = gem_allocate_guc_obj(dev_priv, PAGE_ALIGN(size));
910c0e85e96SFrançois Tigeot 		if (!obj)
911c0e85e96SFrançois Tigeot 			return;
912c0e85e96SFrançois Tigeot 
913c0e85e96SFrançois Tigeot 		guc->ads_obj = obj;
914c0e85e96SFrançois Tigeot 	}
915c0e85e96SFrançois Tigeot 
916c0e85e96SFrançois Tigeot 	page = i915_gem_object_get_page(obj, 0);
917c0e85e96SFrançois Tigeot 	ads = kmap(page);
918c0e85e96SFrançois Tigeot 
919c0e85e96SFrançois Tigeot 	/*
920c0e85e96SFrançois Tigeot 	 * The GuC requires a "Golden Context" when it reinitialises
921c0e85e96SFrançois Tigeot 	 * engines after a reset. Here we use the Render ring default
922c0e85e96SFrançois Tigeot 	 * context, which must already exist and be pinned in the GGTT,
923c0e85e96SFrançois Tigeot 	 * so its address won't change after we've told the GuC where
924c0e85e96SFrançois Tigeot 	 * to find it.
925c0e85e96SFrançois Tigeot 	 */
9268621f407SFrançois Tigeot 	engine = &dev_priv->engine[RCS];
9278621f407SFrançois Tigeot 	ads->golden_context_lrca = engine->status_page.gfx_addr;
928c0e85e96SFrançois Tigeot 
9298621f407SFrançois Tigeot 	for_each_engine(engine, dev_priv)
9308621f407SFrançois Tigeot 		ads->eng_state_size[engine->guc_id] = intel_lr_context_size(engine);
931c0e85e96SFrançois Tigeot 
932c0e85e96SFrançois Tigeot 	/* GuC scheduling policies */
9331487f786SFrançois Tigeot 	policies = (void *)ads + sizeof(struct guc_ads);
934c0e85e96SFrançois Tigeot 	init_guc_policies(policies);
935c0e85e96SFrançois Tigeot 
936c0e85e96SFrançois Tigeot 	ads->scheduler_policies = i915_gem_obj_ggtt_offset(obj) +
937c0e85e96SFrançois Tigeot 			sizeof(struct guc_ads);
938c0e85e96SFrançois Tigeot 
939c0e85e96SFrançois Tigeot 	/* MMIO reg state */
9401487f786SFrançois Tigeot 	reg_state = (void *)policies + sizeof(struct guc_policies);
941c0e85e96SFrançois Tigeot 
9428621f407SFrançois Tigeot 	for_each_engine(engine, dev_priv) {
9438621f407SFrançois Tigeot 		reg_state->mmio_white_list[engine->guc_id].mmio_start =
9448621f407SFrançois Tigeot 			engine->mmio_base + GUC_MMIO_WHITE_LIST_START;
945c0e85e96SFrançois Tigeot 
946c0e85e96SFrançois Tigeot 		/* Nothing to be saved or restored for now. */
9478621f407SFrançois Tigeot 		reg_state->mmio_white_list[engine->guc_id].count = 0;
948c0e85e96SFrançois Tigeot 	}
949c0e85e96SFrançois Tigeot 
950c0e85e96SFrançois Tigeot 	ads->reg_state_addr = ads->scheduler_policies +
951c0e85e96SFrançois Tigeot 			sizeof(struct guc_policies);
952c0e85e96SFrançois Tigeot 
953c0e85e96SFrançois Tigeot 	ads->reg_state_buffer = ads->reg_state_addr +
954c0e85e96SFrançois Tigeot 			sizeof(struct guc_mmio_reg_state);
955c0e85e96SFrançois Tigeot 
956c0e85e96SFrançois Tigeot 	kunmap(page);
957c0e85e96SFrançois Tigeot }
958c0e85e96SFrançois Tigeot 
959352ff8bdSFrançois Tigeot /*
960352ff8bdSFrançois Tigeot  * Set up the memory resources to be shared with the GuC.  At this point,
961352ff8bdSFrançois Tigeot  * we require just one object that can be mapped through the GGTT.
962352ff8bdSFrançois Tigeot  */
9631487f786SFrançois Tigeot int i915_guc_submission_init(struct drm_i915_private *dev_priv)
964352ff8bdSFrançois Tigeot {
965352ff8bdSFrançois Tigeot 	const size_t ctxsize = sizeof(struct guc_context_desc);
966352ff8bdSFrançois Tigeot 	const size_t poolsize = GUC_MAX_GPU_CONTEXTS * ctxsize;
967352ff8bdSFrançois Tigeot 	const size_t gemsize = round_up(poolsize, PAGE_SIZE);
968352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
969352ff8bdSFrançois Tigeot 
9701487f786SFrançois Tigeot 	/* Wipe bitmap & delete client in case of reinitialisation */
9711487f786SFrançois Tigeot 	bitmap_clear(guc->doorbell_bitmap, 0, GUC_MAX_DOORBELLS);
9721487f786SFrançois Tigeot 	i915_guc_submission_disable(dev_priv);
9731487f786SFrançois Tigeot 
974352ff8bdSFrançois Tigeot 	if (!i915.enable_guc_submission)
975352ff8bdSFrançois Tigeot 		return 0; /* not enabled  */
976352ff8bdSFrançois Tigeot 
977352ff8bdSFrançois Tigeot 	if (guc->ctx_pool_obj)
978352ff8bdSFrançois Tigeot 		return 0; /* already allocated */
979352ff8bdSFrançois Tigeot 
9801487f786SFrançois Tigeot 	guc->ctx_pool_obj = gem_allocate_guc_obj(dev_priv, gemsize);
981352ff8bdSFrançois Tigeot 	if (!guc->ctx_pool_obj)
982352ff8bdSFrançois Tigeot 		return -ENOMEM;
983352ff8bdSFrançois Tigeot 
984352ff8bdSFrançois Tigeot 	ida_init(&guc->ctx_ids);
985352ff8bdSFrançois Tigeot 	guc_create_log(guc);
986c0e85e96SFrançois Tigeot 	guc_create_ads(guc);
987c0e85e96SFrançois Tigeot 
988352ff8bdSFrançois Tigeot 	return 0;
989352ff8bdSFrançois Tigeot }
990352ff8bdSFrançois Tigeot 
9911487f786SFrançois Tigeot int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
992352ff8bdSFrançois Tigeot {
993352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
994352ff8bdSFrançois Tigeot 	struct i915_guc_client *client;
995352ff8bdSFrançois Tigeot 
996352ff8bdSFrançois Tigeot 	/* client for execbuf submission */
9971487f786SFrançois Tigeot 	client = guc_client_alloc(dev_priv,
9981487f786SFrançois Tigeot 				  GUC_CTX_PRIORITY_KMD_NORMAL,
9991487f786SFrançois Tigeot 				  dev_priv->kernel_context);
1000352ff8bdSFrançois Tigeot 	if (!client) {
1001352ff8bdSFrançois Tigeot 		DRM_ERROR("Failed to create execbuf guc_client\n");
1002352ff8bdSFrançois Tigeot 		return -ENOMEM;
1003352ff8bdSFrançois Tigeot 	}
1004352ff8bdSFrançois Tigeot 
1005352ff8bdSFrançois Tigeot 	guc->execbuf_client = client;
1006352ff8bdSFrançois Tigeot 	host2guc_sample_forcewake(guc, client);
10071487f786SFrançois Tigeot 	guc_init_doorbell_hw(guc);
1008352ff8bdSFrançois Tigeot 
1009352ff8bdSFrançois Tigeot 	return 0;
1010352ff8bdSFrançois Tigeot }
1011352ff8bdSFrançois Tigeot 
10121487f786SFrançois Tigeot void i915_guc_submission_disable(struct drm_i915_private *dev_priv)
1013352ff8bdSFrançois Tigeot {
1014352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
1015352ff8bdSFrançois Tigeot 
10161487f786SFrançois Tigeot 	guc_client_free(dev_priv, guc->execbuf_client);
1017352ff8bdSFrançois Tigeot 	guc->execbuf_client = NULL;
1018352ff8bdSFrançois Tigeot }
1019352ff8bdSFrançois Tigeot 
10201487f786SFrançois Tigeot void i915_guc_submission_fini(struct drm_i915_private *dev_priv)
1021352ff8bdSFrançois Tigeot {
1022352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
1023352ff8bdSFrançois Tigeot 
1024c0e85e96SFrançois Tigeot 	gem_release_guc_obj(dev_priv->guc.ads_obj);
1025c0e85e96SFrançois Tigeot 	guc->ads_obj = NULL;
1026c0e85e96SFrançois Tigeot 
1027352ff8bdSFrançois Tigeot 	gem_release_guc_obj(dev_priv->guc.log_obj);
1028352ff8bdSFrançois Tigeot 	guc->log_obj = NULL;
1029352ff8bdSFrançois Tigeot 
1030352ff8bdSFrançois Tigeot 	if (guc->ctx_pool_obj)
1031352ff8bdSFrançois Tigeot 		ida_destroy(&guc->ctx_ids);
1032352ff8bdSFrançois Tigeot 	gem_release_guc_obj(guc->ctx_pool_obj);
1033352ff8bdSFrançois Tigeot 	guc->ctx_pool_obj = NULL;
1034352ff8bdSFrançois Tigeot }
1035352ff8bdSFrançois Tigeot 
1036352ff8bdSFrançois Tigeot /**
1037352ff8bdSFrançois Tigeot  * intel_guc_suspend() - notify GuC entering suspend state
1038352ff8bdSFrançois Tigeot  * @dev:	drm device
1039352ff8bdSFrançois Tigeot  */
1040352ff8bdSFrançois Tigeot int intel_guc_suspend(struct drm_device *dev)
1041352ff8bdSFrançois Tigeot {
1042*303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1043352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
10441487f786SFrançois Tigeot 	struct i915_gem_context *ctx;
1045352ff8bdSFrançois Tigeot 	u32 data[3];
1046352ff8bdSFrançois Tigeot 
10471487f786SFrançois Tigeot 	if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS)
1048352ff8bdSFrançois Tigeot 		return 0;
1049352ff8bdSFrançois Tigeot 
1050c0e85e96SFrançois Tigeot 	ctx = dev_priv->kernel_context;
1051352ff8bdSFrançois Tigeot 
1052352ff8bdSFrançois Tigeot 	data[0] = HOST2GUC_ACTION_ENTER_S_STATE;
1053352ff8bdSFrançois Tigeot 	/* any value greater than GUC_POWER_D0 */
1054352ff8bdSFrançois Tigeot 	data[1] = GUC_POWER_D1;
1055352ff8bdSFrançois Tigeot 	/* first page is shared data with GuC */
1056352ff8bdSFrançois Tigeot 	data[2] = i915_gem_obj_ggtt_offset(ctx->engine[RCS].state);
1057352ff8bdSFrançois Tigeot 
1058352ff8bdSFrançois Tigeot 	return host2guc_action(guc, data, ARRAY_SIZE(data));
1059352ff8bdSFrançois Tigeot }
1060352ff8bdSFrançois Tigeot 
1061352ff8bdSFrançois Tigeot 
1062352ff8bdSFrançois Tigeot /**
1063352ff8bdSFrançois Tigeot  * intel_guc_resume() - notify GuC resuming from suspend state
1064352ff8bdSFrançois Tigeot  * @dev:	drm device
1065352ff8bdSFrançois Tigeot  */
1066352ff8bdSFrançois Tigeot int intel_guc_resume(struct drm_device *dev)
1067352ff8bdSFrançois Tigeot {
1068*303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1069352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
10701487f786SFrançois Tigeot 	struct i915_gem_context *ctx;
1071352ff8bdSFrançois Tigeot 	u32 data[3];
1072352ff8bdSFrançois Tigeot 
10731487f786SFrançois Tigeot 	if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS)
1074352ff8bdSFrançois Tigeot 		return 0;
1075352ff8bdSFrançois Tigeot 
1076c0e85e96SFrançois Tigeot 	ctx = dev_priv->kernel_context;
1077352ff8bdSFrançois Tigeot 
1078352ff8bdSFrançois Tigeot 	data[0] = HOST2GUC_ACTION_EXIT_S_STATE;
1079352ff8bdSFrançois Tigeot 	data[1] = GUC_POWER_D0;
1080352ff8bdSFrançois Tigeot 	/* first page is shared data with GuC */
1081352ff8bdSFrançois Tigeot 	data[2] = i915_gem_obj_ggtt_offset(ctx->engine[RCS].state);
1082352ff8bdSFrançois Tigeot 
1083352ff8bdSFrançois Tigeot 	return host2guc_action(guc, data, ARRAY_SIZE(data));
1084352ff8bdSFrançois Tigeot }
1085