1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright © 2020 - 2021 Intel Corporation
7 * DOC: MEI_PXP Client Driver
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.
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>
26 static inline int mei_pxp_reenable(const struct device
*dev
, struct mei_cl_device
*cldev
)
30 dev_warn(dev
, "Trying to reset the channel...\n");
31 ret
= mei_cldev_disable(cldev
);
33 dev_warn(dev
, "mei_cldev_disable failed. %d\n", ret
);
35 * Explicitly ignoring disable failure,
36 * enable may fix the states and succeed
38 ret
= mei_cldev_enable(cldev
);
40 dev_err(dev
, "mei_cldev_enable failed. %d\n", ret
);
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.
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.
62 mei_pxp_send_message(struct device
*dev
, const void *message
, size_t size
, unsigned long timeout_ms
)
64 struct mei_cl_device
*cldev
;
71 cldev
= to_mei_cl_device(dev
);
73 byte
= mei_cldev_send_timeout(cldev
, message
, size
, timeout_ms
);
75 dev_dbg(dev
, "mei_cldev_send failed. %zd\n", byte
);
82 ret
= mei_pxp_reenable(dev
, cldev
);
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.
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.
111 mei_pxp_receive_message(struct device
*dev
, void *buffer
, size_t size
, unsigned long timeout_ms
)
113 struct mei_cl_device
*cldev
;
121 cldev
= to_mei_cl_device(dev
);
124 byte
= mei_cldev_recv_timeout(cldev
, buffer
, size
, timeout_ms
);
126 dev_dbg(dev
, "mei_cldev_recv failed. %zd\n", byte
);
129 /* Retry the read when pages are reclaimed */
139 ret
= mei_pxp_reenable(dev
, cldev
);
150 * mei_pxp_gsc_command() - sends a gsc command, by sending
151 * a sgl mei message to gsc and receiving reply from gsc
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
160 * Return: bytes sent on Success, <0 on Failure
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
)
166 struct mei_cl_device
*cldev
;
168 cldev
= to_mei_cl_device(dev
);
170 return mei_cldev_send_gsc_command(cldev
, client_id
, fence_id
, sg_in
, total_in_len
, sg_out
);
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
,
180 static int mei_component_master_bind(struct device
*dev
)
182 struct mei_cl_device
*cldev
= to_mei_cl_device(dev
);
183 struct i915_pxp_component
*comp_master
= mei_cldev_get_drvdata(cldev
);
186 comp_master
->ops
= &mei_pxp_ops
;
187 comp_master
->tee_dev
= dev
;
188 ret
= component_bind_all(dev
, comp_master
);
195 static void mei_component_master_unbind(struct device
*dev
)
197 struct mei_cl_device
*cldev
= to_mei_cl_device(dev
);
198 struct i915_pxp_component
*comp_master
= mei_cldev_get_drvdata(cldev
);
200 component_unbind_all(dev
, comp_master
);
203 static const struct component_master_ops mei_component_master_ops
= {
204 .bind
= mei_component_master_bind
,
205 .unbind
= mei_component_master_unbind
,
209 * mei_pxp_component_match - compare function for matching mei pxp.
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
215 * @dev: master device
216 * @subcomponent: subcomponent to match (I915_COMPONENT_PXP)
217 * @data: compare data (mei pxp device)
220 * * 1 - if components match
223 static int mei_pxp_component_match(struct device
*dev
, int subcomponent
,
226 struct device
*base
= data
;
231 if (!dev
->driver
|| strcmp(dev
->driver
->name
, "i915") ||
232 subcomponent
!= I915_COMPONENT_PXP
)
236 if (!base
) /* mei device */
239 base
= base
->parent
; /* pci device */
241 if (base
&& dev
== base
)
246 return (base
&& dev
&& dev
== base
);
249 static int mei_pxp_probe(struct mei_cl_device
*cldev
,
250 const struct mei_cl_device_id
*id
)
252 struct i915_pxp_component
*comp_master
;
253 struct component_match
*master_match
;
256 ret
= mei_cldev_enable(cldev
);
258 dev_err(&cldev
->dev
, "mei_cldev_enable Failed. %d\n", ret
);
259 goto enable_err_exit
;
262 comp_master
= kzalloc(sizeof(*comp_master
), GFP_KERNEL
);
269 component_match_add_typed(&cldev
->dev
, &master_match
,
270 mei_pxp_component_match
, &cldev
->dev
);
271 if (IS_ERR_OR_NULL(master_match
)) {
276 mei_cldev_set_drvdata(cldev
, comp_master
);
277 ret
= component_master_add_with_match(&cldev
->dev
,
278 &mei_component_master_ops
,
281 dev_err(&cldev
->dev
, "Master comp add failed %d\n", ret
);
288 mei_cldev_set_drvdata(cldev
, NULL
);
290 mei_cldev_disable(cldev
);
295 static void mei_pxp_remove(struct mei_cl_device
*cldev
)
297 struct i915_pxp_component
*comp_master
= mei_cldev_get_drvdata(cldev
);
300 component_master_del(&cldev
->dev
, &mei_component_master_ops
);
302 mei_cldev_set_drvdata(cldev
, NULL
);
304 ret
= mei_cldev_disable(cldev
);
306 dev_warn(&cldev
->dev
, "mei_cldev_disable() failed\n");
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)
313 static struct mei_cl_device_id mei_pxp_tbl
[] = {
314 { .uuid
= MEI_GUID_PXP
, .version
= MEI_CL_VERSION_ANY
},
317 MODULE_DEVICE_TABLE(mei
, mei_pxp_tbl
);
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
,
326 module_mei_cl_driver(mei_pxp_driver
);
328 MODULE_AUTHOR("Intel Corporation");
329 MODULE_LICENSE("GPL");
330 MODULE_DESCRIPTION("MEI PXP");