From: Alex Dai <yu....@intel.com>

Allocate a gem obj to hold GuC log data. Also a debugfs interface
(i915_guc_log_dump) is provided to print out the log content.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu....@intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c        | 29 +++++++++++++
 drivers/gpu/drm/i915/i915_drv.h            |  1 +
 drivers/gpu/drm/i915/i915_params.c         |  5 +++
 drivers/gpu/drm/i915/intel_guc.h           |  3 +-
 drivers/gpu/drm/i915/intel_guc_loader.c    | 66 +++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_guc_scheduler.c |  9 ++--
 6 files changed, 105 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c 
b/drivers/gpu/drm/i915/i915_debugfs.c
index ec10ca0..1618410 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2323,6 +2323,34 @@ static int i915_guc_info(struct seq_file *m, void *data)
        return 0;
 }
 
+static int i915_guc_log_dump(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *log_obj = dev_priv->guc.log_obj;
+       u32 *log;
+       int i = 0, pg;
+
+       if (!log_obj)
+               return 0;
+
+       for (pg = 0; pg < log_obj->base.size / PAGE_SIZE; pg++) {
+               log = kmap_atomic(i915_gem_object_get_page(log_obj, pg));
+
+               for (i = 0; i < PAGE_SIZE / sizeof(u32); i += 4)
+                       seq_printf(m, "0x%08x 0x%08x 0x%08x 0x%08x\n",
+                                  *(log + i), *(log + i + 1),
+                                  *(log + i + 2), *(log + i + 3));
+
+               kunmap_atomic(log);
+       }
+
+       seq_putc(m, '\n');
+
+       return 0;
+}
+
 static int i915_edp_psr_status(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = m->private;
@@ -4747,6 +4775,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
        {"i915_guc_info", i915_guc_info, 0},
        {"i915_guc_load_status", i915_guc_load_status_info, 0},
+       {"i915_guc_log_dump", i915_guc_log_dump, 0},
        {"i915_frequency_info", i915_frequency_info, 0},
        {"i915_hangcheck_info", i915_hangcheck_info, 0},
        {"i915_drpc_info", i915_drpc_info, 0},
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 28a448a..c2d88d9 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2498,6 +2498,7 @@ struct i915_params {
        bool disable_display;
        bool disable_vtd_wa;
        bool enable_guc_scheduling;
+       unsigned int guc_log_level;
        int use_mmio_flip;
        int mmio_debug;
        bool verbose_state_checks;
diff --git a/drivers/gpu/drm/i915/i915_params.c 
b/drivers/gpu/drm/i915/i915_params.c
index 9ad2e27..95e4eb7 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -54,6 +54,7 @@ struct i915_params i915 __read_mostly = {
        .verbose_state_checks = 1,
        .nuclear_pageflip = 0,
        .enable_guc_scheduling = false,
+       .guc_log_level = 0,
 };
 
 module_param_named(modeset, i915.modeset, int, 0400);
@@ -188,3 +189,7 @@ MODULE_PARM_DESC(nuclear_pageflip,
 
 module_param_named(enable_guc_scheduling, i915.enable_guc_scheduling, bool, 
0400);
 MODULE_PARM_DESC(enable_guc_scheduling, "Enable GuC scheduling 
(default:false)");
+
+module_param_named(guc_log_level, i915.guc_log_level, int, 0400);
+MODULE_PARM_DESC(guc_log_level,
+       "GuC firmware logging level (0:disabled, 1~4:enabled)");
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 4ed2d6a..e47e648 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -62,6 +62,7 @@ struct intel_guc {
        spinlock_t host2guc_lock;
 
        struct drm_i915_gem_object *ctx_pool_obj;
+       struct drm_i915_gem_object *log_obj;
 
        struct i915_guc_client *execbuf_client;
 
@@ -177,7 +178,7 @@ int guc_scheduler_init(struct drm_device *dev);
 void guc_scheduler_fini(struct drm_device *dev);
 int guc_scheduler_enable(struct drm_device *dev);
 void guc_scheduler_disable(struct drm_device *dev);
-bool sanitize_enable_guc_scheduling(struct drm_device *dev);
+void sanitize_enable_guc_scheduling(struct drm_device *dev);
 
 /* intel_guc_client.c */
 struct i915_guc_client*
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c 
b/drivers/gpu/drm/i915/intel_guc_loader.c
index dafab32..3a33618 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -46,6 +46,12 @@
  * 512K. In order to exclude 0-512K address space from GGTT, all gfx objects
  * used by GuC is pinned with PIN_OFFSET_BIAS along with size of WOPCM.
  *
+ * Firmware log:
+ * Firmware log is enabled by setting i915.guc_log_level to non-negative level.
+ * Log data is printed out via reading debugfs i915_guc_log_dump. Reading from
+ * i915_guc_load_status will print out firmware loading status and scratch
+ * registers value.
+ *
  */
 
 #define I915_GUC_UCODE_GEN8 "i915/guc_gen8.bin"
@@ -53,6 +59,10 @@
 MODULE_FIRMWARE(I915_GUC_UCODE_GEN8);
 MODULE_FIRMWARE(I915_GUC_UCODE_GEN9);
 
+#define GUC_LOG_DPC_PAGES      3
+#define GUC_LOG_ISR_PAGES      3
+#define GUC_LOG_CRASH_PAGES    1
+
 /**
  * intel_guc_allocate_gem_obj() - Allocate gem object for GuC usage
  * @dev:       drm device
@@ -211,6 +221,51 @@ static u32 get_core_family(struct drm_device *dev)
        }
 }
 
+static void create_guc_log(struct intel_guc *guc, u32 *params)
+{
+       struct drm_i915_private *dev_priv =
+                       container_of(guc, struct drm_i915_private, guc);
+       struct drm_i915_gem_object *obj;
+       u32 flags, size;
+
+       /* The first page is to save log buffer state. Allocate one
+        * extra page for others in case for overlap */
+       size = (1 + GUC_LOG_DPC_PAGES + 1 +
+               GUC_LOG_ISR_PAGES + 1 +
+               GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT;
+
+       if (!guc->log_obj) {
+               obj = intel_guc_allocate_gem_obj(dev_priv->dev, size);
+               if (!obj) {
+                       /* logging will be off */
+                       *(params + GUC_CTL_LOG_PARAMS) = 0;
+                       i915.guc_log_level = 0;
+                       return;
+               }
+
+               guc->log_obj = obj;
+       }
+       else
+               obj = guc->log_obj;
+
+       /* each allocated unit is a page */
+       flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL |
+               (GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) |
+               (GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) |
+               (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT);
+
+       size = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; /* in pages */
+       flags |= size << GUC_LOG_BUF_ADDR_SHIFT;
+
+       *(params + GUC_CTL_LOG_PARAMS) = flags;
+
+       i915.guc_log_level--;
+       if (i915.guc_log_level > GUC_LOG_VERBOSITY_ULTRA)
+               i915.guc_log_level = GUC_LOG_VERBOSITY_ULTRA;
+
+       *(params + GUC_CTL_DEBUG) |= i915.guc_log_level;
+}
+
 static void set_guc_init_params(struct drm_i915_private *dev_priv)
 {
        u32 params[GUC_CTL_MAX_DWORDS];
@@ -234,7 +289,9 @@ static void set_guc_init_params(struct drm_i915_private 
*dev_priv)
        params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
                        GUC_CTL_VCS2_ENABLED;
 
-       /* XXX: Set up log buffer */
+       /* Set up log buffer */
+       if (i915.guc_log_level > 0)
+               create_guc_log(&dev_priv->guc, params);
 
        /* If GuC scheduling is enabled, setup params here. */
        if (i915.enable_guc_scheduling) {
@@ -357,7 +414,7 @@ int intel_guc_load_ucode(struct drm_device *dev, bool wait)
        struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
        int err;
 
-       i915.enable_guc_scheduling = sanitize_enable_guc_scheduling(dev);
+       sanitize_enable_guc_scheduling(dev);
 
        DRM_DEBUG_DRIVER("GuC: wait %d, fetch status %d, load status %d\n",
                wait, guc_fw->uc_fw_fetch_status, guc_fw->uc_fw_load_status);
@@ -467,6 +524,11 @@ void intel_guc_ucode_fini(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 
+       if (dev_priv->guc.log_obj) {
+               intel_guc_release_gem_obj(dev_priv->guc.log_obj);
+               dev_priv->guc.log_obj = NULL;
+       }
+
        guc_scheduler_fini(dev);
 
        intel_uc_fw_fini(dev, guc_fw);
diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c 
b/drivers/gpu/drm/i915/intel_guc_scheduler.c
index c0b7231..ea1ff28 100644
--- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -155,11 +155,10 @@ void guc_scheduler_disable(struct drm_device *dev)
        }
 }
 
-bool sanitize_enable_guc_scheduling(struct drm_device *dev)
+void sanitize_enable_guc_scheduling(struct drm_device *dev)
 {
-       if (!HAS_GUC_UCODE(dev) || !HAS_GUC_SCHED(dev))
-               return false;
-
-       return i915.enable_execlists && i915.enable_guc_scheduling;
+       if (!HAS_GUC_UCODE(dev) || !HAS_GUC_SCHED(dev) ||
+           !i915.enable_execlists)
+               i915.enable_guc_scheduling = false;
 }
 
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to