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 #define INTEL_LB_CMD 0x12 63 #define INTEL_LB_RSP (INTEL_LB_CMD | 0x80) 64 65 #define INTEL_LB_SEND_TIMEOUT_MSEC 3000 66 #define INTEL_LB_RECV_TIMEOUT_MSEC 3000 67 68 /** 69 * struct mei_lb_req - Late Binding request structure 70 * @header: MKHI message header (see struct mkhi_msg_hdr) 71 * @type: Type of the Late Binding payload 72 * @flags: Flags to be passed to the authentication firmware (e.g. %INTEL_LB_FLAGS_IS_PERSISTENT) 73 * @reserved: Reserved for future use by authentication firmware, must be set to 0 74 * @payload_size: Size of the payload data in bytes 75 * @payload: Payload data to be sent to the authentication firmware 76 */ 77 struct mei_lb_req { 78 struct mkhi_msg_hdr header; 79 __le32 type; 80 __le32 flags; 81 __le32 reserved[2]; 82 __le32 payload_size; 83 u8 payload[] __counted_by(payload_size); 84 } __packed; 85 86 /** 87 * struct mei_lb_rsp - Late Binding response structure 88 * @header: MKHI message header (see struct mkhi_msg_hdr) 89 * @type: Type of the Late Binding payload 90 * @reserved: Reserved for future use by authentication firmware, must be set to 0 91 * @status: Status returned by authentication firmware (see &enum intel_lb_status) 92 */ 93 struct mei_lb_rsp { 94 struct mkhi_msg_hdr header; 95 __le32 type; 96 __le32 reserved[2]; 97 __le32 status; 98 } __packed; 99 100 static bool mei_lb_check_response(const struct device *dev, ssize_t bytes, 101 struct mei_lb_rsp *rsp) 102 { 103 /* 104 * Received message size may be smaller than the full message size when 105 * reply contains only MKHI header with result field set to the error code. 106 * Check the header size and content first to output exact error, if needed, 107 * and then process to the whole message. 108 */ 109 if (bytes < sizeof(rsp->header)) { 110 dev_err(dev, "Received less than header size from the firmware: %zd < %zu\n", 111 bytes, sizeof(rsp->header)); 112 return false; 113 } 114 if (rsp->header.group_id != MKHI_GROUP_ID_GFX) { 115 dev_err(dev, "Mismatch group id: 0x%x instead of 0x%x\n", 116 rsp->header.group_id, MKHI_GROUP_ID_GFX); 117 return false; 118 } 119 if (rsp->header.command != INTEL_LB_RSP) { 120 dev_err(dev, "Mismatch command: 0x%x instead of 0x%x\n", 121 rsp->header.command, INTEL_LB_RSP); 122 return false; 123 } 124 if (rsp->header.result) { 125 dev_err(dev, "Error in result: 0x%x\n", rsp->header.result); 126 return false; 127 } 128 if (bytes < sizeof(*rsp)) { 129 dev_err(dev, "Received less than message size from the firmware: %zd < %zu\n", 130 bytes, sizeof(*rsp)); 131 return false; 132 } 133 134 return true; 135 } 136 137 static int mei_lb_push_payload(struct device *dev, u32 type, u32 flags, 138 const void *payload, size_t payload_size) 139 { 140 struct mei_cl_device *cldev; 141 struct mei_lb_req *req = NULL; 142 struct mei_lb_rsp rsp; 143 size_t req_size; 144 ssize_t bytes; 145 int ret; 146 147 cldev = to_mei_cl_device(dev); 148 149 ret = mei_cldev_enable(cldev); 150 if (ret) { 151 dev_dbg(dev, "Failed to enable firmware client. %d\n", ret); 152 return ret; 153 } 154 155 req_size = struct_size(req, payload, payload_size); 156 if (req_size > mei_cldev_mtu(cldev)) { 157 dev_err(dev, "Payload is too big: %zu\n", payload_size); 158 ret = -EMSGSIZE; 159 goto end; 160 } 161 162 req = kmalloc(req_size, GFP_KERNEL); 163 if (!req) { 164 ret = -ENOMEM; 165 goto end; 166 } 167 168 req->header.group_id = MKHI_GROUP_ID_GFX; 169 req->header.command = INTEL_LB_CMD; 170 req->type = cpu_to_le32(type); 171 req->flags = cpu_to_le32(flags); 172 req->reserved[0] = 0; 173 req->reserved[1] = 0; 174 req->payload_size = cpu_to_le32(payload_size); 175 memcpy(req->payload, payload, payload_size); 176 177 bytes = mei_cldev_send_timeout(cldev, (u8 *)req, req_size, 178 INTEL_LB_SEND_TIMEOUT_MSEC); 179 if (bytes < 0) { 180 dev_err(dev, "Failed to send late binding request to firmware. %zd\n", bytes); 181 ret = bytes; 182 goto end; 183 } 184 185 bytes = mei_cldev_recv_timeout(cldev, (u8 *)&rsp, sizeof(rsp), 186 INTEL_LB_RECV_TIMEOUT_MSEC); 187 if (bytes < 0) { 188 dev_err(dev, "Failed to receive late binding reply from MEI firmware. %zd\n", 189 bytes); 190 ret = bytes; 191 goto end; 192 } 193 if (!mei_lb_check_response(dev, bytes, &rsp)) { 194 dev_err(dev, "Bad response from the firmware. header: %02x %02x %02x %02x\n", 195 rsp.header.group_id, rsp.header.command, 196 rsp.header.reserved, rsp.header.result); 197 ret = -EPROTO; 198 goto end; 199 } 200 201 dev_dbg(dev, "status = %u\n", le32_to_cpu(rsp.status)); 202 ret = (int)le32_to_cpu(rsp.status); 203 end: 204 mei_cldev_disable(cldev); 205 kfree(req); 206 return ret; 207 } 208 209 static const struct intel_lb_component_ops mei_lb_ops = { 210 .push_payload = mei_lb_push_payload, 211 }; 212 213 static int mei_lb_component_master_bind(struct device *dev) 214 { 215 return component_bind_all(dev, (void *)&mei_lb_ops); 216 } 217 218 static void mei_lb_component_master_unbind(struct device *dev) 219 { 220 component_unbind_all(dev, (void *)&mei_lb_ops); 221 } 222 223 static const struct component_master_ops mei_lb_component_master_ops = { 224 .bind = mei_lb_component_master_bind, 225 .unbind = mei_lb_component_master_unbind, 226 }; 227 228 static int mei_lb_component_match(struct device *dev, int subcomponent, 229 void *data) 230 { 231 /* 232 * This function checks if requester is Intel %PCI_CLASS_DISPLAY_VGA or 233 * %PCI_CLASS_DISPLAY_OTHER device, and checks if the requester is the 234 * grand parent of mei_if i.e. late bind MEI device 235 */ 236 struct device *base = data; 237 struct pci_dev *pdev; 238 239 if (!dev) 240 return 0; 241 242 if (!dev_is_pci(dev)) 243 return 0; 244 245 pdev = to_pci_dev(dev); 246 247 if (pdev->vendor != PCI_VENDOR_ID_INTEL) 248 return 0; 249 250 if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) && 251 pdev->class != (PCI_CLASS_DISPLAY_OTHER << 8)) 252 return 0; 253 254 if (subcomponent != INTEL_COMPONENT_LB) 255 return 0; 256 257 base = base->parent; 258 if (!base) /* mei device */ 259 return 0; 260 261 base = base->parent; /* pci device */ 262 263 return !!base && dev == base; 264 } 265 266 static int mei_lb_probe(struct mei_cl_device *cldev, 267 const struct mei_cl_device_id *id) 268 { 269 struct component_match *master_match = NULL; 270 int ret; 271 272 component_match_add_typed(&cldev->dev, &master_match, 273 mei_lb_component_match, &cldev->dev); 274 if (IS_ERR_OR_NULL(master_match)) 275 return -ENOMEM; 276 277 ret = component_master_add_with_match(&cldev->dev, 278 &mei_lb_component_master_ops, 279 master_match); 280 if (ret < 0) 281 dev_err(&cldev->dev, "Failed to add late binding master component. %d\n", ret); 282 283 return ret; 284 } 285 286 static void mei_lb_remove(struct mei_cl_device *cldev) 287 { 288 component_master_del(&cldev->dev, &mei_lb_component_master_ops); 289 } 290 291 #define MEI_GUID_MKHI UUID_LE(0xe2c2afa2, 0x3817, 0x4d19, \ 292 0x9d, 0x95, 0x6, 0xb1, 0x6b, 0x58, 0x8a, 0x5d) 293 294 static const struct mei_cl_device_id mei_lb_tbl[] = { 295 { .uuid = MEI_GUID_MKHI, .version = MEI_CL_VERSION_ANY }, 296 { } 297 }; 298 MODULE_DEVICE_TABLE(mei, mei_lb_tbl); 299 300 static struct mei_cl_driver mei_lb_driver = { 301 .id_table = mei_lb_tbl, 302 .name = "mei_lb", 303 .probe = mei_lb_probe, 304 .remove = mei_lb_remove, 305 }; 306 307 module_mei_cl_driver(mei_lb_driver); 308 309 MODULE_AUTHOR("Intel Corporation"); 310 MODULE_LICENSE("GPL"); 311 MODULE_DESCRIPTION("MEI Late Binding Firmware Update/Upload"); 312