drm/i915: Add Guc/HuC firmware details to error state
authorMichal Wajdeczko <michal.wajdeczko@intel.com>
Thu, 26 Oct 2017 17:36:55 +0000 (17:36 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Mon, 6 Nov 2017 14:22:06 +0000 (14:22 +0000)
Include GuC and HuC firmware details in captured error state
to provide additional debug information. To reuse existing
uc firmware pretty printer, introduce new drm-printer variant
that works with our i915_error_state_buf output. Also update
uc firmware pretty printer to accept const input.

v2: don't rely on current caps (Chris)
    dump correct fw info (Michal)
v3: simplify capture of custom paths (Chris)
v4: improve 'why' comment (Joonas)
    trim output if no fw path (Michal)
    group code around uc error state (Michal)
v5: use error in cleanup_uc (Michal)

Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171026173657.49648-1-michal.wajdeczko@intel.com
[ickle: allow printing uc_fw after allocation failure]
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/intel_uc_fw.c
drivers/gpu/drm/i915/intel_uc_fw.h

index 72bb5b5..632249f 100644 (file)
@@ -913,6 +913,11 @@ struct i915_gpu_state {
        struct intel_device_info device_info;
        struct i915_params params;
 
+       struct i915_error_uc {
+               struct intel_uc_fw guc_fw;
+               struct intel_uc_fw huc_fw;
+       } uc;
+
        /* Generic register state */
        u32 eir;
        u32 pgtbl_er;
index 653fb69..bc26400 100644 (file)
@@ -30,6 +30,8 @@
 #include <generated/utsrelease.h>
 #include <linux/stop_machine.h>
 #include <linux/zlib.h>
+#include <drm/drm_print.h>
+
 #include "i915_drv.h"
 
 static const char *engine_str(int engine)
@@ -175,6 +177,21 @@ static void i915_error_puts(struct drm_i915_error_state_buf *e,
 #define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
 #define err_puts(e, s) i915_error_puts(e, s)
 
+static void __i915_printfn_error(struct drm_printer *p, struct va_format *vaf)
+{
+       i915_error_vprintf(p->arg, vaf->fmt, *vaf->va);
+}
+
+static inline struct drm_printer
+i915_error_printer(struct drm_i915_error_state_buf *e)
+{
+       struct drm_printer p = {
+               .printfn = __i915_printfn_error,
+               .arg = e,
+       };
+       return p;
+}
+
 #ifdef CONFIG_DRM_I915_COMPRESS_ERROR
 
 struct compress {
@@ -589,6 +606,20 @@ static void err_print_pciid(struct drm_i915_error_state_buf *m,
                   pdev->subsystem_device);
 }
 
+static void err_print_uc(struct drm_i915_error_state_buf *m,
+                        const struct i915_error_uc *error_uc)
+{
+       struct drm_printer p = i915_error_printer(m);
+       const struct i915_gpu_state *error =
+               container_of(error_uc, typeof(*error), uc);
+
+       if (!error->device_info.has_guc)
+               return;
+
+       intel_uc_fw_dump(&error_uc->guc_fw, &p);
+       intel_uc_fw_dump(&error_uc->huc_fw, &p);
+}
+
 int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                            const struct i915_gpu_state *error)
 {
@@ -773,6 +804,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 
        err_print_capabilities(m, &error->device_info);
        err_print_params(m, &error->params);
+       err_print_uc(m, &error->uc);
 
        if (m->bytes == 0 && m->err)
                return m->err;
@@ -831,6 +863,14 @@ static __always_inline void free_param(const char *type, void *x)
                kfree(*(void **)x);
 }
 
+static void cleanup_uc_state(struct i915_gpu_state *error)
+{
+       struct i915_error_uc *error_uc = &error->uc;
+
+       kfree(error_uc->guc_fw.path);
+       kfree(error_uc->huc_fw.path);
+}
+
 void __i915_gpu_state_free(struct kref *error_ref)
 {
        struct i915_gpu_state *error =
@@ -870,6 +910,8 @@ void __i915_gpu_state_free(struct kref *error_ref)
        I915_PARAMS_FOR_EACH(FREE);
 #undef FREE
 
+       cleanup_uc_state(error);
+
        kfree(error);
 }
 
@@ -1559,6 +1601,26 @@ static void i915_capture_pinned_buffers(struct drm_i915_private *dev_priv,
        error->pinned_bo = bo;
 }
 
+static void capture_uc_state(struct i915_gpu_state *error)
+{
+       struct drm_i915_private *i915 = error->i915;
+       struct i915_error_uc *error_uc = &error->uc;
+
+       /* Capturing uC state won't be useful if there is no GuC */
+       if (!error->device_info.has_guc)
+               return;
+
+       error_uc->guc_fw = i915->guc.fw;
+       error_uc->huc_fw = i915->huc.fw;
+
+       /* Non-default firmware paths will be specified by the modparam.
+        * As modparams are generally accesible from the userspace make
+        * explicit copies of the firmware paths.
+        */
+       error_uc->guc_fw.path = kstrdup(i915->guc.fw.path, GFP_ATOMIC);
+       error_uc->huc_fw.path = kstrdup(i915->huc.fw.path, GFP_ATOMIC);
+}
+
 static void i915_gem_capture_guc_log_buffer(struct drm_i915_private *dev_priv,
                                            struct i915_gpu_state *error)
 {
@@ -1710,6 +1772,8 @@ static int capture(void *data)
        I915_PARAMS_FOR_EACH(DUP);
 #undef DUP
 
+       capture_uc_state(error);
+
        i915_capture_gen_state(error->i915, error);
        i915_capture_reg_state(error->i915, error);
        i915_gem_record_fences(error->i915, error);
index 973888e..4bc82d3 100644 (file)
@@ -299,7 +299,7 @@ void intel_uc_fw_fini(struct intel_uc_fw *uc_fw)
  *
  * Pretty printer for uC firmware.
  */
-void intel_uc_fw_dump(struct intel_uc_fw *uc_fw, struct drm_printer *p)
+void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
 {
        drm_printf(p, "%s firmware: %s\n",
                   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
index 1329036..5394d9d 100644 (file)
@@ -116,6 +116,6 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
                       int (*xfer)(struct intel_uc_fw *uc_fw,
                                   struct i915_vma *vma));
 void intel_uc_fw_fini(struct intel_uc_fw *uc_fw);
-void intel_uc_fw_dump(struct intel_uc_fw *uc_fw, struct drm_printer *p);
+void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p);
 
 #endif