[Intel-gfx] [PATCH v2 15/18] drm/i915: Enable GuC firmware log

yu.dai at intel.com yu.dai at intel.com
Fri Apr 3 11:08:41 PDT 2015


From: Alex Dai <yu.dai at 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.dai at 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



More information about the Intel-gfx mailing list