mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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>
This commit is contained in:
committed by
Lucas De Marchi
parent
67de7982d5
commit
efa29317a5
@@ -45,6 +45,121 @@ late_bind_to_xe(struct xe_late_bind *late_bind)
|
||||
return container_of(late_bind, struct xe_device, late_bind);
|
||||
}
|
||||
|
||||
static struct xe_device *
|
||||
late_bind_fw_to_xe(struct xe_late_bind_fw *lb_fw)
|
||||
{
|
||||
return container_of(lb_fw, struct xe_device, late_bind.late_bind_fw[lb_fw->id]);
|
||||
}
|
||||
|
||||
/* Refer to the "Late Bind based Firmware Layout" documentation entry for details */
|
||||
static int parse_cpd_header(struct xe_late_bind_fw *lb_fw,
|
||||
const void *data, size_t size, const char *manifest_entry)
|
||||
{
|
||||
struct xe_device *xe = late_bind_fw_to_xe(lb_fw);
|
||||
const struct gsc_cpd_header_v2 *header = data;
|
||||
const struct gsc_manifest_header *manifest;
|
||||
const struct gsc_cpd_entry *entry;
|
||||
size_t min_size = sizeof(*header);
|
||||
u32 offset;
|
||||
int i;
|
||||
|
||||
/* manifest_entry is mandatory */
|
||||
xe_assert(xe, manifest_entry);
|
||||
|
||||
if (size < min_size || header->header_marker != GSC_CPD_HEADER_MARKER)
|
||||
return -ENOENT;
|
||||
|
||||
if (header->header_length < sizeof(struct gsc_cpd_header_v2)) {
|
||||
drm_err(&xe->drm, "%s late binding fw: Invalid CPD header length %u!\n",
|
||||
fw_id_to_name[lb_fw->id], header->header_length);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
min_size = header->header_length + sizeof(struct gsc_cpd_entry) * header->num_of_entries;
|
||||
if (size < min_size) {
|
||||
drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n",
|
||||
fw_id_to_name[lb_fw->id], size, min_size);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/* Look for the manifest first */
|
||||
entry = (void *)header + header->header_length;
|
||||
for (i = 0; i < header->num_of_entries; i++, entry++)
|
||||
if (strcmp(entry->name, manifest_entry) == 0)
|
||||
offset = entry->offset & GSC_CPD_ENTRY_OFFSET_MASK;
|
||||
|
||||
if (!offset) {
|
||||
drm_err(&xe->drm, "%s late binding fw: Failed to find manifest_entry\n",
|
||||
fw_id_to_name[lb_fw->id]);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
min_size = offset + sizeof(struct gsc_manifest_header);
|
||||
if (size < min_size) {
|
||||
drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n",
|
||||
fw_id_to_name[lb_fw->id], size, min_size);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
manifest = data + offset;
|
||||
|
||||
lb_fw->version = manifest->fw_version;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Refer to the "Late Bind based Firmware Layout" documentation entry for details */
|
||||
static int parse_lb_layout(struct xe_late_bind_fw *lb_fw,
|
||||
const void *data, size_t size, const char *fpt_entry)
|
||||
{
|
||||
struct xe_device *xe = late_bind_fw_to_xe(lb_fw);
|
||||
const struct csc_fpt_header *header = data;
|
||||
const struct csc_fpt_entry *entry;
|
||||
size_t min_size = sizeof(*header);
|
||||
u32 offset;
|
||||
int i;
|
||||
|
||||
/* fpt_entry is mandatory */
|
||||
xe_assert(xe, fpt_entry);
|
||||
|
||||
if (size < min_size || header->header_marker != CSC_FPT_HEADER_MARKER)
|
||||
return -ENOENT;
|
||||
|
||||
if (header->header_length < sizeof(struct csc_fpt_header)) {
|
||||
drm_err(&xe->drm, "%s late binding fw: Invalid FPT header length %u!\n",
|
||||
fw_id_to_name[lb_fw->id], header->header_length);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
min_size = header->header_length + sizeof(struct csc_fpt_entry) * header->num_of_entries;
|
||||
if (size < min_size) {
|
||||
drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n",
|
||||
fw_id_to_name[lb_fw->id], size, min_size);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/* Look for the cpd header first */
|
||||
entry = (void *)header + header->header_length;
|
||||
for (i = 0; i < header->num_of_entries; i++, entry++)
|
||||
if (strcmp(entry->name, fpt_entry) == 0)
|
||||
offset = entry->offset;
|
||||
|
||||
if (!offset) {
|
||||
drm_err(&xe->drm, "%s late binding fw: Failed to find fpt_entry\n",
|
||||
fw_id_to_name[lb_fw->id]);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
min_size = offset + sizeof(struct gsc_cpd_header_v2);
|
||||
if (size < min_size) {
|
||||
drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n",
|
||||
fw_id_to_name[lb_fw->id], size, min_size);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
return parse_cpd_header(lb_fw, data + offset, size - offset, "LTES.man");
|
||||
}
|
||||
|
||||
static const char *xe_late_bind_parse_status(uint32_t status)
|
||||
{
|
||||
switch (status) {
|
||||
@@ -224,6 +339,10 @@ static int __xe_late_bind_fw_init(struct xe_late_bind *late_bind, u32 fw_id)
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
ret = parse_lb_layout(lb_fw, fw->data, fw->size, "LTES");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
lb_fw->payload_size = fw->size;
|
||||
lb_fw->payload = drmm_kzalloc(&xe->drm, lb_fw->payload_size, GFP_KERNEL);
|
||||
if (!lb_fw->payload) {
|
||||
@@ -231,6 +350,11 @@ static int __xe_late_bind_fw_init(struct xe_late_bind *late_bind, u32 fw_id)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
drm_info(&xe->drm, "Using %s firmware from %s version %u.%u.%u.%u\n",
|
||||
fw_id_to_name[lb_fw->id], lb_fw->blob_path,
|
||||
lb_fw->version.major, lb_fw->version.minor,
|
||||
lb_fw->version.hotfix, lb_fw->version.build);
|
||||
|
||||
memcpy((void *)lb_fw->payload, fw->data, lb_fw->payload_size);
|
||||
release_firmware(fw);
|
||||
INIT_WORK(&lb_fw->work, xe_late_bind_work);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include "xe_uc_fw_abi.h"
|
||||
|
||||
#define XE_LB_MAX_PAYLOAD_SIZE SZ_4K
|
||||
|
||||
@@ -39,6 +40,8 @@ struct xe_late_bind_fw {
|
||||
size_t payload_size;
|
||||
/** @work: worker to upload latebind blob */
|
||||
struct work_struct work;
|
||||
/** @version: late binding blob manifest version */
|
||||
struct gsc_version version;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -336,4 +336,70 @@ struct gsc_manifest_header {
|
||||
u32 exponent_size; /* in dwords */
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* DOC: Late binding Firmware Layout
|
||||
*
|
||||
* The Late binding binary starts with FPT header, which contains locations
|
||||
* of various partitions of the binary. Here we're interested in finding out
|
||||
* manifest version. To the manifest version, we need to locate CPD header
|
||||
* one of the entry in CPD header points to manifest header. Manifest header
|
||||
* contains the version.
|
||||
*
|
||||
* +================================================+
|
||||
* | FPT Header |
|
||||
* +================================================+
|
||||
* | FPT entries[] |
|
||||
* | entry1 |
|
||||
* | ... |
|
||||
* | entryX |
|
||||
* | "LTES" |
|
||||
* | ... |
|
||||
* | offset >-----------------------------|------o
|
||||
* +================================================+ |
|
||||
* |
|
||||
* +================================================+ |
|
||||
* | CPD Header |<-----o
|
||||
* +================================================+
|
||||
* | CPD entries[] |
|
||||
* | entry1 |
|
||||
* | ... |
|
||||
* | entryX |
|
||||
* | "LTES.man" |
|
||||
* | ... |
|
||||
* | offset >----------------------------|------o
|
||||
* +================================================+ |
|
||||
* |
|
||||
* +================================================+ |
|
||||
* | Manifest Header |<-----o
|
||||
* | ... |
|
||||
* | FW version |
|
||||
* | ... |
|
||||
* +================================================+
|
||||
*/
|
||||
|
||||
/* FPT Headers */
|
||||
struct csc_fpt_header {
|
||||
u32 header_marker;
|
||||
#define CSC_FPT_HEADER_MARKER 0x54504624
|
||||
u32 num_of_entries;
|
||||
u8 header_version;
|
||||
u8 entry_version;
|
||||
u8 header_length; /* in bytes */
|
||||
u8 flags;
|
||||
u16 ticks_to_add;
|
||||
u16 tokens_to_add;
|
||||
u32 uma_size;
|
||||
u32 crc32;
|
||||
struct gsc_version fitc_version;
|
||||
} __packed;
|
||||
|
||||
struct csc_fpt_entry {
|
||||
u8 name[4]; /* partition name */
|
||||
u32 reserved1;
|
||||
u32 offset; /* offset from beginning of CSE region */
|
||||
u32 length; /* partition length in bytes */
|
||||
u32 reserved2[3];
|
||||
u32 partition_flags;
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user