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 create = {
139 .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS,
140 };
141 struct drm_i915_gem_context_create_ext_setparam vm_param = {
142 .param = {
143 .param = I915_CONTEXT_PARAM_VM,
144 .value = vm_id,
145 },
146 };
147
148 intel_i915_gem_add_ext(&create.extensions,
149 I915_CONTEXT_CREATE_EXT_SETPARAM,
150 &set_engines.base);
151 intel_i915_gem_add_ext(&create.extensions,
152 I915_CONTEXT_CREATE_EXT_SETPARAM,
153 &recoverable_param.base);
154
155 if (vm_id != 0) {
156 intel_i915_gem_add_ext(&create.extensions,
157 I915_CONTEXT_CREATE_EXT_SETPARAM,
158 &vm_param.base);
159 }
160
161 if (flags & INTEL_GEM_CREATE_CONTEXT_EXT_PROTECTED_FLAG) {
162 intel_i915_gem_add_ext(&create.extensions,
163 I915_CONTEXT_CREATE_EXT_SETPARAM,
164 &protected_param.base);
165 }
166
167 if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT, &create) == -1)
168 return false;
169
170 *context_id = create.ctx_id;
171 return true;
172 }
173
174 bool
i915_gem_set_context_param(int fd,uint32_t context,uint32_t param,uint64_t value)175 i915_gem_set_context_param(int fd, uint32_t context, uint32_t param,
176 uint64_t value)
177 {
178 struct drm_i915_gem_context_param p = {
179 .ctx_id = context,
180 .param = param,
181 .value = value,
182 };
183 return intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, &p) == 0;
184 }
185
186 bool
i915_gem_get_context_param(int fd,uint32_t context,uint32_t param,uint64_t * value)187 i915_gem_get_context_param(int fd, uint32_t context, uint32_t param,
188 uint64_t *value)
189 {
190 struct drm_i915_gem_context_param gp = {
191 .ctx_id = context,
192 .param = param,
193 };
194 if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &gp))
195 return false;
196 *value = gp.value;
197 return true;
198 }
199
200 bool
i915_gem_read_render_timestamp(int fd,uint64_t * value)201 i915_gem_read_render_timestamp(int fd, uint64_t *value)
202 {
203 struct drm_i915_reg_read reg_read = {
204 .offset = RCS_TIMESTAMP | I915_REG_READ_8B_WA,
205 };
206
207 int ret = intel_ioctl(fd, DRM_IOCTL_I915_REG_READ, ®_read);
208 if (ret == 0)
209 *value = reg_read.val;
210 return ret == 0;
211 }
212
213 bool
i915_gem_create_context_ext(int fd,enum intel_gem_create_context_flags flags,uint32_t * ctx_id)214 i915_gem_create_context_ext(int fd,
215 enum intel_gem_create_context_flags flags,
216 uint32_t *ctx_id)
217 {
218 struct drm_i915_gem_context_create_ext_setparam recoverable_param = {
219 .param = {
220 .param = I915_CONTEXT_PARAM_RECOVERABLE,
221 .value = flags & INTEL_GEM_CREATE_CONTEXT_EXT_RECOVERABLE_FLAG,
222 },
223 };
224 struct drm_i915_gem_context_create_ext_setparam protected_param = {
225 .param = {
226 .param = I915_CONTEXT_PARAM_PROTECTED_CONTENT,
227 .value = flags & INTEL_GEM_CREATE_CONTEXT_EXT_PROTECTED_FLAG,
228 },
229 };
230 struct drm_i915_gem_context_create_ext create = {
231 .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS,
232 };
233
234 intel_i915_gem_add_ext(&create.extensions,
235 I915_CONTEXT_CREATE_EXT_SETPARAM,
236 &recoverable_param.base);
237 intel_i915_gem_add_ext(&create.extensions,
238 I915_CONTEXT_CREATE_EXT_SETPARAM,
239 &protected_param.base);
240
241 if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT, &create))
242 return false;
243
244 *ctx_id = create.ctx_id;
245 return true;
246 }
247
248 bool
i915_gem_supports_protected_context(int fd)249 i915_gem_supports_protected_context(int fd)
250 {
251 int val = 0;
252 uint32_t ctx_id;
253 bool ret;
254
255 errno = 0;
256 if (!i915_gem_get_param(fd, I915_PARAM_PXP_STATUS, &val)) {
257 if (errno == ENODEV)
258 return false;
259 } else {
260 return (val > 0);
261 }
262
263 /* failed without ENODEV, so older kernels require a creation test */
264 ret = i915_gem_create_context_ext(fd,
265 INTEL_GEM_CREATE_CONTEXT_EXT_PROTECTED_FLAG,
266 &ctx_id);
267 if (!ret)
268 return ret;
269
270 i915_gem_destroy_context(fd, ctx_id);
271 return ret;
272 }
273
274 bool
i915_gem_get_param(int fd,uint32_t param,int * value)275 i915_gem_get_param(int fd, uint32_t param, int *value)
276 {
277 drm_i915_getparam_t gp = {
278 .param = param,
279 .value = value,
280 };
281 return intel_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0;
282 }
283
284 bool
i915_gem_can_render_on_fd(int fd)285 i915_gem_can_render_on_fd(int fd)
286 {
287 int val;
288 return intel_gem_get_param(fd, I915_PARAM_CHIPSET_ID, &val) && val > 0;
289 }
290