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 PXP_EVENT_TYPE_IRQ; 45 } 46 47 if (iir & GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT) 48 pxp->session_events |= PXP_TERMINATION_COMPLETE | PXP_EVENT_TYPE_IRQ; 49 50 if (pxp->session_events) 51 queue_work(system_unbound_wq, &pxp->session_work); 52 } 53 54 static inline void __pxp_set_interrupts(struct intel_gt *gt, u32 interrupts) 55 { 56 struct intel_uncore *uncore = gt->uncore; 57 const u32 mask = interrupts << 16; 58 59 intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_ENABLE, mask); 60 intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_MASK, ~mask); 61 } 62 63 static inline void pxp_irq_reset(struct intel_gt *gt) 64 { 65 spin_lock_irq(gt->irq_lock); 66 gen11_gt_reset_one_iir(gt, 0, GEN11_KCR); 67 spin_unlock_irq(gt->irq_lock); 68 } 69 70 void intel_pxp_irq_enable(struct intel_pxp *pxp) 71 { 72 struct intel_gt *gt = pxp->ctrl_gt; 73 74 spin_lock_irq(gt->irq_lock); 75 76 if (!pxp->irq_enabled) 77 WARN_ON_ONCE(gen11_gt_reset_one_iir(gt, 0, GEN11_KCR)); 78 79 __pxp_set_interrupts(gt, GEN12_PXP_INTERRUPTS); 80 pxp->irq_enabled = true; 81 82 spin_unlock_irq(gt->irq_lock); 83 } 84 85 void intel_pxp_irq_disable(struct intel_pxp *pxp) 86 { 87 struct intel_gt *gt = pxp->ctrl_gt; 88 89 /* 90 * We always need to submit a global termination when we re-enable the 91 * interrupts, so there is no need to make sure that the session state 92 * makes sense at the end of this function. Just make sure this is not 93 * called in a path were the driver consider the session as valid and 94 * doesn't call a termination on restart. 95 */ 96 GEM_WARN_ON(intel_pxp_is_active(pxp)); 97 98 spin_lock_irq(gt->irq_lock); 99 100 pxp->irq_enabled = false; 101 __pxp_set_interrupts(gt, 0); 102 103 spin_unlock_irq(gt->irq_lock); 104 intel_synchronize_irq(gt->i915); 105 106 pxp_irq_reset(gt); 107 108 flush_work(&pxp->session_work); 109 } 110