Skip to content

Commit efa2931

Browse files
bnilawarlucasdemarchi
authored andcommitted
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>
1 parent 67de798 commit efa2931

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-0
lines changed

drivers/gpu/drm/xe/xe_late_bind_fw.c

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,121 @@ late_bind_to_xe(struct xe_late_bind *late_bind)
4545
return container_of(late_bind, struct xe_device, late_bind);
4646
}
4747

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+
48163
static const char *xe_late_bind_parse_status(uint32_t status)
49164
{
50165
switch (status) {
@@ -224,13 +339,22 @@ static int __xe_late_bind_fw_init(struct xe_late_bind *late_bind, u32 fw_id)
224339
return -ENODATA;
225340
}
226341

342+
ret = parse_lb_layout(lb_fw, fw->data, fw->size, "LTES");
343+
if (ret)
344+
return ret;
345+
227346
lb_fw->payload_size = fw->size;
228347
lb_fw->payload = drmm_kzalloc(&xe->drm, lb_fw->payload_size, GFP_KERNEL);
229348
if (!lb_fw->payload) {
230349
release_firmware(fw);
231350
return -ENOMEM;
232351
}
233352

353+
drm_info(&xe->drm, "Using %s firmware from %s version %u.%u.%u.%u\n",
354+
fw_id_to_name[lb_fw->id], lb_fw->blob_path,
355+
lb_fw->version.major, lb_fw->version.minor,
356+
lb_fw->version.hotfix, lb_fw->version.build);
357+
234358
memcpy((void *)lb_fw->payload, fw->data, lb_fw->payload_size);
235359
release_firmware(fw);
236360
INIT_WORK(&lb_fw->work, xe_late_bind_work);

drivers/gpu/drm/xe/xe_late_bind_fw_types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/mutex.h>
1111
#include <linux/types.h>
1212
#include <linux/workqueue.h>
13+
#include "xe_uc_fw_abi.h"
1314

1415
#define XE_LB_MAX_PAYLOAD_SIZE SZ_4K
1516

@@ -39,6 +40,8 @@ struct xe_late_bind_fw {
3940
size_t payload_size;
4041
/** @work: worker to upload latebind blob */
4142
struct work_struct work;
43+
/** @version: late binding blob manifest version */
44+
struct gsc_version version;
4245
};
4346

4447
/**

drivers/gpu/drm/xe/xe_uc_fw_abi.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,4 +336,70 @@ struct gsc_manifest_header {
336336
u32 exponent_size; /* in dwords */
337337
} __packed;
338338

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+
339405
#endif

0 commit comments

Comments
 (0)