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