1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright © 2020 - 2021 Intel Corporation
4 */
5
6 /**
7 * DOC: MEI_PXP Client Driver
8 *
9 * The mei_pxp driver acts as a translation layer between PXP
10 * protocol implementer (I915) and ME FW by translating PXP
11 * negotiation messages to ME FW command payloads and vice versa.
12 */
13
14 #include <linux/delay.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
17 #include <linux/mei.h>
18 #include <linux/mei_cl_bus.h>
19 #include <linux/component.h>
20 #include <drm/drm_connector.h>
21 #include <drm/i915_component.h>
22 #include <drm/i915_pxp_tee_interface.h>
23
24 #include "mei_pxp.h"
25
mei_pxp_reenable(const struct device * dev,struct mei_cl_device * cldev)26 static inline int mei_pxp_reenable(const struct device *dev, struct mei_cl_device *cldev)
27 {
28 int ret;
29
30 dev_warn(dev, "Trying to reset the channel...\n");
31 ret = mei_cldev_disable(cldev);
32 if (ret < 0)
33 dev_warn(dev, "mei_cldev_disable failed. %d\n", ret);
34 /*
35 * Explicitly ignoring disable failure,
36 * enable may fix the states and succeed
37 */
38 ret = mei_cldev_enable(cldev);
39 if (ret < 0)
40 dev_err(dev, "mei_cldev_enable failed. %d\n", ret);
41 return ret;
42 }
43
44 /**
45 * mei_pxp_send_message() - Sends a PXP message to ME FW.
46 * @dev: device corresponding to the mei_cl_device
47 * @message: a message buffer to send
48 * @size: size of the message
49 * @timeout_ms: timeout in milliseconds, zero means wait indefinitely.
50 *
51 * Returns: 0 on Success, <0 on Failure with the following defined failures.
52 * -ENODEV: Client was not connected.
53 * Caller may attempt to try again immediately.
54 * -ENOMEM: Internal memory allocation failure experienced.
55 * Caller may sleep to allow kernel reclaim before retrying.
56 * -EINTR : Calling thread received a signal. Caller may choose
57 * to abandon with the same thread id.
58 * -ETIME : Request is timed out.
59 * Caller may attempt to try again immediately.
60 */
61 static int
mei_pxp_send_message(struct device * dev,const void * message,size_t size,unsigned long timeout_ms)62 mei_pxp_send_message(struct device *dev, const void *message, size_t size, unsigned long timeout_ms)
63 {
64 struct mei_cl_device *cldev;
65 ssize_t byte;
66 int ret;
67
68 if (!dev || !message)
69 return -EINVAL;
70
71 cldev = to_mei_cl_device(dev);
72
73 byte = mei_cldev_send_timeout(cldev, message, size, timeout_ms);
74 if (byte < 0) {
75 dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
76 switch (byte) {
77 case -ENOMEM:
78 fallthrough;
79 case -ENODEV:
80 fallthrough;
81 case -ETIME:
82 ret = mei_pxp_reenable(dev, cldev);
83 if (ret)
84 byte = ret;
85 break;
86 }
87 return byte;
88 }
89
90 return 0;
91 }
92
93 /**
94 * mei_pxp_receive_message() - Receives a PXP message from ME FW.
95 * @dev: device corresponding to the mei_cl_device
96 * @buffer: a message buffer to contain the received message
97 * @size: size of the buffer
98 * @timeout_ms: timeout in milliseconds, zero means wait indefinitely.
99 *
100 * Returns: number of bytes send on Success, <0 on Failure with the following defined failures.
101 * -ENODEV: Client was not connected.
102 * Caller may attempt to try again from send immediately.
103 * -ENOMEM: Internal memory allocation failure experienced.
104 * Caller may sleep to allow kernel reclaim before retrying.
105 * -EINTR : Calling thread received a signal. Caller will need to repeat calling
106 * (with a different owning thread) to retrieve existing unclaimed response
107 * (and may discard it).
108 * -ETIME : Request is timed out.
109 * Caller may attempt to try again from send immediately.
110 */
111 static int
mei_pxp_receive_message(struct device * dev,void * buffer,size_t size,unsigned long timeout_ms)112 mei_pxp_receive_message(struct device *dev, void *buffer, size_t size, unsigned long timeout_ms)
113 {
114 struct mei_cl_device *cldev;
115 ssize_t byte;
116 bool retry = false;
117 int ret;
118
119 if (!dev || !buffer)
120 return -EINVAL;
121
122 cldev = to_mei_cl_device(dev);
123
124 retry:
125 byte = mei_cldev_recv_timeout(cldev, buffer, size, timeout_ms);
126 if (byte < 0) {
127 dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
128 switch (byte) {
129 case -ENOMEM:
130 /* Retry the read when pages are reclaimed */
131 msleep(20);
132 if (!retry) {
133 retry = true;
134 goto retry;
135 }
136 fallthrough;
137 case -ENODEV:
138 fallthrough;
139 case -ETIME:
140 ret = mei_pxp_reenable(dev, cldev);
141 if (ret)
142 byte = ret;
143 break;
144 }
145 }
146
147 return byte;
148 }
149
150 /**
151 * mei_pxp_gsc_command() - sends a gsc command, by sending
152 * a sgl mei message to gsc and receiving reply from gsc
153 *
154 * @dev: device corresponding to the mei_cl_device
155 * @client_id: client id to send the command to
156 * @fence_id: fence id to send the command to
157 * @sg_in: scatter gather list containing addresses for rx message buffer
158 * @total_in_len: total length of data in 'in' sg, can be less than the sum of buffers sizes
159 * @sg_out: scatter gather list containing addresses for tx message buffer
160 *
161 * Return: bytes sent on Success, <0 on Failure
162 */
mei_pxp_gsc_command(struct device * dev,u8 client_id,u32 fence_id,struct scatterlist * sg_in,size_t total_in_len,struct scatterlist * sg_out)163 static ssize_t mei_pxp_gsc_command(struct device *dev, u8 client_id, u32 fence_id,
164 struct scatterlist *sg_in, size_t total_in_len,
165 struct scatterlist *sg_out)
166 {
167 struct mei_cl_device *cldev;
168
169 cldev = to_mei_cl_device(dev);
170
171 return mei_cldev_send_gsc_command(cldev, client_id, fence_id, sg_in, total_in_len, sg_out);
172 }
173
174 static const struct i915_pxp_component_ops mei_pxp_ops = {
175 .owner = THIS_MODULE,
176 .send = mei_pxp_send_message,
177 .recv = mei_pxp_receive_message,
178 .gsc_command = mei_pxp_gsc_command,
179 };
180
mei_component_master_bind(struct device * dev)181 static int mei_component_master_bind(struct device *dev)
182 {
183 struct mei_cl_device *cldev = to_mei_cl_device(dev);
184 struct i915_pxp_component *comp_master = mei_cldev_get_drvdata(cldev);
185 int ret;
186
187 comp_master->ops = &mei_pxp_ops;
188 comp_master->tee_dev = dev;
189 ret = component_bind_all(dev, comp_master);
190 if (ret < 0)
191 return ret;
192
193 return 0;
194 }
195
mei_component_master_unbind(struct device * dev)196 static void mei_component_master_unbind(struct device *dev)
197 {
198 struct mei_cl_device *cldev = to_mei_cl_device(dev);
199 struct i915_pxp_component *comp_master = mei_cldev_get_drvdata(cldev);
200
201 component_unbind_all(dev, comp_master);
202 }
203
204 static const struct component_master_ops mei_component_master_ops = {
205 .bind = mei_component_master_bind,
206 .unbind = mei_component_master_unbind,
207 };
208
209 /**
210 * mei_pxp_component_match - compare function for matching mei pxp.
211 *
212 * The function checks if the driver is i915, the subcomponent is PXP
213 * and the grand parent of pxp and the parent of i915 are the same
214 * PCH device.
215 *
216 * @dev: master device
217 * @subcomponent: subcomponent to match (I915_COMPONENT_PXP)
218 * @data: compare data (mei pxp device)
219 *
220 * Return:
221 * * 1 - if components match
222 * * 0 - otherwise
223 */
mei_pxp_component_match(struct device * dev,int subcomponent,void * data)224 static int mei_pxp_component_match(struct device *dev, int subcomponent,
225 void *data)
226 {
227 struct device *base = data;
228
229 if (!dev)
230 return 0;
231
232 if (!dev->driver || strcmp(dev->driver->name, "i915") ||
233 subcomponent != I915_COMPONENT_PXP)
234 return 0;
235
236 base = base->parent;
237 if (!base) /* mei device */
238 return 0;
239
240 base = base->parent; /* pci device */
241 /* for dgfx */
242 if (base && dev == base)
243 return 1;
244
245 /* for pch */
246 dev = dev->parent;
247 return (base && dev && dev == base);
248 }
249
mei_pxp_probe(struct mei_cl_device * cldev,const struct mei_cl_device_id * id)250 static int mei_pxp_probe(struct mei_cl_device *cldev,
251 const struct mei_cl_device_id *id)
252 {
253 struct i915_pxp_component *comp_master;
254 struct component_match *master_match;
255 int ret;
256
257 ret = mei_cldev_enable(cldev);
258 if (ret < 0) {
259 dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret);
260 goto enable_err_exit;
261 }
262
263 comp_master = kzalloc(sizeof(*comp_master), GFP_KERNEL);
264 if (!comp_master) {
265 ret = -ENOMEM;
266 goto err_exit;
267 }
268
269 master_match = NULL;
270 component_match_add_typed(&cldev->dev, &master_match,
271 mei_pxp_component_match, &cldev->dev);
272 if (IS_ERR_OR_NULL(master_match)) {
273 ret = -ENOMEM;
274 goto err_exit;
275 }
276
277 mei_cldev_set_drvdata(cldev, comp_master);
278 ret = component_master_add_with_match(&cldev->dev,
279 &mei_component_master_ops,
280 master_match);
281 if (ret < 0) {
282 dev_err(&cldev->dev, "Master comp add failed %d\n", ret);
283 goto err_exit;
284 }
285
286 return 0;
287
288 err_exit:
289 mei_cldev_set_drvdata(cldev, NULL);
290 kfree(comp_master);
291 mei_cldev_disable(cldev);
292 enable_err_exit:
293 return ret;
294 }
295
mei_pxp_remove(struct mei_cl_device * cldev)296 static void mei_pxp_remove(struct mei_cl_device *cldev)
297 {
298 struct i915_pxp_component *comp_master = mei_cldev_get_drvdata(cldev);
299 int ret;
300
301 component_master_del(&cldev->dev, &mei_component_master_ops);
302 kfree(comp_master);
303 mei_cldev_set_drvdata(cldev, NULL);
304
305 ret = mei_cldev_disable(cldev);
306 if (ret)
307 dev_warn(&cldev->dev, "mei_cldev_disable() failed\n");
308 }
309
310 /* fbf6fcf1-96cf-4e2e-a6a6-1bab8cbe36b1 : PAVP GUID*/
311 #define MEI_GUID_PXP UUID_LE(0xfbf6fcf1, 0x96cf, 0x4e2e, 0xA6, \
312 0xa6, 0x1b, 0xab, 0x8c, 0xbe, 0x36, 0xb1)
313
314 static struct mei_cl_device_id mei_pxp_tbl[] = {
315 { .uuid = MEI_GUID_PXP, .version = MEI_CL_VERSION_ANY },
316 { }
317 };
318 MODULE_DEVICE_TABLE(mei, mei_pxp_tbl);
319
320 static struct mei_cl_driver mei_pxp_driver = {
321 .id_table = mei_pxp_tbl,
322 .name = KBUILD_MODNAME,
323 .probe = mei_pxp_probe,
324 .remove = mei_pxp_remove,
325 };
326
327 module_mei_cl_driver(mei_pxp_driver);
328
329 MODULE_AUTHOR("Intel Corporation");
330 MODULE_LICENSE("GPL");
331 MODULE_DESCRIPTION("MEI PXP");
332