mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	 2052287a74
			
		
	
	
		2052287a74
		
	
	
	
	
		
			
			Use <> not "" for including headers from include/drm. Signed-off-by: Jani Nikula <jani.nikula@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20211116135813.19806-1-jani.nikula@intel.com
		
			
				
	
	
		
			177 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: MIT
 | |
| /*
 | |
|  * Copyright(c) 2020, Intel Corporation. All rights reserved.
 | |
|  */
 | |
| 
 | |
| #include <drm/i915_drm.h>
 | |
| 
 | |
| #include "i915_drv.h"
 | |
| 
 | |
| #include "intel_pxp.h"
 | |
| #include "intel_pxp_cmd.h"
 | |
| #include "intel_pxp_session.h"
 | |
| #include "intel_pxp_tee.h"
 | |
| #include "intel_pxp_types.h"
 | |
| 
 | |
| #define ARB_SESSION I915_PROTECTED_CONTENT_DEFAULT_SESSION /* shorter define */
 | |
| 
 | |
| #define GEN12_KCR_SIP _MMIO(0x32260) /* KCR hwdrm session in play 0-31 */
 | |
| 
 | |
| /* PXP global terminate register for session termination */
 | |
| #define PXP_GLOBAL_TERMINATE _MMIO(0x320f8)
 | |
| 
 | |
| static bool intel_pxp_session_is_in_play(struct intel_pxp *pxp, u32 id)
 | |
| {
 | |
| 	struct intel_uncore *uncore = pxp_to_gt(pxp)->uncore;
 | |
| 	intel_wakeref_t wakeref;
 | |
| 	u32 sip = 0;
 | |
| 
 | |
| 	/* if we're suspended the session is considered off */
 | |
| 	with_intel_runtime_pm_if_in_use(uncore->rpm, wakeref)
 | |
| 		sip = intel_uncore_read(uncore, GEN12_KCR_SIP);
 | |
| 
 | |
| 	return sip & BIT(id);
 | |
| }
 | |
| 
 | |
| static int pxp_wait_for_session_state(struct intel_pxp *pxp, u32 id, bool in_play)
 | |
