1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright(c) 2020 Intel Corporation.
4 */
5
6 #include <linux/component.h>
7
8 #include <drm/i915_pxp_tee_interface.h>
9 #include <drm/i915_component.h>
10
11 #include "gem/i915_gem_lmem.h"
12
13 #include "i915_drv.h"
14
15 #include "intel_pxp.h"
16 #include "intel_pxp_cmd_interface_42.h"
17 #include "intel_pxp_huc.h"
18 #include "intel_pxp_session.h"
19 #include "intel_pxp_tee.h"
20 #include "intel_pxp_types.h"
21
intel_pxp_tee_io_message(struct intel_pxp * pxp,void * msg_in,u32 msg_in_size,void * msg_out,u32 msg_out_max_size,u32 * msg_out_rcv_size)22 static int intel_pxp_tee_io_message(struct intel_pxp *pxp,
23 void *msg_in, u32 msg_in_size,
24 void *msg_out, u32 msg_out_max_size,
25 u32 *msg_out_rcv_size)
26 {
27 struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
28 struct i915_pxp_component *pxp_component = pxp->pxp_component;
29 int ret = 0;
30
31 mutex_lock(&pxp->tee_mutex);
32
33 /*
34 * The binding of the component is asynchronous from i915 probe, so we
35 * can't be sure it has happened.
36 */
37 if (!pxp_component) {
38 ret = -ENODEV;
39 goto unlock;
40 }
41
42 ret = pxp_component->ops->send(pxp_component->tee_dev, msg_in, msg_in_size);
43 if (ret) {
44 drm_err(&i915->drm, "Failed to send PXP TEE message\n");
45 goto unlock;
46 }
47
48 ret = pxp_component->ops->recv(pxp_component->tee_dev, msg_out, msg_out_max_size);
49 if (ret < 0) {
50 drm_err(&i915->drm, "Failed to receive PXP TEE message\n");
51 goto unlock;
52 }
53
54 if (ret > msg_out_max_size) {
55 drm_err(&i915->drm,
56 "Failed to receive PXP TEE message due to unexpected output size\n");
57 ret = -ENOSPC;
58 goto unlock;
59 }
60
61 if (msg_out_rcv_size)
62 *msg_out_rcv_size = ret;
63
64 ret = 0;
65 unlock:
66 mutex_unlock(&pxp->tee_mutex);
67 return ret;
68 }
69
intel_pxp_tee_stream_message(struct intel_pxp * pxp,u8 client_id,u32 fence_id,void * msg_in,size_t msg_in_len,void * msg_out,size_t msg_out_len)70 int intel_pxp_tee_stream_message(struct intel_pxp *pxp,
71 u8 client_id, u32 fence_id,
72 void *msg_in, size_t msg_in_len,
73 void *msg_out, size_t msg_out_len)
74 {
75 /* TODO: for bigger objects we need to use a sg of 4k pages */
76 const size_t max_msg_size = PAGE_SIZE;
77 struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
78 struct i915_pxp_component *pxp_component = pxp->pxp_component;
79 unsigned int offset = 0;
80 struct scatterlist *sg;
81 int ret;
82
83 if (msg_in_len > max_msg_size || msg_out_len > max_msg_size)
84 return -ENOSPC;
85
86 mutex_lock(&pxp->tee_mutex);
87
88 if (unlikely(!pxp_component || !pxp_component->ops->gsc_command)) {
89 ret = -ENODEV;
90 goto unlock;
91 }
92
93 GEM_BUG_ON(!pxp->stream_cmd.obj);
94
95 sg = i915_gem_object_get_sg_dma(pxp->stream_cmd.obj, 0, &offset);
96
97 memcpy(pxp->stream_cmd.vaddr, msg_in, msg_in_len);
98
99 ret = pxp_component->ops->gsc_command(pxp_component->tee_dev, client_id,
100 fence_id, sg, msg_in_len, sg);
101 if (ret < 0)
102 drm_err(&i915->drm, "Failed to send PXP TEE gsc command\n");
103 else
104 memcpy(msg_out, pxp->stream_cmd.vaddr, msg_out_len);
105
106 unlock:
107 mutex_unlock(&pxp->tee_mutex);
108 return ret;
109 }
110
111 /**
112 * i915_pxp_tee_component_bind - bind function to pass the function pointers to pxp_tee
113 * @i915_kdev: pointer to i915 kernel device
114 * @tee_kdev: pointer to tee kernel device
115 * @data: pointer to pxp_tee_master containing the function pointers
116 *
117 * This bind function is called during the system boot or resume from system sleep.
118 *
119 * Return: return 0 if successful.
120 */
i915_pxp_tee_component_bind(struct device * i915_kdev,struct device * tee_kdev,void * data)121 static int i915_pxp_tee_component_bind(struct device *i915_kdev,
122 struct device *tee_kdev, void *data)
123 {
124 struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
125 struct intel_pxp *pxp = i915->pxp;
126 struct intel_uc *uc = &pxp->ctrl_gt->uc;
127 intel_wakeref_t wakeref;
128 int ret = 0;
129
130 mutex_lock(&pxp->tee_mutex);
131 pxp->pxp_component = data;
132 pxp->pxp_component->tee_dev = tee_kdev;
133 mutex_unlock(&pxp->tee_mutex);
134
135 if (intel_uc_uses_huc(uc) && intel_huc_is_loaded_by_gsc(&uc->huc)) {
136 with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
137 /* load huc via pxp */
138 ret = intel_huc_fw_load_and_auth_via_gsc(&uc->huc);
139 if (ret < 0)
140 drm_err(&i915->drm, "failed to load huc via gsc %d\n", ret);
141 }
142 }
143
144 /* if we are suspended, the HW will be re-initialized on resume */
145 wakeref = intel_runtime_pm_get_if_in_use(&i915->runtime_pm);
146 if (!wakeref)
147 return 0;
148
149 /* the component is required to fully start the PXP HW */
150 if (intel_pxp_is_enabled(pxp))
151 intel_pxp_init_hw(pxp);
152
153 intel_runtime_pm_put(&i915->runtime_pm, wakeref);
154
155 return ret;
156 }
157
i915_pxp_tee_component_unbind(struct device * i915_kdev,struct device * tee_kdev,void * data)158 static void i915_pxp_tee_component_unbind(struct device *i915_kdev,
159 struct device *tee_kdev, void *data)
160 {
161 struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
162 struct intel_pxp *pxp = i915->pxp;
163 intel_wakeref_t wakeref;
164
165 if (intel_pxp_is_enabled(pxp))
166 with_intel_runtime_pm_if_in_use(&i915->runtime_pm, wakeref)
167 intel_pxp_fini_hw(pxp);
168
169 mutex_lock(&pxp->tee_mutex);
170 pxp->pxp_component = NULL;
171 mutex_unlock(&pxp->tee_mutex);
172 }
173
174 static const struct component_ops i915_pxp_tee_component_ops = {
175 .bind = i915_pxp_tee_component_bind,
176 .unbind = i915_pxp_tee_component_unbind,
177 };
178
alloc_streaming_command(struct intel_pxp * pxp)179 static int alloc_streaming_command(struct intel_pxp *pxp)
180 {
181 struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
182 struct drm_i915_gem_object *obj = NULL;
183 void *cmd;
184 int err;
185
186 pxp->stream_cmd.obj = NULL;
187 pxp->stream_cmd.vaddr = NULL;
188
189 if (!IS_DGFX(i915))
190 return 0;
191
192 /* allocate lmem object of one page for PXP command memory and store it */
193 obj = i915_gem_object_create_lmem(i915, PAGE_SIZE, I915_BO_ALLOC_CONTIGUOUS);
194 if (IS_ERR(obj)) {
195 drm_err(&i915->drm, "Failed to allocate pxp streaming command!\n");
196 return PTR_ERR(obj);
197 }
198
199 err = i915_gem_object_pin_pages_unlocked(obj);
200 if (err) {
201 drm_err(&i915->drm, "Failed to pin gsc message page!\n");
202 goto out_put;
203 }
204
205 /* map the lmem into the virtual memory pointer */
206 cmd = i915_gem_object_pin_map_unlocked(obj, i915_coherent_map_type(i915, obj, true));
207 if (IS_ERR(cmd)) {
208 drm_err(&i915->drm, "Failed to map gsc message page!\n");
209 err = PTR_ERR(cmd);
210 goto out_unpin;
211 }
212
213 memset(cmd, 0, obj->base.size);
214
215 pxp->stream_cmd.obj = obj;
216 pxp->stream_cmd.vaddr = cmd;
217
218 return 0;
219
220 out_unpin:
221 i915_gem_object_unpin_pages(obj);
222 out_put:
223 i915_gem_object_put(obj);
224 return err;
225 }
226
free_streaming_command(struct intel_pxp * pxp)227 static void free_streaming_command(struct intel_pxp *pxp)
228 {
229 struct drm_i915_gem_object *obj = fetch_and_zero(&pxp->stream_cmd.obj);
230
231 if (!obj)
232 return;
233
234 i915_gem_object_unpin_map(obj);
235 i915_gem_object_unpin_pages(obj);
236 i915_gem_object_put(obj);
237 }
238
intel_pxp_tee_component_init(struct intel_pxp * pxp)239 int intel_pxp_tee_component_init(struct intel_pxp *pxp)
240 {
241 int ret;
242 struct intel_gt *gt = pxp->ctrl_gt;
243 struct drm_i915_private *i915 = gt->i915;
244
245 mutex_init(&pxp->tee_mutex);
246
247 ret = alloc_streaming_command(pxp);
248 if (ret)
249 return ret;
250
251 ret = component_add_typed(i915->drm.dev, &i915_pxp_tee_component_ops,
252 I915_COMPONENT_PXP);
253 if (ret < 0) {
254 drm_err(&i915->drm, "Failed to add PXP component (%d)\n", ret);
255 goto out_free;
256 }
257
258 pxp->pxp_component_added = true;
259
260 return 0;
261
262 out_free:
263 free_streaming_command(pxp);
264 return ret;
265 }
266
intel_pxp_tee_component_fini(struct intel_pxp * pxp)267 void intel_pxp_tee_component_fini(struct intel_pxp *pxp)
268 {
269 struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
270
271 if (!pxp->pxp_component_added)
272 return;
273
274 component_del(i915->drm.dev, &i915_pxp_tee_component_ops);
275 pxp->pxp_component_added = false;
276
277 free_streaming_command(pxp);
278 }
279
intel_pxp_tee_cmd_create_arb_session(struct intel_pxp * pxp,int arb_session_id)280 int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp,
281 int arb_session_id)
282 {
283 struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
284 struct pxp42_create_arb_in msg_in = {0};
285 struct pxp42_create_arb_out msg_out = {0};
286 int ret;
287
288 msg_in.header.api_version = PXP_APIVER(4, 2);
289 msg_in.header.command_id = PXP42_CMDID_INIT_SESSION;
290 msg_in.header.buffer_len = sizeof(msg_in) - sizeof(msg_in.header);
291 msg_in.protection_mode = PXP42_ARB_SESSION_MODE_HEAVY;
292 msg_in.session_id = arb_session_id;
293
294 ret = intel_pxp_tee_io_message(pxp,
295 &msg_in, sizeof(msg_in),
296 &msg_out, sizeof(msg_out),
297 NULL);
298
299 if (ret)
300 drm_err(&i915->drm, "Failed to send tee msg ret=[%d]\n", ret);
301 else if (msg_out.header.status == PXP_STATUS_ERROR_API_VERSION)
302 drm_dbg(&i915->drm, "PXP firmware version unsupported, requested: "
303 "CMD-ID-[0x%08x] on API-Ver-[0x%08x]\n",
304 msg_in.header.command_id, msg_in.header.api_version);
305 else if (msg_out.header.status != 0x0)
306 drm_warn(&i915->drm, "PXP firmware failed arb session init request ret=[0x%08x]\n",
307 msg_out.header.status);
308
309 return ret;
310 }
311