Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 505 lines 15 kB view raw
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");