1 /*
2 * Copyright © 2022 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 #include "i915/intel_gem.h"
25
26 #include "common/intel_gem.h"
27 #include "i915/intel_engine.h"
28
29 #include "drm-uapi/i915_drm.h"
30
31 bool
i915_gem_create_context(int fd,uint32_t * context_id)32 i915_gem_create_context(int fd, uint32_t *context_id)
33 {
34 struct drm_i915_gem_context_create create = {};
35 if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create))
36 return false;
37 *context_id = create.ctx_id;
38 return true;
39 }
40
41 bool
i915_gem_destroy_context(int fd,uint32_t context_id)42 i915_gem_destroy_context(int fd, uint32_t context_id)
43 {
44 struct drm_i915_gem_context_destroy destroy = {
45 .ctx_id = context_id,
46 };
47 return intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, &destroy) == 0;
48 }
49
50 bool
i915_gem_create_context_engines(int fd,enum intel_gem_create_context_flags flags,const struct intel_query_engine_info * info,int num_engines,enum intel_engine_class * engine_classes,uint32_t vm_id,uint32_t * context_id)51 i915_gem_create_context_engines(int fd,
52 enum intel_gem_create_context_flags flags,
53 const struct intel_query_engine_info *info,
54 int num_engines, enum intel_engine_class *engine_classes,
55 uint32_t vm_id,
56 uint32_t *context_id)
57 {
58 assert(info != NULL);
59 assert(num_engines <= 64);
60 I915_DEFINE_CONTEXT_PARAM_ENGINES(engines_param, 64);
61 engines_param.extensions = 0;
62
63 /* For each type of intel_engine_class of interest, we keep track of
64 * the previous engine instance used.
65 */
66 int last_engine_idx[] = {
67 [INTEL_ENGINE_CLASS_RENDER] = -1,
68 [INTEL_ENGINE_CLASS_COPY] = -1,
69 [INTEL_ENGINE_CLASS_COMPUTE] = -1,
70 [INTEL_ENGINE_CLASS_VIDEO] = -1,
71 };
72
73 int engine_counts[] = {
74 [INTEL_ENGINE_CLASS_RENDER] =
75 intel_engines_count(info, INTEL_ENGINE_CLASS_RENDER),
76 [INTEL_ENGINE_CLASS_COPY] =
77 intel_engines_count(info, INTEL_ENGINE_CLASS_COPY),
78 [INTEL_ENGINE_CLASS_COMPUTE] =
79 intel_engines_count(info, INTEL_ENGINE_CLASS_COMPUTE),
80 [INTEL_ENGINE_CLASS_VIDEO] =
81 intel_engines_count(info, INTEL_ENGINE_CLASS_VIDEO),
82 };
83
84 /* For each queue, we look for the next instance that matches the class we
85 * need.
86 */
87 for (int i = 0; i < num_engines; i++) {
88 enum intel_engine_class engine_class = engine_classes[i];
89 assert(engine_class == INTEL_ENGINE_CLASS_RENDER ||
90 engine_class == INTEL_ENGINE_CLASS_COPY ||
91 engine_class == INTEL_ENGINE_CLASS_COMPUTE ||
92 engine_class == INTEL_ENGINE_CLASS_VIDEO);
93 if (engine_counts[engine_class] <= 0)
94 return false;
95
96 /* Run through the engines reported by the kernel looking for the next
97 * matching instance. We loop in case we want to create multiple
98 * contexts on an engine instance.
99 */
100 int engine_instance = -1;
101 for (int i = 0; i < info->num_engines; i++) {
102 int *idx = &last_engine_idx[engine_class];
103 if (++(*idx) >= info->num_engines)
104 *idx = 0;
105 if (info->engines[*idx].engine_class == engine_class) {
106 engine_instance = info->engines[*idx].engine_instance;
107 break;
108 }
109 }
110 if (engine_instance < 0)
111 return false;
112
113 engines_param.engines[i].engine_class = intel_engine_class_to_i915(engine_class);
114 engines_param.engines[i].engine_instance = engine_instance;
115 }
116
117 uint32_t size = sizeof(engines_param.extensions);
118 size += sizeof(engines_param.engines[0]) * num_engines;
119 struct drm_i915_gem_context_create_ext_setparam set_engines = {
120 .param = {
121 .param = I915_CONTEXT_PARAM_ENGINES,
122 .value = (uintptr_t)&engines_param,
123 .size = size,
124 }
125 };
126 struct drm_i915_gem_context_create_ext_setparam protected_param = {
127 .param = {
128 .param = I915_CONTEXT_PARAM_PROTECTED_CONTENT,
129 .value = flags & INTEL_GEM_CREATE_CONTEXT_EXT_PROTECTED_FLAG,
130 },
131 };
132 struct drm_i915_gem_context_create_ext_setparam recoverable_param = {
133 .param = {
134 .param = I915_CONTEXT_PARAM_RECOVERABLE,
135 .value = flags & INTEL_GEM_CREATE_CONTEXT_EXT_RECOVERABLE_FLAG,
136 },
137 };
138 struct drm_i915_gem_context_create_ext_setparam low_latency_param = {
139 .param = {
140 .param = I915_CONTEXT_PARAM_LOW_LATENCY,
141 .value = flags & INTEL_GEM_CREATE_CONTEXT_EXT_LOW_LATENCY_FLAG,
142 }
143 };
144 struct drm_i915_gem_context_create_ext create = {
145 .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS,
146 };
147 struct drm_i915_gem_context_create_ext_setparam vm_param = {
148 .param = {
149 .param = I915_CONTEXT_PARAM_VM,
150 .value = vm_id,
151 },
152 };
153
154 intel_i915_gem_add_ext(&create.extensions,
155 I915_CONTEXT_CREATE_EXT_SETPARAM,
156 &set_engines.base);
157 intel_i915_gem_add_ext(&create.extensions,
158 I915_CONTEXT_CREATE_EXT_SETPARAM,
159 &recoverable_param.base);
160
161 if (vm_id != 0) {
162 intel_i915_gem_add_ext(&create.extensions,
163 I915_CONTEXT_CREATE_EXT_SETPARAM,
164 &vm_param.base);
165 }
166
167 if (flags & INTEL_GEM_CREATE_CONTEXT_EXT_PROTECTED_FLAG) {
168 intel_i915_gem_add_ext(&create.extensions,
169 I915_CONTEXT_CREATE_EXT_SETPARAM,
170 &protected_param.base);
171 }
172
173 if (flags & INTEL_GEM_CREATE_CONTEXT_EXT_LOW_LATENCY_FLAG) {
174 intel_i915_gem_add_ext(&create.extensions,
175 I915_CONTEXT_CREATE_EXT_SETPARAM,
176 &low_latency_param.base);
177 }
178
179 if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT, &create) == -1)
180 return false;
181
182 *context_id = create.ctx_id;
183 return true;
184 }
185
186 bool
i915_gem_set_context_param(int fd,uint32_t context,uint32_t param,uint64_t value)187 i915_gem_set_context_param(int fd, uint32_t context, uint32_t param,
188 uint64_t value)
189 {
190 struct drm_i915_gem_context_param p = {
191 .ctx_id = context,
192 .param = param,
193 .value = value,
194 };
195 return intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, &p) == 0;
196 }
197
198 bool
i915_gem_get_context_param(int fd,uint32_t context,uint32_t param,uint64_t * value)199 i915_gem_get_context_param(int fd, uint32_t context, uint32_t param,
200 uint64_t *value)
201 {
202 struct drm_i915_gem_context_param gp = {
203 .ctx_id = context,
204 .param = param,
205 };
206 if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &gp))
207 return false;
208 *value = gp.value;
209 return true;
210 }
211
212 bool
i915_gem_read_render_timestamp(int fd,uint64_t * value)213 i915_gem_read_render_timestamp(int fd, uint64_t *value)
214 {
215 struct drm_i915_reg_read reg_read = {
216 .offset = RCS_TIMESTAMP | I915_REG_READ_8B_WA,
217 };
218
219 int ret = intel_ioctl(fd, DRM_IOCTL_I915_REG_READ, ®_read);
220 if (ret == 0)
221 *value = reg_read.val;
222 return ret == 0;
223 }
224
225 bool
i915_gem_create_context_ext(int fd,enum intel_gem_create_context_flags flags,uint32_t * ctx_id)226 i915_gem_create_context_ext(int fd,
227 enum intel_gem_create_context_flags flags,
228 uint32_t *ctx_id)
229 {
230 struct drm_i915_gem_context_create_ext_setparam recoverable_param = {
231 .param = {
232 .param = I915_CONTEXT_PARAM_RECOVERABLE,
233 .value = flags & INTEL_GEM_CREATE_CONTEXT_EXT_RECOVERABLE_FLAG,
234 },
235 };
236 struct drm_i915_gem_context_create_ext_setparam protected_param = {
237 .param = {
238 .param = I915_CONTEXT_PARAM_PROTECTED_CONTENT,
239 .value = flags & INTEL_GEM_CREATE_CONTEXT_EXT_PROTECTED_FLAG,
240 },
241 };
242 struct drm_i915_gem_context_create_ext create = {
243 .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS,
244 };
245
246 intel_i915_gem_add_ext(&create.extensions,
247 I915_CONTEXT_CREATE_EXT_SETPARAM,
248 &recoverable_param.base);
249 intel_i915_gem_add_ext(&create.extensions,
250 I915_CONTEXT_CREATE_EXT_SETPARAM,
251 &protected_param.base);
252
253 if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT, &create))
254 return false;
255
256 *ctx_id = create.ctx_id;
257 return true;
258 }
259
260 bool
i915_gem_supports_protected_context(int fd)261 i915_gem_supports_protected_context(int fd)
262 {
263 int val = 0;
264 uint32_t ctx_id;
265 bool ret;
266
267 errno = 0;
268 if (!i915_gem_get_param(fd, I915_PARAM_PXP_STATUS, &val)) {
269 if (errno == ENODEV)
270 return false;
271 } else {
272 return (val > 0);
273 }
274
275 /* failed without ENODEV, so older kernels require a creation test */
276 ret = i915_gem_create_context_ext(fd,
277 INTEL_GEM_CREATE_CONTEXT_EXT_PROTECTED_FLAG,
278 &ctx_id);
279 if (!ret)
280 return ret;
281
282 i915_gem_destroy_context(fd, ctx_id);
283 return ret;
284 }
285
286 bool
i915_gem_get_param(int fd,uint32_t param,int * value)287 i915_gem_get_param(int fd, uint32_t param, int *value)
288 {
289 drm_i915_getparam_t gp = {
290 .param = param,
291 .value = value,
292 };
293 return intel_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0;
294 }
295
296 bool
i915_gem_can_render_on_fd(int fd)297 i915_gem_can_render_on_fd(int fd)
298 {
299 int val;
300 return intel_gem_get_param(fd, I915_PARAM_CHIPSET_ID, &val) && val > 0;
301 }
302