191 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright(c) 2020, Intel Corporation. All rights reserved.4 */5 6#include "i915_drv.h"7 8#include "intel_pxp.h"9#include "intel_pxp_cmd.h"10#include "intel_pxp_gsccs.h"11#include "intel_pxp_session.h"12#include "intel_pxp_tee.h"13#include "intel_pxp_types.h"14#include "intel_pxp_regs.h"15 16#define ARB_SESSION I915_PROTECTED_CONTENT_DEFAULT_SESSION /* shorter define */17 18static bool intel_pxp_session_is_in_play(struct intel_pxp *pxp, u32 id)19{20 struct intel_uncore *uncore = pxp->ctrl_gt->uncore;21 intel_wakeref_t wakeref;22 u32 sip = 0;23 24 /* if we're suspended the session is considered off */25 with_intel_runtime_pm_if_in_use(uncore->rpm, wakeref)26 sip = intel_uncore_read(uncore, KCR_SIP(pxp->kcr_base));27 28 return sip & BIT(id);29}30 31static int pxp_wait_for_session_state(struct intel_pxp *pxp, u32 id, bool in_play)32{33 struct intel_uncore *uncore = pxp->ctrl_gt->uncore;34 intel_wakeref_t wakeref;35 u32 mask = BIT(id);36 int ret;37 38 /* if we're suspended the session is considered off */39 wakeref = intel_runtime_pm_get_if_in_use(uncore->rpm);40 if (!wakeref)41 return in_play ? -ENODEV : 0;42 43 ret = intel_wait_for_register(uncore,44 KCR_SIP(pxp->kcr_base),45 mask,46 in_play ? mask : 0,47 250);48 49 intel_runtime_pm_put(uncore->rpm, wakeref);50 51 return ret;52}53 54static int pxp_create_arb_session(struct intel_pxp *pxp)55{56 struct intel_gt *gt = pxp->ctrl_gt;57 int ret;58 59 pxp->arb_is_valid = false;60 61 if (intel_pxp_session_is_in_play(pxp, ARB_SESSION)) {62 drm_err(>->i915->drm, "arb session already in play at creation time\n");63 return -EEXIST;64 }65 66 if (HAS_ENGINE(pxp->ctrl_gt, GSC0))67 ret = intel_pxp_gsccs_create_session(pxp, ARB_SESSION);68 else69 ret = intel_pxp_tee_cmd_create_arb_session(pxp, ARB_SESSION);70 if (ret) {71 drm_err(>->i915->drm, "tee cmd for arb session creation failed\n");72 return ret;73 }74 75 ret = pxp_wait_for_session_state(pxp, ARB_SESSION, true);76 if (ret) {77 drm_dbg(>->i915->drm, "arb session failed to go in play\n");78 return ret;79 }80 drm_dbg(>->i915->drm, "PXP ARB session is alive\n");81 82 if (!++pxp->key_instance)83 ++pxp->key_instance;84 85 pxp->arb_is_valid = true;86 87 return 0;88}89 90static int pxp_terminate_arb_session_and_global(struct intel_pxp *pxp)91{92 int ret;93 struct intel_gt *gt = pxp->ctrl_gt;94 95 /* must mark termination in progress calling this function */96 GEM_WARN_ON(pxp->arb_is_valid);97 98 /* terminate the hw sessions */99 ret = intel_pxp_terminate_session(pxp, ARB_SESSION);100 if (ret) {101 drm_err(>->i915->drm, "Failed to submit session termination\n");102 return ret;103 }104 105 ret = pxp_wait_for_session_state(pxp, ARB_SESSION, false);106 if (ret) {107 drm_err(>->i915->drm, "Session state did not clear\n");108 return ret;109 }110 111 intel_uncore_write(gt->uncore, KCR_GLOBAL_TERMINATE(pxp->kcr_base), 1);112 113 if (HAS_ENGINE(gt, GSC0))114 intel_pxp_gsccs_end_arb_fw_session(pxp, ARB_SESSION);115 else116 intel_pxp_tee_end_arb_fw_session(pxp, ARB_SESSION);117 118 return ret;119}120 121void intel_pxp_terminate(struct intel_pxp *pxp, bool post_invalidation_needs_restart)122{123 int ret;124 125 pxp->hw_state_invalidated = post_invalidation_needs_restart;126 127 /*128 * if we fail to submit the termination there is no point in waiting for129 * it to complete. PXP will be marked as non-active until the next130 * termination is issued.131 */132 ret = pxp_terminate_arb_session_and_global(pxp);133 if (ret)134 complete_all(&pxp->termination);135}136 137static void pxp_terminate_complete(struct intel_pxp *pxp)138{139 /* Re-create the arb session after teardown handle complete */140 if (fetch_and_zero(&pxp->hw_state_invalidated)) {141 drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: creating arb_session after invalidation");142 pxp_create_arb_session(pxp);143 }144 145 complete_all(&pxp->termination);146}147 148static void pxp_session_work(struct work_struct *work)149{150 struct intel_pxp *pxp = container_of(work, typeof(*pxp), session_work);151 struct intel_gt *gt = pxp->ctrl_gt;152 intel_wakeref_t wakeref;153 u32 events = 0;154 155 spin_lock_irq(gt->irq_lock);156 events = fetch_and_zero(&pxp->session_events);157 spin_unlock_irq(gt->irq_lock);158 159 if (!events)160 return;161 162 drm_dbg(>->i915->drm, "PXP: processing event-flags 0x%08x", events);163 164 if (events & PXP_INVAL_REQUIRED)165 intel_pxp_invalidate(pxp);166 167 /*168 * If we're processing an event while suspending then don't bother,169 * we're going to re-init everything on resume anyway.170 */171 wakeref = intel_runtime_pm_get_if_in_use(gt->uncore->rpm);172 if (!wakeref)173 return;174 175 if (events & PXP_TERMINATION_REQUEST) {176 events &= ~PXP_TERMINATION_COMPLETE;177 intel_pxp_terminate(pxp, true);178 }179 180 if (events & PXP_TERMINATION_COMPLETE)181 pxp_terminate_complete(pxp);182 183 intel_runtime_pm_put(gt->uncore->rpm, wakeref);184}185 186void intel_pxp_session_management_init(struct intel_pxp *pxp)187{188 mutex_init(&pxp->arb_mutex);189 INIT_WORK(&pxp->session_work, pxp_session_work);190}191