1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright(c) 2020 Intel Corporation. 4 */ 5 #include <linux/workqueue.h> 6 7 #include "gt/intel_gt_irq.h" 8 #include "gt/intel_gt_regs.h" 9 #include "gt/intel_gt_types.h" 10 11 #include "i915_irq.h" 12 #include "i915_reg.h" 13 14 #include "intel_pxp.h" 15 #include "intel_pxp_irq.h" 16 #include "intel_pxp_session.h" 17 #include "intel_pxp_types.h" 18 #include "intel_runtime_pm.h" 19 20 /** 21 * intel_pxp_irq_handler - Handles PXP interrupts. 22 * @pxp: pointer to pxp struct 23 * @iir: interrupt vector 24 */ 25 void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir) 26 { 27 struct intel_gt *gt; 28 29 if (GEM_WARN_ON(!intel_pxp_is_enabled(pxp))) 30 return; 31 32 gt = pxp->ctrl_gt; 33 34 lockdep_assert_held(gt->irq_lock); 35 36 if (unlikely(!iir)) 37 return; 38 39 if (iir & (GEN12_DISPLAY_PXP_STATE_TERMINATED_INTERRUPT | 40 GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT)) { 41 /* immediately mark PXP as inactive on termination */ 42 intel_pxp_mark_termination_in_progress(pxp); 43 pxp->session_events |= PXP_TERMINATION_REQUEST | PXP_INVAL_REQUIRED; 44 } 45 46 if (iir & GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT) 47 pxp->session_events |= PXP_TERMINATION_COMPLETE; 48 49 if (pxp->session_events) 50 queue_work(system_unbound_wq, &pxp->session_work); 51 } 52 53 static inline void __pxp_set_interrupts(struct intel_gt *gt, u32 interrupts) 54 { 55 struct intel_uncore *uncore = gt->uncore; 56 const u32 mask = interrupts << 16; 57 58 intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_ENABLE, mask); 59 intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_MASK, ~mask); 60 } 61 62 static inline void pxp_irq_reset(struct intel_gt *gt) 63 { 64 spin_lock_irq(gt->irq_lock); 65 gen11_gt_reset_one_iir(gt, 0, GEN11_KCR); 66 spin_unlock_irq(gt->irq_lock); 67 } 68 69 void intel_pxp_irq_enable(struct intel_pxp *pxp) 70 { 71 struct intel_gt *gt = pxp->ctrl_gt; 72 73 spin_lock_irq(gt->irq_lock); 74 75 if (!pxp->irq_enabled) 76 WARN_ON_ONCE(gen11_gt_reset_one_iir(gt, 0, GEN11_KCR)); 77 78 __pxp_set_interrupts(gt, GEN12_PXP_INTERRUPTS); 79 pxp->irq_enabled = true; 80 81 spin_unlock_irq(gt->irq_lock); 82 } 83 84 void intel_pxp_irq_disable(struct intel_pxp *pxp) 85 { 86 struct intel_gt *gt = pxp->ctrl_gt; 87 88 /* 89 * We always need to submit a global termination when we re-enable the 90 * interrupts, so there is no need to make sure that the session state 91 * makes sense at the end of this function. Just make sure this is not 92 * called in a path were the driver consider the session as valid and 93 * doesn't call a termination on restart. 94 */ 95 GEM_WARN_ON(intel_pxp_is_active(pxp)); 96 97 spin_lock_irq(gt->irq_lock); 98 99 pxp->irq_enabled = false; 100 __pxp_set_interrupts(gt, 0); 101 102 spin_unlock_irq(gt->irq_lock); 103 intel_synchronize_irq(gt->i915); 104 105 pxp_irq_reset(gt); 106 107 flush_work(&pxp->session_work); 108 } 109