xref: /linux/drivers/misc/mei/mei_lb.c (revision cb4eb6771c0f8fd1c52a8f6fdec7762fb087380a)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2025 Intel Corporation
4  */
5 
6 #include <linux/component.h>
7 #include <linux/mei_cl_bus.h>
8 #include <linux/module.h>
9 #include <linux/overflow.h>
10 #include <linux/pci.h>
11 #include <linux/slab.h>
12 #include <linux/uuid.h>
13 
14 #include <drm/intel/i915_component.h>
15 #include <drm/intel/intel_lb_mei_interface.h>
16 
17 #include "mkhi.h"
18 
19 /**
20  * DOC: Late Binding Firmware Update/Upload
21  *
22  * Late Binding is a firmware update/upload mechanism that allows configuration
23  * payloads to be securely delivered and applied at runtime, rather than
24  * being embedded in the system firmware image (e.g., IFWI or SPI flash).
25  *
26  * This mechanism is used to update device-level configuration such as:
27  * - Fan controller
28  * - Voltage regulator (VR)
29  *
30  * Key Characteristics:
31  * ---------------------
32  * - Runtime Delivery:
33  *   Firmware blobs are loaded by the host driver (e.g., Xe KMD)
34  *   after the GPU or SoC has booted.
35  *
36  * - Secure and Authenticated:
37  *   All payloads are signed and verified by the authentication firmware.
38  *
39  * - No Firmware Flashing Required:
40  *   Updates are applied in volatile memory and do not require SPI flash
41  *   modification or system reboot.
42  *
43  * - Re-entrant:
44  *   Multiple updates of the same or different types can be applied
45  *   sequentially within a single boot session.
46  *
47  * - Version Controlled:
48  *   Each payload includes version and security version number (SVN)
49  *   metadata to support anti-rollback enforcement.
50  *
51  * Upload Flow:
52  * ------------
53  * 1. Host driver (KMD or user-space tool) loads the late binding firmware.
54  * 2. Firmware is passed to the MEI interface and forwarded to
55  *    authentication firmware.
56  * 3. Authentication firmware authenticates the payload and extracts
57  *    command and data arrays.
58  * 4. Authentication firmware delivers the configuration to PUnit/PCODE.
59  * 5. Status is returned back to the host via MEI.
60  */
61 
62 /* Late Binding version 1 */
63 
64 #define INTEL_LB_CMD	0x12
65 #define INTEL_LB_RSP	(INTEL_LB_CMD | 0x80)
66 
67 #define INTEL_LB_SEND_TIMEOUT_MSEC 3000
68 #define INTEL_LB_RECV_TIMEOUT_MSEC 3000
69 
70 #define MEI_GUID_MKHI UUID_LE(0xe2c2afa2, 0x3817, 0x4d19, \
71 			      0x9d, 0x95, 0x6, 0xb1, 0x6b, 0x58, 0x8a, 0x5d)
72 
73 /**
74  * struct mei_lb_req - Late Binding request structure
75  * @header: MKHI message header (see struct mkhi_msg_hdr)
76  * @type: Type of the Late Binding payload
77  * @flags: Flags to be passed to the authentication firmware (e.g. %INTEL_LB_FLAGS_IS_PERSISTENT)
78  * @reserved: Reserved for future use by authentication firmware, must be set to 0
79  * @payload_size: Size of the payload data in bytes
80  * @payload: Payload data to be sent to the authentication firmware
81  */
82 struct mei_lb_req {
83 	struct mkhi_msg_hdr header;
84 	__le32 type;
85 	__le32 flags;
86 	__le32 reserved[2];
87 	__le32 payload_size;
88 	u8 payload[] __counted_by(payload_size);
89 } __packed;
90 
91 /**
92  * struct mei_lb_rsp - Late Binding response structure
93  * @header: MKHI message header (see struct mkhi_msg_hdr)
94  * @type: Type of the Late Binding payload
95  * @reserved: Reserved for future use by authentication firmware, must be set to 0
96  * @status: Status returned by authentication firmware (see &enum intel_lb_status)
97  */
98 struct mei_lb_rsp {
99 	struct mkhi_msg_hdr header;
100 	__le32 type;
101 	__le32 reserved[2];
102 	__le32 status;
103 } __packed;
104 
105 /* Late Binding version 2 */
106 
107 #define MEI_LB2_CMD 0x01
108 
109 #define MEI_LB2_HDR_FLAG_RSP 0x01
110 
111 #define MEI_GUID_LB UUID_LE(0x4ed87243, 0x3980, 0x4d8e, \
112 			    0xb1, 0xf9, 0x6f, 0xb7, 0xc0, 0x14, 0x8c, 0x4d)
113 
114 /**
115  * struct mei_lb2_header - Late Binding2 header
116  * @command_id:
117  * @flags: Flags for transport layer (e.g. MEI_LB2_HDR_FLAG_RSP)
118  * @reserved: Reserved for future use by authentication firmware, must be set to 0
119  */
120 struct mei_lb2_header {
121 	__le32 command_id;
122 	u8 flags;
123 	u8 reserved[3];
124 };
125 
126 /**
127  * struct mei_lb2_rsp_header - Late Binding2 response header
128  * @header: Common command header
129  * @status: Status returned by authentication firmware (see &enum intel_lb_status)
130  */
131 struct mei_lb2_rsp_header {
132 	struct mei_lb2_header header;
133 	__le32 status;
134 };
135 
136 #define MEI_LB2_FLAG_FST_CHUNK 0x02
137 #define MEI_LB2_FLAG_LST_CHUNK 0x04
138 
139 /**
140  * struct mei_lb2_req - Late Binding2 request
141  * @header: Common command header
142  * @type: Type of the Late Binding payload (see &enum intel_lb_type)
143  * @flags: Flags to be passed to the authentication firmware (MEI_LB2_FLAG_*)
144  * @reserved: Reserved for future use by authentication firmware, must be set to 0
145  * @total_payload_size: Size of whole Late Binding package in bytes
146  * @payload_size: Size of the payload chunk in bytes
147  * @payload: Data chunk to be sent to the authentication firmware
148  */
149 struct mei_lb2_req {
150 	struct mei_lb2_header header;
151 	__le32 type;
152 	__le32 flags;
153 	__le32 reserved;
154 	__le32 total_payload_size;
155 	__le32 payload_size;
156 	u8 payload[] __counted_by(payload_size);
157 };
158 
159 /**
160  * struct mei_lb2_rsp - Late Binding2 response
161  * @rheader: Common response header
162  * @type: Type of the Late Binding payload (see &enum intel_lb_type)
163  * @reserved: Reserved for future use by authentication firmware, must be set to 0
164  */
165 struct mei_lb2_rsp {
166 	struct mei_lb2_rsp_header rheader;
167 	__le32 type;
168 	__le32 reserved[2];
169 };
170 
mei_lb_check_response_v1(const struct device * dev,ssize_t bytes,struct mei_lb_rsp * rsp)171 static bool mei_lb_check_response_v1(const struct device *dev, ssize_t bytes,
172 				     struct mei_lb_rsp *rsp)
173 {
174 	/*
175 	 * Received message size may be smaller than the full message size when
176 	 * reply contains only MKHI header with result field set to the error code.
177 	 * Check the header size and content first to output exact error, if needed,
178 	 * and then process to the whole message.
179 	 */
180 	if (bytes < sizeof(rsp->header)) {
181 		dev_err(dev, "Received less than header size from the firmware: %zd < %zu\n",
182 			bytes, sizeof(rsp->header));
183 		return false;
184 	}
185 	if (rsp->header.group_id != MKHI_GROUP_ID_GFX) {
186 		dev_err(dev, "Mismatch group id: 0x%x instead of 0x%x\n",
187 			rsp->header.group_id, MKHI_GROUP_ID_GFX);
188 		return false;
189 	}
190 	if (rsp->header.command != INTEL_LB_RSP) {
191 		dev_err(dev, "Mismatch command: 0x%x instead of 0x%x\n",
192 			rsp->header.command, INTEL_LB_RSP);
193 		return false;
194 	}
195 	if (rsp->header.result) {
196 		dev_err(dev, "Error in result: 0x%x\n", rsp->header.result);
197 		return false;
198 	}
199 	if (bytes < sizeof(*rsp)) {
200 		dev_err(dev, "Received less than message size from the firmware: %zd < %zu\n",
201 			bytes, sizeof(*rsp));
202 		return false;
203 	}
204 
205 	return true;
206 }
207 
mei_lb_push_payload_v1(struct device * dev,struct mei_cl_device * cldev,u32 type,u32 flags,const void * payload,size_t payload_size)208 static int mei_lb_push_payload_v1(struct device *dev, struct mei_cl_device *cldev,
209 				  u32 type, u32 flags, const void *payload, size_t payload_size)
210 {
211 	struct mei_lb_req *req = NULL;
212 	struct mei_lb_rsp rsp;
213 	size_t req_size;
214 	ssize_t bytes;
215 	int ret;
216 
217 	req_size = struct_size(req, payload, payload_size);
218 	if (req_size > mei_cldev_mtu(cldev)) {
219 		dev_err(dev, "Payload is too big: %zu\n", payload_size);
220 		ret = -EMSGSIZE;
221 		goto end;
222 	}
223 
224 	req = kmalloc(req_size, GFP_KERNEL);
225 	if (!req) {
226 		ret = -ENOMEM;
227 		goto end;
228 	}
229 
230 	req->header.group_id = MKHI_GROUP_ID_GFX;
231 	req->header.command = INTEL_LB_CMD;
232 	req->type = cpu_to_le32(type);
233 	req->flags = cpu_to_le32(flags);
234 	req->reserved[0] = 0;
235 	req->reserved[1] = 0;
236 	req->payload_size = cpu_to_le32(payload_size);
237 	memcpy(req->payload, payload, payload_size);
238 
239 	bytes = mei_cldev_send_timeout(cldev, (u8 *)req, req_size,
240 				       INTEL_LB_SEND_TIMEOUT_MSEC);
241 	if (bytes < 0) {
242 		dev_err(dev, "Failed to send late binding request to firmware. %zd\n", bytes);
243 		ret = bytes;
244 		goto end;
245 	}
246 
247 	bytes = mei_cldev_recv_timeout(cldev, (u8 *)&rsp, sizeof(rsp),
248 				       INTEL_LB_RECV_TIMEOUT_MSEC);
249 	if (bytes < 0) {
250 		dev_err(dev, "Failed to receive late binding reply from MEI firmware. %zd\n",
251 			bytes);
252 		ret = bytes;
253 		goto end;
254 	}
255 	if (!mei_lb_check_response_v1(dev, bytes, &rsp)) {
256 		dev_err(dev, "Bad response from the firmware. header: %02x %02x %02x %02x\n",
257 			rsp.header.group_id, rsp.header.command,
258 			rsp.header.reserved, rsp.header.result);
259 		ret = -EPROTO;
260 		goto end;
261 	}
262 
263 	dev_dbg(dev, "status = %u\n", le32_to_cpu(rsp.status));
264 	ret = (int)le32_to_cpu(rsp.status);
265 end:
266 	kfree(req);
267 	return ret;
268 }
269 
mei_lb_check_response_v2(const struct device * dev,ssize_t bytes,struct mei_lb2_rsp * rsp)270 static int mei_lb_check_response_v2(const struct device *dev, ssize_t bytes,
271 				    struct mei_lb2_rsp *rsp)
272 {
273 	/*
274 	 * Received message size may be smaller than the full message size when
275 	 * reply contains only header with status field set to the error code.
276 	 * Check the header size and content first to output exact error, if needed,
277 	 * and then process to the whole message.
278 	 */
279 	if (bytes < sizeof(rsp->rheader)) {
280 		dev_err(dev, "Received less than header size from the firmware: %zd < %zu\n",
281 			bytes, sizeof(rsp->rheader));
282 		return -ENOMSG;
283 	}
284 	if (rsp->rheader.header.command_id != MEI_LB2_CMD) {
285 		dev_err(dev, "Mismatch command: 0x%x instead of 0x%x\n",
286 			rsp->rheader.header.command_id, MEI_LB2_CMD);
287 		return -EPROTO;
288 	}
289 	if (!(rsp->rheader.header.flags & MEI_LB2_HDR_FLAG_RSP)) {
290 		dev_err(dev, "Not a response: 0x%x\n", rsp->rheader.header.flags);
291 		return -EBADMSG;
292 	}
293 	if (rsp->rheader.status) {
294 		dev_err(dev, "Error in result: 0x%x\n", rsp->rheader.status);
295 		return (int)le32_to_cpu(rsp->rheader.status);
296 	}
297 	if (bytes < sizeof(*rsp)) {
298 		dev_err(dev, "Received less than message size from the firmware: %zd < %zu\n",
299 			bytes, sizeof(*rsp));
300 		return -ENODATA;
301 	}
302 
303 	return 0;
304 }
305 
mei_lb_push_payload_v2(struct device * dev,struct mei_cl_device * cldev,u32 type,u32 flags,const void * payload,size_t payload_size)306 static int mei_lb_push_payload_v2(struct device *dev, struct mei_cl_device *cldev,
307 				  u32 type, u32 flags, const void *payload, size_t payload_size)
308 {
309 	u32 first_chunk, last_chunk;
310 	struct mei_lb2_rsp rsp;
311 	size_t sent_data = 0;
312 	size_t chunk_size;
313 	size_t req_size;
314 	ssize_t bytes;
315 	int ret;
316 
317 	struct mei_lb2_req *req __free(kfree) = kzalloc(mei_cldev_mtu(cldev), GFP_KERNEL);
318 	if (!req)
319 		return -ENOMEM;
320 
321 	first_chunk = MEI_LB2_FLAG_FST_CHUNK;
322 	last_chunk = 0;
323 	do {
324 		chunk_size = min(payload_size - sent_data, mei_cldev_mtu(cldev) - sizeof(*req));
325 
326 		req_size = struct_size(req, payload, chunk_size);
327 		if (sent_data + chunk_size == payload_size)
328 			last_chunk = MEI_LB2_FLAG_LST_CHUNK;
329 
330 		req->header.command_id = MEI_LB2_CMD;
331 		req->type = cpu_to_le32(type);
332 		req->flags = cpu_to_le32(flags | first_chunk | last_chunk);
333 		req->reserved = 0;
334 		req->total_payload_size = cpu_to_le32(payload_size);
335 		req->payload_size = cpu_to_le32(chunk_size);
336 		memcpy(req->payload, payload + sent_data, chunk_size);
337 
338 		dev_dbg(dev, "Sending %zu bytes from offset %zu of %zu%s%s\n",
339 			chunk_size, sent_data, payload_size,
340 			first_chunk ? " first" : "", last_chunk ? " last" : "");
341 
342 		bytes = mei_cldev_send_timeout(cldev, (u8 *)req, req_size,
343 					       INTEL_LB_SEND_TIMEOUT_MSEC);
344 		if (bytes < 0) {
345 			dev_err(dev, "Failed to send late binding request to firmware. %zd\n",
346 				bytes);
347 			return bytes;
348 		}
349 
350 		bytes = mei_cldev_recv_timeout(cldev, (u8 *)&rsp, sizeof(rsp),
351 					       INTEL_LB_RECV_TIMEOUT_MSEC);
352 		if (bytes < 0) {
353 			dev_err(dev, "Failed to receive late binding reply from firmware. %zd\n",
354 				bytes);
355 			return bytes;
356 		}
357 		ret = mei_lb_check_response_v2(dev, bytes, &rsp);
358 		if (ret)
359 			return ret;
360 
361 		/* prepare for the next chunk */
362 		sent_data += chunk_size;
363 		first_chunk = 0;
364 	} while (!last_chunk);
365 
366 	return 0;
367 }
368 
mei_lb_push_payload(struct device * dev,u32 type,u32 flags,const void * payload,size_t payload_size)369 static int mei_lb_push_payload(struct device *dev, u32 type, u32 flags,
370 			       const void *payload, size_t payload_size)
371 {
372 	struct mei_cl_device *cldev = to_mei_cl_device(dev);
373 	int ret;
374 
375 	ret = mei_cldev_enable(cldev);
376 	if (ret) {
377 		dev_dbg(dev, "Failed to enable firmware client. %d\n", ret);
378 		return ret;
379 	}
380 
381 	if (memcmp(&MEI_GUID_LB, mei_cldev_uuid(cldev), sizeof(uuid_le)) == 0)
382 		ret = mei_lb_push_payload_v2(dev, cldev, type, flags, payload, payload_size);
383 	else
384 		ret = mei_lb_push_payload_v1(dev, cldev, type, flags, payload, payload_size);
385 
386 	mei_cldev_disable(cldev);
387 	return ret;
388 }
389 
390 static const struct intel_lb_component_ops mei_lb_ops = {
391 	.push_payload = mei_lb_push_payload,
392 };
393 
mei_lb_component_master_bind(struct device * dev)394 static int mei_lb_component_master_bind(struct device *dev)
395 {
396 	return component_bind_all(dev, (void *)&mei_lb_ops);
397 }
398 
mei_lb_component_master_unbind(struct device * dev)399 static void mei_lb_component_master_unbind(struct device *dev)
400 {
401 	component_unbind_all(dev, (void *)&mei_lb_ops);
402 }
403 
404 static const struct component_master_ops mei_lb_component_master_ops = {
405 	.bind = mei_lb_component_master_bind,
406 	.unbind = mei_lb_component_master_unbind,
407 };
408 
mei_lb_component_match(struct device * dev,int subcomponent,void * data)409 static int mei_lb_component_match(struct device *dev, int subcomponent,
410 				  void *data)
411 {
412 	/*
413 	 * This function checks if requester is Intel vendor,
414 	 * determines if MEI is standalone PCI device or the auxiliary one
415 	 * and checks the following:
416 	 * 0) PCI parent: (e.g. /sys/class/mei/mei0/device -> ../../../0000:15:00.0)
417 	 *  the requester and MEI device has the same grand parent
418 	 * 1) Auxiliary parent: (e.g. /sys/class/mei/mei1/device -> ../../../xe.mei-gscfi.768)
419 	 *  the requester is the parent of MEI device
420 	 */
421 	struct device *base = data;
422 	struct device *basep = dev;
423 	struct pci_dev *pdev;
424 
425 	if (!dev)
426 		return 0;
427 
428 	if (!dev_is_pci(dev))
429 		return 0;
430 
431 	pdev = to_pci_dev(dev);
432 
433 	if (pdev->vendor != PCI_VENDOR_ID_INTEL)
434 		return 0;
435 
436 	if (subcomponent != INTEL_COMPONENT_LB)
437 		return 0;
438 
439 	base = base->parent;
440 	if (!base) /* MEI device */
441 		return 0;
442 
443 	if (dev_is_pci(base)) {
444 		/* case 0) PCI parent */
445 		base = base->parent; /* bridge 1 */
446 		if (!base)
447 			return 0;
448 		base = base->parent; /* bridge 2 */
449 
450 		basep = basep->parent; /* bridge 1 */
451 		if (!basep)
452 			return 0;
453 		basep = basep->parent; /* bridge 2 */
454 	} else {
455 		/* case 1) Auxiliary parent */
456 		base = base->parent; /* PCI device */
457 	}
458 
459 	return !!base && !!basep && base == basep;
460 }
461 
mei_lb_probe(struct mei_cl_device * cldev,const struct mei_cl_device_id * id)462 static int mei_lb_probe(struct mei_cl_device *cldev,
463 			const struct mei_cl_device_id *id)
464 {
465 	struct component_match *master_match = NULL;
466 	int ret;
467 
468 	component_match_add_typed(&cldev->dev, &master_match,
469 				  mei_lb_component_match, &cldev->dev);
470 	if (IS_ERR_OR_NULL(master_match))
471 		return -ENOMEM;
472 
473 	ret = component_master_add_with_match(&cldev->dev,
474 					      &mei_lb_component_master_ops,
475 					      master_match);
476 	if (ret < 0)
477 		dev_err(&cldev->dev, "Failed to add late binding master component. %d\n", ret);
478 
479 	return ret;
480 }
481 
mei_lb_remove(struct mei_cl_device * cldev)482 static void mei_lb_remove(struct mei_cl_device *cldev)
483 {
484 	component_master_del(&cldev->dev, &mei_lb_component_master_ops);
485 }
486 
487 static const struct mei_cl_device_id mei_lb_tbl[] = {
488 	{ .uuid = MEI_GUID_MKHI, .version = 1 },
489 	{ .uuid = MEI_GUID_LB, .version = MEI_CL_VERSION_ANY },
490 	{ }
491 };
492 MODULE_DEVICE_TABLE(mei, mei_lb_tbl);
493 
494 static struct mei_cl_driver mei_lb_driver = {
495 	.id_table = mei_lb_tbl,
496 	.name = "mei_lb",
497 	.probe = mei_lb_probe,
498 	.remove	= mei_lb_remove,
499 };
500 
501 module_mei_cl_driver(mei_lb_driver);
502 
503 MODULE_AUTHOR("Intel Corporation");
504 MODULE_LICENSE("GPL");
505 MODULE_DESCRIPTION("MEI Late Binding Firmware Update/Upload");
506