History

drm/i915/pxp: Implement PXP irq handler

The HW will generate a teardown interrupt when session termination is required, which requires i915 to submit a terminating batch. Once the HW is done with the termination it will generate another interrupt, at which point it is safe to re-create the session. Since the termination and re-creation flow is something we want to trigger from the driver as well, use a common work function that can be called both from the irq handler and from the driver set-up flows, which has the addded benefit of allowing us to skip any extra locks because the work itself serializes the operations. v2: use struct completion instead of bool (Chris) v3: drop locks, clean up functions and improve comments (Chris), move to common work function. v4: improve comments, simplify wait logic (Rodrigo) v5: unconditionally set interrupts, rename state_attacked var (Rodrigo) v10: remove inclusion of intel_gt_types.h from intel_pxp.h (Jani)

Huang, Sean Z committed 5 years ago

Commit 2ae09681 parent 95c9e1211 files · +284 −16Browse files

Unified · Split

11 files
  1. drivers/gpu/drm/i915/Makefile +1 −0
  2. drivers/gpu/drm/i915/gt/intel_gt_irq.c +7 −0
  3. drivers/gpu/drm/i915/i915_reg.h +1 −0
  4. drivers/gpu/drm/i915/pxp/intel_pxp.c +60 −6
  5. drivers/gpu/drm/i915/pxp/intel_pxp.h +8 −0
  6. drivers/gpu/drm/i915/pxp/intel_pxp_irq.c +100 −0
  7. drivers/gpu/drm/i915/pxp/intel_pxp_irq.h +32 −0
  8. drivers/gpu/drm/i915/pxp/intel_pxp_session.c +51 −3
  9. drivers/gpu/drm/i915/pxp/intel_pxp_session.h +2 −3
  10. drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +4 −4
  11. drivers/gpu/drm/i915/pxp/intel_pxp_types.h +18 −0
