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
282282 i915-$(CONFIG_DRM_I915_PXP) += \
283283 pxp/intel_pxp.o \
284284 pxp/intel_pxp_cmd.o \
285+ pxp/intel_pxp_irq.o \
285286 pxp/intel_pxp_session.o \
286287 pxp/intel_pxp_tee.o
287288
drivers/gpu/drm/i915/gt/intel_gt_irq.c+7−0
@@ -13,6 +13,7 @@ · 12 unmodified lines
1313 #include "intel_lrc_reg.h"
1414 #include "intel_uncore.h"
1515 #include "intel_rps.h"
16+#include "pxp/intel_pxp_irq.h"
1617
1718 static void guc_irq_handler(struct intel_guc *guc, u16 iir)
1819 {
@@ -64,6 +65,9 @@ gen11_other_irq_handler(struct intel_gt *gt, const u8 instance, · 45 unmodified lines
6465 if (instance == OTHER_GTPM_INSTANCE)
6566 return gen11_rps_irq_handler(&gt->rps, iir);
6667
68+ if (instance == OTHER_KCR_INSTANCE)
69+ return intel_pxp_irq_handler(&gt->pxp, iir);
70+
6771 WARN_ONCE(1, "unhandled other interrupt instance=0x%x, iir=0x%x\n",
6872 instance, iir);
6973 }
@@ -196,6 +200,9 @@ void gen11_gt_irq_reset(struct intel_gt *gt) · 126 unmodified lines
196200 intel_uncore_write(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK, ~0);
197201 intel_uncore_write(uncore, GEN11_GUC_SG_INTR_ENABLE, 0);
198202 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);
199206 }
200207
201208 void 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
81248124 /* irq instances for OTHER_CLASS */
81258125 #define OTHER_GUC_INSTANCE 0
81268126 #define OTHER_GTPM_INSTANCE 1
8127+#define OTHER_KCR_INSTANCE 4
81278128
81288129 #define GEN11_INTR_IDENTITY_REG(x) _MMIO(0x190060 + ((x) * 4))
81298130
drivers/gpu/drm/i915/pxp/intel_pxp.c+60−6
@@ -2,7 +2,9 @@ · 1 unmodified line
22 /*
33 * Copyright(c) 2020 Intel Corporation.
44 */
5+#include <linux/workqueue.h>
56 #include "intel_pxp.h"
7+#include "intel_pxp_irq.h"
68 #include "intel_pxp_session.h"
79 #include "intel_pxp_tee.h"
810 #include "gt/intel_context.h"
@@ -80,6 +82,16 @@ void intel_pxp_init(struct intel_pxp *pxp) · 71 unmodified lines
8082
8183 mutex_init(&pxp->tee_mutex);
8284
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+
8395 ret = create_vcs_context(pxp);
8496 if (ret)
8597 return;
@@ -108,19 +120,61 @@ void intel_pxp_fini(struct intel_pxp *pxp) · 22 unmodified lines
108120 destroy_vcs_context(pxp);
109121 }
110122
111−void intel_pxp_init_hw(struct intel_pxp *pxp)
123+void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp)
112124 {
113− int ret;
125+ pxp->arb_is_valid = false;
126+ reinit_completion(&pxp->termination);
127+}
128+
129+static 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+}
114143
144+/*
145+ * the arb session is restarted from the irq work when we receive the
146+ * termination completion interrupt
147+ */
148+int 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+
163+void intel_pxp_init_hw(struct intel_pxp *pxp)
164+{
115165 kcr_pxp_enable(pxp_to_gt(pxp));
166+ intel_pxp_irq_enable(pxp);
116167
117− /* always emit a full termination to clean the state */
118− ret = intel_pxp_terminate_arb_session_and_global(pxp);
119− if (!ret)
120− intel_pxp_create_arb_session(pxp);
168+ /*
169+ * the session could've been attacked while we weren't loaded, so
170+ * handle it as if it was and re-create it.
171+ */
172+ intel_pxp_queue_termination(pxp);
121173 }
122174
123175 void intel_pxp_fini_hw(struct intel_pxp *pxp)
124176 {
125177 kcr_pxp_disable(pxp_to_gt(pxp));
178+
179+ intel_pxp_irq_disable(pxp);
126180 }
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
2222
2323 void intel_pxp_init_hw(struct intel_pxp *pxp);
2424 void intel_pxp_fini_hw(struct intel_pxp *pxp);
25+
26+void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp);
27+int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp);
2528 #else
2629 static inline void intel_pxp_init(struct intel_pxp *pxp)
2730 {
@@ -30,6 +33,11 @@ static inline void intel_pxp_init(struct intel_pxp *pxp) · 2 unmodified lines
3033 static inline void intel_pxp_fini(struct intel_pxp *pxp)
3134 {
3235 }
36+
37+static inline int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp)
38+{
39+ return -ENODEV;
40+}
3341 #endif
3442
3543 #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+ */
19+void 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+
45+static 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+
54+static 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+
61+void 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+
76+void 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+
11+struct 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
23+void intel_pxp_irq_enable(struct intel_pxp *pxp);
24+void intel_pxp_irq_disable(struct intel_pxp *pxp);
25+void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir);
26+#else
27+static 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
4848 return ret;
4949 }
5050
51−int intel_pxp_create_arb_session(struct intel_pxp *pxp)
51+static int pxp_create_arb_session(struct intel_pxp *pxp)
5252 {
5353 struct intel_gt *gt = pxp_to_gt(pxp);
5454 int ret;
@@ -77,12 +77,13 @@ int intel_pxp_create_arb_session(struct intel_pxp *pxp) · 22 unmodified lines
7777 return 0;
7878 }
7979
80−int intel_pxp_terminate_arb_session_and_global(struct intel_pxp *pxp)
80+static int pxp_terminate_arb_session_and_global(struct intel_pxp *pxp)
8181 {
8282 int ret;
8383 struct intel_gt *gt = pxp_to_gt(pxp);
8484
85− pxp->arb_is_valid = false;
85+ /* must mark termination in progress calling this function */
86+ GEM_WARN_ON(pxp->arb_is_valid);
8687
8788 /* terminate the hw sessions */
8889 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
101102
102103 return ret;
103104 }
105+
106+static 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+
122+static 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+
131+void 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
88
99 #include <linux/types.h>
1010
11−struct intel_pxp;
11+struct work_struct;
1212
13−int intel_pxp_create_arb_session(struct intel_pxp *pxp);
14−int intel_pxp_terminate_arb_session_and_global(struct intel_pxp *pxp);
13+void intel_pxp_session_work(struct work_struct *work);
1514
1615 #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
8080 {
8181 struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
8282 struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev);
83+ int ret;
8384
8485 mutex_lock(&pxp->tee_mutex);
8586 pxp->pxp_component = data;
@@ -88,15 +89,14 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, · 2 unmodified lines
8889
8990 /* the component is required to fully start the PXP HW */
9091 intel_pxp_init_hw(pxp);
91−
92− if (!pxp->arb_is_valid) {
92+ ret = intel_pxp_wait_for_arb_start(pxp);
93+ if (ret) {
9394 drm_err(&i915->drm, "Failed to create arb session during bind\n");
9495 intel_pxp_fini_hw(pxp);
9596 pxp->pxp_component = NULL;
96− return -EIO;
9797 }
9898
99− return 0;
99+ return ret;
100100 }
101101
102102 static 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
66 #ifndef __INTEL_PXP_TYPES_H__
77 #define __INTEL_PXP_TYPES_H__
88
9+#include <linux/completion.h>
910 #include <linux/mutex.h>
1011 #include <linux/types.h>
12+#include <linux/workqueue.h>
1113
1214 struct intel_context;
1315 struct i915_pxp_component;
@@ -26,6 +28,22 @@ struct intel_pxp { · 12 unmodified lines
2628 bool arb_is_valid;
2729
2830 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)
2947 };
3048
3149 #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