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

drm/xe/xe_late_bind_fw: Extract and print version info

Extract and print version info of the late binding binary.

v2: Some refinements (Daniele)

Signed-off-by: Badal Nilawar <badal.nilawar@intel.com>
Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://lore.kernel.org/r/20250905154953.3974335-10-badal.nilawar@intel.com
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>

authored by

Badal Nilawar and committed by
Lucas De Marchi
efa29317 67de7982

+193
+124
drivers/gpu/drm/xe/xe_late_bind_fw.c
··· 45 45 return container_of(late_bind, struct xe_device, late_bind); 46 46 } 47 47 48 + static struct xe_device * 49 + late_bind_fw_to_xe(struct xe_late_bind_fw *lb_fw) 50 + { 51 + return container_of(lb_fw, struct xe_device, late_bind.late_bind_fw[lb_fw->id]); 52 + } 53 + 54 + /* Refer to the "Late Bind based Firmware Layout" documentation entry for details */ 55 + static int parse_cpd_header(struct xe_late_bind_fw *lb_fw, 56 + const void *data, size_t size, const char *manifest_entry) 57 + { 58 + struct xe_device *xe = late_bind_fw_to_xe(lb_fw); 59 + const struct gsc_cpd_header_v2 *header = data; 60 + const struct gsc_manifest_header *manifest; 61 + const struct gsc_cpd_entry *entry; 62 + size_t min_size = sizeof(*header); 63 + u32 offset; 64 + int i; 65 + 66 + /* manifest_entry is mandatory */ 67 + xe_assert(xe, manifest_entry); 68 + 69 + if (size < min_size || header->header_marker != GSC_CPD_HEADER_MARKER) 70 + return -ENOENT; 71 + 72 + if (header->header_length < sizeof(struct gsc_cpd_header_v2)) { 73 + drm_err(&xe->drm, "%s late binding fw: Invalid CPD header length %u!\n", 74 + fw_id_to_name[lb_fw->id], header->header_length); 75 + return -EINVAL; 76 + } 77 + 78 + min_size = header->header_length + sizeof(struct gsc_cpd_entry) * header->num_of_entries; 79 + if (size < min_size) { 80 + drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n", 81 + fw_id_to_name[lb_fw->id], size, min_size); 82 + return -ENODATA; 83 + } 84 + 85 + /* Look for the manifest first */ 86 + entry = (void *)header + header->header_length; 87 + for (i = 0; i < header->num_of_entries; i++, entry++) 88 + if (strcmp(entry->name, manifest_entry) == 0) 89 + offset = entry->offset & GSC_CPD_ENTRY_OFFSET_MASK; 90 + 91 + if (!offset) { 92 + drm_err(&xe->drm, "%s late binding fw: Failed to find manifest_entry\n", 93 + fw_id_to_name[lb_fw->id]); 94 + return -ENODATA; 95 + } 96 + 97 + min_size = offset + sizeof(struct gsc_manifest_header); 98 + if (size < min_size) { 99 + drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n", 100 + fw_id_to_name[lb_fw->id], size, min_size); 101 + return -ENODATA; 102 + } 103 + 104 + manifest = data + offset; 105 + 106 + lb_fw->version = manifest->fw_version; 107 + 108 + return 0; 109 + } 110 + 111 + /* Refer to the "Late Bind based Firmware Layout" documentation entry for details */ 112 + static int parse_lb_layout(struct xe_late_bind_fw *lb_fw, 113 + const void *data, size_t size, const char *fpt_entry) 114 + { 115 + struct xe_device *xe = late_bind_fw_to_xe(lb_fw); 116 + const struct csc_fpt_header *header = data; 117 + const struct csc_fpt_entry *entry; 118 + size_t min_size = sizeof(*header); 119 + u32 offset; 120 + int i; 121 + 122 + /* fpt_entry is mandatory */ 123 + xe_assert(xe, fpt_entry); 124 + 125 + if (size < min_size || header->header_marker != CSC_FPT_HEADER_MARKER) 126 + return -ENOENT; 127 + 128 + if (header->header_length < sizeof(struct csc_fpt_header)) { 129 + drm_err(&xe->drm, "%s late binding fw: Invalid FPT header length %u!\n", 130 + fw_id_to_name[lb_fw->id], header->header_length); 131 + return -EINVAL; 132 + } 133 + 134 + min_size = header->header_length + sizeof(struct csc_fpt_entry) * header->num_of_entries; 135 + if (size < min_size) { 136 + drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n", 137 + fw_id_to_name[lb_fw->id], size, min_size); 138 + return -ENODATA; 139 + } 140 + 141 + /* Look for the cpd header first */ 142 + entry = (void *)header + header->header_length; 143 + for (i = 0; i < header->num_of_entries; i++, entry++) 144 + if (strcmp(entry->name, fpt_entry) == 0) 145 + offset = entry->offset; 146 + 147 + if (!offset) { 148 + drm_err(&xe->drm, "%s late binding fw: Failed to find fpt_entry\n", 149 + fw_id_to_name[lb_fw->id]); 150 + return -ENODATA; 151 + } 152 + 153 + min_size = offset + sizeof(struct gsc_cpd_header_v2); 154 + if (size < min_size) { 155 + drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n", 156 + fw_id_to_name[lb_fw->id], size, min_size); 157 + return -ENODATA; 158 + } 159 + 160 + return parse_cpd_header(lb_fw, data + offset, size - offset, "LTES.man"); 161 + } 162 + 48 163 static const char *xe_late_bind_parse_status(uint32_t status) 49 164 { 50 165 switch (status) { ··· 339 224 return -ENODATA; 340 225 } 341 226 227 + ret = parse_lb_layout(lb_fw, fw->data, fw->size, "LTES"); 228 + if (ret) 229 + return ret; 230 + 342 231 lb_fw->payload_size = fw->size; 343 232 lb_fw->payload = drmm_kzalloc(&xe->drm, lb_fw->payload_size, GFP_KERNEL); 344 233 if (!lb_fw->payload) { 345 234 release_firmware(fw); 346 235 return -ENOMEM; 347 236 } 237 + 238 + drm_info(&xe->drm, "Using %s firmware from %s version %u.%u.%u.%u\n", 239 + fw_id_to_name[lb_fw->id], lb_fw->blob_path, 240 + lb_fw->version.major, lb_fw->version.minor, 241 + lb_fw->version.hotfix, lb_fw->version.build); 348 242 349 243 memcpy((void *)lb_fw->payload, fw->data, lb_fw->payload_size); 350 244 release_firmware(fw);
+3
drivers/gpu/drm/xe/xe_late_bind_fw_types.h
··· 10 10 #include <linux/mutex.h> 11 11 #include <linux/types.h> 12 12 #include <linux/workqueue.h> 13 + #include "xe_uc_fw_abi.h" 13 14 14 15 #define XE_LB_MAX_PAYLOAD_SIZE SZ_4K 15 16 ··· 40 39 size_t payload_size; 41 40 /** @work: worker to upload latebind blob */ 42 41 struct work_struct work; 42 + /** @version: late binding blob manifest version */ 43 + struct gsc_version version; 43 44 }; 44 45 45 46 /**
+66
drivers/gpu/drm/xe/xe_uc_fw_abi.h
··· 336 336 u32 exponent_size; /* in dwords */ 337 337 } __packed; 338 338 339 + /** 340 + * DOC: Late binding Firmware Layout 341 + * 342 + * The Late binding binary starts with FPT header, which contains locations 343 + * of various partitions of the binary. Here we're interested in finding out 344 + * manifest version. To the manifest version, we need to locate CPD header 345 + * one of the entry in CPD header points to manifest header. Manifest header 346 + * contains the version. 347 + * 348 + * +================================================+ 349 + * | FPT Header | 350 + * +================================================+ 351 + * | FPT entries[] | 352 + * | entry1 | 353 + * | ... | 354 + * | entryX | 355 + * | "LTES" | 356 + * | ... | 357 + * | offset >-----------------------------|------o 358 + * +================================================+ | 359 + * | 360 + * +================================================+ | 361 + * | CPD Header |<-----o 362 + * +================================================+ 363 + * | CPD entries[] | 364 + * | entry1 | 365 + * | ... | 366 + * | entryX | 367 + * | "LTES.man" | 368 + * | ... | 369 + * | offset >----------------------------|------o 370 + * +================================================+ | 371 + * | 372 + * +================================================+ | 373 + * | Manifest Header |<-----o 374 + * | ... | 375 + * | FW version | 376 + * | ... | 377 + * +================================================+ 378 + */ 379 + 380 + /* FPT Headers */ 381 + struct csc_fpt_header { 382 + u32 header_marker; 383 + #define CSC_FPT_HEADER_MARKER 0x54504624 384 + u32 num_of_entries; 385 + u8 header_version; 386 + u8 entry_version; 387 + u8 header_length; /* in bytes */ 388 + u8 flags; 389 + u16 ticks_to_add; 390 + u16 tokens_to_add; 391 + u32 uma_size; 392 + u32 crc32; 393 + struct gsc_version fitc_version; 394 + } __packed; 395 + 396 + struct csc_fpt_entry { 397 + u8 name[4]; /* partition name */ 398 + u32 reserved1; 399 + u32 offset; /* offset from beginning of CSE region */ 400 + u32 length; /* partition length in bytes */ 401 + u32 reserved2[3]; 402 + u32 partition_flags; 403 + } __packed; 404 + 339 405 #endif