| {
 | |
| 	struct intel_uncore *uncore = pxp_to_gt(pxp)->uncore;
 | |
| 	intel_wakeref_t wakeref;
 | |
| 	u32 mask = BIT(id);
 | |
| 	int ret;
 | |
| 
 | |
| 	/* if we're suspended the session is considered off */
 | |
| 	wakeref = intel_runtime_pm_get_if_in_use(uncore->rpm);
 | |
| 	if (!wakeref)
 | |
| 		return in_play ? -ENODEV : 0;
 | |
| 
 | |
| 	ret = intel_wait_for_register(uncore,
 | |
| 				      GEN12_KCR_SIP,
 | |
| 				      mask,
 | |
| 				      in_play ? mask : 0,
 | |
| 				      100);
 | |
| 
 | |
| 	intel_runtime_pm_put(uncore->rpm, wakeref);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static int pxp_create_arb_session(struct intel_pxp *pxp)
 | |
| {
 | |
| 	struct intel_gt *gt = pxp_to_gt(pxp);
 | |
| 	int ret;
 | |
| 
 | |
| 	pxp->arb_is_valid = false;
 | |
| 
 | |
| 	if (intel_pxp_session_is_in_play(pxp, ARB_SESSION)) {
 | |
| 		drm_err(>->i915->drm, "arb session already in play at creation time\n");
 | |
| 		return -EEXIST;
 | |
| 	}
 | |
| 
 | |
| 	ret = intel_pxp_tee_cmd_create_arb_session(pxp, ARB_SESSION);
 | |
| 	if (ret) {
 | |
| 		drm_err(>->i915->drm, "tee cmd for arb session creation failed\n");
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	ret = pxp_wait_for_session_state(pxp, ARB_SESSION, true);
 | |
| 	if (ret) {
 | |
| 		drm_err(>->i915->drm, "arb session failed to go in play\n");
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	if (!++pxp->key_instance)
 | |
| 		++pxp->key_instance;
 | |
| 
 | |
| 	pxp->arb_is_valid = true;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int pxp_terminate_arb_session_and_global(struct intel_pxp *pxp)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct intel_gt *gt = pxp_to_gt(pxp);
 | |
| 
 | |
| 	/* must mark termination in progress calling this function */
 | |
| 	GEM_WARN_ON(pxp->arb_is_valid);
 | |
| 
 | |
| 	/* terminate the hw sessions */
 | |
| 	ret = intel_pxp_terminate_session(pxp, ARB_SESSION);
 | |
| 	if (ret) {
 | |
| 		drm_err(>->i915->drm, "Failed to submit session termination\n");
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	ret = pxp_wait_for_session_state(pxp, ARB_SESSION, false);
 | |
| 	if (ret) {
 | |
| 		drm_err(>->i915->drm, "Session state did not clear\n");
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	intel_uncore_write(gt->uncore, PXP_GLOBAL_TERMINATE, 1);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static void pxp_terminate(struct intel_pxp *pxp)
 | |
| {
 | |
| 	int ret;
 | |
| 
 | |
| 	pxp->hw_state_invalidated = true;
 | |
| 
 | |
| 	/*
 | |
| 	 * if we fail to submit the termination there is no point in waiting for
 | |
| 	 * it to complete. PXP will be marked as non-active until the next
 | |
| 	 * termination is issued.
 | |
| 	 */
 | |
| 	ret = pxp_terminate_arb_session_and_global(pxp);
 | |
| 	if (ret)
 | |
| 		complete_all(&pxp->termination);
 | |
| }
 | |
| 
 | |
| static void pxp_terminate_complete(struct intel_pxp *pxp)
 | |
| {
 | |
| 	/* Re-create the arb session after teardown handle complete */
 | |
| 	if (fetch_and_zero(&pxp->hw_state_invalidated))
 | |
| 		pxp_create_arb_session(pxp);
 | |
| 
 | |
| 	complete_all(&pxp->termination);
 | |
| }
 | |
| 
 | |
| void intel_pxp_session_work(struct work_struct *work)
 | |
| {
 | |
| 	struct intel_pxp *pxp = container_of(work, typeof(*pxp), session_work);
 | |
| 	struct intel_gt *gt = pxp_to_gt(pxp);
 | |
| 	intel_wakeref_t wakeref;
 | |
| 	u32 events = 0;
 | |
| 
 | |
| 	spin_lock_irq(>->irq_lock);
 | |
| 	events = fetch_and_zero(&pxp->session_events);
 | |
| 	spin_unlock_irq(>->irq_lock);
 | |
| 
 | |
| 	if (!events)
 | |
| 		return;
 | |
| 
 | |
| 	if (events & PXP_INVAL_REQUIRED)
 | |
| 		intel_pxp_invalidate(pxp);
 | |
| 
 | |
| 	/*
 | |
| 	 * If we're processing an event while suspending then don't bother,
 | |
| 	 * we're going to re-init everything on resume anyway.
 | |
| 	 */
 | |
| 	wakeref = intel_runtime_pm_get_if_in_use(gt->uncore->rpm);
 | |
| 	if (!wakeref)
 | |
| 		return;
 | |
| 
 | |
| 	if (events & PXP_TERMINATION_REQUEST) {
 | |
| 		events &= ~PXP_TERMINATION_COMPLETE;
 | |
| 		pxp_terminate(pxp);
 | |
| 	}
 | |
| 
 | |
| 	if (events & PXP_TERMINATION_COMPLETE)
 | |
| 		pxp_terminate_complete(pxp);
 | |
| 
 | |
| 	intel_runtime_pm_put(gt->uncore->rpm, wakeref);
 | |
| }
 |