162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright(c) 2020 Intel Corporation. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/workqueue.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "gem/i915_gem_context.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "gt/intel_context.h" 1062306a36Sopenharmony_ci#include "gt/intel_gt.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "i915_drv.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "intel_pxp.h" 1562306a36Sopenharmony_ci#include "intel_pxp_gsccs.h" 1662306a36Sopenharmony_ci#include "intel_pxp_irq.h" 1762306a36Sopenharmony_ci#include "intel_pxp_regs.h" 1862306a36Sopenharmony_ci#include "intel_pxp_session.h" 1962306a36Sopenharmony_ci#include "intel_pxp_tee.h" 2062306a36Sopenharmony_ci#include "intel_pxp_types.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/** 2362306a36Sopenharmony_ci * DOC: PXP 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * PXP (Protected Xe Path) is a feature available in Gen12 and newer platforms. 2662306a36Sopenharmony_ci * It allows execution and flip to display of protected (i.e. encrypted) 2762306a36Sopenharmony_ci * objects. The SW support is enabled via the CONFIG_DRM_I915_PXP kconfig. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Objects can opt-in to PXP encryption at creation time via the 3062306a36Sopenharmony_ci * I915_GEM_CREATE_EXT_PROTECTED_CONTENT create_ext flag. For objects to be 3162306a36Sopenharmony_ci * correctly protected they must be used in conjunction with a context created 3262306a36Sopenharmony_ci * with the I915_CONTEXT_PARAM_PROTECTED_CONTENT flag. See the documentation 3362306a36Sopenharmony_ci * of those two uapi flags for details and restrictions. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * Protected objects are tied to a pxp session; currently we only support one 3662306a36Sopenharmony_ci * session, which i915 manages and whose index is available in the uapi 3762306a36Sopenharmony_ci * (I915_PROTECTED_CONTENT_DEFAULT_SESSION) for use in instructions targeting 3862306a36Sopenharmony_ci * protected objects. 3962306a36Sopenharmony_ci * The session is invalidated by the HW when certain events occur (e.g. 4062306a36Sopenharmony_ci * suspend/resume). When this happens, all the objects that were used with the 4162306a36Sopenharmony_ci * session are marked as invalid and all contexts marked as using protected 4262306a36Sopenharmony_ci * content are banned. Any further attempt at using them in an execbuf call is 4362306a36Sopenharmony_ci * rejected, while flips are converted to black frames. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * Some of the PXP setup operations are performed by the Management Engine, 4662306a36Sopenharmony_ci * which is handled by the mei driver; communication between i915 and mei is 4762306a36Sopenharmony_ci * performed via the mei_pxp component module. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cibool intel_pxp_is_supported(const struct intel_pxp *pxp) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci return IS_ENABLED(CONFIG_DRM_I915_PXP) && pxp; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cibool intel_pxp_is_enabled(const struct intel_pxp *pxp) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci return IS_ENABLED(CONFIG_DRM_I915_PXP) && pxp && pxp->ce; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cibool intel_pxp_is_active(const struct intel_pxp *pxp) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci return IS_ENABLED(CONFIG_DRM_I915_PXP) && pxp && pxp->arb_is_valid; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic void kcr_pxp_set_status(const struct intel_pxp *pxp, bool enable) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci u32 val = enable ? _MASKED_BIT_ENABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES) : 6862306a36Sopenharmony_ci _MASKED_BIT_DISABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci intel_uncore_write(pxp->ctrl_gt->uncore, KCR_INIT(pxp->kcr_base), val); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void kcr_pxp_enable(const struct intel_pxp *pxp) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci kcr_pxp_set_status(pxp, true); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void kcr_pxp_disable(const struct intel_pxp *pxp) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci kcr_pxp_set_status(pxp, false); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int create_vcs_context(struct intel_pxp *pxp) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci static struct lock_class_key pxp_lock; 8662306a36Sopenharmony_ci struct intel_gt *gt = pxp->ctrl_gt; 8762306a36Sopenharmony_ci struct intel_engine_cs *engine; 8862306a36Sopenharmony_ci struct intel_context *ce; 8962306a36Sopenharmony_ci int i; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * Find the first VCS engine present. We're guaranteed there is one 9362306a36Sopenharmony_ci * if we're in this function due to the check in has_pxp 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci for (i = 0, engine = NULL; !engine; i++) 9662306a36Sopenharmony_ci engine = gt->engine_class[VIDEO_DECODE_CLASS][i]; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci GEM_BUG_ON(!engine || engine->class != VIDEO_DECODE_CLASS); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci ce = intel_engine_create_pinned_context(engine, engine->gt->vm, SZ_4K, 10162306a36Sopenharmony_ci I915_GEM_HWS_PXP_ADDR, 10262306a36Sopenharmony_ci &pxp_lock, "pxp_context"); 10362306a36Sopenharmony_ci if (IS_ERR(ce)) { 10462306a36Sopenharmony_ci drm_err(>->i915->drm, "failed to create VCS ctx for PXP\n"); 10562306a36Sopenharmony_ci return PTR_ERR(ce); 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci pxp->ce = ce; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic void destroy_vcs_context(struct intel_pxp *pxp) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci if (pxp->ce) 11662306a36Sopenharmony_ci intel_engine_destroy_pinned_context(fetch_and_zero(&pxp->ce)); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic void pxp_init_full(struct intel_pxp *pxp) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct intel_gt *gt = pxp->ctrl_gt; 12262306a36Sopenharmony_ci int ret; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* 12562306a36Sopenharmony_ci * we'll use the completion to check if there is a termination pending, 12662306a36Sopenharmony_ci * so we start it as completed and we reinit it when a termination 12762306a36Sopenharmony_ci * is triggered. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci init_completion(&pxp->termination); 13062306a36Sopenharmony_ci complete_all(&pxp->termination); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (pxp->ctrl_gt->type == GT_MEDIA) 13362306a36Sopenharmony_ci pxp->kcr_base = MTL_KCR_BASE; 13462306a36Sopenharmony_ci else 13562306a36Sopenharmony_ci pxp->kcr_base = GEN12_KCR_BASE; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci intel_pxp_session_management_init(pxp); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci ret = create_vcs_context(pxp); 14062306a36Sopenharmony_ci if (ret) 14162306a36Sopenharmony_ci return; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (HAS_ENGINE(pxp->ctrl_gt, GSC0)) 14462306a36Sopenharmony_ci ret = intel_pxp_gsccs_init(pxp); 14562306a36Sopenharmony_ci else 14662306a36Sopenharmony_ci ret = intel_pxp_tee_component_init(pxp); 14762306a36Sopenharmony_ci if (ret) 14862306a36Sopenharmony_ci goto out_context; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci drm_info(>->i915->drm, "Protected Xe Path (PXP) protected content support initialized\n"); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ciout_context: 15562306a36Sopenharmony_ci destroy_vcs_context(pxp); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic struct intel_gt *find_gt_for_required_teelink(struct drm_i915_private *i915) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * NOTE: Only certain platforms require PXP-tee-backend dependencies 16262306a36Sopenharmony_ci * for HuC authentication. For now, its limited to DG2. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_INTEL_MEI_PXP) && IS_ENABLED(CONFIG_INTEL_MEI_GSC) && 16562306a36Sopenharmony_ci intel_huc_is_loaded_by_gsc(&to_gt(i915)->uc.huc) && intel_uc_uses_huc(&to_gt(i915)->uc)) 16662306a36Sopenharmony_ci return to_gt(i915); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return NULL; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic struct intel_gt *find_gt_for_required_protected_content(struct drm_i915_private *i915) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_DRM_I915_PXP) || !INTEL_INFO(i915)->has_pxp) 17462306a36Sopenharmony_ci return NULL; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * For MTL onwards, PXP-controller-GT needs to have a valid GSC engine 17862306a36Sopenharmony_ci * on the media GT. NOTE: if we have a media-tile with a GSC-engine, 17962306a36Sopenharmony_ci * the VDBOX is already present so skip that check. We also have to 18062306a36Sopenharmony_ci * ensure the GSC and HUC firmware are coming online 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci if (i915->media_gt && HAS_ENGINE(i915->media_gt, GSC0) && 18362306a36Sopenharmony_ci intel_uc_fw_is_loadable(&i915->media_gt->uc.gsc.fw) && 18462306a36Sopenharmony_ci intel_uc_fw_is_loadable(&i915->media_gt->uc.huc.fw)) 18562306a36Sopenharmony_ci return i915->media_gt; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* 18862306a36Sopenharmony_ci * Else we rely on mei-pxp module but only on legacy platforms 18962306a36Sopenharmony_ci * prior to having separate media GTs and has a valid VDBOX. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_INTEL_MEI_PXP) && !i915->media_gt && VDBOX_MASK(to_gt(i915))) 19262306a36Sopenharmony_ci return to_gt(i915); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return NULL; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ciint intel_pxp_init(struct drm_i915_private *i915) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct intel_gt *gt; 20062306a36Sopenharmony_ci bool is_full_feature = false; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* 20362306a36Sopenharmony_ci * NOTE: Get the ctrl_gt before checking intel_pxp_is_supported since 20462306a36Sopenharmony_ci * we still need it if PXP's backend tee transport is needed. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci gt = find_gt_for_required_protected_content(i915); 20762306a36Sopenharmony_ci if (gt) 20862306a36Sopenharmony_ci is_full_feature = true; 20962306a36Sopenharmony_ci else 21062306a36Sopenharmony_ci gt = find_gt_for_required_teelink(i915); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (!gt) 21362306a36Sopenharmony_ci return -ENODEV; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* 21662306a36Sopenharmony_ci * At this point, we will either enable full featured PXP capabilities 21762306a36Sopenharmony_ci * including session and object management, or we will init the backend tee 21862306a36Sopenharmony_ci * channel for internal users such as HuC loading by GSC 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci i915->pxp = kzalloc(sizeof(*i915->pxp), GFP_KERNEL); 22162306a36Sopenharmony_ci if (!i915->pxp) 22262306a36Sopenharmony_ci return -ENOMEM; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* init common info used by all feature-mode usages*/ 22562306a36Sopenharmony_ci i915->pxp->ctrl_gt = gt; 22662306a36Sopenharmony_ci mutex_init(&i915->pxp->tee_mutex); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * If full PXP feature is not available but HuC is loaded by GSC on pre-MTL 23062306a36Sopenharmony_ci * such as DG2, we can skip the init of the full PXP session/object management 23162306a36Sopenharmony_ci * and just init the tee channel. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci if (is_full_feature) 23462306a36Sopenharmony_ci pxp_init_full(i915->pxp); 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci intel_pxp_tee_component_init(i915->pxp); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_civoid intel_pxp_fini(struct drm_i915_private *i915) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci if (!i915->pxp) 24462306a36Sopenharmony_ci return; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci i915->pxp->arb_is_valid = false; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (HAS_ENGINE(i915->pxp->ctrl_gt, GSC0)) 24962306a36Sopenharmony_ci intel_pxp_gsccs_fini(i915->pxp); 25062306a36Sopenharmony_ci else 25162306a36Sopenharmony_ci intel_pxp_tee_component_fini(i915->pxp); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci destroy_vcs_context(i915->pxp); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci kfree(i915->pxp); 25662306a36Sopenharmony_ci i915->pxp = NULL; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_civoid intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci pxp->arb_is_valid = false; 26262306a36Sopenharmony_ci reinit_completion(&pxp->termination); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic void pxp_queue_termination(struct intel_pxp *pxp) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct intel_gt *gt = pxp->ctrl_gt; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* 27062306a36Sopenharmony_ci * We want to get the same effect as if we received a termination 27162306a36Sopenharmony_ci * interrupt, so just pretend that we did. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci spin_lock_irq(gt->irq_lock); 27462306a36Sopenharmony_ci intel_pxp_mark_termination_in_progress(pxp); 27562306a36Sopenharmony_ci pxp->session_events |= PXP_TERMINATION_REQUEST; 27662306a36Sopenharmony_ci queue_work(system_unbound_wq, &pxp->session_work); 27762306a36Sopenharmony_ci spin_unlock_irq(gt->irq_lock); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic bool pxp_component_bound(struct intel_pxp *pxp) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci bool bound = false; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci mutex_lock(&pxp->tee_mutex); 28562306a36Sopenharmony_ci if (pxp->pxp_component) 28662306a36Sopenharmony_ci bound = true; 28762306a36Sopenharmony_ci mutex_unlock(&pxp->tee_mutex); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return bound; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ciint intel_pxp_get_backend_timeout_ms(struct intel_pxp *pxp) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci if (HAS_ENGINE(pxp->ctrl_gt, GSC0)) 29562306a36Sopenharmony_ci return GSCFW_MAX_ROUND_TRIP_LATENCY_MS; 29662306a36Sopenharmony_ci else 29762306a36Sopenharmony_ci return 250; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int __pxp_global_teardown_final(struct intel_pxp *pxp) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci int timeout; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (!pxp->arb_is_valid) 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci /* 30762306a36Sopenharmony_ci * To ensure synchronous and coherent session teardown completion 30862306a36Sopenharmony_ci * in response to suspend or shutdown triggers, don't use a worker. 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci intel_pxp_mark_termination_in_progress(pxp); 31162306a36Sopenharmony_ci intel_pxp_terminate(pxp, false); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci timeout = intel_pxp_get_backend_timeout_ms(pxp); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (!wait_for_completion_timeout(&pxp->termination, msecs_to_jiffies(timeout))) 31662306a36Sopenharmony_ci return -ETIMEDOUT; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int __pxp_global_teardown_restart(struct intel_pxp *pxp) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci int timeout; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (pxp->arb_is_valid) 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci /* 32862306a36Sopenharmony_ci * The arb-session is currently inactive and we are doing a reset and restart 32962306a36Sopenharmony_ci * due to a runtime event. Use the worker that was designed for this. 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_ci pxp_queue_termination(pxp); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci timeout = intel_pxp_get_backend_timeout_ms(pxp); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (!wait_for_completion_timeout(&pxp->termination, msecs_to_jiffies(timeout))) 33662306a36Sopenharmony_ci return -ETIMEDOUT; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_civoid intel_pxp_end(struct intel_pxp *pxp) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct drm_i915_private *i915 = pxp->ctrl_gt->i915; 34462306a36Sopenharmony_ci intel_wakeref_t wakeref; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (!intel_pxp_is_enabled(pxp)) 34762306a36Sopenharmony_ci return; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci wakeref = intel_runtime_pm_get(&i915->runtime_pm); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci mutex_lock(&pxp->arb_mutex); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (__pxp_global_teardown_final(pxp)) 35462306a36Sopenharmony_ci drm_dbg(&i915->drm, "PXP end timed out\n"); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci mutex_unlock(&pxp->arb_mutex); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci intel_pxp_fini_hw(pxp); 35962306a36Sopenharmony_ci intel_runtime_pm_put(&i915->runtime_pm, wakeref); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/* 36362306a36Sopenharmony_ci * this helper is used by both intel_pxp_start and by 36462306a36Sopenharmony_ci * the GET_PARAM IOCTL that user space calls. Thus, the 36562306a36Sopenharmony_ci * return values here should match the UAPI spec. 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ciint intel_pxp_get_readiness_status(struct intel_pxp *pxp) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci if (!intel_pxp_is_enabled(pxp)) 37062306a36Sopenharmony_ci return -ENODEV; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (HAS_ENGINE(pxp->ctrl_gt, GSC0)) { 37362306a36Sopenharmony_ci if (wait_for(intel_pxp_gsccs_is_ready_for_sessions(pxp), 250)) 37462306a36Sopenharmony_ci return 2; 37562306a36Sopenharmony_ci } else { 37662306a36Sopenharmony_ci if (wait_for(pxp_component_bound(pxp), 250)) 37762306a36Sopenharmony_ci return 2; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci return 1; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/* 38362306a36Sopenharmony_ci * the arb session is restarted from the irq work when we receive the 38462306a36Sopenharmony_ci * termination completion interrupt 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_ciint intel_pxp_start(struct intel_pxp *pxp) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci int ret = 0; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ret = intel_pxp_get_readiness_status(pxp); 39162306a36Sopenharmony_ci if (ret < 0) 39262306a36Sopenharmony_ci return ret; 39362306a36Sopenharmony_ci else if (ret > 1) 39462306a36Sopenharmony_ci return -EIO; /* per UAPI spec, user may retry later */ 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci mutex_lock(&pxp->arb_mutex); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ret = __pxp_global_teardown_restart(pxp); 39962306a36Sopenharmony_ci if (ret) 40062306a36Sopenharmony_ci goto unlock; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* make sure the compiler doesn't optimize the double access */ 40362306a36Sopenharmony_ci barrier(); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (!pxp->arb_is_valid) 40662306a36Sopenharmony_ci ret = -EIO; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ciunlock: 40962306a36Sopenharmony_ci mutex_unlock(&pxp->arb_mutex); 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_civoid intel_pxp_init_hw(struct intel_pxp *pxp) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci kcr_pxp_enable(pxp); 41662306a36Sopenharmony_ci intel_pxp_irq_enable(pxp); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_civoid intel_pxp_fini_hw(struct intel_pxp *pxp) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci kcr_pxp_disable(pxp); 42262306a36Sopenharmony_ci intel_pxp_irq_disable(pxp); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ciint intel_pxp_key_check(struct intel_pxp *pxp, 42662306a36Sopenharmony_ci struct drm_i915_gem_object *obj, 42762306a36Sopenharmony_ci bool assign) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci if (!intel_pxp_is_active(pxp)) 43062306a36Sopenharmony_ci return -ENODEV; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (!i915_gem_object_is_protected(obj)) 43362306a36Sopenharmony_ci return -EINVAL; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci GEM_BUG_ON(!pxp->key_instance); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* 43862306a36Sopenharmony_ci * If this is the first time we're using this object, it's not 43962306a36Sopenharmony_ci * encrypted yet; it will be encrypted with the current key, so mark it 44062306a36Sopenharmony_ci * as such. If the object is already encrypted, check instead if the 44162306a36Sopenharmony_ci * used key is still valid. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_ci if (!obj->pxp_key_instance && assign) 44462306a36Sopenharmony_ci obj->pxp_key_instance = pxp->key_instance; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (obj->pxp_key_instance != pxp->key_instance) 44762306a36Sopenharmony_ci return -ENOEXEC; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_civoid intel_pxp_invalidate(struct intel_pxp *pxp) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct drm_i915_private *i915 = pxp->ctrl_gt->i915; 45562306a36Sopenharmony_ci struct i915_gem_context *ctx, *cn; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* ban all contexts marked as protected */ 45862306a36Sopenharmony_ci spin_lock_irq(&i915->gem.contexts.lock); 45962306a36Sopenharmony_ci list_for_each_entry_safe(ctx, cn, &i915->gem.contexts.list, link) { 46062306a36Sopenharmony_ci struct i915_gem_engines_iter it; 46162306a36Sopenharmony_ci struct intel_context *ce; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (!kref_get_unless_zero(&ctx->ref)) 46462306a36Sopenharmony_ci continue; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (likely(!i915_gem_context_uses_protected_content(ctx))) { 46762306a36Sopenharmony_ci i915_gem_context_put(ctx); 46862306a36Sopenharmony_ci continue; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci spin_unlock_irq(&i915->gem.contexts.lock); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* 47462306a36Sopenharmony_ci * By the time we get here we are either going to suspend with 47562306a36Sopenharmony_ci * quiesced execution or the HW keys are already long gone and 47662306a36Sopenharmony_ci * in this case it is worthless to attempt to close the context 47762306a36Sopenharmony_ci * and wait for its execution. It will hang the GPU if it has 47862306a36Sopenharmony_ci * not already. So, as a fast mitigation, we can ban the 47962306a36Sopenharmony_ci * context as quick as we can. That might race with the 48062306a36Sopenharmony_ci * execbuffer, but currently this is the best that can be done. 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_ci for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) 48362306a36Sopenharmony_ci intel_context_ban(ce, NULL); 48462306a36Sopenharmony_ci i915_gem_context_unlock_engines(ctx); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* 48762306a36Sopenharmony_ci * The context has been banned, no need to keep the wakeref. 48862306a36Sopenharmony_ci * This is safe from races because the only other place this 48962306a36Sopenharmony_ci * is touched is context_release and we're holding a ctx ref 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ci if (ctx->pxp_wakeref) { 49262306a36Sopenharmony_ci intel_runtime_pm_put(&i915->runtime_pm, 49362306a36Sopenharmony_ci ctx->pxp_wakeref); 49462306a36Sopenharmony_ci ctx->pxp_wakeref = 0; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci spin_lock_irq(&i915->gem.contexts.lock); 49862306a36Sopenharmony_ci list_safe_reset_next(ctx, cn, link); 49962306a36Sopenharmony_ci i915_gem_context_put(ctx); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci spin_unlock_irq(&i915->gem.contexts.lock); 50262306a36Sopenharmony_ci} 503