1 /*
2  * Copyright © 2014-2017 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  */
24 
25 #include "intel_guc_ads.h"
26 #include "intel_uc.h"
27 #include "i915_drv.h"
28 
29 /*
30  * The Additional Data Struct (ADS) has pointers for different buffers used by
31  * the GuC. One single gem object contains the ADS struct itself (guc_ads), the
32  * scheduling policies (guc_policies), a structure describing a collection of
33  * register sets (guc_mmio_reg_state) and some extra pages for the GuC to save
34  * its internal state for sleep.
35  */
36 
guc_policy_init(struct guc_policy * policy)37 static void guc_policy_init(struct guc_policy *policy)
38 {
39 	policy->execution_quantum = POLICY_DEFAULT_EXECUTION_QUANTUM_US;
40 	policy->preemption_time = POLICY_DEFAULT_PREEMPTION_TIME_US;
41 	policy->fault_time = POLICY_DEFAULT_FAULT_TIME_US;
42 	policy->policy_flags = 0;
43 }
44 
guc_policies_init(struct guc_policies * policies)45 static void guc_policies_init(struct guc_policies *policies)
46 {
47 	struct guc_policy *policy;
48 	u32 p, i;
49 
50 	policies->dpc_promote_time = POLICY_DEFAULT_DPC_PROMOTE_TIME_US;
51 	policies->max_num_work_items = POLICY_MAX_NUM_WI;
52 
53 	for (p = 0; p < GUC_CLIENT_PRIORITY_NUM; p++) {
54 		for (i = GUC_RENDER_ENGINE; i < GUC_MAX_ENGINES_NUM; i++) {
55 			policy = &policies->policy[p][i];
56 
57 			guc_policy_init(policy);
58 		}
59 	}
60 
61 	policies->is_valid = 1;
62 }
63 
64 /*
65  * The first 80 dwords of the register state context, containing the
66  * execlists and ppgtt registers.
67  */
68 #define LR_HW_CONTEXT_SIZE	(80 * sizeof(u32))
69 
70 /**
71  * intel_guc_ads_create() - creates GuC ADS
72  * @guc: intel_guc struct
73  *
74  */
intel_guc_ads_create(struct intel_guc * guc)75 int intel_guc_ads_create(struct intel_guc *guc)
76 {
77 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
78 	struct i915_vma *vma, *kernel_ctx_vma;
79 	struct page *page;
80 	/* The ads obj includes the struct itself and buffers passed to GuC */
81 	struct {
82 		struct guc_ads ads;
83 		struct guc_policies policies;
84 		struct guc_mmio_reg_state reg_state;
85 		u8 reg_state_buffer[GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE];
86 	} __packed *blob;
87 	struct intel_engine_cs *engine;
88 	enum intel_engine_id id;
89 	const u32 skipped_offset = LRC_HEADER_PAGES * PAGE_SIZE;
90 	const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE;
91 	u32 base;
92 
93 	GEM_BUG_ON(guc->ads_vma);
94 
95 	vma = intel_guc_allocate_vma(guc, PAGE_ALIGN(sizeof(*blob)));
96 	if (IS_ERR(vma))
97 		return PTR_ERR(vma);
98 
99 	guc->ads_vma = vma;
100 
101 	page = i915_vma_first_page(vma);
102 	blob = kmap(page);
103 
104 	/* GuC scheduling policies */
105 	guc_policies_init(&blob->policies);
106 
107 	/* MMIO reg state */
108 	for_each_engine(engine, dev_priv, id) {
109 		blob->reg_state.white_list[engine->guc_id].mmio_start =
110 			engine->mmio_base + GUC_MMIO_WHITE_LIST_START;
111 
112 		/* Nothing to be saved or restored for now. */
113 		blob->reg_state.white_list[engine->guc_id].count = 0;
114 	}
115 
116 	/*
117 	 * The GuC requires a "Golden Context" when it reinitialises
118 	 * engines after a reset. Here we use the Render ring default
119 	 * context, which must already exist and be pinned in the GGTT,
120 	 * so its address won't change after we've told the GuC where
121 	 * to find it. Note that we have to skip our header (1 page),
122 	 * because our GuC shared data is there.
123 	 */
124 	kernel_ctx_vma = to_intel_context(dev_priv->kernel_context,
125 					  dev_priv->engine[RCS])->state;
126 	blob->ads.golden_context_lrca =
127 		intel_guc_ggtt_offset(guc, kernel_ctx_vma) + skipped_offset;
128 
129 	/*
130 	 * The GuC expects us to exclude the portion of the context image that
131 	 * it skips from the size it is to read. It starts reading from after
132 	 * the execlist context (so skipping the first page [PPHWSP] and 80
133 	 * dwords). Weird guc is weird.
134 	 */
135 	for_each_engine(engine, dev_priv, id)
136 		blob->ads.eng_state_size[engine->guc_id] =
137 			engine->context_size - skipped_size;
138 
139 	base = intel_guc_ggtt_offset(guc, vma);
140 	blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
141 	blob->ads.reg_state_buffer = base + ptr_offset(blob, reg_state_buffer);
142 	blob->ads.reg_state_addr = base + ptr_offset(blob, reg_state);
143 
144 	kunmap(page);
145 
146 	return 0;
147 }
148 
intel_guc_ads_destroy(struct intel_guc * guc)149 void intel_guc_ads_destroy(struct intel_guc *guc)
150 {
151 	i915_vma_unpin_and_release(&guc->ads_vma);
152 }
153