[PATCH v4 4/6] drm/xe/guc: Add GuC log init config in LFD format
Zhanjun Dong
zhanjun.dong at intel.com
Wed Apr 23 21:58:19 UTC 2025
Add support to output GuC log init config (LIC) in LFD format.
Signed-off-by: Zhanjun Dong <zhanjun.dong at intel.com>
---
drivers/gpu/drm/xe/xe_guc_log.c | 201 +++++++++++++++++++++++++++++++-
1 file changed, 198 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_guc_log.c b/drivers/gpu/drm/xe/xe_guc_log.c
index e362e407f6d5..3fdf3823e2d0 100644
--- a/drivers/gpu/drm/xe/xe_guc_log.c
+++ b/drivers/gpu/drm/xe/xe_guc_log.c
@@ -7,6 +7,7 @@
#include <linux/fault-inject.h>
+#include <linux/utsname.h>
#include <drm/drm_managed.h>
#include "abi/guc_log_lfd_abi.h"
@@ -20,6 +21,30 @@
#include "xe_mmio.h"
#include "xe_module.h"
+/* LFD supported LIC type range */
+#define GUC_LOG_LIC_TYPE_FIRST (GUC_LOG_LIC_TYPE_GUC_SW_VERSION)
+#define GUC_LOG_LIC_TYPE_LAST (GUC_LOG_LIC_TYPE_BUILD_PLATFORM_ID)
+
+struct guc_log_buffer_entry_list {
+ u32 offset;
+ u32 rd_ptr;
+ u32 wr_ptr;
+ u32 buf_size;
+};
+
+struct guc_log_init_config_save {
+ /*
+ * Array of init config KLVs.
+ * Range from GUC_LOG_LIC_TYPE_FIRST to GUC_LOG_LIC_TYPE_LAST
+ */
+ u32 KLV[GUC_LOG_LIC_TYPE_LAST - GUC_LOG_LIC_TYPE_FIRST + 1];
+ struct guc_log_buffer_entry_list entry[GUC_LOG_BUFFER_STATE_HEADER_ENTRY_COUNT];
+};
+
+static const struct guc_logfile_lfd_data default_guc_logfile_lfd_data = {
+ .dw0 = FIELD_PREP_CONST(GUC_LOGFILE_LFD_MAGIC, GUC_LOGFILE_LFD_HEADER_MAGIC)
+};
+
static const struct guc_logfile_header default_guc_logfile_header = {
.magic = LFD_DRIVER_KEY_STREAMING,
.version.dw0 = FIELD_PREP_CONST(GUC_LOGFILE_FMT_VER_MINOR_VERSION,
@@ -28,6 +53,28 @@ static const struct guc_logfile_header default_guc_logfile_header = {
GUC_LOG_FILE_FORMAT_VERSION_MAJOR)
};
+static struct guc_log_buffer_entry_markers {
+ u32 key[2];
+} const entry_markers[4] = {
+ {{
+ LFD_LOG_BUFFER_MARKER_1V2,
+ LFD_LOG_BUFFER_MARKER_2
+ }},
+ {{
+ LFD_LOG_BUFFER_MARKER_1V2,
+ LFD_CRASH_DUMP_BUFFER_MARKER_2
+ }},
+ {{
+ LFD_STATE_CAPTURE_BUFFER_MARKER_1V2,
+ LFD_STATE_CAPTURE_BUFFER_MARKER_2
+ }},
+ {{
+ GUC_LOG_INIT_CONFIG_LIC_MAGIC,
+ ((GUC_LOG_INIT_CONFIG_FORMAT_VERSION_MAJOR << 16)
+ | GUC_LOG_INIT_CONFIG_FORMAT_VERSION_MINOR)
+ }}
+};
+
static struct xe_guc *
log_to_guc(struct xe_guc_log *log)
{
@@ -225,10 +272,156 @@ void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_
}
}
+static int xe_guc_log_add_lfd_header(void *buf, int buf_size)
+{
+ int len = sizeof(default_guc_logfile_lfd_data);
+
+ memcpy(buf, &default_guc_logfile_lfd_data, len);
+ return len;
+}
+
+static int xe_guc_log_add_payload(void *buf, int buf_size, u32 data_len, void *data)
+{
+ struct guc_logfile_lfd_data *lfd = buf;
+
+ /* make length DW aligned */
+ lfd->desc_dw_size = DIV_ROUND_UP(data_len, sizeof(u32));
+ memcpy(lfd->data, data, data_len);
+ return lfd->desc_dw_size * sizeof(u32);
+}
+
+static int xe_guc_log_add_typed_payload(void *buf, int buf_size, u32 type,
+ u32 data_len, void *data)
+{
+ struct guc_logfile_lfd_data *lfd = buf;
+ int index;
+
+ index = xe_guc_log_add_lfd_header(buf, buf_size);
+ lfd->dw0 |= FIELD_PREP(GUC_LOGFILE_LFD_DESC_TYPE, type);
+ index += xe_guc_log_add_payload(buf, buf_size, data_len, data);
+
+ return index;
+}
+
+static inline int lic_type_to_KLV_index(u32 lic_type)
+{
+ XE_WARN_ON(lic_type < GUC_LOG_LIC_TYPE_FIRST || lic_type > GUC_LOG_LIC_TYPE_LAST);
+
+ return lic_type - GUC_LOG_LIC_TYPE_FIRST;
+}
+
+static int xe_guc_log_add_klv(void *buf, int size, u32 lic_type,
+ struct guc_log_init_config_save *config)
+{
+ int klv_index = lic_type_to_KLV_index(lic_type);
+
+ return xe_guc_log_add_typed_payload(buf, size, lic_type, sizeof(u32),
+ &config->KLV[klv_index]);
+}
+
+static int xe_guc_log_add_os_id(void *buf, int buf_size, u32 id)
+{
+ struct guc_logfile_lfd_data *lfd = buf;
+ struct guc_lfd_data_os_id *os_id;
+ char *version;
+ int info_len;
+
+ os_id = (void *)lfd->data;
+ os_id->os_id = id;
+
+ version = init_utsname()->release;
+ info_len = strlen(version) + 1;
+
+ if (buf_size < sizeof(struct guc_logfile_lfd_data) + info_len)
+ return -ENOMEM;
+
+ strscpy(os_id->build_version, version, info_len);
+
+ return xe_guc_log_add_typed_payload(buf, buf_size, GUC_LFD_TYPE_OS_ID,
+ info_len + sizeof(*os_id), os_id);
+}
+
+static void xe_guc_log_loop_log_init(struct guc_log_init_config *init,
+ struct guc_log_init_config_save *config)
+{
+ struct guc_klv_generic_dw_t *p = (void *)init->data;
+ int i;
+
+ for (i = 0; i < init->dw_size;) {
+ int klv_len = FIELD_PREP(GUC_KLV_0_LEN, p->kl) + 1;
+ int key = FIELD_PREP(GUC_KLV_0_KEY, p->kl);
+
+ if (key < GUC_LOG_LIC_TYPE_FIRST || key > GUC_LOG_LIC_TYPE_LAST)
+ break;
+ config->KLV[lic_type_to_KLV_index(key)] = p->value;
+ i += klv_len;
+ p = (void *)((u32 *)p + klv_len);
+ }
+}
+
+static void xe_guc_log_load_lic(void *guc_log, struct guc_log_init_config_save *config)
+{
+ u32 offset = GUC_LOG_BUFFER_STATE_HEADER_LENGTH;
+ struct guc_log_buffer_state *p = guc_log;
+ int i = 0;
+
+ memset(config, 0, sizeof(struct guc_log_init_config_save));
+ while (p) {
+ for (i = 0; i < GUC_LOG_BUFFER_STATE_HEADER_ENTRY_COUNT; i++) {
+ if (p->marker[0] == entry_markers[i].key[0] &&
+ p->marker[1] == entry_markers[i].key[1]) {
+ config->entry[i].offset = offset;
+ config->entry[i].rd_ptr = p->read_ptr;
+ config->entry[i].wr_ptr = p->write_ptr;
+ config->entry[i].buf_size = p->size;
+
+ if (i != GUC_LOG_BUFFER_STATE_HEADER_ENTRY_INIT) {
+ offset += p->size;
+ p++;
+ } else {
+ /* Load log init config */
+ xe_guc_log_loop_log_init((void *)p,
+ config);
+
+ /* Init config is the last */
+ return;
+ }
+ }
+ }
+ if (i >= GUC_LOG_BUFFER_STATE_HEADER_ENTRY_COUNT)
+ break;
+ }
+}
+
+static int
+xe_guc_log_output_lfd_init(char *buf, struct xe_guc_log_snapshot *snapshot,
+ struct guc_log_init_config_save *config)
+{
+ int type, len, index;
+
+ /* fill LFD file header */
+ memcpy(buf, &default_guc_logfile_header, sizeof(default_guc_logfile_header));
+ index = offsetof(struct guc_logfile_header, lfd_stream);
+
+ /* FW required types */
+ for (type = GUC_LOG_LIC_TYPE_FIRST; type <= GUC_LOG_LIC_TYPE_LAST; type++)
+ index += xe_guc_log_add_klv(&buf[index], GUC_LOG_CHUNK_SIZE - index, type, config);
+
+ /* KMD required type(s) */
+ len = xe_guc_log_add_os_id(&buf[index], GUC_LOG_CHUNK_SIZE - index,
+ GUC_LFD_OS_TYPE_OSID_LIN);
+ if (len < 0)
+ return len;
+ index += len;
+
+ return index;
+}
+
static void
xe_guc_log_snapshot_print_lfd(struct xe_guc_log_snapshot *snapshot, struct drm_printer *p,
struct xe_guc_log *log)
{
+ struct guc_log_init_config_save config;
char *lfd_buf;
int index;
@@ -242,9 +435,11 @@ xe_guc_log_snapshot_print_lfd(struct xe_guc_log_snapshot *snapshot, struct drm_p
goto lfd_out;
}
- /* Fill LFD file header */
- memcpy(lfd_buf, &default_guc_logfile_header, sizeof(default_guc_logfile_header));
- index = offsetof(struct guc_logfile_header, lfd_stream);
+ xe_guc_log_load_lic(snapshot->copy[0], &config);
+ index = xe_guc_log_output_lfd_init(lfd_buf, snapshot, &config);
+ if (index < 0)
+ goto lfd_out;
+
xe_print_blob_ascii85(p, "[LOG].data", 0, lfd_buf, 0, (size_t)index);
lfd_out:
--
2.34.1
More information about the Intel-xe
mailing list