xref: /openbsd/sys/dev/pci/drm/i915/pxp/intel_pxp.c (revision f005ef32)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright(c) 2020 Intel Corporation.
4  */
5 #include <linux/workqueue.h>
6 
7 #include "gem/i915_gem_context.h"
8 
9 #include "gt/intel_context.h"
10 #include "gt/intel_gt.h"
11 
12 #include "i915_drv.h"
13 
14 #include "intel_pxp.h"
15 #include "intel_pxp_gsccs.h"
16 #include "intel_pxp_irq.h"
17 #include "intel_pxp_regs.h"
18 #include "intel_pxp_session.h"
19 #include "intel_pxp_tee.h"
20 #include "intel_pxp_types.h"
21 
22 /**
23  * DOC: PXP
24  *
25  * PXP (Protected Xe Path) is a feature available in Gen12 and newer platforms.
26  * It allows execution and flip to display of protected (i.e. encrypted)
27  * objects. The SW support is enabled via the CONFIG_DRM_I915_PXP kconfig.
28  *
29  * Objects can opt-in to PXP encryption at creation time via the
30  * I915_GEM_CREATE_EXT_PROTECTED_CONTENT create_ext flag. For objects to be
31  * correctly protected they must be used in conjunction with a context created
32  * with the I915_CONTEXT_PARAM_PROTECTED_CONTENT flag. See the documentation
33  * of those two uapi flags for details and restrictions.
34  *
35  * Protected objects are tied to a pxp session; currently we only support one
36  * session, which i915 manages and whose index is available in the uapi
37  * (I915_PROTECTED_CONTENT_DEFAULT_SESSION) for use in instructions targeting
38  * protected objects.
39  * The session is invalidated by the HW when certain events occur (e.g.
40  * suspend/resume). When this happens, all the objects that were used with the
41  * session are marked as invalid and all contexts marked as using protected
42  * content are banned. Any further attempt at using them in an execbuf call is
43  * rejected, while flips are converted to black frames.
44  *
45  * Some of the PXP setup operations are performed by the Management Engine,
46  * which is handled by the mei driver; communication between i915 and mei is
47  * performed via the mei_pxp component module.
48  */
49 
intel_pxp_is_supported(const struct intel_pxp * pxp)50 bool intel_pxp_is_supported(const struct intel_pxp *pxp)
51 {
52 	return IS_ENABLED(CONFIG_DRM_I915_PXP) && pxp;
53 }
54 
intel_pxp_is_enabled(const struct intel_pxp * pxp)55 bool intel_pxp_is_enabled(const struct intel_pxp *pxp)
56 {
57 	return IS_ENABLED(CONFIG_DRM_I915_PXP) && pxp && pxp->ce;
58 }
59 
intel_pxp_is_active(const struct intel_pxp * pxp)60 bool intel_pxp_is_active(const struct intel_pxp *pxp)
61 {
62 	return IS_ENABLED(CONFIG_DRM_I915_PXP) && pxp && pxp->arb_is_valid;
63 }
64 
kcr_pxp_set_status(const struct intel_pxp * pxp,bool enable)65 static void kcr_pxp_set_status(const struct intel_pxp *pxp, bool enable)
66 {
67 	u32 val = enable ? _MASKED_BIT_ENABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES) :
68 		  _MASKED_BIT_DISABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES);
69 
70 	intel_uncore_write(pxp->ctrl_gt->uncore, KCR_INIT(pxp->kcr_base), val);
71 }
72 
kcr_pxp_enable(const struct intel_pxp * pxp)73 static void kcr_pxp_enable(const struct intel_pxp *pxp)
74 {
75 	kcr_pxp_set_status(pxp, true);
76 }
77 
kcr_pxp_disable(const struct intel_pxp * pxp)78 static void kcr_pxp_disable(const struct intel_pxp *pxp)
79 {
80 	kcr_pxp_set_status(pxp, false);
81 }
82 
create_vcs_context(struct intel_pxp * pxp)83 static int create_vcs_context(struct intel_pxp *pxp)
84 {
85 	static struct lock_class_key pxp_lock;
86 	struct intel_gt *gt = pxp->ctrl_gt;
87 	struct intel_engine_cs *engine;
88 	struct intel_context *ce;
89 	int i;
90 
91 	/*
92 	 * Find the first VCS engine present. We're guaranteed there is one
93 	 * if we're in this function due to the check in has_pxp
94 	 */
95 	for (i = 0, engine = NULL; !engine; i++)
96 		engine = gt->engine_class[VIDEO_DECODE_CLASS][i];
97 
98 	GEM_BUG_ON(!engine || engine->class != VIDEO_DECODE_CLASS);
99 
100 	ce = intel_engine_create_pinned_context(engine, engine->gt->vm, SZ_4K,
101 						I915_GEM_HWS_PXP_ADDR,
102 						&pxp_lock, "pxp_context");
103 	if (IS_ERR(ce)) {
104 		drm_err(&gt->i915->drm, "failed to create VCS ctx for PXP\n");
105 		return PTR_ERR(ce);
106 	}
107 
108 	pxp->ce = ce;
109 
110 	return 0;
111 }
112 
destroy_vcs_context(struct intel_pxp * pxp)113 static void destroy_vcs_context(struct intel_pxp *pxp)
114 {
115 	if (pxp->ce)
116 		intel_engine_destroy_pinned_context(fetch_and_zero(&pxp->ce));
117 }
118 
pxp_init_full(struct intel_pxp * pxp)119 static void pxp_init_full(struct intel_pxp *pxp)
120 {
121 	struct intel_gt *gt = pxp->ctrl_gt;
122 	int ret;
123 
124 	/*
125 	 * we'll use the completion to check if there is a termination pending,
126 	 * so we start it as completed and we reinit it when a termination
127 	 * is triggered.
128 	 */
129 	init_completion(&pxp->termination);
130 	complete_all(&pxp->termination);
131 
132 	if (pxp->ctrl_gt->type == GT_MEDIA)
133 		pxp->kcr_base = MTL_KCR_BASE;
134 	else
135 		pxp->kcr_base = GEN12_KCR_BASE;
136 
137 	intel_pxp_session_management_init(pxp);
138 
139 	ret = create_vcs_context(pxp);
140 	if (ret)
141 		return;
142 
143 	if (HAS_ENGINE(pxp->ctrl_gt, GSC0))
144 		ret = intel_pxp_gsccs_init(pxp);
145 	else
146 		ret = intel_pxp_tee_component_init(pxp);
147 	if (ret)
148 		goto out_context;
149 
150 	drm_info(&gt->i915->drm, "Protected Xe Path (PXP) protected content support initialized\n");
151 
152 	return;
153 
154 out_context:
155 	destroy_vcs_context(pxp);
156 }
157 
find_gt_for_required_teelink(struct drm_i915_private * i915)158 static struct intel_gt *find_gt_for_required_teelink(struct drm_i915_private *i915)
159 {
160 	/*
161 	 * NOTE: Only certain platforms require PXP-tee-backend dependencies
162 	 * for HuC authentication. For now, its limited to DG2.
163 	 */
164 	if (IS_ENABLED(CONFIG_INTEL_MEI_PXP) && IS_ENABLED(CONFIG_INTEL_MEI_GSC) &&
165 	    intel_huc_is_loaded_by_gsc(&to_gt(i915)->uc.huc) && intel_uc_uses_huc(&to_gt(i915)->uc))
166 		return to_gt(i915);
167 
168 	return NULL;
169 }
170 
find_gt_for_required_protected_content(struct drm_i915_private * i915)171 static struct intel_gt *find_gt_for_required_protected_content(struct drm_i915_private *i915)
172 {
173 	if (!IS_ENABLED(CONFIG_DRM_I915_PXP) || !INTEL_INFO(i915)->has_pxp)
174 		return NULL;
175 
176 	/*
177 	 * For MTL onwards, PXP-controller-GT needs to have a valid GSC engine
178 	 * on the media GT. NOTE: if we have a media-tile with a GSC-engine,
179 	 * the VDBOX is already present so skip that check. We also have to
180 	 * ensure the GSC and HUC firmware are coming online
181 	 */
182 	if (i915->media_gt && HAS_ENGINE(i915->media_gt, GSC0) &&
183 	    intel_uc_fw_is_loadable(&i915->media_gt->uc.gsc.fw) &&
184 	    intel_uc_fw_is_loadable(&i915->media_gt->uc.huc.fw))
185 		return i915->media_gt;
186 
187 	/*
188 	 * Else we rely on mei-pxp module but only on legacy platforms
189 	 * prior to having separate media GTs and has a valid VDBOX.
190 	 */
191 	if (IS_ENABLED(CONFIG_INTEL_MEI_PXP) && !i915->media_gt && VDBOX_MASK(to_gt(i915)))
192 		return to_gt(i915);
193 
194 	return NULL;
195 }
196 
intel_pxp_init(struct drm_i915_private * i915)197 int intel_pxp_init(struct drm_i915_private *i915)
198 {
199 	struct intel_gt *gt;
200 	bool is_full_feature = false;
201 
202 	/*
203 	 * NOTE: Get the ctrl_gt before checking intel_pxp_is_supported since
204 	 * we still need it if PXP's backend tee transport is needed.
205 	 */
206 	gt = find_gt_for_required_protected_content(i915);
207 	if (gt)
208 		is_full_feature = true;
209 	else
210 		gt = find_gt_for_required_teelink(i915);
211 
212 	if (!gt)
213 		return -ENODEV;
214 
215 	/*
216 	 * At this point, we will either enable full featured PXP capabilities
217 	 * including session and object management, or we will init the backend tee
218 	 * channel for internal users such as HuC loading by GSC
219 	 */
220 	i915->pxp = kzalloc(sizeof(*i915->pxp), GFP_KERNEL);
221 	if (!i915->pxp)
222 		return -ENOMEM;
223 
224 	/* init common info used by all feature-mode usages*/
225 	i915->pxp->ctrl_gt = gt;
226 	rw_init(&i915->pxp->tee_mutex, "pxptee");
227 
228 	/*
229 	 * If full PXP feature is not available but HuC is loaded by GSC on pre-MTL
230 	 * such as DG2, we can skip the init of the full PXP session/object management
231 	 * and just init the tee channel.
232 	 */
233 	if (is_full_feature)
234 		pxp_init_full(i915->pxp);
235 	else
236 		intel_pxp_tee_component_init(i915->pxp);
237 
238 	return 0;
239 }
240 
intel_pxp_fini(struct drm_i915_private * i915)241 void intel_pxp_fini(struct drm_i915_private *i915)
242 {
243 	if (!i915->pxp)
244 		return;
245 
246 	i915->pxp->arb_is_valid = false;
247 
248 	if (HAS_ENGINE(i915->pxp->ctrl_gt, GSC0))
249 		intel_pxp_gsccs_fini(i915->pxp);
250 	else
251 		intel_pxp_tee_component_fini(i915->pxp);
252 
253 	destroy_vcs_context(i915->pxp);
254 
255 	kfree(i915->pxp);
256 	i915->pxp = NULL;
257 }
258 
intel_pxp_mark_termination_in_progress(struct intel_pxp * pxp)259 void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp)
260 {
261 	pxp->arb_is_valid = false;
262 	reinit_completion(&pxp->termination);
263 }
264 
pxp_queue_termination(struct intel_pxp * pxp)265 static void pxp_queue_termination(struct intel_pxp *pxp)
266 {
267 	struct intel_gt *gt = pxp->ctrl_gt;
268 
269 	/*
270 	 * We want to get the same effect as if we received a termination
271 	 * interrupt, so just pretend that we did.
272 	 */
273 	spin_lock_irq(gt->irq_lock);
274 	intel_pxp_mark_termination_in_progress(pxp);
275 	pxp->session_events |= PXP_TERMINATION_REQUEST;
276 	queue_work(system_unbound_wq, &pxp->session_work);
277 	spin_unlock_irq(gt->irq_lock);
278 }
279 
pxp_component_bound(struct intel_pxp * pxp)280 static bool pxp_component_bound(struct intel_pxp *pxp)
281 {
282 	bool bound = false;
283 
284 	mutex_lock(&pxp->tee_mutex);
285 	if (pxp->pxp_component)
286 		bound = true;
287 	mutex_unlock(&pxp->tee_mutex);
288 
289 	return bound;
290 }
291 
intel_pxp_get_backend_timeout_ms(struct intel_pxp * pxp)292 int intel_pxp_get_backend_timeout_ms(struct intel_pxp *pxp)
293 {
294 	if (HAS_ENGINE(pxp->ctrl_gt, GSC0))
295 		return GSCFW_MAX_ROUND_TRIP_LATENCY_MS;
296 	else
297 		return 250;
298 }
299 
__pxp_global_teardown_final(struct intel_pxp * pxp)300 static int __pxp_global_teardown_final(struct intel_pxp *pxp)
301 {
302 	int timeout;
303 
304 	if (!pxp->arb_is_valid)
305 		return 0;
306 	/*
307 	 * To ensure synchronous and coherent session teardown completion
308 	 * in response to suspend or shutdown triggers, don't use a worker.
309 	 */
310 	intel_pxp_mark_termination_in_progress(pxp);
311 	intel_pxp_terminate(pxp, false);
312 
313 	timeout = intel_pxp_get_backend_timeout_ms(pxp);
314 
315 	if (!wait_for_completion_timeout(&pxp->termination, msecs_to_jiffies(timeout)))
316 		return -ETIMEDOUT;
317 
318 	return 0;
319 }
320 
__pxp_global_teardown_restart(struct intel_pxp * pxp)321 static int __pxp_global_teardown_restart(struct intel_pxp *pxp)
322 {
323 	int timeout;
324 
325 	if (pxp->arb_is_valid)
326 		return 0;
327 	/*
328 	 * The arb-session is currently inactive and we are doing a reset and restart
329 	 * due to a runtime event. Use the worker that was designed for this.
330 	 */
331 	pxp_queue_termination(pxp);
332 
333 	timeout = intel_pxp_get_backend_timeout_ms(pxp);
334 
335 	if (!wait_for_completion_timeout(&pxp->termination, msecs_to_jiffies(timeout)))
336 		return -ETIMEDOUT;
337 
338 	return 0;
339 }
340 
intel_pxp_end(struct intel_pxp * pxp)341 void intel_pxp_end(struct intel_pxp *pxp)
342 {
343 	struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
344 	intel_wakeref_t wakeref;
345 
346 	if (!intel_pxp_is_enabled(pxp))
347 		return;
348 
349 	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
350 
351 	mutex_lock(&pxp->arb_mutex);
352 
353 	if (__pxp_global_teardown_final(pxp))
354 		drm_dbg(&i915->drm, "PXP end timed out\n");
355 
356 	mutex_unlock(&pxp->arb_mutex);
357 
358 	intel_pxp_fini_hw(pxp);
359 	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
360 }
361 
362 /*
363  * this helper is used by both intel_pxp_start and by
364  * the GET_PARAM IOCTL that user space calls. Thus, the
365  * return values here should match the UAPI spec.
366  */
intel_pxp_get_readiness_status(struct intel_pxp * pxp)367 int intel_pxp_get_readiness_status(struct intel_pxp *pxp)
368 {
369 	if (!intel_pxp_is_enabled(pxp))
370 		return -ENODEV;
371 
372 	if (HAS_ENGINE(pxp->ctrl_gt, GSC0)) {
373 		if (wait_for(intel_pxp_gsccs_is_ready_for_sessions(pxp), 250))
374 			return 2;
375 	} else {
376 		if (wait_for(pxp_component_bound(pxp), 250))
377 			return 2;
378 	}
379 	return 1;
380 }
381 
382 /*
383  * the arb session is restarted from the irq work when we receive the
384  * termination completion interrupt
385  */
intel_pxp_start(struct intel_pxp * pxp)386 int intel_pxp_start(struct intel_pxp *pxp)
387 {
388 	int ret = 0;
389 
390 	ret = intel_pxp_get_readiness_status(pxp);
391 	if (ret < 0)
392 		return ret;
393 	else if (ret > 1)
394 		return -EIO; /* per UAPI spec, user may retry later */
395 
396 	mutex_lock(&pxp->arb_mutex);
397 
398 	ret = __pxp_global_teardown_restart(pxp);
399 	if (ret)
400 		goto unlock;
401 
402 	/* make sure the compiler doesn't optimize the double access */
403 	barrier();
404 
405 	if (!pxp->arb_is_valid)
406 		ret = -EIO;
407 
408 unlock:
409 	mutex_unlock(&pxp->arb_mutex);
410 	return ret;
411 }
412 
intel_pxp_init_hw(struct intel_pxp * pxp)413 void intel_pxp_init_hw(struct intel_pxp *pxp)
414 {
415 	kcr_pxp_enable(pxp);
416 	intel_pxp_irq_enable(pxp);
417 }
418 
intel_pxp_fini_hw(struct intel_pxp * pxp)419 void intel_pxp_fini_hw(struct intel_pxp *pxp)
420 {
421 	kcr_pxp_disable(pxp);
422 	intel_pxp_irq_disable(pxp);
423 }
424 
intel_pxp_key_check(struct intel_pxp * pxp,struct drm_i915_gem_object * obj,bool assign)425 int intel_pxp_key_check(struct intel_pxp *pxp,
426 			struct drm_i915_gem_object *obj,
427 			bool assign)
428 {
429 	if (!intel_pxp_is_active(pxp))
430 		return -ENODEV;
431 
432 	if (!i915_gem_object_is_protected(obj))
433 		return -EINVAL;
434 
435 	GEM_BUG_ON(!pxp->key_instance);
436 
437 	/*
438 	 * If this is the first time we're using this object, it's not
439 	 * encrypted yet; it will be encrypted with the current key, so mark it
440 	 * as such. If the object is already encrypted, check instead if the
441 	 * used key is still valid.
442 	 */
443 	if (!obj->pxp_key_instance && assign)
444 		obj->pxp_key_instance = pxp->key_instance;
445 
446 	if (obj->pxp_key_instance != pxp->key_instance)
447 		return -ENOEXEC;
448 
449 	return 0;
450 }
451 
intel_pxp_invalidate(struct intel_pxp * pxp)452 void intel_pxp_invalidate(struct intel_pxp *pxp)
453 {
454 	struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
455 	struct i915_gem_context *ctx, *cn;
456 
457 	/* ban all contexts marked as protected */
458 	spin_lock_irq(&i915->gem.contexts.lock);
459 	list_for_each_entry_safe(ctx, cn, &i915->gem.contexts.list, link) {
460 		struct i915_gem_engines_iter it;
461 		struct intel_context *ce;
462 
463 		if (!kref_get_unless_zero(&ctx->ref))
464 			continue;
465 
466 		if (likely(!i915_gem_context_uses_protected_content(ctx))) {
467 			i915_gem_context_put(ctx);
468 			continue;
469 		}
470 
471 		spin_unlock_irq(&i915->gem.contexts.lock);
472 
473 		/*
474 		 * By the time we get here we are either going to suspend with
475 		 * quiesced execution or the HW keys are already long gone and
476 		 * in this case it is worthless to attempt to close the context
477 		 * and wait for its execution. It will hang the GPU if it has
478 		 * not already. So, as a fast mitigation, we can ban the
479 		 * context as quick as we can. That might race with the
480 		 * execbuffer, but currently this is the best that can be done.
481 		 */
482 		for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it)
483 			intel_context_ban(ce, NULL);
484 		i915_gem_context_unlock_engines(ctx);
485 
486 		/*
487 		 * The context has been banned, no need to keep the wakeref.
488 		 * This is safe from races because the only other place this
489 		 * is touched is context_release and we're holding a ctx ref
490 		 */
491 		if (ctx->pxp_wakeref) {
492 			intel_runtime_pm_put(&i915->runtime_pm,
493 					     ctx->pxp_wakeref);
494 			ctx->pxp_wakeref = 0;
495 		}
496 
497 		spin_lock_irq(&i915->gem.contexts.lock);
498 		list_safe_reset_next(ctx, cn, link);
499 		i915_gem_context_put(ctx);
500 	}
501 	spin_unlock_irq(&i915->gem.contexts.lock);
502 }
503