Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 */
82struct 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 */
98struct 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 */
120struct 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 */
131struct 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 */
149struct 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 */
165struct mei_lb2_rsp {
166 struct mei_lb2_rsp_header rheader;
167 __le32 type;
168 __le32 reserved[2];
169};
170
171static 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
208static 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);
265end:
266 kfree(req);
267 return ret;
268}
269
270static 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
306static 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
369static 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
390static const struct intel_lb_component_ops mei_lb_ops = {
391 .push_payload = mei_lb_push_payload,
392};
393
394static int mei_lb_component_master_bind(struct device *dev)
395{
396 return component_bind_all(dev, (void *)&mei_lb_ops);
397}
398
399static void mei_lb_component_master_unbind(struct device *dev)
400{
401 component_unbind_all(dev, (void *)&mei_lb_ops);
402}
403
404static 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
409static 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
462static 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
482static void mei_lb_remove(struct mei_cl_device *cldev)
483{
484 component_master_del(&cldev->dev, &mei_lb_component_master_ops);
485}
486
487static 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};
492MODULE_DEVICE_TABLE(mei, mei_lb_tbl);
493
494static 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
501module_mei_cl_driver(mei_lb_driver);
502
503MODULE_AUTHOR("Intel Corporation");
504MODULE_LICENSE("GPL");
505MODULE_DESCRIPTION("MEI Late Binding Firmware Update/Upload");