xref: /linux/drivers/misc/mei/pxp/mei_pxp.c (revision ab475966455ce285c2c9978a3e3bfe97d75ff8d4)
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");
331