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/pci.h>
17 #include <linux/slab.h>
18 #include <linux/mei.h>
19 #include <linux/mei_cl_bus.h>
20 #include <linux/component.h>
21 #include <drm/drm_connector.h>
22 #include <drm/intel/i915_component.h>
23 #include <drm/intel/i915_pxp_tee_interface.h>
27 static inline int mei_pxp_reenable(const struct device
*dev
, struct mei_cl_device
*cldev
)
31 dev_warn(dev
, "Trying to reset the channel...\n");
32 ret
= mei_cldev_disable(cldev
);
34 dev_warn(dev
, "mei_cldev_disable failed. %d\n", ret
);
36 * Explicitly ignoring disable failure,
37 * enable may fix the states and succeed
39 ret
= mei_cldev_enable(cldev
);
41 dev_err(dev
, "mei_cldev_enable failed. %d\n", ret
);
46 * mei_pxp_send_message() - Sends a PXP message to ME FW.
47 * @dev: device corresponding to the mei_cl_device
48 * @message: a message buffer to send
49 * @size: size of the message
50 * @timeout_ms: timeout in milliseconds, zero means wait indefinitely.
52 * Returns: 0 on Success, <0 on Failure with the following defined failures.
53 * -ENODEV: Client was not connected.
54 * Caller may attempt to try again immediately.
55 * -ENOMEM: Internal memory allocation failure experienced.
56 * Caller may sleep to allow kernel reclaim before retrying.
57 * -EINTR : Calling thread received a signal. Caller may choose
58 * to abandon with the same thread id.
59 * -ETIME : Request is timed out.
60 * Caller may attempt to try again immediately.
63 mei_pxp_send_message(struct device
*dev
, const void *message
, size_t size
, unsigned long timeout_ms
)
65 struct mei_cl_device
*cldev
;
72 cldev
= to_mei_cl_device(dev
);
74 byte
= mei_cldev_send_timeout(cldev
, message
, size
, timeout_ms
);
76 dev_dbg(dev
, "mei_cldev_send failed. %zd\n", byte
);
83 ret
= mei_pxp_reenable(dev
, cldev
);
95 * mei_pxp_receive_message() - Receives a PXP message from ME FW.
96 * @dev: device corresponding to the mei_cl_device
97 * @buffer: a message buffer to contain the received message
98 * @size: size of the buffer
99 * @timeout_ms: timeout in milliseconds, zero means wait indefinitely.
101 * Returns: number of bytes send on Success, <0 on Failure with the following defined failures.
102 * -ENODEV: Client was not connected.
103 * Caller may attempt to try again from send immediately.
104 * -ENOMEM: Internal memory allocation failure experienced.
105 * Caller may sleep to allow kernel reclaim before retrying.
106 * -EINTR : Calling thread received a signal. Caller will need to repeat calling
107 * (with a different owning thread) to retrieve existing unclaimed response
108 * (and may discard it).
109 * -ETIME : Request is timed out.
110 * Caller may attempt to try again from send immediately.
113 mei_pxp_receive_message(struct device
*dev
, void *buffer
, size_t size
, unsigned long timeout_ms
)
115 struct mei_cl_device
*cldev
;
123 cldev
= to_mei_cl_device(dev
);
126 byte
= mei_cldev_recv_timeout(cldev
, buffer
, size
, timeout_ms
);
128 dev_dbg(dev
, "mei_cldev_recv failed. %zd\n", byte
);
131 /* Retry the read when pages are reclaimed */
141 ret
= mei_pxp_reenable(dev
, cldev
);
152 * mei_pxp_gsc_command() - sends a gsc command, by sending
153 * a sgl mei message to gsc and receiving reply from gsc
155 * @dev: device corresponding to the mei_cl_device
156 * @client_id: client id to send the command to
157 * @fence_id: fence id to send the command to
158 * @sg_in: scatter gather list containing addresses for rx message buffer
159 * @total_in_len: total length of data in 'in' sg, can be less than the sum of buffers sizes
160 * @sg_out: scatter gather list containing addresses for tx message buffer
162 * Return: bytes sent on Success, <0 on Failure
164 static ssize_t
mei_pxp_gsc_command(struct device
*dev
, u8 client_id
, u32 fence_id
,
165 struct scatterlist
*sg_in
, size_t total_in_len
,
166 struct scatterlist
*sg_out
)
168 struct mei_cl_device
*cldev
;
170 cldev
= to_mei_cl_device(dev
);
172 return mei_cldev_send_gsc_command(cldev
, client_id
, fence_id
, sg_in
, total_in_len
, sg_out
);
175 static const struct i915_pxp_component_ops mei_pxp_ops
= {
176 .owner
= THIS_MODULE
,
177 .send
= mei_pxp_send_message
,
178 .recv
= mei_pxp_receive_message
,
179 .gsc_command
= mei_pxp_gsc_command
,
182 static int mei_component_master_bind(struct device
*dev
)
184 struct mei_cl_device
*cldev
= to_mei_cl_device(dev
);
185 struct i915_pxp_component
*comp_master
= mei_cldev_get_drvdata(cldev
);
188 comp_master
->ops
= &mei_pxp_ops
;
189 comp_master
->tee_dev
= dev
;
190 ret
= component_bind_all(dev
, comp_master
);
197 static void mei_component_master_unbind(struct device
*dev
)
199 struct mei_cl_device
*cldev
= to_mei_cl_device(dev
);
200 struct i915_pxp_component
*comp_master
= mei_cldev_get_drvdata(cldev
);
202 component_unbind_all(dev
, comp_master
);
205 static const struct component_master_ops mei_component_master_ops
= {
206 .bind
= mei_component_master_bind
,
207 .unbind
= mei_component_master_unbind
,
211 * mei_pxp_component_match - compare function for matching mei pxp.
213 * The function checks if the driver is i915, the subcomponent is PXP
214 * and the grand parent of pxp and the parent of i915 are the same
217 * @dev: master device
218 * @subcomponent: subcomponent to match (I915_COMPONENT_PXP)
219 * @data: compare data (mei pxp device)
222 * * 1 - if components match
225 static int mei_pxp_component_match(struct device
*dev
, int subcomponent
,
228 struct device
*base
= data
;
229 struct pci_dev
*pdev
;
234 if (!dev_is_pci(dev
))
237 pdev
= to_pci_dev(dev
);
239 if (pdev
->vendor
!= PCI_VENDOR_ID_INTEL
)
242 if (pdev
->class != (PCI_CLASS_DISPLAY_VGA
<< 8) &&
243 pdev
->class != (PCI_CLASS_DISPLAY_OTHER
<< 8))
246 if (subcomponent
!= I915_COMPONENT_PXP
)
250 if (!base
) /* mei device */
253 base
= base
->parent
; /* pci device */
255 if (base
&& dev
== base
)
260 return (base
&& dev
&& dev
== base
);
263 static int mei_pxp_probe(struct mei_cl_device
*cldev
,
264 const struct mei_cl_device_id
*id
)
266 struct i915_pxp_component
*comp_master
;
267 struct component_match
*master_match
;
270 ret
= mei_cldev_enable(cldev
);
272 dev_err(&cldev
->dev
, "mei_cldev_enable Failed. %d\n", ret
);
273 goto enable_err_exit
;
276 comp_master
= kzalloc(sizeof(*comp_master
), GFP_KERNEL
);
283 component_match_add_typed(&cldev
->dev
, &master_match
,
284 mei_pxp_component_match
, &cldev
->dev
);
285 if (IS_ERR_OR_NULL(master_match
)) {
290 mei_cldev_set_drvdata(cldev
, comp_master
);
291 ret
= component_master_add_with_match(&cldev
->dev
,
292 &mei_component_master_ops
,
295 dev_err(&cldev
->dev
, "Master comp add failed %d\n", ret
);
302 mei_cldev_set_drvdata(cldev
, NULL
);
304 mei_cldev_disable(cldev
);
309 static void mei_pxp_remove(struct mei_cl_device
*cldev
)
311 struct i915_pxp_component
*comp_master
= mei_cldev_get_drvdata(cldev
);
314 component_master_del(&cldev
->dev
, &mei_component_master_ops
);
316 mei_cldev_set_drvdata(cldev
, NULL
);
318 ret
= mei_cldev_disable(cldev
);
320 dev_warn(&cldev
->dev
, "mei_cldev_disable() failed\n");
323 /* fbf6fcf1-96cf-4e2e-a6a6-1bab8cbe36b1 : PAVP GUID*/
324 #define MEI_GUID_PXP UUID_LE(0xfbf6fcf1, 0x96cf, 0x4e2e, 0xA6, \
325 0xa6, 0x1b, 0xab, 0x8c, 0xbe, 0x36, 0xb1)
327 static struct mei_cl_device_id mei_pxp_tbl
[] = {
328 { .uuid
= MEI_GUID_PXP
, .version
= MEI_CL_VERSION_ANY
},
331 MODULE_DEVICE_TABLE(mei
, mei_pxp_tbl
);
333 static struct mei_cl_driver mei_pxp_driver
= {
334 .id_table
= mei_pxp_tbl
,
335 .name
= KBUILD_MODNAME
,
336 .probe
= mei_pxp_probe
,
337 .remove
= mei_pxp_remove
,
340 module_mei_cl_driver(mei_pxp_driver
);
342 MODULE_AUTHOR("Intel Corporation");
343 MODULE_LICENSE("GPL");
344 MODULE_DESCRIPTION("MEI PXP");