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.

mei: lb: add late binding version 2

The second Late Binding version allows to send payload bigger
than client MTU by splitting it to chunks and uses separate
firmware client for transfer.

The component interface is unchanged and driver doing all splitting.

Only one Late Binding version is supported by firmware.
When Late binding version 2 is supported, the new client is advertised
by firmware and existing MKHI will have version 2.
This helps driver to select the right mode of work.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Badal Nilawar <badal.nilawar@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Link: https://patch.msgid.link/20260405112326.1535208-3-alexander.usyskin@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alexander Usyskin and committed by
Greg Kroah-Hartman
773a43b8 3031b76d

+265 -38
+223 -29
drivers/misc/mei/mei_lb.c
··· 59 59 * 5. Status is returned back to the host via MEI. 60 60 */ 61 61 62 + /* Late Binding version 1 */ 63 + 62 64 #define INTEL_LB_CMD 0x12 63 65 #define INTEL_LB_RSP (INTEL_LB_CMD | 0x80) 64 66 65 67 #define INTEL_LB_SEND_TIMEOUT_MSEC 3000 66 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) 67 72 68 73 /** 69 74 * struct mei_lb_req - Late Binding request structure ··· 102 97 __le32 status; 103 98 } __packed; 104 99 105 - static bool mei_lb_check_response(const struct device *dev, ssize_t bytes, 106 - struct mei_lb_rsp *rsp) 100 + /* Late Binding version 2 */ 101 + 102 + #define MEI_LB2_CMD 0x01 103 + 104 + #define MEI_LB2_HDR_FLAG_RSP 0x01 105 + 106 + #define MEI_GUID_LB UUID_LE(0x4ed87243, 0x3980, 0x4d8e, \ 107 + 0xb1, 0xf9, 0x6f, 0xb7, 0xc0, 0x14, 0x8c, 0x4d) 108 + 109 + /** 110 + * struct mei_lb2_header - Late Binding2 header 111 + * @command_id: 112 + * @flags: Flags for transport layer (e.g. MEI_LB2_HDR_FLAG_RSP) 113 + * @reserved: Reserved for future use by authentication firmware, must be set to 0 114 + */ 115 + struct mei_lb2_header { 116 + __le32 command_id; 117 + u8 flags; 118 + u8 reserved[3]; 119 + }; 120 + 121 + /** 122 + * struct mei_lb2_rsp_header - Late Binding2 response header 123 + * @header: Common command header 124 + * @status: Status returned by authentication firmware (see &enum intel_lb_status) 125 + */ 126 + struct mei_lb2_rsp_header { 127 + struct mei_lb2_header header; 128 + __le32 status; 129 + }; 130 + 131 + #define MEI_LB2_FLAG_FST_CHUNK 0x02 132 + #define MEI_LB2_FLAG_LST_CHUNK 0x04 133 + 134 + /** 135 + * struct mei_lb2_req - Late Binding2 request 136 + * @header: Common command header 137 + * @type: Type of the Late Binding payload (see &enum intel_lb_type) 138 + * @flags: Flags to be passed to the authentication firmware (MEI_LB2_FLAG_*) 139 + * @reserved: Reserved for future use by authentication firmware, must be set to 0 140 + * @total_payload_size: Size of whole Late Binding package in bytes 141 + * @payload_size: Size of the payload chunk in bytes 142 + * @payload: Data chunk to be sent to the authentication firmware 143 + */ 144 + struct mei_lb2_req { 145 + struct mei_lb2_header header; 146 + __le32 type; 147 + __le32 flags; 148 + __le32 reserved; 149 + __le32 total_payload_size; 150 + __le32 payload_size; 151 + u8 payload[] __counted_by(payload_size); 152 + }; 153 + 154 + /** 155 + * struct mei_lb2_rsp - Late Binding2 response 156 + * @rheader: Common response header 157 + * @type: Type of the Late Binding payload (see &enum intel_lb_type) 158 + * @reserved: Reserved for future use by authentication firmware, must be set to 0 159 + */ 160 + struct mei_lb2_rsp { 161 + struct mei_lb2_rsp_header rheader; 162 + __le32 type; 163 + __le32 reserved[2]; 164 + }; 165 + 166 + static bool mei_lb_check_response_v1(const struct device *dev, ssize_t bytes, 167 + struct mei_lb_rsp *rsp) 107 168 { 108 169 /* 109 170 * Received message size may be smaller than the full message size when ··· 205 134 return true; 206 135 } 207 136 208 - static int mei_lb_push_payload(struct device *dev, u32 type, u32 flags, 209 - const void *payload, size_t payload_size) 137 + static int mei_lb_push_payload_v1(struct device *dev, struct mei_cl_device *cldev, 138 + u32 type, u32 flags, const void *payload, size_t payload_size) 210 139 { 211 - struct mei_cl_device *cldev; 212 140 struct mei_lb_req *req = NULL; 213 141 struct mei_lb_rsp rsp; 214 142 size_t req_size; 215 143 ssize_t bytes; 216 144 int ret; 217 - 218 - cldev = to_mei_cl_device(dev); 219 - 220 - ret = mei_cldev_enable(cldev); 221 - if (ret) { 222 - dev_dbg(dev, "Failed to enable firmware client. %d\n", ret); 223 - return ret; 224 - } 225 145 226 146 req_size = struct_size(req, payload, payload_size); 227 147 if (req_size > mei_cldev_mtu(cldev)) { ··· 252 190 ret = bytes; 253 191 goto end; 254 192 } 255 - if (!mei_lb_check_response(dev, bytes, &rsp)) { 193 + if (!mei_lb_check_response_v1(dev, bytes, &rsp)) { 256 194 dev_err(dev, "Bad response from the firmware. header: %02x %02x %02x %02x\n", 257 195 rsp.header.group_id, rsp.header.command, 258 196 rsp.header.reserved, rsp.header.result); ··· 263 201 dev_dbg(dev, "status = %u\n", le32_to_cpu(rsp.status)); 264 202 ret = (int)le32_to_cpu(rsp.status); 265 203 end: 266 - mei_cldev_disable(cldev); 267 204 kfree(req); 205 + return ret; 206 + } 207 + 208 + static int mei_lb_check_response_v2(const struct device *dev, ssize_t bytes, 209 + struct mei_lb2_rsp *rsp) 210 + { 211 + /* 212 + * Received message size may be smaller than the full message size when 213 + * reply contains only header with status field set to the error code. 214 + * Check the header size and content first to output exact error, if needed, 215 + * and then process to the whole message. 216 + */ 217 + if (bytes < sizeof(rsp->rheader)) { 218 + dev_err(dev, "Received less than header size from the firmware: %zd < %zu\n", 219 + bytes, sizeof(rsp->rheader)); 220 + return -ENOMSG; 221 + } 222 + if (rsp->rheader.header.command_id != MEI_LB2_CMD) { 223 + dev_err(dev, "Mismatch command: 0x%x instead of 0x%x\n", 224 + rsp->rheader.header.command_id, MEI_LB2_CMD); 225 + return -EPROTO; 226 + } 227 + if (!(rsp->rheader.header.flags & MEI_LB2_HDR_FLAG_RSP)) { 228 + dev_err(dev, "Not a response: 0x%x\n", rsp->rheader.header.flags); 229 + return -EBADMSG; 230 + } 231 + if (rsp->rheader.status) { 232 + dev_err(dev, "Error in result: 0x%x\n", rsp->rheader.status); 233 + return (int)le32_to_cpu(rsp->rheader.status); 234 + } 235 + if (bytes < sizeof(*rsp)) { 236 + dev_err(dev, "Received less than message size from the firmware: %zd < %zu\n", 237 + bytes, sizeof(*rsp)); 238 + return -ENODATA; 239 + } 240 + 241 + return 0; 242 + } 243 + 244 + static int mei_lb_push_payload_v2(struct device *dev, struct mei_cl_device *cldev, 245 + u32 type, u32 flags, const void *payload, size_t payload_size) 246 + { 247 + u32 first_chunk, last_chunk; 248 + struct mei_lb2_rsp rsp; 249 + size_t sent_data = 0; 250 + size_t chunk_size; 251 + size_t req_size; 252 + ssize_t bytes; 253 + int ret; 254 + 255 + struct mei_lb2_req *req __free(kfree) = kzalloc(mei_cldev_mtu(cldev), GFP_KERNEL); 256 + if (!req) 257 + return -ENOMEM; 258 + 259 + first_chunk = MEI_LB2_FLAG_FST_CHUNK; 260 + last_chunk = 0; 261 + do { 262 + chunk_size = min(payload_size - sent_data, mei_cldev_mtu(cldev) - sizeof(*req)); 263 + 264 + req_size = struct_size(req, payload, chunk_size); 265 + if (sent_data + chunk_size == payload_size) 266 + last_chunk = MEI_LB2_FLAG_LST_CHUNK; 267 + 268 + req->header.command_id = MEI_LB2_CMD; 269 + req->type = cpu_to_le32(type); 270 + req->flags = cpu_to_le32(flags | first_chunk | last_chunk); 271 + req->reserved = 0; 272 + req->total_payload_size = cpu_to_le32(payload_size); 273 + req->payload_size = cpu_to_le32(chunk_size); 274 + memcpy(req->payload, payload + sent_data, chunk_size); 275 + 276 + dev_dbg(dev, "Sending %zu bytes from offset %zu of %zu%s%s\n", 277 + chunk_size, sent_data, payload_size, 278 + first_chunk ? " first" : "", last_chunk ? " last" : ""); 279 + 280 + bytes = mei_cldev_send_timeout(cldev, (u8 *)req, req_size, 281 + INTEL_LB_SEND_TIMEOUT_MSEC); 282 + if (bytes < 0) { 283 + dev_err(dev, "Failed to send late binding request to firmware. %zd\n", 284 + bytes); 285 + return bytes; 286 + } 287 + 288 + bytes = mei_cldev_recv_timeout(cldev, (u8 *)&rsp, sizeof(rsp), 289 + INTEL_LB_RECV_TIMEOUT_MSEC); 290 + if (bytes < 0) { 291 + dev_err(dev, "Failed to receive late binding reply from firmware. %zd\n", 292 + bytes); 293 + return bytes; 294 + } 295 + ret = mei_lb_check_response_v2(dev, bytes, &rsp); 296 + if (ret) 297 + return ret; 298 + 299 + /* prepare for the next chunk */ 300 + sent_data += chunk_size; 301 + first_chunk = 0; 302 + } while (!last_chunk); 303 + 304 + return 0; 305 + } 306 + 307 + static int mei_lb_push_payload(struct device *dev, u32 type, u32 flags, 308 + const void *payload, size_t payload_size) 309 + { 310 + struct mei_cl_device *cldev = to_mei_cl_device(dev); 311 + int ret; 312 + 313 + ret = mei_cldev_enable(cldev); 314 + if (ret) { 315 + dev_dbg(dev, "Failed to enable firmware client. %d\n", ret); 316 + return ret; 317 + } 318 + 319 + if (memcmp(&MEI_GUID_LB, mei_cldev_uuid(cldev), sizeof(uuid_le)) == 0) 320 + ret = mei_lb_push_payload_v2(dev, cldev, type, flags, payload, payload_size); 321 + else 322 + ret = mei_lb_push_payload_v1(dev, cldev, type, flags, payload, payload_size); 323 + 324 + mei_cldev_disable(cldev); 268 325 return ret; 269 326 } 270 327 ··· 410 229 void *data) 411 230 { 412 231 /* 413 - * This function checks if requester is Intel %PCI_CLASS_DISPLAY_VGA or 414 - * %PCI_CLASS_DISPLAY_OTHER device, and checks if the requester is the 415 - * grand parent of mei_if i.e. late bind MEI device 232 + * This function checks if requester is Intel vendor, 233 + * determines if MEI is standalone PCI device or the auxiliary one 234 + * and checks the following: 235 + * 0) PCI parent: (e.g. /sys/class/mei/mei0/device -> ../../../0000:15:00.0) 236 + * the requester and MEI device has the same grand parent 237 + * 1) Auxiliary parent: (e.g. /sys/class/mei/mei1/device -> ../../../xe.mei-gscfi.768) 238 + * the requester is the parent of MEI device 416 239 */ 417 240 struct device *base = data; 241 + struct device *basep = dev; 418 242 struct pci_dev *pdev; 419 243 420 244 if (!dev) ··· 433 247 if (pdev->vendor != PCI_VENDOR_ID_INTEL) 434 248 return 0; 435 249 436 - if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) && 437 - pdev->class != (PCI_CLASS_DISPLAY_OTHER << 8)) 438 - return 0; 439 - 440 250 if (subcomponent != INTEL_COMPONENT_LB) 441 251 return 0; 442 252 443 253 base = base->parent; 444 - if (!base) /* mei device */ 254 + if (!base) /* MEI device */ 445 255 return 0; 446 256 447 - base = base->parent; /* pci device */ 257 + if (dev_is_pci(base)) { 258 + /* case 0) PCI parent */ 259 + base = base->parent; /* bridge 1 */ 260 + if (!base) 261 + return 0; 262 + base = base->parent; /* bridge 2 */ 448 263 449 - return !!base && dev == base; 264 + basep = basep->parent; /* bridge 1 */ 265 + if (!basep) 266 + return 0; 267 + basep = basep->parent; /* bridge 2 */ 268 + } else { 269 + /* case 1) Auxiliary parent */ 270 + base = base->parent; /* PCI device */ 271 + } 272 + 273 + return !!base && !!basep && base == basep; 450 274 } 451 275 452 276 static int mei_lb_probe(struct mei_cl_device *cldev, ··· 484 288 component_master_del(&cldev->dev, &mei_lb_component_master_ops); 485 289 } 486 290 487 - #define MEI_GUID_MKHI UUID_LE(0xe2c2afa2, 0x3817, 0x4d19, \ 488 - 0x9d, 0x95, 0x6, 0xb1, 0x6b, 0x58, 0x8a, 0x5d) 489 - 490 291 static const struct mei_cl_device_id mei_lb_tbl[] = { 491 - { .uuid = MEI_GUID_MKHI, .version = MEI_CL_VERSION_ANY }, 292 + { .uuid = MEI_GUID_MKHI, .version = 1 }, 293 + { .uuid = MEI_GUID_LB, .version = MEI_CL_VERSION_ANY }, 492 294 { } 493 295 }; 494 296 MODULE_DEVICE_TABLE(mei, mei_lb_tbl);
+42 -9
include/drm/intel/intel_lb_mei_interface.h
··· 6 6 #ifndef _INTEL_LB_MEI_INTERFACE_H_ 7 7 #define _INTEL_LB_MEI_INTERFACE_H_ 8 8 9 + #include <linux/bits.h> 9 10 #include <linux/types.h> 10 11 11 12 struct device; ··· 22 21 /** 23 22 * enum intel_lb_type - enum to determine late binding payload type 24 23 * @INTEL_LB_TYPE_FAN_CONTROL: Fan controller configuration 24 + * @INTEL_LB_TYPE_OCODE: Ocode firmware 25 25 */ 26 26 enum intel_lb_type { 27 27 INTEL_LB_TYPE_FAN_CONTROL = 1, 28 + INTEL_LB_TYPE_OCODE = 3, 28 29 }; 29 30 30 31 /** ··· 39 36 * @INTEL_LB_STATUS_INVALID_SIGNATURE: Payload has an invalid or untrusted signature 40 37 * @INTEL_LB_STATUS_INVALID_PAYLOAD: Payload contents are not accepted by firmware 41 38 * @INTEL_LB_STATUS_TIMEOUT: Operation timed out before completion 39 + * @INTEL_LB_STATUS_BUFFER_TOO_SMALL: Buffer provided is smaller when expected 40 + * @INTEL_LB_STATUS_INTERNAL_ERROR: Internal firmware error 41 + * @INTEL_LB_STATUS_INVALID_FPT_TABLE: Invalid firmware format table 42 + * @INTEL_LB_STATUS_SIGNED_PAYLOAD_VERIFICATION_ERROR: Error in signature verification 43 + * @INTEL_LB_STATUS_SIGNED_PAYLOAD_INVALID_CPD: Invalid CPD 44 + * @INTEL_LB_STATUS_SIGNED_PAYLOAD_FW_VERSION_MISMATCH: Firmware version mismatch 45 + * @INTEL_LB_STATUS_SIGNED_PAYLOAD_INVALID_MANIFEST: Invalid firmware manifest 46 + * @INTEL_LB_STATUS_SIGNED_PAYLOAD_INVALID_HASH: Wrong hash in signature 47 + * @INTEL_LB_STATUS_SIGNED_PAYLOAD_BINDING_TYPE_MISMATCH: Wrong firmware type provided 48 + * @INTEL_LB_STATUS_SIGNED_PAYLOAD_HANDLE_SVN_FAILED: SVN check failed 49 + * @INTEL_LB_STATUS_DESTINATION_MBOX_FAILURE: Failed to send datat to destination 50 + * @INTEL_LB_STATUS_MISSING_LOADING_PATCH: No loading patch found 51 + * @INTEL_LB_STATUS_INVALID_COMMAND: Invalid command number 52 + * @INTEL_LB_STATUS_INVALID_HECI_HEADER: Invalid transport header 53 + * @INTEL_LB_STATUS_IP_ERROR_START: Base for internal errors 42 54 */ 43 55 enum intel_lb_status { 44 - INTEL_LB_STATUS_SUCCESS = 0, 45 - INTEL_LB_STATUS_4ID_MISMATCH = 1, 46 - INTEL_LB_STATUS_ARB_FAILURE = 2, 47 - INTEL_LB_STATUS_GENERAL_ERROR = 3, 48 - INTEL_LB_STATUS_INVALID_PARAMS = 4, 49 - INTEL_LB_STATUS_INVALID_SIGNATURE = 5, 50 - INTEL_LB_STATUS_INVALID_PAYLOAD = 6, 51 - INTEL_LB_STATUS_TIMEOUT = 7, 56 + INTEL_LB_STATUS_SUCCESS = 0, 57 + INTEL_LB_STATUS_4ID_MISMATCH = 1, 58 + INTEL_LB_STATUS_ARB_FAILURE = 2, 59 + INTEL_LB_STATUS_GENERAL_ERROR = 3, 60 + INTEL_LB_STATUS_INVALID_PARAMS = 4, 61 + INTEL_LB_STATUS_INVALID_SIGNATURE = 5, 62 + INTEL_LB_STATUS_INVALID_PAYLOAD = 6, 63 + INTEL_LB_STATUS_TIMEOUT = 7, 64 + INTEL_LB_STATUS_BUFFER_TOO_SMALL = 8, 65 + INTEL_LB_STATUS_INTERNAL_ERROR = 9, 66 + INTEL_LB_STATUS_INVALID_FPT_TABLE = 10, 67 + INTEL_LB_STATUS_SIGNED_PAYLOAD_VERIFICATION_ERROR = 11, 68 + INTEL_LB_STATUS_SIGNED_PAYLOAD_INVALID_CPD = 12, 69 + INTEL_LB_STATUS_SIGNED_PAYLOAD_FW_VERSION_MISMATCH = 13, 70 + INTEL_LB_STATUS_SIGNED_PAYLOAD_INVALID_MANIFEST = 14, 71 + INTEL_LB_STATUS_SIGNED_PAYLOAD_INVALID_HASH = 15, 72 + INTEL_LB_STATUS_SIGNED_PAYLOAD_BINDING_TYPE_MISMATCH = 16, 73 + INTEL_LB_STATUS_SIGNED_PAYLOAD_HANDLE_SVN_FAILED = 17, 74 + INTEL_LB_STATUS_DESTINATION_MBOX_FAILURE = 18, 75 + INTEL_LB_STATUS_MISSING_LOADING_PATCH = 19, 76 + INTEL_LB_STATUS_INVALID_COMMAND = 20, 77 + INTEL_LB_STATUS_INVALID_HECI_HEADER = 21, 78 + INTEL_LB_STATUS_IP_ERROR_START = BIT(31), 52 79 }; 53 80 54 81 /** ··· 95 62 * @payload_size: Payload buffer size in bytes 96 63 * 97 64 * Return: 0 success, negative errno value on transport failure, 98 - * positive status returned by firmware 65 + * positive error status returned by firmware 99 66 */ 100 67 int (*push_payload)(struct device *dev, u32 type, u32 flags, 101 68 const void *payload, size_t payload_size);