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  */
24a85cb24fSFrançois Tigeot 
25*3f2dd94aSFrançois Tigeot #include <linux/circ_buf.h>
26a85cb24fSFrançois Tigeot #include <trace/events/dma_fence.h>
27352ff8bdSFrançois Tigeot 
28*3f2dd94aSFrançois Tigeot #include "i915_guc_submission.h"
29*3f2dd94aSFrançois Tigeot #include "i915_drv.h"
30*3f2dd94aSFrançois Tigeot 
31352ff8bdSFrançois Tigeot /**
32aee94f86SFrançois Tigeot  * DOC: GuC-based command submission
33352ff8bdSFrançois Tigeot  *
34a85cb24fSFrançois Tigeot  * GuC client:
35a85cb24fSFrançois Tigeot  * A i915_guc_client refers to a submission path through GuC. Currently, there
36a85cb24fSFrançois Tigeot  * is only one of these (the execbuf_client) and this one is charged with all
37a85cb24fSFrançois Tigeot  * submissions to the GuC. This struct is the owner of a doorbell, a process
38a85cb24fSFrançois Tigeot  * descriptor and a workqueue (all of them inside a single gem object that
39a85cb24fSFrançois Tigeot  * contains all required pages for these elements).
40352ff8bdSFrançois Tigeot  *
41a85cb24fSFrançois Tigeot  * GuC stage descriptor:
42a85cb24fSFrançois Tigeot  * During initialization, the driver allocates a static pool of 1024 such
43a85cb24fSFrançois Tigeot  * descriptors, and shares them with the GuC.
44a85cb24fSFrançois Tigeot  * Currently, there exists a 1:1 mapping between a i915_guc_client and a
45a85cb24fSFrançois Tigeot  * guc_stage_desc (via the client's stage_id), so effectively only one
46a85cb24fSFrançois Tigeot  * gets used. This stage descriptor lets the GuC know about the doorbell,
47a85cb24fSFrançois Tigeot  * workqueue and process descriptor. Theoretically, it also lets the GuC
48a85cb24fSFrançois Tigeot  * know about our HW contexts (context ID, etc...), but we actually
49a85cb24fSFrançois Tigeot  * employ a kind of submission where the GuC uses the LRCA sent via the work
50a85cb24fSFrançois Tigeot  * item instead (the single guc_stage_desc associated to execbuf client
51a85cb24fSFrançois Tigeot  * contains information about the default kernel context only, but this is
52a85cb24fSFrançois Tigeot  * essentially unused). This is called a "proxy" submission.
53352ff8bdSFrançois Tigeot  *
54352ff8bdSFrançois Tigeot  * The Scratch registers:
55352ff8bdSFrançois Tigeot  * There are 16 MMIO-based registers start from 0xC180. The kernel driver writes
56352ff8bdSFrançois Tigeot  * a value to the action register (SOFT_SCRATCH_0) along with any data. It then
57352ff8bdSFrançois Tigeot  * triggers an interrupt on the GuC via another register write (0xC4C8).
58352ff8bdSFrançois Tigeot  * Firmware writes a success/fail code back to the action register after
59352ff8bdSFrançois Tigeot  * processes the request. The kernel driver polls waiting for this update and
60352ff8bdSFrançois Tigeot  * then proceeds.
61a85cb24fSFrançois Tigeot  * See intel_guc_send()
62352ff8bdSFrançois Tigeot  *
63352ff8bdSFrançois Tigeot  * Doorbells:
64352ff8bdSFrançois Tigeot  * Doorbells are interrupts to uKernel. A doorbell is a single cache line (QW)
65352ff8bdSFrançois Tigeot  * mapped into process space.
66352ff8bdSFrançois Tigeot  *
67352ff8bdSFrançois Tigeot  * Work Items:
68352ff8bdSFrançois Tigeot  * There are several types of work items that the host may place into a
69352ff8bdSFrançois Tigeot  * workqueue, each with its own requirements and limitations. Currently only
70352ff8bdSFrançois Tigeot  * WQ_TYPE_INORDER is needed to support legacy submission via GuC, which
71352ff8bdSFrançois Tigeot  * represents in-order queue. The kernel driver packs ring tail pointer and an
72352ff8bdSFrançois Tigeot  * ELSP context descriptor dword into Work Item.
731e12ee3bSFrançois Tigeot  * See guc_wq_item_append()
74352ff8bdSFrançois Tigeot  *
75a85cb24fSFrançois Tigeot  * ADS:
76a85cb24fSFrançois Tigeot  * The Additional Data Struct (ADS) has pointers for different buffers used by
77a85cb24fSFrançois Tigeot  * the GuC. One single gem object contains the ADS struct itself (guc_ads), the
78a85cb24fSFrançois Tigeot  * scheduling policies (guc_policies), a structure describing a collection of
79a85cb24fSFrançois Tigeot  * register sets (guc_mmio_reg_state) and some extra pages for the GuC to save
80a85cb24fSFrançois Tigeot  * its internal state for sleep.
81a85cb24fSFrançois Tigeot  *
82352ff8bdSFrançois Tigeot  */
83352ff8bdSFrançois Tigeot 
is_high_priority(struct i915_guc_client * client)84a85cb24fSFrançois Tigeot static inline bool is_high_priority(struct i915_guc_client* client)
85352ff8bdSFrançois Tigeot {
86a85cb24fSFrançois Tigeot 	return client->priority <= GUC_CLIENT_PRIORITY_HIGH;
87352ff8bdSFrançois Tigeot }
88352ff8bdSFrançois Tigeot 
__reserve_doorbell(struct i915_guc_client * client)89a85cb24fSFrançois Tigeot static int __reserve_doorbell(struct i915_guc_client *client)
90352ff8bdSFrançois Tigeot {
91a85cb24fSFrançois Tigeot 	unsigned long offset;
92a85cb24fSFrançois Tigeot 	unsigned long end;
93a85cb24fSFrançois Tigeot 	u16 id;
94352ff8bdSFrançois Tigeot 
95a85cb24fSFrançois Tigeot 	GEM_BUG_ON(client->doorbell_id != GUC_DOORBELL_INVALID);
96352ff8bdSFrançois Tigeot 
97303bf270SFrançois Tigeot 	/*
98a85cb24fSFrançois Tigeot 	 * The bitmap tracks which doorbell registers are currently in use.
99a85cb24fSFrançois Tigeot 	 * It is split into two halves; the first half is used for normal
100a85cb24fSFrançois Tigeot 	 * priority contexts, the second half for high-priority ones.
101303bf270SFrançois Tigeot 	 */
102a85cb24fSFrançois Tigeot 	offset = 0;
103a85cb24fSFrançois Tigeot 	end = GUC_NUM_DOORBELLS/2;
104a85cb24fSFrançois Tigeot 	if (is_high_priority(client)) {
105a85cb24fSFrançois Tigeot 		offset = end;
106a85cb24fSFrançois Tigeot 		end += offset;
107352ff8bdSFrançois Tigeot 	}
108352ff8bdSFrançois Tigeot 
109*3f2dd94aSFrançois Tigeot 	id = find_next_zero_bit(client->guc->doorbell_bitmap, end, offset);
110a85cb24fSFrançois Tigeot 	if (id == end)
111a85cb24fSFrançois Tigeot 		return -ENOSPC;
112352ff8bdSFrançois Tigeot 
113a85cb24fSFrançois Tigeot 	__set_bit(id, client->guc->doorbell_bitmap);
114a85cb24fSFrançois Tigeot 	client->doorbell_id = id;
115a85cb24fSFrançois Tigeot 	DRM_DEBUG_DRIVER("client %u (high prio=%s) reserved doorbell: %d\n",
116a85cb24fSFrançois Tigeot 			 client->stage_id, yesno(is_high_priority(client)),
117a85cb24fSFrançois Tigeot 			 id);
118a85cb24fSFrançois Tigeot 	return 0;
119a85cb24fSFrançois Tigeot }
120a85cb24fSFrançois Tigeot 
__unreserve_doorbell(struct i915_guc_client * client)121a85cb24fSFrançois Tigeot static void __unreserve_doorbell(struct i915_guc_client *client)
122a85cb24fSFrançois Tigeot {
123a85cb24fSFrançois Tigeot 	GEM_BUG_ON(client->doorbell_id == GUC_DOORBELL_INVALID);
124a85cb24fSFrançois Tigeot 
125a85cb24fSFrançois Tigeot 	__clear_bit(client->doorbell_id, client->guc->doorbell_bitmap);
126a85cb24fSFrançois Tigeot 	client->doorbell_id = GUC_DOORBELL_INVALID;
127352ff8bdSFrançois Tigeot }
128352ff8bdSFrançois Tigeot 
129352ff8bdSFrançois Tigeot /*
130352ff8bdSFrançois Tigeot  * Tell the GuC to allocate or deallocate a specific doorbell
131352ff8bdSFrançois Tigeot  */
132352ff8bdSFrançois Tigeot 
__guc_allocate_doorbell(struct intel_guc * guc,u32 stage_id)133a85cb24fSFrançois Tigeot static int __guc_allocate_doorbell(struct intel_guc *guc, u32 stage_id)
134352ff8bdSFrançois Tigeot {
135a85cb24fSFrançois Tigeot 	u32 action[] = {
136a85cb24fSFrançois Tigeot 		INTEL_GUC_ACTION_ALLOCATE_DOORBELL,
137a85cb24fSFrançois Tigeot 		stage_id
138a85cb24fSFrançois Tigeot 	};
139352ff8bdSFrançois Tigeot 
140a85cb24fSFrançois Tigeot 	return intel_guc_send(guc, action, ARRAY_SIZE(action));
141352ff8bdSFrançois Tigeot }
142352ff8bdSFrançois Tigeot 
__guc_deallocate_doorbell(struct intel_guc * guc,u32 stage_id)143a85cb24fSFrançois Tigeot static int __guc_deallocate_doorbell(struct intel_guc *guc, u32 stage_id)
144352ff8bdSFrançois Tigeot {
145a85cb24fSFrançois Tigeot 	u32 action[] = {
146a85cb24fSFrançois Tigeot 		INTEL_GUC_ACTION_DEALLOCATE_DOORBELL,
147a85cb24fSFrançois Tigeot 		stage_id
148a85cb24fSFrançois Tigeot 	};
149352ff8bdSFrançois Tigeot 
150a85cb24fSFrançois Tigeot 	return intel_guc_send(guc, action, ARRAY_SIZE(action));
151352ff8bdSFrançois Tigeot }
152352ff8bdSFrançois Tigeot 
__get_stage_desc(struct i915_guc_client * client)153a85cb24fSFrançois Tigeot static struct guc_stage_desc *__get_stage_desc(struct i915_guc_client *client)
154352ff8bdSFrançois Tigeot {
155a85cb24fSFrançois Tigeot 	struct guc_stage_desc *base = client->guc->stage_desc_pool_vaddr;
156352ff8bdSFrançois Tigeot 
157a85cb24fSFrançois Tigeot 	return &base[client->stage_id];
1584be47400SFrançois Tigeot }
1594be47400SFrançois Tigeot 
160352ff8bdSFrançois Tigeot /*
161352ff8bdSFrançois Tigeot  * Initialise, update, or clear doorbell data shared with the GuC
162352ff8bdSFrançois Tigeot  *
163352ff8bdSFrançois Tigeot  * These functions modify shared data and so need access to the mapped
164352ff8bdSFrançois Tigeot  * client object which contains the page being used for the doorbell
165352ff8bdSFrançois Tigeot  */
166352ff8bdSFrançois Tigeot 
__update_doorbell_desc(struct i915_guc_client * client,u16 new_id)167a85cb24fSFrançois Tigeot static void __update_doorbell_desc(struct i915_guc_client *client, u16 new_id)
168352ff8bdSFrançois Tigeot {
169a85cb24fSFrançois Tigeot 	struct guc_stage_desc *desc;
1701487f786SFrançois Tigeot 
1711487f786SFrançois Tigeot 	/* Update the GuC's idea of the doorbell ID */
172a85cb24fSFrançois Tigeot 	desc = __get_stage_desc(client);
173a85cb24fSFrançois Tigeot 	desc->db_id = new_id;
174a85cb24fSFrançois Tigeot }
1751487f786SFrançois Tigeot 
__get_doorbell(struct i915_guc_client * client)176a85cb24fSFrançois Tigeot static struct guc_doorbell_info *__get_doorbell(struct i915_guc_client *client)
177a85cb24fSFrançois Tigeot {
178a85cb24fSFrançois Tigeot 	return client->vaddr + client->doorbell_offset;
179a85cb24fSFrançois Tigeot }
180a85cb24fSFrançois Tigeot 
has_doorbell(struct i915_guc_client * client)181a85cb24fSFrançois Tigeot static bool has_doorbell(struct i915_guc_client *client)
182a85cb24fSFrançois Tigeot {
183a85cb24fSFrançois Tigeot 	if (client->doorbell_id == GUC_DOORBELL_INVALID)
184a85cb24fSFrançois Tigeot 		return false;
185a85cb24fSFrançois Tigeot 
186a85cb24fSFrançois Tigeot 	return test_bit(client->doorbell_id, client->guc->doorbell_bitmap);
187a85cb24fSFrançois Tigeot }
188a85cb24fSFrançois Tigeot 
__create_doorbell(struct i915_guc_client * client)189a85cb24fSFrançois Tigeot static int __create_doorbell(struct i915_guc_client *client)
190a85cb24fSFrançois Tigeot {
191a85cb24fSFrançois Tigeot 	struct guc_doorbell_info *doorbell;
192a85cb24fSFrançois Tigeot 	int err;
193a85cb24fSFrançois Tigeot 
194a85cb24fSFrançois Tigeot 	doorbell = __get_doorbell(client);
195a85cb24fSFrançois Tigeot 	doorbell->db_status = GUC_DOORBELL_ENABLED;
196*3f2dd94aSFrançois Tigeot 	doorbell->cookie = 0;
197a85cb24fSFrançois Tigeot 
198a85cb24fSFrançois Tigeot 	err = __guc_allocate_doorbell(client->guc, client->stage_id);
199*3f2dd94aSFrançois Tigeot 	if (err)
200a85cb24fSFrançois Tigeot 		doorbell->db_status = GUC_DOORBELL_DISABLED;
201*3f2dd94aSFrançois Tigeot 
202a85cb24fSFrançois Tigeot 	return err;
203a85cb24fSFrançois Tigeot }
204a85cb24fSFrançois Tigeot 
__destroy_doorbell(struct i915_guc_client * client)205a85cb24fSFrançois Tigeot static int __destroy_doorbell(struct i915_guc_client *client)
206a85cb24fSFrançois Tigeot {
207a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = guc_to_i915(client->guc);
208a85cb24fSFrançois Tigeot 	struct guc_doorbell_info *doorbell;
209a85cb24fSFrançois Tigeot 	u16 db_id = client->doorbell_id;
210a85cb24fSFrançois Tigeot 
211a85cb24fSFrançois Tigeot 	GEM_BUG_ON(db_id >= GUC_DOORBELL_INVALID);
212a85cb24fSFrançois Tigeot 
213a85cb24fSFrançois Tigeot 	doorbell = __get_doorbell(client);
214a85cb24fSFrançois Tigeot 	doorbell->db_status = GUC_DOORBELL_DISABLED;
215a85cb24fSFrançois Tigeot 	doorbell->cookie = 0;
216a85cb24fSFrançois Tigeot 
217a85cb24fSFrançois Tigeot 	/* Doorbell release flow requires that we wait for GEN8_DRB_VALID bit
218a85cb24fSFrançois Tigeot 	 * to go to zero after updating db_status before we call the GuC to
219a85cb24fSFrançois Tigeot 	 * release the doorbell */
220a85cb24fSFrançois Tigeot 	if (wait_for_us(!(I915_READ(GEN8_DRBREGL(db_id)) & GEN8_DRB_VALID), 10))
221a85cb24fSFrançois Tigeot 		WARN_ONCE(true, "Doorbell never became invalid after disable\n");
222a85cb24fSFrançois Tigeot 
223a85cb24fSFrançois Tigeot 	return __guc_deallocate_doorbell(client->guc, client->stage_id);
224a85cb24fSFrançois Tigeot }
225a85cb24fSFrançois Tigeot 
create_doorbell(struct i915_guc_client * client)226a85cb24fSFrançois Tigeot static int create_doorbell(struct i915_guc_client *client)
227a85cb24fSFrançois Tigeot {
228a85cb24fSFrançois Tigeot 	int ret;
229a85cb24fSFrançois Tigeot 
230a85cb24fSFrançois Tigeot 	ret = __reserve_doorbell(client);
231a85cb24fSFrançois Tigeot 	if (ret)
232a85cb24fSFrançois Tigeot 		return ret;
233a85cb24fSFrançois Tigeot 
234a85cb24fSFrançois Tigeot 	__update_doorbell_desc(client, client->doorbell_id);
235a85cb24fSFrançois Tigeot 
236a85cb24fSFrançois Tigeot 	ret = __create_doorbell(client);
237a85cb24fSFrançois Tigeot 	if (ret)
238a85cb24fSFrançois Tigeot 		goto err;
239a85cb24fSFrançois Tigeot 
2401487f786SFrançois Tigeot 	return 0;
2411487f786SFrançois Tigeot 
242a85cb24fSFrançois Tigeot err:
243a85cb24fSFrançois Tigeot 	__update_doorbell_desc(client, GUC_DOORBELL_INVALID);
244a85cb24fSFrançois Tigeot 	__unreserve_doorbell(client);
245a85cb24fSFrançois Tigeot 	return ret;
246352ff8bdSFrançois Tigeot }
247352ff8bdSFrançois Tigeot 
destroy_doorbell(struct i915_guc_client * client)248a85cb24fSFrançois Tigeot static int destroy_doorbell(struct i915_guc_client *client)
249352ff8bdSFrançois Tigeot {
250a85cb24fSFrançois Tigeot 	int err;
251352ff8bdSFrançois Tigeot 
252a85cb24fSFrançois Tigeot 	GEM_BUG_ON(!has_doorbell(client));
253352ff8bdSFrançois Tigeot 
254352ff8bdSFrançois Tigeot 	/* XXX: wait for any interrupts */
255352ff8bdSFrançois Tigeot 	/* XXX: wait for workqueue to drain */
256a85cb24fSFrançois Tigeot 
257a85cb24fSFrançois Tigeot 	err = __destroy_doorbell(client);
258a85cb24fSFrançois Tigeot 	if (err)
259a85cb24fSFrançois Tigeot 		return err;
260a85cb24fSFrançois Tigeot 
261a85cb24fSFrançois Tigeot 	__update_doorbell_desc(client, GUC_DOORBELL_INVALID);
262a85cb24fSFrançois Tigeot 
263a85cb24fSFrançois Tigeot 	__unreserve_doorbell(client);
264a85cb24fSFrançois Tigeot 
265a85cb24fSFrançois Tigeot 	return 0;
266352ff8bdSFrançois Tigeot }
267352ff8bdSFrançois Tigeot 
__select_cacheline(struct intel_guc * guc)268a85cb24fSFrançois Tigeot static unsigned long __select_cacheline(struct intel_guc* guc)
2691487f786SFrançois Tigeot {
270a85cb24fSFrançois Tigeot 	unsigned long offset;
271352ff8bdSFrançois Tigeot 
272352ff8bdSFrançois Tigeot 	/* Doorbell uses a single cache line within a page */
273352ff8bdSFrançois Tigeot 	offset = offset_in_page(guc->db_cacheline);
274352ff8bdSFrançois Tigeot 
275352ff8bdSFrançois Tigeot 	/* Moving to next cache line to reduce contention */
276a85cb24fSFrançois Tigeot 	guc->db_cacheline += cache_line_size();
277352ff8bdSFrançois Tigeot 
278a85cb24fSFrançois Tigeot 	DRM_DEBUG_DRIVER("reserved cacheline 0x%lx, next 0x%x, linesize %u\n",
279a85cb24fSFrançois Tigeot 			offset, guc->db_cacheline, cache_line_size());
280352ff8bdSFrançois Tigeot 	return offset;
281352ff8bdSFrançois Tigeot }
282352ff8bdSFrançois Tigeot 
283a85cb24fSFrançois Tigeot static inline struct guc_process_desc *
__get_process_desc(struct i915_guc_client * client)284a85cb24fSFrançois Tigeot __get_process_desc(struct i915_guc_client *client)
285a85cb24fSFrançois Tigeot {
286a85cb24fSFrançois Tigeot 	return client->vaddr + client->proc_desc_offset;
287a85cb24fSFrançois Tigeot }
288a85cb24fSFrançois Tigeot 
289352ff8bdSFrançois Tigeot /*
290352ff8bdSFrançois Tigeot  * Initialise the process descriptor shared with the GuC firmware.
291352ff8bdSFrançois Tigeot  */
guc_proc_desc_init(struct intel_guc * guc,struct i915_guc_client * client)2921e12ee3bSFrançois Tigeot static void guc_proc_desc_init(struct intel_guc *guc,
293352ff8bdSFrançois Tigeot 			       struct i915_guc_client *client)
294352ff8bdSFrançois Tigeot {
295352ff8bdSFrançois Tigeot 	struct guc_process_desc *desc;
296352ff8bdSFrançois Tigeot 
297a85cb24fSFrançois Tigeot 	desc = memset(__get_process_desc(client), 0, sizeof(*desc));
298352ff8bdSFrançois Tigeot 
299352ff8bdSFrançois Tigeot 	/*
300352ff8bdSFrançois Tigeot 	 * XXX: pDoorbell and WQVBaseAddress are pointers in process address
301352ff8bdSFrançois Tigeot 	 * space for ring3 clients (set them as in mmap_ioctl) or kernel
302352ff8bdSFrançois Tigeot 	 * space for kernel clients (map on demand instead? May make debug
303352ff8bdSFrançois Tigeot 	 * easier to have it mapped).
304352ff8bdSFrançois Tigeot 	 */
305352ff8bdSFrançois Tigeot 	desc->wq_base_addr = 0;
306352ff8bdSFrançois Tigeot 	desc->db_base_addr = 0;
307352ff8bdSFrançois Tigeot 
308a85cb24fSFrançois Tigeot 	desc->stage_id = client->stage_id;
309*3f2dd94aSFrançois Tigeot 	desc->wq_size_bytes = GUC_WQ_SIZE;
310352ff8bdSFrançois Tigeot 	desc->wq_status = WQ_STATUS_ACTIVE;
311352ff8bdSFrançois Tigeot 	desc->priority = client->priority;
312352ff8bdSFrançois Tigeot }
313352ff8bdSFrançois Tigeot 
314352ff8bdSFrançois Tigeot /*
315a85cb24fSFrançois Tigeot  * Initialise/clear the stage descriptor shared with the GuC firmware.
316352ff8bdSFrançois Tigeot  *
317352ff8bdSFrançois Tigeot  * This descriptor tells the GuC where (in GGTT space) to find the important
318352ff8bdSFrançois Tigeot  * data structures relating to this client (doorbell, process descriptor,
319352ff8bdSFrançois Tigeot  * write queue, etc).
320352ff8bdSFrançois Tigeot  */
guc_stage_desc_init(struct intel_guc * guc,struct i915_guc_client * client)321a85cb24fSFrançois Tigeot static void guc_stage_desc_init(struct intel_guc *guc,
322352ff8bdSFrançois Tigeot 				struct i915_guc_client *client)
323352ff8bdSFrançois Tigeot {
324c0e85e96SFrançois Tigeot 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
3258621f407SFrançois Tigeot 	struct intel_engine_cs *engine;
3261487f786SFrançois Tigeot 	struct i915_gem_context *ctx = client->owner;
327a85cb24fSFrançois Tigeot 	struct guc_stage_desc *desc;
3281e12ee3bSFrançois Tigeot 	unsigned int tmp;
3298621f407SFrançois Tigeot 	u32 gfx_addr;
330352ff8bdSFrançois Tigeot 
331a85cb24fSFrançois Tigeot 	desc = __get_stage_desc(client);
332a85cb24fSFrançois Tigeot 	memset(desc, 0, sizeof(*desc));
333352ff8bdSFrançois Tigeot 
334a85cb24fSFrançois Tigeot 	desc->attribute = GUC_STAGE_DESC_ATTR_ACTIVE | GUC_STAGE_DESC_ATTR_KERNEL;
335a85cb24fSFrançois Tigeot 	desc->stage_id = client->stage_id;
336a85cb24fSFrançois Tigeot 	desc->priority = client->priority;
337a85cb24fSFrançois Tigeot 	desc->db_id = client->doorbell_id;
338352ff8bdSFrançois Tigeot 
3391e12ee3bSFrançois Tigeot 	for_each_engine_masked(engine, dev_priv, client->engines, tmp) {
3401487f786SFrançois Tigeot 		struct intel_context *ce = &ctx->engine[engine->id];
341*3f2dd94aSFrançois Tigeot 		u32 guc_engine_id = engine->guc_id;
342a85cb24fSFrançois Tigeot 		struct guc_execlist_context *lrc = &desc->lrc[guc_engine_id];
343352ff8bdSFrançois Tigeot 
344352ff8bdSFrançois Tigeot 		/* TODO: We have a design issue to be solved here. Only when we
345352ff8bdSFrançois Tigeot 		 * receive the first batch, we know which engine is used by the
346352ff8bdSFrançois Tigeot 		 * user. But here GuC expects the lrc and ring to be pinned. It
347352ff8bdSFrançois Tigeot 		 * is not an issue for default context, which is the only one
348352ff8bdSFrançois Tigeot 		 * for now who owns a GuC client. But for future owner of GuC
349352ff8bdSFrançois Tigeot 		 * client, need to make sure lrc is pinned prior to enter here.
350352ff8bdSFrançois Tigeot 		 */
3511487f786SFrançois Tigeot 		if (!ce->state)
352352ff8bdSFrançois Tigeot 			break;	/* XXX: continue? */
353352ff8bdSFrançois Tigeot 
354a85cb24fSFrançois Tigeot 		/*
355a85cb24fSFrançois Tigeot 		 * XXX: When this is a GUC_STAGE_DESC_ATTR_KERNEL client (proxy
356a85cb24fSFrançois Tigeot 		 * submission or, in other words, not using a direct submission
357a85cb24fSFrançois Tigeot 		 * model) the KMD's LRCA is not used for any work submission.
358a85cb24fSFrançois Tigeot 		 * Instead, the GuC uses the LRCA of the user mode context (see
359a85cb24fSFrançois Tigeot 		 * guc_wq_item_append below).
360a85cb24fSFrançois Tigeot 		 */
3611487f786SFrançois Tigeot 		lrc->context_desc = lower_32_bits(ce->lrc_desc);
362352ff8bdSFrançois Tigeot 
363352ff8bdSFrançois Tigeot 		/* The state page is after PPHWSP */
364a85cb24fSFrançois Tigeot 		lrc->ring_lrca =
365a85cb24fSFrançois Tigeot 			guc_ggtt_offset(ce->state) + LRC_STATE_PN * PAGE_SIZE;
366a85cb24fSFrançois Tigeot 
367a85cb24fSFrançois Tigeot 		/* XXX: In direct submission, the GuC wants the HW context id
368a85cb24fSFrançois Tigeot 		 * here. In proxy submission, it wants the stage id */
369a85cb24fSFrançois Tigeot 		lrc->context_id = (client->stage_id << GUC_ELC_CTXID_OFFSET) |
3701e12ee3bSFrançois Tigeot 				(guc_engine_id << GUC_ELC_ENGINE_OFFSET);
371352ff8bdSFrançois Tigeot 
372a85cb24fSFrançois Tigeot 		lrc->ring_begin = guc_ggtt_offset(ce->ring->vma);
3731e12ee3bSFrançois Tigeot 		lrc->ring_end = lrc->ring_begin + ce->ring->size - 1;
3741e12ee3bSFrançois Tigeot 		lrc->ring_next_free_location = lrc->ring_begin;
375352ff8bdSFrançois Tigeot 		lrc->ring_current_tail_pointer_value = 0;
376352ff8bdSFrançois Tigeot 
377a85cb24fSFrançois Tigeot 		desc->engines_used |= (1 << guc_engine_id);
378352ff8bdSFrançois Tigeot 	}
379352ff8bdSFrançois Tigeot 
3801e12ee3bSFrançois Tigeot 	DRM_DEBUG_DRIVER("Host engines 0x%x => GuC engines used 0x%x\n",
381a85cb24fSFrançois Tigeot 			client->engines, desc->engines_used);
382a85cb24fSFrançois Tigeot 	WARN_ON(desc->engines_used == 0);
383352ff8bdSFrançois Tigeot 
384352ff8bdSFrançois Tigeot 	/*
3858621f407SFrançois Tigeot 	 * The doorbell, process descriptor, and workqueue are all parts
3868621f407SFrançois Tigeot 	 * of the client object, which the GuC will reference via the GGTT
387352ff8bdSFrançois Tigeot 	 */
388a85cb24fSFrançois Tigeot 	gfx_addr = guc_ggtt_offset(client->vma);
389a85cb24fSFrançois Tigeot 	desc->db_trigger_phy = sg_dma_address(client->vma->pages->sgl) +
3908621f407SFrançois Tigeot 				client->doorbell_offset;
391*3f2dd94aSFrançois Tigeot 	desc->db_trigger_cpu = ptr_to_u64(__get_doorbell(client));
392a85cb24fSFrançois Tigeot 	desc->db_trigger_uk = gfx_addr + client->doorbell_offset;
393a85cb24fSFrançois Tigeot 	desc->process_desc = gfx_addr + client->proc_desc_offset;
394*3f2dd94aSFrançois Tigeot 	desc->wq_addr = gfx_addr + GUC_DB_SIZE;
395*3f2dd94aSFrançois Tigeot 	desc->wq_size = GUC_WQ_SIZE;
396352ff8bdSFrançois Tigeot 
397*3f2dd94aSFrançois Tigeot 	desc->desc_private = ptr_to_u64(client);
398352ff8bdSFrançois Tigeot }
399352ff8bdSFrançois Tigeot 
guc_stage_desc_fini(struct intel_guc * guc,struct i915_guc_client * client)400a85cb24fSFrançois Tigeot static void guc_stage_desc_fini(struct intel_guc *guc,
401352ff8bdSFrançois Tigeot 				struct i915_guc_client *client)
402352ff8bdSFrançois Tigeot {
403a85cb24fSFrançois Tigeot 	struct guc_stage_desc *desc;
404352ff8bdSFrançois Tigeot 
405a85cb24fSFrançois Tigeot 	desc = __get_stage_desc(client);
406a85cb24fSFrançois Tigeot 	memset(desc, 0, sizeof(*desc));
407352ff8bdSFrançois Tigeot }
408352ff8bdSFrançois Tigeot 
4091e12ee3bSFrançois Tigeot /* Construct a Work Item and append it to the GuC's Work Queue */
guc_wq_item_append(struct i915_guc_client * client,struct drm_i915_gem_request * rq)410a85cb24fSFrançois Tigeot static void guc_wq_item_append(struct i915_guc_client *client,
411352ff8bdSFrançois Tigeot 			       struct drm_i915_gem_request *rq)
412352ff8bdSFrançois Tigeot {
4131487f786SFrançois Tigeot 	/* wqi_len is in DWords, and does not include the one-word header */
4141487f786SFrançois Tigeot 	const size_t wqi_size = sizeof(struct guc_wq_item);
4151487f786SFrançois Tigeot 	const u32 wqi_len = wqi_size / sizeof(u32) - 1;
4161e12ee3bSFrançois Tigeot 	struct intel_engine_cs *engine = rq->engine;
417*3f2dd94aSFrançois Tigeot 	struct i915_gem_context *ctx = rq->ctx;
418a85cb24fSFrançois Tigeot 	struct guc_process_desc *desc = __get_process_desc(client);
419352ff8bdSFrançois Tigeot 	struct guc_wq_item *wqi;
420*3f2dd94aSFrançois Tigeot 	u32 ring_tail, wq_off;
421352ff8bdSFrançois Tigeot 
422*3f2dd94aSFrançois Tigeot 	lockdep_assert_held(&client->wq_lock);
4231487f786SFrançois Tigeot 
424*3f2dd94aSFrançois Tigeot 	ring_tail = intel_ring_set_tail(rq->ring, rq->tail) / sizeof(u64);
425*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(ring_tail > WQ_RING_TAIL_MAX);
426352ff8bdSFrançois Tigeot 
427352ff8bdSFrançois Tigeot 	/* For now workqueue item is 4 DWs; workqueue buffer is 2 pages. So we
428352ff8bdSFrançois Tigeot 	 * should not have the case where structure wqi is across page, neither
429352ff8bdSFrançois Tigeot 	 * wrapped to the beginning. This simplifies the implementation below.
430352ff8bdSFrançois Tigeot 	 *
431352ff8bdSFrançois Tigeot 	 * XXX: if not the case, we need save data to a temp wqi and copy it to
432352ff8bdSFrançois Tigeot 	 * workqueue buffer dw by dw.
433352ff8bdSFrançois Tigeot 	 */
4341487f786SFrançois Tigeot 	BUILD_BUG_ON(wqi_size != 16);
435352ff8bdSFrançois Tigeot 
436*3f2dd94aSFrançois Tigeot 	/* Free space is guaranteed. */
437*3f2dd94aSFrançois Tigeot 	wq_off = READ_ONCE(desc->tail);
438*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(CIRC_SPACE(wq_off, READ_ONCE(desc->head),
439*3f2dd94aSFrançois Tigeot 			      GUC_WQ_SIZE) < wqi_size);
4401e12ee3bSFrançois Tigeot 	GEM_BUG_ON(wq_off & (wqi_size - 1));
4411487f786SFrançois Tigeot 
4421487f786SFrançois Tigeot 	/* WQ starts from the page after doorbell / process_desc */
443a85cb24fSFrançois Tigeot 	wqi = client->vaddr + wq_off + GUC_DB_SIZE;
444352ff8bdSFrançois Tigeot 
4451487f786SFrançois Tigeot 	/* Now fill in the 4-word work queue item */
446352ff8bdSFrançois Tigeot 	wqi->header = WQ_TYPE_INORDER |
4471487f786SFrançois Tigeot 		      (wqi_len << WQ_LEN_SHIFT) |
4481e12ee3bSFrançois Tigeot 		      (engine->guc_id << WQ_TARGET_SHIFT) |
449352ff8bdSFrançois Tigeot 		      WQ_NO_WCFLUSH_WAIT;
450352ff8bdSFrançois Tigeot 
451*3f2dd94aSFrançois Tigeot 	wqi->context_desc = lower_32_bits(intel_lr_context_descriptor(ctx, engine));
452352ff8bdSFrançois Tigeot 
453*3f2dd94aSFrançois Tigeot 	wqi->submit_element_info = ring_tail << WQ_RING_TAIL_SHIFT;
4544be47400SFrançois Tigeot 	wqi->fence_id = rq->global_seqno;
455*3f2dd94aSFrançois Tigeot 
456*3f2dd94aSFrançois Tigeot 	/* Postincrement WQ tail for next time. */
457*3f2dd94aSFrançois Tigeot 	WRITE_ONCE(desc->tail, (wq_off + wqi_size) & (GUC_WQ_SIZE - 1));
4581487f786SFrançois Tigeot }
459352ff8bdSFrançois Tigeot 
guc_reset_wq(struct i915_guc_client * client)460a85cb24fSFrançois Tigeot static void guc_reset_wq(struct i915_guc_client *client)
4611487f786SFrançois Tigeot {
462a85cb24fSFrançois Tigeot 	struct guc_process_desc *desc = __get_process_desc(client);
463a85cb24fSFrançois Tigeot 
464a85cb24fSFrançois Tigeot 	desc->head = 0;
465a85cb24fSFrançois Tigeot 	desc->tail = 0;
466a85cb24fSFrançois Tigeot }
467a85cb24fSFrançois Tigeot 
guc_ring_doorbell(struct i915_guc_client * client)468*3f2dd94aSFrançois Tigeot static void guc_ring_doorbell(struct i915_guc_client *client)
469a85cb24fSFrançois Tigeot {
470*3f2dd94aSFrançois Tigeot 	struct guc_doorbell_info *db;
471*3f2dd94aSFrançois Tigeot 	u32 cookie;
4721487f786SFrançois Tigeot 
473*3f2dd94aSFrançois Tigeot 	lockdep_assert_held(&client->wq_lock);
4741487f786SFrançois Tigeot 
4751487f786SFrançois Tigeot 	/* pointer of current doorbell cacheline */
476*3f2dd94aSFrançois Tigeot 	db = __get_doorbell(client);
4771487f786SFrançois Tigeot 
478*3f2dd94aSFrançois Tigeot 	/* we're not expecting the doorbell cookie to change behind our back */
479*3f2dd94aSFrançois Tigeot 	cookie = READ_ONCE(db->cookie);
480*3f2dd94aSFrançois Tigeot 	WARN_ON_ONCE(xchg(&db->cookie, cookie + 1) != cookie);
4811487f786SFrançois Tigeot 
4821487f786SFrançois Tigeot 	/* XXX: doorbell was lost and need to acquire it again */
483*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(db->db_status != GUC_DOORBELL_ENABLED);
484352ff8bdSFrançois Tigeot }
485352ff8bdSFrançois Tigeot 
486352ff8bdSFrançois Tigeot /**
487*3f2dd94aSFrançois Tigeot  * i915_guc_submit() - Submit commands through GuC
488*3f2dd94aSFrançois Tigeot  * @engine: engine associated with the commands
4891487f786SFrançois Tigeot  *
4901487f786SFrançois Tigeot  * The only error here arises if the doorbell hardware isn't functioning
4911487f786SFrançois Tigeot  * as expected, which really shouln't happen.
492352ff8bdSFrançois Tigeot  */
i915_guc_submit(struct intel_engine_cs * engine)493*3f2dd94aSFrançois Tigeot static void i915_guc_submit(struct intel_engine_cs *engine)
494352ff8bdSFrançois Tigeot {
495*3f2dd94aSFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
496*3f2dd94aSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
4971487f786SFrançois Tigeot 	struct i915_guc_client *client = guc->execbuf_client;
498*3f2dd94aSFrançois Tigeot 	struct intel_engine_execlists * const execlists = &engine->execlists;
499*3f2dd94aSFrançois Tigeot 	struct execlist_port *port = execlists->port;
500*3f2dd94aSFrançois Tigeot 	const unsigned int engine_id = engine->id;
501*3f2dd94aSFrançois Tigeot 	unsigned int n;
502352ff8bdSFrançois Tigeot 
503*3f2dd94aSFrançois Tigeot 	for (n = 0; n < execlists_num_ports(execlists); n++) {
504*3f2dd94aSFrançois Tigeot 		struct drm_i915_gem_request *rq;
505*3f2dd94aSFrançois Tigeot 		unsigned int count;
506*3f2dd94aSFrançois Tigeot 
507*3f2dd94aSFrançois Tigeot 		rq = port_unpack(&port[n], &count);
508*3f2dd94aSFrançois Tigeot 		if (rq && count == 0) {
509*3f2dd94aSFrançois Tigeot 			port_set(&port[n], port_pack(rq, ++count));
510*3f2dd94aSFrançois Tigeot 
5114be47400SFrançois Tigeot 			if (i915_vma_is_map_and_fenceable(rq->ring->vma))
5124be47400SFrançois Tigeot 				POSTING_READ_FW(GUC_STATUS);
5134be47400SFrançois Tigeot 
514*3f2dd94aSFrançois Tigeot 			lockmgr(&client->wq_lock, LK_EXCLUSIVE);
515a85cb24fSFrançois Tigeot 
516a85cb24fSFrançois Tigeot 			guc_wq_item_append(client, rq);
517*3f2dd94aSFrançois Tigeot 			guc_ring_doorbell(client);
518352ff8bdSFrançois Tigeot 
519c0e85e96SFrançois Tigeot 			client->submissions[engine_id] += 1;
5201487f786SFrançois Tigeot 
521*3f2dd94aSFrançois Tigeot 			lockmgr(&client->wq_lock, LK_RELEASE);
522a85cb24fSFrançois Tigeot 		}
523*3f2dd94aSFrançois Tigeot 	}
524a85cb24fSFrançois Tigeot }
525a85cb24fSFrançois Tigeot 
nested_enable_signaling(struct drm_i915_gem_request * rq)526a85cb24fSFrançois Tigeot static void nested_enable_signaling(struct drm_i915_gem_request *rq)
527a85cb24fSFrançois Tigeot {
528a85cb24fSFrançois Tigeot 	/* If we use dma_fence_enable_sw_signaling() directly, lockdep
529a85cb24fSFrançois Tigeot 	 * detects an ordering issue between the fence lockclass and the
530a85cb24fSFrançois Tigeot 	 * global_timeline. This circular dependency can only occur via 2
531a85cb24fSFrançois Tigeot 	 * different fences (but same fence lockclass), so we use the nesting
532a85cb24fSFrançois Tigeot 	 * annotation here to prevent the warn, equivalent to the nesting
533a85cb24fSFrançois Tigeot 	 * inside i915_gem_request_submit() for when we also enable the
534a85cb24fSFrançois Tigeot 	 * signaler.
535a85cb24fSFrançois Tigeot 	 */
536a85cb24fSFrançois Tigeot 
537a85cb24fSFrançois Tigeot 	if (test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
538a85cb24fSFrançois Tigeot 			     &rq->fence.flags))
539a85cb24fSFrançois Tigeot 		return;
540a85cb24fSFrançois Tigeot 
541a85cb24fSFrançois Tigeot 	GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags));
542a85cb24fSFrançois Tigeot 	trace_dma_fence_enable_signal(&rq->fence);
543a85cb24fSFrançois Tigeot 
544a85cb24fSFrançois Tigeot 	lockmgr(&rq->lock, LK_EXCLUSIVE);
545*3f2dd94aSFrançois Tigeot 	intel_engine_enable_signaling(rq, true);
546a85cb24fSFrançois Tigeot 	lockmgr(&rq->lock, LK_RELEASE);
547a85cb24fSFrançois Tigeot }
548a85cb24fSFrançois Tigeot 
port_assign(struct execlist_port * port,struct drm_i915_gem_request * rq)549*3f2dd94aSFrançois Tigeot static void port_assign(struct execlist_port *port,
550*3f2dd94aSFrançois Tigeot 			struct drm_i915_gem_request *rq)
551a85cb24fSFrançois Tigeot {
552*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(rq == port_request(port));
553*3f2dd94aSFrançois Tigeot 
554*3f2dd94aSFrançois Tigeot 	if (port_isset(port))
555*3f2dd94aSFrançois Tigeot 		i915_gem_request_put(port_request(port));
556*3f2dd94aSFrançois Tigeot 
557*3f2dd94aSFrançois Tigeot 	port_set(port, port_pack(i915_gem_request_get(rq), port_count(port)));
558*3f2dd94aSFrançois Tigeot 	nested_enable_signaling(rq);
559*3f2dd94aSFrançois Tigeot }
560*3f2dd94aSFrançois Tigeot 
i915_guc_dequeue(struct intel_engine_cs * engine)561*3f2dd94aSFrançois Tigeot static void i915_guc_dequeue(struct intel_engine_cs *engine)
562*3f2dd94aSFrançois Tigeot {
563*3f2dd94aSFrançois Tigeot 	struct intel_engine_execlists * const execlists = &engine->execlists;
564*3f2dd94aSFrançois Tigeot 	struct execlist_port *port = execlists->port;
565*3f2dd94aSFrançois Tigeot 	struct drm_i915_gem_request *last = NULL;
566*3f2dd94aSFrançois Tigeot 	const struct execlist_port * const last_port =
567*3f2dd94aSFrançois Tigeot 		&execlists->port[execlists->port_mask];
568a85cb24fSFrançois Tigeot 	bool submit = false;
569*3f2dd94aSFrançois Tigeot 	struct rb_node *rb;
570*3f2dd94aSFrançois Tigeot 
571*3f2dd94aSFrançois Tigeot 	if (port_isset(port))
572*3f2dd94aSFrançois Tigeot 		port++;
573a85cb24fSFrançois Tigeot 
574a85cb24fSFrançois Tigeot 	spin_lock_irq(&engine->timeline->lock);
575*3f2dd94aSFrançois Tigeot 	rb = execlists->first;
576*3f2dd94aSFrançois Tigeot 	GEM_BUG_ON(rb_first(&execlists->queue) != rb);
577a85cb24fSFrançois Tigeot 	while (rb) {
578*3f2dd94aSFrançois Tigeot 		struct i915_priolist *p = rb_entry(rb, typeof(*p), node);
579*3f2dd94aSFrançois Tigeot 		struct drm_i915_gem_request *rq, *rn;
580a85cb24fSFrançois Tigeot 
581*3f2dd94aSFrançois Tigeot 		list_for_each_entry_safe(rq, rn, &p->requests, priotree.link) {
582a85cb24fSFrançois Tigeot 			if (last && rq->ctx != last->ctx) {
583*3f2dd94aSFrançois Tigeot 				if (port == last_port) {
584*3f2dd94aSFrançois Tigeot 					__list_del_many(&p->requests,
585*3f2dd94aSFrançois Tigeot 							&rq->priotree.link);
586*3f2dd94aSFrançois Tigeot 					goto done;
587*3f2dd94aSFrançois Tigeot 				}
588a85cb24fSFrançois Tigeot 
589*3f2dd94aSFrançois Tigeot 				if (submit)
590*3f2dd94aSFrançois Tigeot 					port_assign(port, last);
591a85cb24fSFrançois Tigeot 				port++;
592a85cb24fSFrançois Tigeot 			}
593a85cb24fSFrançois Tigeot 
594*3f2dd94aSFrançois Tigeot 			INIT_LIST_HEAD(&rq->priotree.link);
595a85cb24fSFrançois Tigeot 			rq->priotree.priority = INT_MAX;
596a85cb24fSFrançois Tigeot 
597*3f2dd94aSFrançois Tigeot 			__i915_gem_request_submit(rq);
598*3f2dd94aSFrançois Tigeot 			trace_i915_gem_request_in(rq, port_index(port, execlists));
599a85cb24fSFrançois Tigeot 			last = rq;
600a85cb24fSFrançois Tigeot 			submit = true;
601a85cb24fSFrançois Tigeot 		}
602*3f2dd94aSFrançois Tigeot 
603*3f2dd94aSFrançois Tigeot 		rb = rb_next(rb);
604*3f2dd94aSFrançois Tigeot 		rb_erase(&p->node, &execlists->queue);
605*3f2dd94aSFrançois Tigeot 		INIT_LIST_HEAD(&p->requests);
606*3f2dd94aSFrançois Tigeot 		if (p->priority != I915_PRIORITY_NORMAL)
607*3f2dd94aSFrançois Tigeot 			kmem_cache_free(engine->i915->priorities, p);
608*3f2dd94aSFrançois Tigeot 	}
609*3f2dd94aSFrançois Tigeot done:
610*3f2dd94aSFrançois Tigeot 	execlists->first = rb;
611a85cb24fSFrançois Tigeot 	if (submit) {
612*3f2dd94aSFrançois Tigeot 		port_assign(port, last);
613*3f2dd94aSFrançois Tigeot 		execlists_set_active(execlists, EXECLISTS_ACTIVE_USER);
614*3f2dd94aSFrançois Tigeot 		i915_guc_submit(engine);
615a85cb24fSFrançois Tigeot 	}
616a85cb24fSFrançois Tigeot 	spin_unlock_irq(&engine->timeline->lock);
617a85cb24fSFrançois Tigeot }
618a85cb24fSFrançois Tigeot 
i915_guc_irq_handler(unsigned long data)619a85cb24fSFrançois Tigeot static void i915_guc_irq_handler(unsigned long data)
620a85cb24fSFrançois Tigeot {
621*3f2dd94aSFrançois Tigeot 	struct intel_engine_cs * const engine = (struct intel_engine_cs *)data;
622*3f2dd94aSFrançois Tigeot 	struct intel_engine_execlists * const execlists = &engine->execlists;
623*3f2dd94aSFrançois Tigeot 	struct execlist_port *port = execlists->port;
624*3f2dd94aSFrançois Tigeot 	const struct execlist_port * const last_port =
625*3f2dd94aSFrançois Tigeot 		&execlists->port[execlists->port_mask];
626a85cb24fSFrançois Tigeot 	struct drm_i915_gem_request *rq;
627a85cb24fSFrançois Tigeot 
628*3f2dd94aSFrançois Tigeot 	rq = port_request(&port[0]);
629a85cb24fSFrançois Tigeot 	while (rq && i915_gem_request_completed(rq)) {
630a85cb24fSFrançois Tigeot 		trace_i915_gem_request_out(rq);
631a85cb24fSFrançois Tigeot 		i915_gem_request_put(rq);
632a85cb24fSFrançois Tigeot 
633*3f2dd94aSFrançois Tigeot 		execlists_port_complete(execlists, port);
634*3f2dd94aSFrançois Tigeot 
635*3f2dd94aSFrançois Tigeot 		rq = port_request(&port[0]);
636*3f2dd94aSFrançois Tigeot 	}
637*3f2dd94aSFrançois Tigeot 	if (!rq)
638*3f2dd94aSFrançois Tigeot 		execlists_clear_active(execlists, EXECLISTS_ACTIVE_USER);
639*3f2dd94aSFrançois Tigeot 
640*3f2dd94aSFrançois Tigeot 	if (!port_isset(last_port))
641*3f2dd94aSFrançois Tigeot 		i915_guc_dequeue(engine);
642352ff8bdSFrançois Tigeot }
643352ff8bdSFrançois Tigeot 
644352ff8bdSFrançois Tigeot /*
645352ff8bdSFrançois Tigeot  * Everything below here is concerned with setup & teardown, and is
646352ff8bdSFrançois Tigeot  * therefore not part of the somewhat time-critical batch-submission
647352ff8bdSFrançois Tigeot  * path of i915_guc_submit() above.
648352ff8bdSFrançois Tigeot  */
649352ff8bdSFrançois Tigeot 
6501e12ee3bSFrançois Tigeot /* Check that a doorbell register is in the expected state */
doorbell_ok(struct intel_guc * guc,u16 db_id)651a85cb24fSFrançois Tigeot static bool doorbell_ok(struct intel_guc *guc, u16 db_id)
6521e12ee3bSFrançois Tigeot {
6531e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
654a85cb24fSFrançois Tigeot 	u32 drbregl;
655a85cb24fSFrançois Tigeot 	bool valid;
6561e12ee3bSFrançois Tigeot 
657a85cb24fSFrançois Tigeot 	GEM_BUG_ON(db_id >= GUC_DOORBELL_INVALID);
658a85cb24fSFrançois Tigeot 
659a85cb24fSFrançois Tigeot 	drbregl = I915_READ(GEN8_DRBREGL(db_id));
660a85cb24fSFrançois Tigeot 	valid = drbregl & GEN8_DRB_VALID;
661a85cb24fSFrançois Tigeot 
662a85cb24fSFrançois Tigeot 	if (test_bit(db_id, guc->doorbell_bitmap) == valid)
6631e12ee3bSFrançois Tigeot 		return true;
6641e12ee3bSFrançois Tigeot 
665a85cb24fSFrançois Tigeot 	DRM_DEBUG_DRIVER("Doorbell %d has unexpected state (0x%x): valid=%s\n",
666a85cb24fSFrançois Tigeot 			 db_id, drbregl, yesno(valid));
6671e12ee3bSFrançois Tigeot 
6681e12ee3bSFrançois Tigeot 	return false;
6691e12ee3bSFrançois Tigeot }
6701e12ee3bSFrançois Tigeot 
6711487f786SFrançois Tigeot /*
672a85cb24fSFrançois Tigeot  * If the GuC thinks that the doorbell is unassigned (e.g. because we reset and
673a85cb24fSFrançois Tigeot  * reloaded the GuC FW) we can use this function to tell the GuC to reassign the
674a85cb24fSFrançois Tigeot  * doorbell to the rightful owner.
6751487f786SFrançois Tigeot  */
__reset_doorbell(struct i915_guc_client * client,u16 db_id)676a85cb24fSFrançois Tigeot static int __reset_doorbell(struct i915_guc_client* client, u16 db_id)
6771487f786SFrançois Tigeot {
678a85cb24fSFrançois Tigeot 	int err;
6791487f786SFrançois Tigeot 
680a85cb24fSFrançois Tigeot 	__update_doorbell_desc(client, db_id);
681a85cb24fSFrançois Tigeot 	err = __create_doorbell(client);
682a85cb24fSFrançois Tigeot 	if (!err)
683a85cb24fSFrançois Tigeot 		err = __destroy_doorbell(client);
6841487f786SFrançois Tigeot 
685a85cb24fSFrançois Tigeot 	return err;
6861487f786SFrançois Tigeot }
6871487f786SFrançois Tigeot 
688a85cb24fSFrançois Tigeot /*
689a85cb24fSFrançois Tigeot  * Set up & tear down each unused doorbell in turn, to ensure that all doorbell
690a85cb24fSFrançois Tigeot  * HW is (re)initialised. For that end, we might have to borrow the first
691a85cb24fSFrançois Tigeot  * client. Also, tell GuC about all the doorbells in use by all clients.
692a85cb24fSFrançois Tigeot  * We do this because the KMD, the GuC and the doorbell HW can easily go out of
693a85cb24fSFrançois Tigeot  * sync (e.g. we can reset the GuC, but not the doorbel HW).
694a85cb24fSFrançois Tigeot  */
guc_init_doorbell_hw(struct intel_guc * guc)695a85cb24fSFrançois Tigeot static int guc_init_doorbell_hw(struct intel_guc *guc)
696a85cb24fSFrançois Tigeot {
697a85cb24fSFrançois Tigeot 	struct i915_guc_client *client = guc->execbuf_client;
698a85cb24fSFrançois Tigeot 	bool recreate_first_client = false;
699a85cb24fSFrançois Tigeot 	u16 db_id;
700a85cb24fSFrançois Tigeot 	int ret;
7011487f786SFrançois Tigeot 
702a85cb24fSFrançois Tigeot 	/* For unused doorbells, make sure they are disabled */
703a85cb24fSFrançois Tigeot 	for_each_clear_bit(db_id, guc->doorbell_bitmap, GUC_NUM_DOORBELLS) {
704a85cb24fSFrançois Tigeot 		if (doorbell_ok(guc, db_id))
705a85cb24fSFrançois Tigeot 			continue;
706a85cb24fSFrançois Tigeot 
707a85cb24fSFrançois Tigeot 		if (has_doorbell(client)) {
708a85cb24fSFrançois Tigeot 			/* Borrow execbuf_client (we will recreate it later) */
709a85cb24fSFrançois Tigeot 			destroy_doorbell(client);
710a85cb24fSFrançois Tigeot 			recreate_first_client = true;
711a85cb24fSFrançois Tigeot 		}
712a85cb24fSFrançois Tigeot 
713a85cb24fSFrançois Tigeot 		ret = __reset_doorbell(client, db_id);
714a85cb24fSFrançois Tigeot 		WARN(ret, "Doorbell %u reset failed, err %d\n", db_id, ret);
715a85cb24fSFrançois Tigeot 	}
716a85cb24fSFrançois Tigeot 
717a85cb24fSFrançois Tigeot 	if (recreate_first_client) {
718a85cb24fSFrançois Tigeot 		ret = __reserve_doorbell(client);
719a85cb24fSFrançois Tigeot 		if (unlikely(ret)) {
720a85cb24fSFrançois Tigeot 			DRM_ERROR("Couldn't re-reserve first client db: %d\n", ret);
721a85cb24fSFrançois Tigeot 			return ret;
722a85cb24fSFrançois Tigeot 		}
723a85cb24fSFrançois Tigeot 
724a85cb24fSFrançois Tigeot 		__update_doorbell_desc(client, client->doorbell_id);
725a85cb24fSFrançois Tigeot 	}
726a85cb24fSFrançois Tigeot 
727a85cb24fSFrançois Tigeot 	/* Now for every client (and not only execbuf_client) make sure their
728a85cb24fSFrançois Tigeot 	 * doorbells are known by the GuC */
729a85cb24fSFrançois Tigeot 	//for (client = client_list; client != NULL; client = client->next)
730a85cb24fSFrançois Tigeot 	{
731a85cb24fSFrançois Tigeot 		ret = __create_doorbell(client);
732a85cb24fSFrançois Tigeot 		if (ret) {
733a85cb24fSFrançois Tigeot 			DRM_ERROR("Couldn't recreate client %u doorbell: %d\n",
734a85cb24fSFrançois Tigeot 				client->stage_id, ret);
735a85cb24fSFrançois Tigeot 			return ret;
736a85cb24fSFrançois Tigeot 		}
737a85cb24fSFrançois Tigeot 	}
738a85cb24fSFrançois Tigeot 
739a85cb24fSFrançois Tigeot 	/* Read back & verify all (used & unused) doorbell registers */
740a85cb24fSFrançois Tigeot 	for (db_id = 0; db_id < GUC_NUM_DOORBELLS; ++db_id)
741a85cb24fSFrançois Tigeot 		WARN_ON(!doorbell_ok(guc, db_id));
742a85cb24fSFrançois Tigeot 
743a85cb24fSFrançois Tigeot 	return 0;
7441487f786SFrançois Tigeot }
7451487f786SFrançois Tigeot 
746352ff8bdSFrançois Tigeot /**
747352ff8bdSFrançois Tigeot  * guc_client_alloc() - Allocate an i915_guc_client
7481487f786SFrançois Tigeot  * @dev_priv:	driver private data structure
7491e12ee3bSFrançois Tigeot  * @engines:	The set of engines to enable for this client
750352ff8bdSFrançois Tigeot  * @priority:	four levels priority _CRITICAL, _HIGH, _NORMAL and _LOW
751352ff8bdSFrançois Tigeot  * 		The kernel client to replace ExecList submission is created with
752352ff8bdSFrançois Tigeot  * 		NORMAL priority. Priority of a client for scheduler can be HIGH,
753352ff8bdSFrançois Tigeot  * 		while a preemption context can use CRITICAL.
754aee94f86SFrançois Tigeot  * @ctx:	the context that owns the client (we use the default render
755aee94f86SFrançois Tigeot  * 		context)
756352ff8bdSFrançois Tigeot  *
7578621f407SFrançois Tigeot  * Return:	An i915_guc_client object if success, else NULL.
758352ff8bdSFrançois Tigeot  */
7591487f786SFrançois Tigeot static struct i915_guc_client *
guc_client_alloc(struct drm_i915_private * dev_priv,u32 engines,u32 priority,struct i915_gem_context * ctx)7601487f786SFrançois Tigeot guc_client_alloc(struct drm_i915_private *dev_priv,
761*3f2dd94aSFrançois Tigeot 		 u32 engines,
762*3f2dd94aSFrançois Tigeot 		 u32 priority,
7631487f786SFrançois Tigeot 		 struct i915_gem_context *ctx)
764352ff8bdSFrançois Tigeot {
765352ff8bdSFrançois Tigeot 	struct i915_guc_client *client;
766352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
7671e12ee3bSFrançois Tigeot 	struct i915_vma *vma;
7684be47400SFrançois Tigeot 	void *vaddr;
769a85cb24fSFrançois Tigeot 	int ret;
770352ff8bdSFrançois Tigeot 
771352ff8bdSFrançois Tigeot 	client = kzalloc(sizeof(*client), GFP_KERNEL);
772352ff8bdSFrançois Tigeot 	if (!client)
773a85cb24fSFrançois Tigeot 		return ERR_PTR(-ENOMEM);
774352ff8bdSFrançois Tigeot 
775352ff8bdSFrançois Tigeot 	client->guc = guc;
776a85cb24fSFrançois Tigeot 	client->owner = ctx;
7771e12ee3bSFrançois Tigeot 	client->engines = engines;
7781e12ee3bSFrançois Tigeot 	client->priority = priority;
779a85cb24fSFrançois Tigeot 	client->doorbell_id = GUC_DOORBELL_INVALID;
780a85cb24fSFrançois Tigeot 	lockinit(&client->wq_lock, "i9gcwql", 0, 0);
781352ff8bdSFrançois Tigeot 
782a85cb24fSFrançois Tigeot 	ret = ida_simple_get(&guc->stage_ids, 0, GUC_MAX_STAGE_DESCRIPTORS,
783a85cb24fSFrançois Tigeot 				GFP_KERNEL);
784a85cb24fSFrançois Tigeot 	if (ret < 0)
785a85cb24fSFrançois Tigeot 		goto err_client;
786a85cb24fSFrançois Tigeot 
787a85cb24fSFrançois Tigeot 	client->stage_id = ret;
788352ff8bdSFrançois Tigeot 
789352ff8bdSFrançois Tigeot 	/* The first page is doorbell/proc_desc. Two followed pages are wq. */
790a85cb24fSFrançois Tigeot 	vma = intel_guc_allocate_vma(guc, GUC_DB_SIZE + GUC_WQ_SIZE);
791a85cb24fSFrançois Tigeot 	if (IS_ERR(vma)) {
792a85cb24fSFrançois Tigeot 		ret = PTR_ERR(vma);
793a85cb24fSFrançois Tigeot 		goto err_id;
794a85cb24fSFrançois Tigeot 	}
795352ff8bdSFrançois Tigeot 
7968621f407SFrançois Tigeot 	/* We'll keep just the first (doorbell/proc) page permanently kmap'd. */
7971e12ee3bSFrançois Tigeot 	client->vma = vma;
7984be47400SFrançois Tigeot 
7994be47400SFrançois Tigeot 	vaddr = i915_gem_object_pin_map(vma->obj, I915_MAP_WB);
800a85cb24fSFrançois Tigeot 	if (IS_ERR(vaddr)) {
801a85cb24fSFrançois Tigeot 		ret = PTR_ERR(vaddr);
802a85cb24fSFrançois Tigeot 		goto err_vma;
803a85cb24fSFrançois Tigeot 	}
8044be47400SFrançois Tigeot 	client->vaddr = vaddr;
8051e12ee3bSFrançois Tigeot 
806a85cb24fSFrançois Tigeot 	client->doorbell_offset = __select_cacheline(guc);
807352ff8bdSFrançois Tigeot 
808352ff8bdSFrançois Tigeot 	/*
809352ff8bdSFrançois Tigeot 	 * Since the doorbell only requires a single cacheline, we can save
810352ff8bdSFrançois Tigeot 	 * space by putting the application process descriptor in the same
811352ff8bdSFrançois Tigeot 	 * page. Use the half of the page that doesn't include the doorbell.
812352ff8bdSFrançois Tigeot 	 */
813352ff8bdSFrançois Tigeot 	if (client->doorbell_offset >= (GUC_DB_SIZE / 2))
814352ff8bdSFrançois Tigeot 		client->proc_desc_offset = 0;
815352ff8bdSFrançois Tigeot 	else
816352ff8bdSFrançois Tigeot 		client->proc_desc_offset = (GUC_DB_SIZE / 2);
817352ff8bdSFrançois Tigeot 
8181e12ee3bSFrançois Tigeot 	guc_proc_desc_init(guc, client);
819a85cb24fSFrançois Tigeot 	guc_stage_desc_init(guc, client);
820352ff8bdSFrançois Tigeot 
821a85cb24fSFrançois Tigeot 	ret = create_doorbell(client);
822a85cb24fSFrançois Tigeot 	if (ret)
823a85cb24fSFrançois Tigeot 		goto err_vaddr;
824a85cb24fSFrançois Tigeot 
825a85cb24fSFrançois Tigeot 	DRM_DEBUG_DRIVER("new priority %u client %p for engine(s) 0x%x: stage_id %u\n",
826a85cb24fSFrançois Tigeot 			 priority, client, client->engines, client->stage_id);
827a85cb24fSFrançois Tigeot 	DRM_DEBUG_DRIVER("doorbell id %u, cacheline offset 0x%lx\n",
8281487f786SFrançois Tigeot 			 client->doorbell_id, client->doorbell_offset);
829352ff8bdSFrançois Tigeot 
830352ff8bdSFrançois Tigeot 	return client;
831352ff8bdSFrançois Tigeot 
832a85cb24fSFrançois Tigeot err_vaddr:
833a85cb24fSFrançois Tigeot 	i915_gem_object_unpin_map(client->vma->obj);
834a85cb24fSFrançois Tigeot err_vma:
835a85cb24fSFrançois Tigeot 	i915_vma_unpin_and_release(&client->vma);
836a85cb24fSFrançois Tigeot err_id:
837a85cb24fSFrançois Tigeot 	ida_simple_remove(&guc->stage_ids, client->stage_id);
838a85cb24fSFrançois Tigeot err_client:
839a85cb24fSFrançois Tigeot 	kfree(client);
840a85cb24fSFrançois Tigeot 	return ERR_PTR(ret);
841352ff8bdSFrançois Tigeot }
842352ff8bdSFrançois Tigeot 
guc_client_free(struct i915_guc_client * client)843a85cb24fSFrançois Tigeot static void guc_client_free(struct i915_guc_client *client)
844a85cb24fSFrançois Tigeot {
8454be47400SFrançois Tigeot 	/*
846a85cb24fSFrançois Tigeot 	 * XXX: wait for any outstanding submissions before freeing memory.
847a85cb24fSFrançois Tigeot 	 * Be sure to drop any locks
8484be47400SFrançois Tigeot 	 */
8494be47400SFrançois Tigeot 
850a85cb24fSFrançois Tigeot 	/* FIXME: in many cases, by the time we get here the GuC has been
851a85cb24fSFrançois Tigeot 	 * reset, so we cannot destroy the doorbell properly. Ignore the
852a85cb24fSFrançois Tigeot 	 * error message for now */
853a85cb24fSFrançois Tigeot 	destroy_doorbell(client);
854a85cb24fSFrançois Tigeot 	guc_stage_desc_fini(client->guc, client);
855a85cb24fSFrançois Tigeot 	i915_gem_object_unpin_map(client->vma->obj);
856a85cb24fSFrançois Tigeot 	i915_vma_unpin_and_release(&client->vma);
857a85cb24fSFrançois Tigeot 	ida_simple_remove(&client->guc->stage_ids, client->stage_id);
858a85cb24fSFrançois Tigeot 	kfree(client);
8594be47400SFrançois Tigeot }
8604be47400SFrançois Tigeot 
guc_policy_init(struct guc_policy * policy)861*3f2dd94aSFrançois Tigeot static void guc_policy_init(struct guc_policy *policy)
862*3f2dd94aSFrançois Tigeot {
863*3f2dd94aSFrançois Tigeot 	policy->execution_quantum = POLICY_DEFAULT_EXECUTION_QUANTUM_US;
864*3f2dd94aSFrançois Tigeot 	policy->preemption_time = POLICY_DEFAULT_PREEMPTION_TIME_US;
865*3f2dd94aSFrançois Tigeot 	policy->fault_time = POLICY_DEFAULT_FAULT_TIME_US;
866*3f2dd94aSFrançois Tigeot 	policy->policy_flags = 0;
867*3f2dd94aSFrançois Tigeot }
868*3f2dd94aSFrançois Tigeot 
guc_policies_init(struct guc_policies * policies)8691e12ee3bSFrançois Tigeot static void guc_policies_init(struct guc_policies *policies)
870c0e85e96SFrançois Tigeot {
871c0e85e96SFrançois Tigeot 	struct guc_policy *policy;
872c0e85e96SFrançois Tigeot 	u32 p, i;
873c0e85e96SFrançois Tigeot 
874*3f2dd94aSFrançois Tigeot 	policies->dpc_promote_time = POLICY_DEFAULT_DPC_PROMOTE_TIME_US;
875c0e85e96SFrançois Tigeot 	policies->max_num_work_items = POLICY_MAX_NUM_WI;
876c0e85e96SFrançois Tigeot 
877a85cb24fSFrançois Tigeot 	for (p = 0; p < GUC_CLIENT_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 
881*3f2dd94aSFrançois Tigeot 			guc_policy_init(policy);
882c0e85e96SFrançois Tigeot 		}
883c0e85e96SFrançois Tigeot 	}
884c0e85e96SFrançois Tigeot 
885c0e85e96SFrançois Tigeot 	policies->is_valid = 1;
886c0e85e96SFrançois Tigeot }
887c0e85e96SFrançois Tigeot 
888*3f2dd94aSFrançois Tigeot /*
889*3f2dd94aSFrançois Tigeot  * The first 80 dwords of the register state context, containing the
890*3f2dd94aSFrançois Tigeot  * execlists and ppgtt registers.
891*3f2dd94aSFrançois Tigeot  */
892*3f2dd94aSFrançois Tigeot #define LR_HW_CONTEXT_SIZE	(80 * sizeof(u32))
893*3f2dd94aSFrançois Tigeot 
guc_ads_create(struct intel_guc * guc)894a85cb24fSFrançois Tigeot static int guc_ads_create(struct intel_guc *guc)
895c0e85e96SFrançois Tigeot {
896c0e85e96SFrançois Tigeot 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
8971e12ee3bSFrançois Tigeot 	struct i915_vma *vma;
898a85cb24fSFrançois Tigeot 	struct page *page;
899a85cb24fSFrançois Tigeot 	/* The ads obj includes the struct itself and buffers passed to GuC */
900a85cb24fSFrançois Tigeot 	struct {
901a85cb24fSFrançois Tigeot 		struct guc_ads ads;
902a85cb24fSFrançois Tigeot 		struct guc_policies policies;
903a85cb24fSFrançois Tigeot 		struct guc_mmio_reg_state reg_state;
904a85cb24fSFrançois Tigeot 		u8 reg_state_buffer[GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE];
905a85cb24fSFrançois Tigeot 	} __packed *blob;
9068621f407SFrançois Tigeot 	struct intel_engine_cs *engine;
9071e12ee3bSFrançois Tigeot 	enum intel_engine_id id;
908*3f2dd94aSFrançois Tigeot 	const u32 skipped_offset = LRC_HEADER_PAGES * PAGE_SIZE;
909*3f2dd94aSFrançois Tigeot 	const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE;
910a85cb24fSFrançois Tigeot 	u32 base;
911c0e85e96SFrançois Tigeot 
912a85cb24fSFrançois Tigeot 	GEM_BUG_ON(guc->ads_vma);
913c0e85e96SFrançois Tigeot 
914a85cb24fSFrançois Tigeot 	vma = intel_guc_allocate_vma(guc, PAGE_ALIGN(sizeof(*blob)));
9151e12ee3bSFrançois Tigeot 	if (IS_ERR(vma))
916a85cb24fSFrançois Tigeot 		return PTR_ERR(vma);
917c0e85e96SFrançois Tigeot 
9181e12ee3bSFrançois Tigeot 	guc->ads_vma = vma;
919c0e85e96SFrançois Tigeot 
9201e12ee3bSFrançois Tigeot 	page = i915_vma_first_page(vma);
921a85cb24fSFrançois Tigeot 	blob = kmap(page);
922a85cb24fSFrançois Tigeot 
923a85cb24fSFrançois Tigeot 	/* GuC scheduling policies */
924a85cb24fSFrançois Tigeot 	guc_policies_init(&blob->policies);
925a85cb24fSFrançois Tigeot 
926a85cb24fSFrançois Tigeot 	/* MMIO reg state */
927a85cb24fSFrançois Tigeot 	for_each_engine(engine, dev_priv, id) {
928a85cb24fSFrançois Tigeot 		blob->reg_state.white_list[engine->guc_id].mmio_start =
929a85cb24fSFrançois Tigeot 			engine->mmio_base + GUC_MMIO_WHITE_LIST_START;
930a85cb24fSFrançois Tigeot 
931a85cb24fSFrançois Tigeot 		/* Nothing to be saved or restored for now. */
932a85cb24fSFrançois Tigeot 		blob->reg_state.white_list[engine->guc_id].count = 0;
933a85cb24fSFrançois Tigeot 	}
934c0e85e96SFrançois Tigeot 
935c0e85e96SFrançois Tigeot 	/*
936c0e85e96SFrançois Tigeot 	 * The GuC requires a "Golden Context" when it reinitialises
937c0e85e96SFrançois Tigeot 	 * engines after a reset. Here we use the Render ring default
938c0e85e96SFrançois Tigeot 	 * context, which must already exist and be pinned in the GGTT,
939c0e85e96SFrançois Tigeot 	 * so its address won't change after we've told the GuC where
940*3f2dd94aSFrançois Tigeot 	 * to find it. Note that we have to skip our header (1 page),
941*3f2dd94aSFrançois Tigeot 	 * because our GuC shared data is there.
942c0e85e96SFrançois Tigeot 	 */
943a85cb24fSFrançois Tigeot 	blob->ads.golden_context_lrca =
944*3f2dd94aSFrançois Tigeot 		guc_ggtt_offset(dev_priv->kernel_context->engine[RCS].state) + skipped_offset;
945c0e85e96SFrançois Tigeot 
946*3f2dd94aSFrançois Tigeot 	/*
947*3f2dd94aSFrançois Tigeot 	 * The GuC expects us to exclude the portion of the context image that
948*3f2dd94aSFrançois Tigeot 	 * it skips from the size it is to read. It starts reading from after
949*3f2dd94aSFrançois Tigeot 	 * the execlist context (so skipping the first page [PPHWSP] and 80
950*3f2dd94aSFrançois Tigeot 	 * dwords). Weird guc is weird.
951*3f2dd94aSFrançois Tigeot 	 */
9521e12ee3bSFrançois Tigeot 	for_each_engine(engine, dev_priv, id)
953*3f2dd94aSFrançois Tigeot 		blob->ads.eng_state_size[engine->guc_id] = engine->context_size - skipped_size;
954c0e85e96SFrançois Tigeot 
955a85cb24fSFrançois Tigeot 	base = guc_ggtt_offset(vma);
956a85cb24fSFrançois Tigeot 	blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
957a85cb24fSFrançois Tigeot 	blob->ads.reg_state_buffer = base + ptr_offset(blob, reg_state_buffer);
958a85cb24fSFrançois Tigeot 	blob->ads.reg_state_addr = base + ptr_offset(blob, reg_state);
959c0e85e96SFrançois Tigeot 
960c0e85e96SFrançois Tigeot 	kunmap(page);
961a85cb24fSFrançois Tigeot 
962a85cb24fSFrançois Tigeot 	return 0;
963a85cb24fSFrançois Tigeot }
964a85cb24fSFrançois Tigeot 
guc_ads_destroy(struct intel_guc * guc)965a85cb24fSFrançois Tigeot static void guc_ads_destroy(struct intel_guc *guc)
966a85cb24fSFrançois Tigeot {
967a85cb24fSFrançois Tigeot 	i915_vma_unpin_and_release(&guc->ads_vma);
968c0e85e96SFrançois Tigeot }
969c0e85e96SFrançois Tigeot 
970352ff8bdSFrançois Tigeot /*
971a85cb24fSFrançois Tigeot  * Set up the memory resources to be shared with the GuC (via the GGTT)
972a85cb24fSFrançois Tigeot  * at firmware loading time.
973352ff8bdSFrançois Tigeot  */
i915_guc_submission_init(struct drm_i915_private * dev_priv)9741487f786SFrançois Tigeot int i915_guc_submission_init(struct drm_i915_private *dev_priv)
975352ff8bdSFrançois Tigeot {
976352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
9771e12ee3bSFrançois Tigeot 	struct i915_vma *vma;
978a85cb24fSFrançois Tigeot 	void *vaddr;
979a85cb24fSFrançois Tigeot 	int ret;
980352ff8bdSFrançois Tigeot 
981a85cb24fSFrançois Tigeot 	if (guc->stage_desc_pool)
982a85cb24fSFrançois Tigeot 		return 0;
9831487f786SFrançois Tigeot 
984a85cb24fSFrançois Tigeot 	vma = intel_guc_allocate_vma(guc,
985a85cb24fSFrançois Tigeot 				PAGE_ALIGN(sizeof(struct guc_stage_desc) *
986a85cb24fSFrançois Tigeot 					GUC_MAX_STAGE_DESCRIPTORS));
9871e12ee3bSFrançois Tigeot 	if (IS_ERR(vma))
9881e12ee3bSFrançois Tigeot 		return PTR_ERR(vma);
989352ff8bdSFrançois Tigeot 
990a85cb24fSFrançois Tigeot 	guc->stage_desc_pool = vma;
991a85cb24fSFrançois Tigeot 
992a85cb24fSFrançois Tigeot 	vaddr = i915_gem_object_pin_map(guc->stage_desc_pool->obj, I915_MAP_WB);
993a85cb24fSFrançois Tigeot 	if (IS_ERR(vaddr)) {
994a85cb24fSFrançois Tigeot 		ret = PTR_ERR(vaddr);
995a85cb24fSFrançois Tigeot 		goto err_vma;
996a85cb24fSFrançois Tigeot 	}
997a85cb24fSFrançois Tigeot 
998a85cb24fSFrançois Tigeot 	guc->stage_desc_pool_vaddr = vaddr;
999a85cb24fSFrançois Tigeot 
1000a85cb24fSFrançois Tigeot 	ret = intel_guc_log_create(guc);
1001a85cb24fSFrançois Tigeot 	if (ret < 0)
1002a85cb24fSFrançois Tigeot 		goto err_vaddr;
1003a85cb24fSFrançois Tigeot 
1004a85cb24fSFrançois Tigeot 	ret = guc_ads_create(guc);
1005a85cb24fSFrançois Tigeot 	if (ret < 0)
1006a85cb24fSFrançois Tigeot 		goto err_log;
1007a85cb24fSFrançois Tigeot 
1008a85cb24fSFrançois Tigeot 	ida_init(&guc->stage_ids);
1009c0e85e96SFrançois Tigeot 
1010352ff8bdSFrançois Tigeot 	return 0;
1011352ff8bdSFrançois Tigeot 
1012a85cb24fSFrançois Tigeot err_log:
1013a85cb24fSFrançois Tigeot 	intel_guc_log_destroy(guc);
1014a85cb24fSFrançois Tigeot err_vaddr:
1015a85cb24fSFrançois Tigeot 	i915_gem_object_unpin_map(guc->stage_desc_pool->obj);
1016a85cb24fSFrançois Tigeot err_vma:
1017a85cb24fSFrançois Tigeot 	i915_vma_unpin_and_release(&guc->stage_desc_pool);
1018a85cb24fSFrançois Tigeot 	return ret;
1019352ff8bdSFrançois Tigeot }
1020352ff8bdSFrançois Tigeot 
i915_guc_submission_fini(struct drm_i915_private * dev_priv)10211487f786SFrançois Tigeot void i915_guc_submission_fini(struct drm_i915_private *dev_priv)
1022352ff8bdSFrançois Tigeot {
1023352ff8bdSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
1024352ff8bdSFrançois Tigeot 
1025a85cb24fSFrançois Tigeot 	ida_destroy(&guc->stage_ids);
1026a85cb24fSFrançois Tigeot 	guc_ads_destroy(guc);
1027a85cb24fSFrançois Tigeot 	intel_guc_log_destroy(guc);
1028a85cb24fSFrançois Tigeot 	i915_gem_object_unpin_map(guc->stage_desc_pool->obj);
1029a85cb24fSFrançois Tigeot 	i915_vma_unpin_and_release(&guc->stage_desc_pool);
1030a85cb24fSFrançois Tigeot }
1031c0e85e96SFrançois Tigeot 
guc_interrupts_capture(struct drm_i915_private * dev_priv)1032a85cb24fSFrançois Tigeot static void guc_interrupts_capture(struct drm_i915_private *dev_priv)
1033a85cb24fSFrançois Tigeot {
1034*3f2dd94aSFrançois Tigeot 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
1035a85cb24fSFrançois Tigeot 	struct intel_engine_cs *engine;
1036a85cb24fSFrançois Tigeot 	enum intel_engine_id id;
1037a85cb24fSFrançois Tigeot 	int irqs;
1038a85cb24fSFrançois Tigeot 
1039a85cb24fSFrançois Tigeot 	/* tell all command streamers to forward interrupts (but not vblank) to GuC */
1040a85cb24fSFrançois Tigeot 	irqs = _MASKED_BIT_ENABLE(GFX_INTERRUPT_STEERING);
1041a85cb24fSFrançois Tigeot 	for_each_engine(engine, dev_priv, id)
1042a85cb24fSFrançois Tigeot 		I915_WRITE(RING_MODE_GEN7(engine), irqs);
1043a85cb24fSFrançois Tigeot 
1044a85cb24fSFrançois Tigeot 	/* route USER_INTERRUPT to Host, all others are sent to GuC. */
1045a85cb24fSFrançois Tigeot 	irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
1046a85cb24fSFrançois Tigeot 	       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
1047a85cb24fSFrançois Tigeot 	/* These three registers have the same bit definitions */
1048a85cb24fSFrançois Tigeot 	I915_WRITE(GUC_BCS_RCS_IER, ~irqs);
1049a85cb24fSFrançois Tigeot 	I915_WRITE(GUC_VCS2_VCS1_IER, ~irqs);
1050a85cb24fSFrançois Tigeot 	I915_WRITE(GUC_WD_VECS_IER, ~irqs);
1051a85cb24fSFrançois Tigeot 
1052a85cb24fSFrançois Tigeot 	/*
1053a85cb24fSFrançois Tigeot 	 * The REDIRECT_TO_GUC bit of the PMINTRMSK register directs all
1054a85cb24fSFrançois Tigeot 	 * (unmasked) PM interrupts to the GuC. All other bits of this
1055a85cb24fSFrançois Tigeot 	 * register *disable* generation of a specific interrupt.
1056a85cb24fSFrançois Tigeot 	 *
1057a85cb24fSFrançois Tigeot 	 * 'pm_intrmsk_mbz' indicates bits that are NOT to be set when
1058a85cb24fSFrançois Tigeot 	 * writing to the PM interrupt mask register, i.e. interrupts
1059a85cb24fSFrançois Tigeot 	 * that must not be disabled.
1060a85cb24fSFrançois Tigeot 	 *
1061a85cb24fSFrançois Tigeot 	 * If the GuC is handling these interrupts, then we must not let
1062a85cb24fSFrançois Tigeot 	 * the PM code disable ANY interrupt that the GuC is expecting.
1063a85cb24fSFrançois Tigeot 	 * So for each ENABLED (0) bit in this register, we must SET the
1064a85cb24fSFrançois Tigeot 	 * bit in pm_intrmsk_mbz so that it's left enabled for the GuC.
1065a85cb24fSFrançois Tigeot 	 * GuC needs ARAT expired interrupt unmasked hence it is set in
1066a85cb24fSFrançois Tigeot 	 * pm_intrmsk_mbz.
1067a85cb24fSFrançois Tigeot 	 *
1068a85cb24fSFrançois Tigeot 	 * Here we CLEAR REDIRECT_TO_GUC bit in pm_intrmsk_mbz, which will
1069a85cb24fSFrançois Tigeot 	 * result in the register bit being left SET!
1070a85cb24fSFrançois Tigeot 	 */
1071*3f2dd94aSFrançois Tigeot 	rps->pm_intrmsk_mbz |= ARAT_EXPIRED_INTRMSK;
1072*3f2dd94aSFrançois Tigeot 	rps->pm_intrmsk_mbz &= ~GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
1073a85cb24fSFrançois Tigeot }
1074a85cb24fSFrançois Tigeot 
guc_interrupts_release(struct drm_i915_private * dev_priv)1075a85cb24fSFrançois Tigeot static void guc_interrupts_release(struct drm_i915_private *dev_priv)
1076a85cb24fSFrançois Tigeot {
1077*3f2dd94aSFrançois Tigeot 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
1078a85cb24fSFrançois Tigeot 	struct intel_engine_cs *engine;
1079a85cb24fSFrançois Tigeot 	enum intel_engine_id id;
1080a85cb24fSFrançois Tigeot 	int irqs;
1081a85cb24fSFrançois Tigeot 
1082a85cb24fSFrançois Tigeot 	/*
1083a85cb24fSFrançois Tigeot 	 * tell all command streamers NOT to forward interrupts or vblank
1084a85cb24fSFrançois Tigeot 	 * to GuC.
1085a85cb24fSFrançois Tigeot 	 */
1086a85cb24fSFrançois Tigeot 	irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_NEVER);
1087a85cb24fSFrançois Tigeot 	irqs |= _MASKED_BIT_DISABLE(GFX_INTERRUPT_STEERING);
1088a85cb24fSFrançois Tigeot 	for_each_engine(engine, dev_priv, id)
1089a85cb24fSFrançois Tigeot 		I915_WRITE(RING_MODE_GEN7(engine), irqs);
1090a85cb24fSFrançois Tigeot 
1091a85cb24fSFrançois Tigeot 	/* route all GT interrupts to the host */
1092a85cb24fSFrançois Tigeot 	I915_WRITE(GUC_BCS_RCS_IER, 0);
1093a85cb24fSFrançois Tigeot 	I915_WRITE(GUC_VCS2_VCS1_IER, 0);
1094a85cb24fSFrançois Tigeot 	I915_WRITE(GUC_WD_VECS_IER, 0);
1095a85cb24fSFrançois Tigeot 
1096*3f2dd94aSFrançois Tigeot 	rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
1097*3f2dd94aSFrançois Tigeot 	rps->pm_intrmsk_mbz &= ~ARAT_EXPIRED_INTRMSK;
1098a85cb24fSFrançois Tigeot }
1099a85cb24fSFrançois Tigeot 
i915_guc_submission_enable(struct drm_i915_private * dev_priv)1100a85cb24fSFrançois Tigeot int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
1101a85cb24fSFrançois Tigeot {
1102a85cb24fSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
1103a85cb24fSFrançois Tigeot 	struct i915_guc_client *client = guc->execbuf_client;
1104a85cb24fSFrançois Tigeot 	struct intel_engine_cs *engine;
1105a85cb24fSFrançois Tigeot 	enum intel_engine_id id;
1106a85cb24fSFrançois Tigeot 	int err;
1107a85cb24fSFrançois Tigeot 
1108*3f2dd94aSFrançois Tigeot 	/*
1109*3f2dd94aSFrançois Tigeot 	 * We're using GuC work items for submitting work through GuC. Since
1110*3f2dd94aSFrançois Tigeot 	 * we're coalescing multiple requests from a single context into a
1111*3f2dd94aSFrançois Tigeot 	 * single work item prior to assigning it to execlist_port, we can
1112*3f2dd94aSFrançois Tigeot 	 * never have more work items than the total number of ports (for all
1113*3f2dd94aSFrançois Tigeot 	 * engines). The GuC firmware is controlling the HEAD of work queue,
1114*3f2dd94aSFrançois Tigeot 	 * and it is guaranteed that it will remove the work item from the
1115*3f2dd94aSFrançois Tigeot 	 * queue before our request is completed.
1116*3f2dd94aSFrançois Tigeot 	 */
1117*3f2dd94aSFrançois Tigeot 	BUILD_BUG_ON(ARRAY_SIZE(engine->execlists.port) *
1118*3f2dd94aSFrançois Tigeot 		     sizeof(struct guc_wq_item) *
1119*3f2dd94aSFrançois Tigeot 		     I915_NUM_ENGINES > GUC_WQ_SIZE);
1120*3f2dd94aSFrançois Tigeot 
1121a85cb24fSFrançois Tigeot 	if (!client) {
1122a85cb24fSFrançois Tigeot 		client = guc_client_alloc(dev_priv,
1123a85cb24fSFrançois Tigeot 					  INTEL_INFO(dev_priv)->ring_mask,
1124a85cb24fSFrançois Tigeot 					  GUC_CLIENT_PRIORITY_KMD_NORMAL,
1125a85cb24fSFrançois Tigeot 					  dev_priv->kernel_context);
1126a85cb24fSFrançois Tigeot 		if (IS_ERR(client)) {
1127a85cb24fSFrançois Tigeot 			DRM_ERROR("Failed to create GuC client for execbuf!\n");
1128a85cb24fSFrançois Tigeot 			return PTR_ERR(client);
1129a85cb24fSFrançois Tigeot 		}
1130a85cb24fSFrançois Tigeot 
1131a85cb24fSFrançois Tigeot 		guc->execbuf_client = client;
1132a85cb24fSFrançois Tigeot 	}
1133a85cb24fSFrançois Tigeot 
1134a85cb24fSFrançois Tigeot 	err = intel_guc_sample_forcewake(guc);
1135a85cb24fSFrançois Tigeot 	if (err)
1136a85cb24fSFrançois Tigeot 		goto err_execbuf_client;
1137a85cb24fSFrançois Tigeot 
1138a85cb24fSFrançois Tigeot 	guc_reset_wq(client);
1139a85cb24fSFrançois Tigeot 
1140a85cb24fSFrançois Tigeot 	err = guc_init_doorbell_hw(guc);
1141a85cb24fSFrançois Tigeot 	if (err)
1142a85cb24fSFrançois Tigeot 		goto err_execbuf_client;
1143a85cb24fSFrançois Tigeot 
1144a85cb24fSFrançois Tigeot 	/* Take over from manual control of ELSP (execlists) */
1145a85cb24fSFrançois Tigeot 	guc_interrupts_capture(dev_priv);
1146a85cb24fSFrançois Tigeot 
1147a85cb24fSFrançois Tigeot 	for_each_engine(engine, dev_priv, id) {
1148*3f2dd94aSFrançois Tigeot 		struct intel_engine_execlists * const execlists = &engine->execlists;
1149a85cb24fSFrançois Tigeot 		/* The tasklet was initialised by execlists, and may be in
1150a85cb24fSFrançois Tigeot 		 * a state of flux (across a reset) and so we just want to
1151a85cb24fSFrançois Tigeot 		 * take over the callback without changing any other state
1152a85cb24fSFrançois Tigeot 		 * in the tasklet.
1153a85cb24fSFrançois Tigeot 		 */
1154*3f2dd94aSFrançois Tigeot 		execlists->irq_tasklet.func = i915_guc_irq_handler;
1155a85cb24fSFrançois Tigeot 		clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
1156*3f2dd94aSFrançois Tigeot 		tasklet_schedule(&execlists->irq_tasklet);
1157a85cb24fSFrançois Tigeot 	}
1158a85cb24fSFrançois Tigeot 
1159a85cb24fSFrançois Tigeot 	return 0;
1160a85cb24fSFrançois Tigeot 
1161a85cb24fSFrançois Tigeot err_execbuf_client:
1162a85cb24fSFrançois Tigeot 	guc_client_free(guc->execbuf_client);
1163a85cb24fSFrançois Tigeot 	guc->execbuf_client = NULL;
1164a85cb24fSFrançois Tigeot 	return err;
1165a85cb24fSFrançois Tigeot }
1166a85cb24fSFrançois Tigeot 
i915_guc_submission_disable(struct drm_i915_private * dev_priv)1167a85cb24fSFrançois Tigeot void i915_guc_submission_disable(struct drm_i915_private *dev_priv)
1168a85cb24fSFrançois Tigeot {
1169a85cb24fSFrançois Tigeot 	struct intel_guc *guc = &dev_priv->guc;
1170a85cb24fSFrançois Tigeot 
1171a85cb24fSFrançois Tigeot 	guc_interrupts_release(dev_priv);
1172a85cb24fSFrançois Tigeot 
1173a85cb24fSFrançois Tigeot 	/* Revert back to manual ELSP submission */
1174a85cb24fSFrançois Tigeot 	intel_engines_reset_default_submission(dev_priv);
1175a85cb24fSFrançois Tigeot 
1176a85cb24fSFrançois Tigeot 	guc_client_free(guc->execbuf_client);
1177a85cb24fSFrançois Tigeot 	guc->execbuf_client = NULL;
1178352ff8bdSFrançois Tigeot }
1179