| 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(wq: system_unbound_wq, work: &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, val: mask); |
| 60 | intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_MASK, val: ~mask); |
| 61 | } |
| 62 | |
| 63 | static inline void pxp_irq_reset(struct intel_gt *gt) |
| 64 | { |
| 65 | spin_lock_irq(lock: gt->irq_lock); |
| 66 | gen11_gt_reset_one_iir(gt, bank: 0, GEN11_KCR); |
| 67 | spin_unlock_irq(lock: 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(lock: 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(lock: 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(lock: gt->irq_lock); |
| 99 | |
| 100 | pxp->irq_enabled = false; |
| 101 | __pxp_set_interrupts(gt, interrupts: 0); |
| 102 | |
| 103 | spin_unlock_irq(lock: gt->irq_lock); |
| 104 | intel_synchronize_irq(i915: gt->i915); |
| 105 | |
| 106 | pxp_irq_reset(gt); |
| 107 | |
| 108 | flush_work(work: &pxp->session_work); |
| 109 | } |
| 110 | |