// SPDX-License-Identifier: MIT /* * Copyright(c) 2020 Intel Corporation. */ #include #include "intel_pxp.h" #include "intel_pxp_irq.h" #include "intel_pxp_session.h" #include "gt/intel_gt_irq.h" #include "gt/intel_gt_types.h" #include "i915_irq.h" #include "i915_reg.h" #include "intel_runtime_pm.h" /** * intel_pxp_irq_handler - Handles PXP interrupts. * @pxp: pointer to pxp struct * @iir: interrupt vector */ void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir) { struct intel_gt *gt = pxp_to_gt(pxp); if (GEM_WARN_ON(!intel_pxp_is_enabled(pxp))) return; lockdep_assert_held(>->irq_lock); if (unlikely(!iir)) return; if (iir & (GEN12_DISPLAY_PXP_STATE_TERMINATED_INTERRUPT | GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT)) { /* immediately mark PXP as inactive on termination */ intel_pxp_mark_termination_in_progress(pxp); pxp->session_events |= PXP_TERMINATION_REQUEST | PXP_INVAL_REQUIRED; } if (iir & GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT) pxp->session_events |= PXP_TERMINATION_COMPLETE; if (pxp->session_events) queue_work(system_unbound_wq, &pxp->session_work); } static inline void __pxp_set_interrupts(struct intel_gt *gt, u32 interrupts) { struct intel_uncore *uncore = gt->uncore; const u32 mask = interrupts << 16; intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_ENABLE, mask); intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_MASK, ~mask); } static inline void pxp_irq_reset(struct intel_gt *gt) { spin_lock_irq(>->irq_lock); gen11_gt_reset_one_iir(gt, 0, GEN11_KCR); spin_unlock_irq(>->irq_lock); } void intel_pxp_irq_enable(struct intel_pxp *pxp) { struct intel_gt *gt = pxp_to_gt(pxp); spin_lock_irq(>->irq_lock); if (!pxp->irq_enabled) WARN_ON_ONCE(gen11_gt_reset_one_iir(gt, 0, GEN11_KCR)); __pxp_set_interrupts(gt, GEN12_PXP_INTERRUPTS); pxp->irq_enabled = true; spin_unlock_irq(>->irq_lock); } void intel_pxp_irq_disable(struct intel_pxp *pxp) { struct intel_gt *gt = pxp_to_gt(pxp); /* * We always need to submit a global termination when we re-enable the * interrupts, so there is no need to make sure that the session state * makes sense at the end of this function. Just make sure this is not * called in a path were the driver consider the session as valid and * doesn't call a termination on restart. */ GEM_WARN_ON(intel_pxp_is_active(pxp)); spin_lock_irq(>->irq_lock); pxp->irq_enabled = false; __pxp_set_interrupts(gt, 0); spin_unlock_irq(>->irq_lock); intel_synchronize_irq(gt->i915); pxp_irq_reset(gt); flush_work(&pxp->session_work); }