drivers/gpu/drm/i915/Makefile+1−0
@@ -282,6 +282,7 @@ i915-y += i915_perf.o · 281 unmodified lines
282i915-$(CONFIG_DRM_I915_PXP) += \282i915-$(CONFIG_DRM_I915_PXP) += \
283 pxp/intel_pxp.o \283 pxp/intel_pxp.o \
284 pxp/intel_pxp_cmd.o \284 pxp/intel_pxp_cmd.o \
285 pxp/intel_pxp_irq.o \
285 pxp/intel_pxp_session.o \286 pxp/intel_pxp_session.o \
286 pxp/intel_pxp_tee.o287 pxp/intel_pxp_tee.o
287 288
drivers/gpu/drm/i915/gt/intel_gt_irq.c+7−0
@@ -13,6 +13,7 @@ · 12 unmodified lines
13#include "intel_lrc_reg.h"13#include "intel_lrc_reg.h"
14#include "intel_uncore.h"14#include "intel_uncore.h"
15#include "intel_rps.h"15#include "intel_rps.h"
16#include "pxp/intel_pxp_irq.h"
16 17
17static void guc_irq_handler(struct intel_guc *guc, u16 iir)18static void guc_irq_handler(struct intel_guc *guc, u16 iir)
18{19{
@@ -64,6 +65,9 @@ gen11_other_irq_handler(struct intel_gt *gt, const u8 instance, · 45 unmodified lines
64 if (instance == OTHER_GTPM_INSTANCE)65 if (instance == OTHER_GTPM_INSTANCE)
65 return gen11_rps_irq_handler(&gt->rps, iir);66 return gen11_rps_irq_handler(&gt->rps, iir);
66 67
68 if (instance == OTHER_KCR_INSTANCE)
69 return intel_pxp_irq_handler(&gt->pxp, iir);
70
67 WARN_ONCE(1, "unhandled other interrupt instance=0x%x, iir=0x%x\n",71 WARN_ONCE(1, "unhandled other interrupt instance=0x%x, iir=0x%x\n",
68 instance, iir);72 instance, iir);
69}73}
@@ -196,6 +200,9 @@ void gen11_gt_irq_reset(struct intel_gt *gt) · 126 unmodified lines
196 intel_uncore_write(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK, ~0);200 intel_uncore_write(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK, ~0);
197 intel_uncore_write(uncore, GEN11_GUC_SG_INTR_ENABLE, 0);201 intel_uncore_write(uncore, GEN11_GUC_SG_INTR_ENABLE, 0);
198 intel_uncore_write(uncore, GEN11_GUC_SG_INTR_MASK, ~0);202 intel_uncore_write(uncore, GEN11_GUC_SG_INTR_MASK, ~0);
203
204 intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_ENABLE, 0);
205 intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_MASK, ~0);
199}206}
200 207
201void gen11_gt_irq_postinstall(struct intel_gt *gt)208void gen11_gt_irq_postinstall(struct intel_gt *gt)
drivers/gpu/drm/i915/i915_reg.h+1−0
@@ -8124,6 +8124,7 @@ enum { · 8123 unmodified lines
8124/* irq instances for OTHER_CLASS */8124/* irq instances for OTHER_CLASS */
8125#define OTHER_GUC_INSTANCE 08125#define OTHER_GUC_INSTANCE 0
8126#define OTHER_GTPM_INSTANCE 18126#define OTHER_GTPM_INSTANCE 1
8127#define OTHER_KCR_INSTANCE 4
8127 8128
8128#define GEN11_INTR_IDENTITY_REG(x) _MMIO(0x190060 + ((x) * 4))8129#define GEN11_INTR_IDENTITY_REG(x) _MMIO(0x190060 + ((x) * 4))
8129 8130
drivers/gpu/drm/i915/pxp/intel_pxp.c+60−6
@@ -2,7 +2,9 @@ · 1 unmodified line
2/*2/*
3 * Copyright(c) 2020 Intel Corporation.3 * Copyright(c) 2020 Intel Corporation.
4 */4 */
5#include <linux/workqueue.h>
5#include "intel_pxp.h"6#include "intel_pxp.h"
7#include "intel_pxp_irq.h"
6#include "intel_pxp_session.h"8#include "intel_pxp_session.h"
7#include "intel_pxp_tee.h"9#include "intel_pxp_tee.h"
8#include "gt/intel_context.h"10#include "gt/intel_context.h"
@@ -80,6 +82,16 @@ void intel_pxp_init(struct intel_pxp *pxp) · 71 unmodified lines
80 82
81 mutex_init(&pxp->tee_mutex);83 mutex_init(&pxp->tee_mutex);
82 84
85 /*
86 * we'll use the completion to check if there is a termination pending,
87 * so we start it as completed and we reinit it when a termination
88 * is triggered.
89 */
90 init_completion(&pxp->termination);
91 complete_all(&pxp->termination);
92
93 INIT_WORK(&pxp->session_work, intel_pxp_session_work);
94
83 ret = create_vcs_context(pxp);95 ret = create_vcs_context(pxp);
84 if (ret)96 if (ret)
85 return;97 return;
@@ -108,19 +120,61 @@ void intel_pxp_fini(struct intel_pxp *pxp) · 22 unmodified lines
108 destroy_vcs_context(pxp);120 destroy_vcs_context(pxp);
109}121}
110 122
111void intel_pxp_init_hw(struct intel_pxp *pxp)123void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp)
112{124{
113 int ret;125 pxp->arb_is_valid = false;
126 reinit_completion(&pxp->termination);
127}
128
129static void intel_pxp_queue_termination(struct intel_pxp *pxp)
130{
131 struct intel_gt *gt = pxp_to_gt(pxp);
132
133 /*
134 * We want to get the same effect as if we received a termination
135 * interrupt, so just pretend that we did.
136 */
137 spin_lock_irq(&gt->irq_lock);
138 intel_pxp_mark_termination_in_progress(pxp);
139 pxp->session_events |= PXP_TERMINATION_REQUEST;
140 queue_work(system_unbound_wq, &pxp->session_work);
141 spin_unlock_irq(&gt->irq_lock);
142}
114 143
144/*
145 * the arb session is restarted from the irq work when we receive the
146 * termination completion interrupt
147 */
148int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp)
149{
150 if (!intel_pxp_is_enabled(pxp))
151 return 0;
152
153 if (!wait_for_completion_timeout(&pxp->termination,
154 msecs_to_jiffies(100)))
155 return -ETIMEDOUT;
156
157 if (!pxp->arb_is_valid)
158 return -EIO;
159
160 return 0;
161}
162
163void intel_pxp_init_hw(struct intel_pxp *pxp)
164{
115 kcr_pxp_enable(pxp_to_gt(pxp));165 kcr_pxp_enable(pxp_to_gt(pxp));
166 intel_pxp_irq_enable(pxp);
116 167
117 /* always emit a full termination to clean the state */168 /*
118 ret = intel_pxp_terminate_arb_session_and_global(pxp);169 * the session could've been attacked while we weren't loaded, so
119 if (!ret)170 * handle it as if it was and re-create it.
120 intel_pxp_create_arb_session(pxp);171 */
172 intel_pxp_queue_termination(pxp);
121}173}
122 174
123void intel_pxp_fini_hw(struct intel_pxp *pxp)175void intel_pxp_fini_hw(struct intel_pxp *pxp)
124{176{
125 kcr_pxp_disable(pxp_to_gt(pxp));177 kcr_pxp_disable(pxp_to_gt(pxp));
178
179 intel_pxp_irq_disable(pxp);
126}180}
drivers/gpu/drm/i915/pxp/intel_pxp.h+8−0
@@ -22,6 +22,9 @@ void intel_pxp_fini(struct intel_pxp *pxp); · 21 unmodified lines
22 22
23void intel_pxp_init_hw(struct intel_pxp *pxp);23void intel_pxp_init_hw(struct intel_pxp *pxp);
24void intel_pxp_fini_hw(struct intel_pxp *pxp);24void intel_pxp_fini_hw(struct intel_pxp *pxp);
25
26void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp);
27int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp);
25#else28#else
26static inline void intel_pxp_init(struct intel_pxp *pxp)29static inline void intel_pxp_init(struct intel_pxp *pxp)
27{30{
@@ -30,6 +33,11 @@ static inline void intel_pxp_init(struct intel_pxp *pxp) · 2 unmodified lines
30static inline void intel_pxp_fini(struct intel_pxp *pxp)33static inline void intel_pxp_fini(struct intel_pxp *pxp)
31{34{
32}35}
36
37static inline int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp)
38{
39 return -ENODEV;
40}
33#endif41#endif
34 42
35#endif /* __INTEL_PXP_H__ */43#endif /* __INTEL_PXP_H__ */
drivers/gpu/drm/i915/pxp/intel_pxp_irq.c+100−0
@@ -0,0 +1,100 @@
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright(c) 2020 Intel Corporation.
4 */
5#include <linux/workqueue.h>
6#include "intel_pxp.h"
7#include "intel_pxp_irq.h"
8#include "intel_pxp_session.h"
9#include "gt/intel_gt_irq.h"
10#include "gt/intel_gt_types.h"
11#include "i915_irq.h"
12#include "i915_reg.h"
13
14/**
15 * intel_pxp_irq_handler - Handles PXP interrupts.
16 * @pxp: pointer to pxp struct
17 * @iir: interrupt vector
18 */
19void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir)
20{
21 struct intel_gt *gt = pxp_to_gt(pxp);
22
23 if (GEM_WARN_ON(!intel_pxp_is_enabled(pxp)))
24 return;
25
26 lockdep_assert_held(&gt->irq_lock);
27
28 if (unlikely(!iir))
29 return;
30
31 if (iir & (GEN12_DISPLAY_PXP_STATE_TERMINATED_INTERRUPT |
32 GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT)) {
33 /* immediately mark PXP as inactive on termination */
34 intel_pxp_mark_termination_in_progress(pxp);
35 pxp->session_events |= PXP_TERMINATION_REQUEST;
36 }
37
38 if (iir & GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT)
39 pxp->session_events |= PXP_TERMINATION_COMPLETE;
40
41 if (pxp->session_events)
42 queue_work(system_unbound_wq, &pxp->session_work);
43}
44
45static inline void __pxp_set_interrupts(struct intel_gt *gt, u32 interrupts)
46{
47 struct intel_uncore *uncore = gt->uncore;
48 const u32 mask = interrupts << 16;
49
50 intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_ENABLE, mask);
51 intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_MASK, ~mask);
52}
53
54static inline void pxp_irq_reset(struct intel_gt *gt)
55{
56 spin_lock_irq(&gt->irq_lock);
57 gen11_gt_reset_one_iir(gt, 0, GEN11_KCR);
58 spin_unlock_irq(&gt->irq_lock);
59}
60
61void intel_pxp_irq_enable(struct intel_pxp *pxp)
62{
63 struct intel_gt *gt = pxp_to_gt(pxp);
64
65 spin_lock_irq(&gt->irq_lock);
66
67 if (!pxp->irq_enabled)
68 WARN_ON_ONCE(gen11_gt_reset_one_iir(gt, 0, GEN11_KCR));
69
70 __pxp_set_interrupts(gt, GEN12_PXP_INTERRUPTS);
71 pxp->irq_enabled = true;
72
73 spin_unlock_irq(&gt->irq_lock);
74}
75
76void intel_pxp_irq_disable(struct intel_pxp *pxp)
77{
78 struct intel_gt *gt = pxp_to_gt(pxp);
79
80 /*
81 * We always need to submit a global termination when we re-enable the
82 * interrupts, so there is no need to make sure that the session state
83 * makes sense at the end of this function. Just make sure this is not
84 * called in a path were the driver consider the session as valid and
85 * doesn't call a termination on restart.
86 */
87 GEM_WARN_ON(intel_pxp_is_active(pxp));
88
89 spin_lock_irq(&gt->irq_lock);
90
91 pxp->irq_enabled = false;
92 __pxp_set_interrupts(gt, 0);
93
94 spin_unlock_irq(&gt->irq_lock);
95 intel_synchronize_irq(gt->i915);
96
97 pxp_irq_reset(gt);
98
99 flush_work(&pxp->session_work);
100}
drivers/gpu/drm/i915/pxp/intel_pxp_irq.h+32−0
@@ -0,0 +1,32 @@
1/* SPDX-License-Identifier: MIT */
2/*
3 * Copyright(c) 2020, Intel Corporation. All rights reserved.
4 */
5
6#ifndef __INTEL_PXP_IRQ_H__
7#define __INTEL_PXP_IRQ_H__
8
9#include <linux/types.h>
10
11struct intel_pxp;
12
13#define GEN12_DISPLAY_PXP_STATE_TERMINATED_INTERRUPT BIT(1)
14#define GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT BIT(2)
15#define GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT BIT(3)
16
17#define GEN12_PXP_INTERRUPTS \
18 (GEN12_DISPLAY_PXP_STATE_TERMINATED_INTERRUPT | \
19 GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT | \
20 GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT)
21
22#ifdef CONFIG_DRM_I915_PXP
23void intel_pxp_irq_enable(struct intel_pxp *pxp);
24void intel_pxp_irq_disable(struct intel_pxp *pxp);
25void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir);
26#else
27static inline void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir)
28{
29}
30#endif
31
32#endif /* __INTEL_PXP_IRQ_H__ */
drivers/gpu/drm/i915/pxp/intel_pxp_session.c+51−3
@@ -48,7 +48,7 @@ static int pxp_wait_for_session_state(struct intel_pxp *pxp, u32 id, bool in_pla · 47 unmodified lines
48 return ret;48 return ret;
49}49}
50 50
51int intel_pxp_create_arb_session(struct intel_pxp *pxp)51static int pxp_create_arb_session(struct intel_pxp *pxp)
52{52{
53 struct intel_gt *gt = pxp_to_gt(pxp);53 struct intel_gt *gt = pxp_to_gt(pxp);
54 int ret;54 int ret;
@@ -77,12 +77,13 @@ int intel_pxp_create_arb_session(struct intel_pxp *pxp) · 22 unmodified lines
77 return 0;77 return 0;
78}78}
79 79
80int intel_pxp_terminate_arb_session_and_global(struct intel_pxp *pxp)80static int pxp_terminate_arb_session_and_global(struct intel_pxp *pxp)
81{81{
82 int ret;82 int ret;
83 struct intel_gt *gt = pxp_to_gt(pxp);83 struct intel_gt *gt = pxp_to_gt(pxp);
84 84
85 pxp->arb_is_valid = false;85 /* must mark termination in progress calling this function */
86 GEM_WARN_ON(pxp->arb_is_valid);
86 87
87 /* terminate the hw sessions */88 /* terminate the hw sessions */
88 ret = intel_pxp_terminate_session(pxp, ARB_SESSION);89 ret = intel_pxp_terminate_session(pxp, ARB_SESSION);
@@ -101,3 +102,50 @@ int intel_pxp_terminate_arb_session_and_global(struct intel_pxp *pxp) · 12 unmodified lines
101 102
102 return ret;103 return ret;
103}104}
105
106static void pxp_terminate(struct intel_pxp *pxp)
107{
108 int ret;
109
110 pxp->hw_state_invalidated = true;
111
112 /*
113 * if we fail to submit the termination there is no point in waiting for
114 * it to complete. PXP will be marked as non-active until the next
115 * termination is issued.
116 */
117 ret = pxp_terminate_arb_session_and_global(pxp);
118 if (ret)
119 complete_all(&pxp->termination);
120}
121
122static void pxp_terminate_complete(struct intel_pxp *pxp)
123{
124 /* Re-create the arb session after teardown handle complete */
125 if (fetch_and_zero(&pxp->hw_state_invalidated))
126 pxp_create_arb_session(pxp);
127
128 complete_all(&pxp->termination);
129}
130
131void intel_pxp_session_work(struct work_struct *work)
132{
133 struct intel_pxp *pxp = container_of(work, typeof(*pxp), session_work);
134 struct intel_gt *gt = pxp_to_gt(pxp);
135 u32 events = 0;
136
137 spin_lock_irq(&gt->irq_lock);
138 events = fetch_and_zero(&pxp->session_events);
139 spin_unlock_irq(&gt->irq_lock);
140
141 if (!events)
142 return;
143
144 if (events & PXP_TERMINATION_REQUEST) {
145 events &= ~PXP_TERMINATION_COMPLETE;
146 pxp_terminate(pxp);
147 }
148
149 if (events & PXP_TERMINATION_COMPLETE)
150 pxp_terminate_complete(pxp);
151}
drivers/gpu/drm/i915/pxp/intel_pxp_session.h+2−3
@@ -8,9 +8,8 @@ · 7 unmodified lines
8 8
9#include <linux/types.h>9#include <linux/types.h>
10 10
11struct intel_pxp;11struct work_struct;
12 12
13int intel_pxp_create_arb_session(struct intel_pxp *pxp);13void intel_pxp_session_work(struct work_struct *work);
14int intel_pxp_terminate_arb_session_and_global(struct intel_pxp *pxp);
15 14
16#endif /* __INTEL_PXP_SESSION_H__ */15#endif /* __INTEL_PXP_SESSION_H__ */
drivers/gpu/drm/i915/pxp/intel_pxp_tee.c+4−4
@@ -80,6 +80,7 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, · 79 unmodified lines
80{80{
81 struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);81 struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
82 struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev);82 struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev);
83 int ret;
83 84
84 mutex_lock(&pxp->tee_mutex);85 mutex_lock(&pxp->tee_mutex);
85 pxp->pxp_component = data;86 pxp->pxp_component = data;
@@ -88,15 +89,14 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, · 2 unmodified lines
88 89
89 /* the component is required to fully start the PXP HW */90 /* the component is required to fully start the PXP HW */
90 intel_pxp_init_hw(pxp);91 intel_pxp_init_hw(pxp);
91 92 ret = intel_pxp_wait_for_arb_start(pxp);
92 if (!pxp->arb_is_valid) {93 if (ret) {
93 drm_err(&i915->drm, "Failed to create arb session during bind\n");94 drm_err(&i915->drm, "Failed to create arb session during bind\n");
94 intel_pxp_fini_hw(pxp);95 intel_pxp_fini_hw(pxp);
95 pxp->pxp_component = NULL;96 pxp->pxp_component = NULL;
96 return -EIO;
97 }97 }
98 98
99 return 0;99 return ret;
100}100}
101 101
102static void i915_pxp_tee_component_unbind(struct device *i915_kdev,102static void i915_pxp_tee_component_unbind(struct device *i915_kdev,
drivers/gpu/drm/i915/pxp/intel_pxp_types.h+18−0
@@ -6,8 +6,10 @@ · 5 unmodified lines
6#ifndef __INTEL_PXP_TYPES_H__6#ifndef __INTEL_PXP_TYPES_H__
7#define __INTEL_PXP_TYPES_H__7#define __INTEL_PXP_TYPES_H__
8 8
9#include <linux/completion.h>
9#include <linux/mutex.h>10#include <linux/mutex.h>
10#include <linux/types.h>11#include <linux/types.h>
12#include <linux/workqueue.h>
11 13
12struct intel_context;14struct intel_context;
13struct i915_pxp_component;15struct i915_pxp_component;
@@ -26,6 +28,22 @@ struct intel_pxp { · 12 unmodified lines
26 bool arb_is_valid;28 bool arb_is_valid;
27 29
28 struct mutex tee_mutex; /* protects the tee channel binding */30 struct mutex tee_mutex; /* protects the tee channel binding */
31
32 /*
33 * If the HW perceives an attack on the integrity of the encryption it
34 * will invalidate the keys and expect SW to re-initialize the session.
35 * We keep track of this state to make sure we only re-start the arb
36 * session when required.
37 */
38 bool hw_state_invalidated;
39
40 bool irq_enabled;
41 struct completion termination;
42
43 struct work_struct session_work;
44 u32 session_events; /* protected with gt->irq_lock */
45#define PXP_TERMINATION_REQUEST BIT(0)
46#define PXP_TERMINATION_COMPLETE BIT(1)
29};47};
30 48
31#endif /* __INTEL_PXP_TYPES_H__ */49#endif /* __INTEL_PXP_TYPES_H__ */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t