summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/xe/xe_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/xe/xe_log.c')
-rw-r--r--drivers/gpu/drm/xe/xe_log.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/drivers/gpu/drm/xe/xe_log.c b/drivers/gpu/drm/xe/xe_log.c
new file mode 100644
index 000000000000..5549ef6966fd
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_log.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <kunit/static_stub.h>
+#include <kunit/visibility.h>
+
+#include "abi/xe_log_abi.h"
+
+#include "xe_device.h"
+#include "xe_log.h"
+#include "xe_printk.h"
+
+static void log_emit_cper(struct pci_dev *pdev, int cper_sev, enum xe_sigid sigid,
+ u32 component, u32 location, const void *data, size_t len,
+ struct va_format *vaf)
+{
+ KUNIT_STATIC_STUB_REDIRECT(log_emit_cper, pdev, cper_sev, sigid,
+ component, location, data, len, vaf);
+ /* TODO */
+}
+
+static const char *log_unknown_component_prefix(u32 component)
+{
+ u32 class = FIELD_GET(XE_LOG_COMPONENT_CLASS_MASK, component);
+ u32 type = FIELD_GET(XE_LOG_COMPONENT_TYPE_MASK, component);
+
+ WARN(IS_ENABLED(CONFIG_DRM_XE_DEBUG), "LOG: unrecognized component %u.%u\n", class, type);
+ switch (class) {
+#define MAKE_XE_LOG_COMPONENT_CLASS_PREFIX(_CLASS) \
+ case XE_LOG_COMPONENT_CLASS_##_CLASS: return #_CLASS "? ";
+ MAKE_XE_LOG_COMPONENT_CLASS_PREFIX(SYSTEM)
+ MAKE_XE_LOG_COMPONENT_CLASS_PREFIX(DRIVER)
+ MAKE_XE_LOG_COMPONENT_CLASS_PREFIX(FEATURE)
+ MAKE_XE_LOG_COMPONENT_CLASS_PREFIX(FIRMWARE)
+ MAKE_XE_LOG_COMPONENT_CLASS_PREFIX(HARDWARE)
+#undef MAKE_XE_LOG_COMPONENT_CLASS_PREFIX
+ }
+ return "COMP? ";
+}
+
+static const char *log_component_prefix(u32 component)
+{
+ switch (component) {
+#define MAKE_XE_LOG_COMPONENT_CASE_PREFIX(_CLASS, _ID, _TAG, _SIG, _NAME) \
+ case XE_LOG_COMPONENT_##_TAG: return #_TAG ": ";
+ DEFINE_XE_LOG_COMPONENTS(MAKE_XE_LOG_COMPONENT_CASE_PREFIX)
+#undef MAKE_XE_LOG_COMPONENT_CASE_PREFIX
+ }
+
+ return component ? log_unknown_component_prefix(component) : "";
+}
+
+static struct xe_gt *get_gt_safe(struct pci_dev *pdev, u8 id)
+{
+ struct xe_device *xe = pdev_to_xe_device(pdev);
+
+ return xe ? xe_device_get_gt(xe, id) : NULL;
+}
+
+static struct xe_tile *get_tile_safe(struct pci_dev *pdev, u8 id)
+{
+ struct xe_device *xe = pdev_to_xe_device(pdev);
+
+ return xe && id < xe->info.tile_count ? &xe->tiles[id] : NULL;
+}
+
+static const char *log_location_prefix(struct pci_dev *pdev, u32 location, char *buf, size_t size)
+{
+ u32 type = FIELD_GET(XE_LOG_LOCATION_TYPE_MASK, location);
+ u32 id = FIELD_GET(XE_LOG_LOCATION_ID_MASK, location);
+
+ if (!location || type == XE_LOG_LOCATION_TYPE_DEVICE) {
+ if (id)
+ goto unrecognized;
+ strscpy(buf, "", size);
+ } else if (type == XE_LOG_LOCATION_TYPE_TILE) {
+ struct xe_tile *tile = get_tile_safe(pdev, id);
+
+ if (!tile)
+ goto unrecognized;
+ snprintf(buf, size, "Tile%u: ", id);
+ } else if (type == XE_LOG_LOCATION_TYPE_GT) {
+ struct xe_gt *gt = get_gt_safe(pdev, id);
+
+ if (!gt)
+ goto unrecognized;
+ snprintf(buf, size, "Tile%u: GT%u: ", gt->tile->id, id);
+ } else {
+ goto unrecognized;
+ }
+
+ return buf;
+
+unrecognized:
+ pci_WARN(pdev, IS_ENABLED(CONFIG_DRM_XE_DEBUG),
+ "LOG: unrecognized location %u.%u\n", type, id);
+ snprintf(buf, size, "LOC%u.%u? ", type, id);
+ return buf;
+}
+
+static bool is_hw_sigid(enum xe_sigid sigid)
+{
+ return (int)sigid >= INTEL_SIGID_GPU_XE_HARDWARE_START;
+}
+
+static bool is_sev_error(int cper_sev)
+{
+ return cper_sev != CPER_SEV_INFORMATIONAL;
+}
+
+static const char *log_hwe_prefix(int cper_sev, enum xe_sigid sigid)
+{
+ return is_sev_error(cper_sev) && is_hw_sigid(sigid) ? HW_ERR : "";
+}
+
+static const char *log_sev_prefix(int cper_sev)
+{
+ switch (cper_sev) {
+ case CPER_SEV_FATAL:
+ return "FATAL ";
+ case CPER_SEV_RECOVERABLE:
+ return "";
+ case CPER_SEV_CORRECTED:
+ return "CORRECTED ";
+ case CPER_SEV_INFORMATIONAL:
+ return "";
+ default:
+ WARN(IS_ENABLED(CONFIG_DRM_XE_DEBUG), "LOG: unknown severity %d\n", cper_sev);
+ return "";
+ }
+}
+
+#define __LOG_DRM_PRINTK_FMT(fmt, args...) "[drm] " fmt, ##args
+#define __LOG_DRM_PRINTK_ERR_FMT(fmt, args...) __LOG_DRM_PRINTK_FMT("*ERROR* " fmt, args)
+
+static void log_dmesg_vprintk(struct pci_dev *pdev, int cper_sev, struct va_format *vaf)
+{
+ KUNIT_STATIC_STUB_REDIRECT(log_dmesg_vprintk, pdev, cper_sev, vaf);
+
+ if (cper_sev == CPER_SEV_INFORMATIONAL)
+ pci_info(pdev, __LOG_DRM_PRINTK_FMT("%pV", vaf));
+ else
+ pci_err(pdev, __LOG_DRM_PRINTK_ERR_FMT("%pV", vaf));
+}
+
+static void log_dmesg_printf(struct pci_dev *pdev, int cper_sev, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ log_dmesg_vprintk(pdev, cper_sev, &vaf);
+
+ va_end(args);
+}
+
+static void log_emit_dmesg(struct pci_dev *pdev, int cper_sev, enum xe_sigid sigid,
+ u32 component, u32 location, const void *data, size_t len,
+ struct va_format *vaf)
+{
+ char buf[32];
+ const char *loc_prefix = log_location_prefix(pdev, location, buf, sizeof(buf));
+ const char *comp_prefix = log_component_prefix(component);
+ const char *hwe_prefix = log_hwe_prefix(cper_sev, sigid);
+ const char *sev_prefix = log_sev_prefix(cper_sev);
+
+ if (IS_ERR(data))
+ log_dmesg_printf(pdev, cper_sev, "SIGID=%u %s(%pe) %s%s%s%pV",
+ sigid, sev_prefix, data, hwe_prefix,
+ loc_prefix, comp_prefix, vaf);
+ else if (data && len)
+ log_dmesg_printf(pdev, cper_sev, "SIGID=%u %s(%*phN) %s%s%s%pV",
+ sigid, sev_prefix, (int)len, data, hwe_prefix,
+ loc_prefix, comp_prefix, vaf);
+ else
+ log_dmesg_printf(pdev, cper_sev, "SIGID=%u %s%s%s%s%pV",
+ sigid, sev_prefix, hwe_prefix,
+ loc_prefix, comp_prefix, vaf);
+}
+
+/**
+ * __xe_log_emit() - Emit a structured SIGID log entry
+ * @pdev: the &pci_dev device
+ * @cper_sev: CPER severity (CPER_SEV_FATAL, CPER_SEV_RECOVERABLE, ...)
+ * @sigid: signature identifier, see &enum xe_sigid
+ * @component: component identifier
+ * @location: location details of the @component
+ * @data: pointer to the additional details, or ERR_PTR, or NULL if not applicable
+ * @len: length of the @data in bytes, or 0 if not applicable
+ * @fmt: printf-style format string
+ * @...: format arguments
+ *
+ * Emits a dmesg line that includes a single stable, machine-matchable token
+ * ``SIGID=<n>`` followed by the optional severity token (like ``FATAL``) and,
+ * when @data pointer is set, either the error printed with %pe or a packed hex
+ * dump of the @data binary blob. The dmesg line will also include printf-style
+ * text message.
+ *
+ * Note that the full dmesg line, with the free text message, is only a debugging
+ * aid, not an interface! Only the ``SIGID=<n>`` token is stable there.
+ * The durable machine record is the CPER carrying the same SIGID.
+ *
+ * Note: generation of the CPER record is a planned follow-up.
+ *
+ * Examples::
+ *
+ * <3> xe 0000:03:00.0: [drm] *ERROR* SIGID=104 FATAL (-EPROTO) Invalid GuC reply
+ * <3> xe 0000:03:00.0: [drm] *ERROR* SIGID=106 (-ETIMEDOUT) Engine 'rcs0' hung
+ * <6> xe 0000:03:00.0: [drm] SIGID=103 In survivability mode
+ */
+void __xe_log_emit(struct pci_dev *pdev, int cper_sev, enum xe_sigid sigid,
+ u32 component, u32 location, const void *data, size_t len,
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ log_emit_dmesg(pdev, cper_sev, sigid, component, location, data, len, &vaf);
+ log_emit_cper(pdev, cper_sev, sigid, component, location, data, len, &vaf);
+
+ va_end(args);
+}
+
+#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
+#include "tests/xe_log_kunit.c"
+#endif