]> git.ipfire.org Git - thirdparty/kernel/stable.git/blob - drivers/misc/mei/pxp/mei_pxp.c
KVM: Harden copying of userspace-array against overflow
[thirdparty/kernel/stable.git] / drivers / misc / mei / pxp / mei_pxp.c
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
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
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 }
88
89 return byte;
90 }
91
92 /**
93 * mei_pxp_receive_message() - Receives a PXP message from ME FW.
94 * @dev: device corresponding to the mei_cl_device
95 * @buffer: a message buffer to contain the received message
96 * @size: size of the buffer
97 * @timeout_ms: timeout in milliseconds, zero means wait indefinitely.
98 *
99 * Returns: number of bytes send on Success, <0 on Failure with the following defined failures.
100 * -ENODEV: Client was not connected.
101 * Caller may attempt to try again from send immediately.
102 * -ENOMEM: Internal memory allocation failure experienced.
103 * Caller may sleep to allow kernel reclaim before retrying.
104 * -EINTR : Calling thread received a signal. Caller will need to repeat calling
105 * (with a different owning thread) to retrieve existing unclaimed response
106 * (and may discard it).
107 * -ETIME : Request is timed out.
108 * Caller may attempt to try again from send immediately.
109 */
110 static int
111 mei_pxp_receive_message(struct device *dev, void *buffer, size_t size, unsigned long timeout_ms)
112 {
113 struct mei_cl_device *cldev;
114 ssize_t byte;
115 bool retry = false;
116 int ret;
117
118 if (!dev || !buffer)
119 return -EINVAL;
120
121 cldev = to_mei_cl_device(dev);
122
123 retry:
124 byte = mei_cldev_recv_timeout(cldev, buffer, size, timeout_ms);
125 if (byte < 0) {
126 dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
127 switch (byte) {
128 case -ENOMEM:
129 /* Retry the read when pages are reclaimed */
130 msleep(20);
131 if (!retry) {
132 retry = true;
133 goto retry;
134 }
135 fallthrough;
136 case -ENODEV:
137 fallthrough;
138 case -ETIME:
139 ret = mei_pxp_reenable(dev, cldev);
140 if (ret)
141 byte = ret;
142 break;
143 }
144 }
145
146 return byte;
147 }
148
149 /**
150 * mei_pxp_gsc_command() - sends a gsc command, by sending
151 * a sgl mei message to gsc and receiving reply from gsc
152 *
153 * @dev: device corresponding to the mei_cl_device
154 * @client_id: client id to send the command to
155 * @fence_id: fence id to send the command to
156 * @sg_in: scatter gather list containing addresses for rx message buffer
157 * @total_in_len: total length of data in 'in' sg, can be less than the sum of buffers sizes
158 * @sg_out: scatter gather list containing addresses for tx message buffer
159 *
160 * Return: bytes sent on Success, <0 on Failure
161 */
162 static ssize_t mei_pxp_gsc_command(struct device *dev, u8 client_id, u32 fence_id,
163 struct scatterlist *sg_in, size_t total_in_len,
164 struct scatterlist *sg_out)
165 {
166 struct mei_cl_device *cldev;
167
168 cldev = to_mei_cl_device(dev);
169
170 return mei_cldev_send_gsc_command(cldev, client_id, fence_id, sg_in, total_in_len, sg_out);
171 }
172
173 static const struct i915_pxp_component_ops mei_pxp_ops = {
174 .owner = THIS_MODULE,
175 .send = mei_pxp_send_message,
176 .recv = mei_pxp_receive_message,
177 .gsc_command = mei_pxp_gsc_command,
178 };
179
180 static int mei_component_master_bind(struct device *dev)
181 {
182 struct mei_cl_device *cldev = to_mei_cl_device(dev);
183 struct i915_pxp_component *comp_master = mei_cldev_get_drvdata(cldev);
184 int ret;
185
186 comp_master->ops = &mei_pxp_ops;
187 comp_master->tee_dev = dev;
188 ret = component_bind_all(dev, comp_master);
189 if (ret < 0)
190 return ret;
191
192 return 0;
193 }
194
195 static void mei_component_master_unbind(struct device *dev)
196 {
197 struct mei_cl_device *cldev = to_mei_cl_device(dev);
198 struct i915_pxp_component *comp_master = mei_cldev_get_drvdata(cldev);
199
200 component_unbind_all(dev, comp_master);
201 }
202
203 static const struct component_master_ops mei_component_master_ops = {
204 .bind = mei_component_master_bind,
205 .unbind = mei_component_master_unbind,
206 };
207
208 /**
209 * mei_pxp_component_match - compare function for matching mei pxp.
210 *
211 * The function checks if the driver is i915, the subcomponent is PXP
212 * and the grand parent of pxp and the parent of i915 are the same
213 * PCH device.
214 *
215 * @dev: master device
216 * @subcomponent: subcomponent to match (I915_COMPONENT_PXP)
217 * @data: compare data (mei pxp device)
218 *
219 * Return:
220 * * 1 - if components match
221 * * 0 - otherwise
222 */
223 static int mei_pxp_component_match(struct device *dev, int subcomponent,
224 void *data)
225 {
226 struct device *base = data;
227
228 if (!dev)
229 return 0;
230
231 if (!dev->driver || strcmp(dev->driver->name, "i915") ||
232 subcomponent != I915_COMPONENT_PXP)
233 return 0;
234
235 base = base->parent;
236 if (!base) /* mei device */
237 return 0;
238
239 base = base->parent; /* pci device */
240 /* for dgfx */
241 if (base && dev == base)
242 return 1;
243
244 /* for pch */
245 dev = dev->parent;
246 return (base && dev && dev == base);
247 }
248
249 static int mei_pxp_probe(struct mei_cl_device *cldev,
250 const struct mei_cl_device_id *id)
251 {
252 struct i915_pxp_component *comp_master;
253 struct component_match *master_match;
254 int ret;
255
256 ret = mei_cldev_enable(cldev);
257 if (ret < 0) {
258 dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret);
259 goto enable_err_exit;
260 }
261
262 comp_master = kzalloc(sizeof(*comp_master), GFP_KERNEL);
263 if (!comp_master) {
264 ret = -ENOMEM;
265 goto err_exit;
266 }
267
268 master_match = NULL;
269 component_match_add_typed(&cldev->dev, &master_match,
270 mei_pxp_component_match, &cldev->dev);
271 if (IS_ERR_OR_NULL(master_match)) {
272 ret = -ENOMEM;
273 goto err_exit;
274 }
275
276 mei_cldev_set_drvdata(cldev, comp_master);
277 ret = component_master_add_with_match(&cldev->dev,
278 &mei_component_master_ops,
279 master_match);
280 if (ret < 0) {
281 dev_err(&cldev->dev, "Master comp add failed %d\n", ret);
282 goto err_exit;
283 }
284
285 return 0;
286
287 err_exit:
288 mei_cldev_set_drvdata(cldev, NULL);
289 kfree(comp_master);
290 mei_cldev_disable(cldev);
291 enable_err_exit:
292 return ret;
293 }
294
295 static void mei_pxp_remove(struct mei_cl_device *cldev)
296 {
297 struct i915_pxp_component *comp_master = mei_cldev_get_drvdata(cldev);
298 int ret;
299
300 component_master_del(&cldev->dev, &mei_component_master_ops);
301 kfree(comp_master);
302 mei_cldev_set_drvdata(cldev, NULL);
303
304 ret = mei_cldev_disable(cldev);
305 if (ret)
306 dev_warn(&cldev->dev, "mei_cldev_disable() failed\n");
307 }
308
309 /* fbf6fcf1-96cf-4e2e-a6a6-1bab8cbe36b1 : PAVP GUID*/
310 #define MEI_GUID_PXP UUID_LE(0xfbf6fcf1, 0x96cf, 0x4e2e, 0xA6, \
311 0xa6, 0x1b, 0xab, 0x8c, 0xbe, 0x36, 0xb1)
312
313 static struct mei_cl_device_id mei_pxp_tbl[] = {
314 { .uuid = MEI_GUID_PXP, .version = MEI_CL_VERSION_ANY },
315 { }
316 };
317 MODULE_DEVICE_TABLE(mei, mei_pxp_tbl);
318
319 static struct mei_cl_driver mei_pxp_driver = {
320 .id_table = mei_pxp_tbl,
321 .name = KBUILD_MODNAME,
322 .probe = mei_pxp_probe,
323 .remove = mei_pxp_remove,
324 };
325
326 module_mei_cl_driver(mei_pxp_driver);
327
328 MODULE_AUTHOR("Intel Corporation");
329 MODULE_LICENSE("GPL");
330 MODULE_DESCRIPTION("MEI PXP");