diff mbox

[10/15] drm/i915: Enable GuC firmware log

Message ID 1434393394-21002-11-git-send-email-david.s.gordon@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dave Gordon June 15, 2015, 6:36 p.m. UTC
From: Alex Dai <yu.dai@intel.com>

Allocate a GEM object to hold GuC log data. 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@intel.com>
Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c        |   29 +++++++++++++++++++
 drivers/gpu/drm/i915/i915_guc_submission.c |   43 ++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)

Comments

Chris Wilson June 15, 2015, 9:40 p.m. UTC | #1
On Mon, Jun 15, 2015 at 07:36:28PM +0100, Dave Gordon wrote:
> From: Alex Dai <yu.dai@intel.com>
> 
> Allocate a GEM object to hold GuC log data. 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@intel.com>
> Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c        |   29 +++++++++++++++++++
>  drivers/gpu/drm/i915/i915_guc_submission.c |   43 ++++++++++++++++++++++++++++
>  2 files changed, 72 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index c52a745..b0aa4af 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -2388,6 +2388,34 @@ static int i915_guc_load_status_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));

Coherency? You don't mention in the changelong how you expect this to be
used. Do you have some parser that polls the debugfs for changes? If
this is likely to become API, use a context parameter instead to return
a handle to the log bo.

> +
> +		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');

You already have a newline at the end.
-Chris
Tvrtko Ursulin June 16, 2015, 9:26 a.m. UTC | #2
On 06/15/2015 07:36 PM, Dave Gordon wrote:
> From: Alex Dai <yu.dai@intel.com>
>
> Allocate a GEM object to hold GuC log data. 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@intel.com>
> Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_debugfs.c        |   29 +++++++++++++++++++
>   drivers/gpu/drm/i915/i915_guc_submission.c |   43 ++++++++++++++++++++++++++++
>   2 files changed, 72 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index c52a745..b0aa4af 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -2388,6 +2388,34 @@ static int i915_guc_load_status_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);
> +	}

This doesn't look performance critical, but you could also use sg_miter_ 
family of functions/macros to iterate and kmap sg list pages. I did not 
bother figuring out what kind of smarts i915_gem_object_get_page does, 
but it is not likely it can beat sg_miter_ for efficiency.

Regards,

Tvrtko
Chris Wilson June 16, 2015, 11:40 a.m. UTC | #3
On Tue, Jun 16, 2015 at 10:26:40AM +0100, Tvrtko Ursulin wrote:
> 
> On 06/15/2015 07:36 PM, Dave Gordon wrote:
> >From: Alex Dai <yu.dai@intel.com>
> >
> >Allocate a GEM object to hold GuC log data. 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@intel.com>
> >Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
> >---
> >  drivers/gpu/drm/i915/i915_debugfs.c        |   29 +++++++++++++++++++
> >  drivers/gpu/drm/i915/i915_guc_submission.c |   43 ++++++++++++++++++++++++++++
> >  2 files changed, 72 insertions(+)
> >
> >diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> >index c52a745..b0aa4af 100644
> >--- a/drivers/gpu/drm/i915/i915_debugfs.c
> >+++ b/drivers/gpu/drm/i915/i915_debugfs.c
> >@@ -2388,6 +2388,34 @@ static int i915_guc_load_status_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);
> >+	}
> 
> This doesn't look performance critical, but you could also use
> sg_miter_ family of functions/macros to iterate and kmap sg list
> pages. I did not bother figuring out what kind of smarts
> i915_gem_object_get_page does, but it is not likely it can beat
> sg_miter_ for efficiency.

It does. I have patches to replace more uses of sg_page_iter because it
is the slow point in many functions.
-Chris
Tvrtko Ursulin June 16, 2015, 12:29 p.m. UTC | #4
On 06/16/2015 12:40 PM, Chris Wilson wrote:
> On Tue, Jun 16, 2015 at 10:26:40AM +0100, Tvrtko Ursulin wrote:
>>
>> On 06/15/2015 07:36 PM, Dave Gordon wrote:
>>> From: Alex Dai <yu.dai@intel.com>
>>>
>>> Allocate a GEM object to hold GuC log data. 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@intel.com>
>>> Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
>>> ---
>>>   drivers/gpu/drm/i915/i915_debugfs.c        |   29 +++++++++++++++++++
>>>   drivers/gpu/drm/i915/i915_guc_submission.c |   43 ++++++++++++++++++++++++++++
>>>   2 files changed, 72 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>>> index c52a745..b0aa4af 100644
>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>> @@ -2388,6 +2388,34 @@ static int i915_guc_load_status_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);
>>> +	}
>>
>> This doesn't look performance critical, but you could also use
>> sg_miter_ family of functions/macros to iterate and kmap sg list
>> pages. I did not bother figuring out what kind of smarts
>> i915_gem_object_get_page does, but it is not likely it can beat
>> sg_miter_ for efficiency.
>
> It does. I have patches to replace more uses of sg_page_iter because it
> is the slow point in many functions.

Oh wow, so a "3rd party" random access iterator, used in sequential mode 
over a naturally sequential data structure, beats the native sequential 
iterator for performance? Amazing. :)

Regards,

Tvrtko
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index c52a745..b0aa4af 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2388,6 +2388,34 @@  static int i915_guc_load_status_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;
@@ -5083,6 +5111,7 @@  static const struct drm_info_list i915_debugfs_list[] = {
 	{"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
 	{"i915_gem_batch_pool", i915_gem_batch_pool_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_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 273cf38..4efb73a 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -75,6 +75,47 @@  static void gem_release_guc_obj(struct drm_i915_gem_object *obj)
 	drm_gem_object_unreference(&obj->base);
 }
 
+static void guc_create_log(struct intel_guc *guc)
+{
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	struct drm_i915_gem_object *obj;
+	unsigned long offset;
+	uint32_t size, flags;
+
+	if (i915.guc_log_level < GUC_LOG_VERBOSITY_MIN)
+		return;
+
+	if (i915.guc_log_level > GUC_LOG_VERBOSITY_MAX)
+		i915.guc_log_level = GUC_LOG_VERBOSITY_MAX;
+
+	/* 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;
+
+	obj = guc->log_obj;
+	if (!obj) {
+		obj = gem_allocate_guc_obj(dev_priv->dev, size);
+		if (!obj) {
+			/* logging will be off */
+			i915.guc_log_level = -1;
+			return;
+		}
+
+		guc->log_obj = 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);
+
+	offset = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; /* in pages */
+	guc->log_flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
+}
+
 /*
  * Set up the memory resources to be shared with the GuC.  At this point,
  * we require just one object that can be mapped through the GGTT.
@@ -104,6 +145,8 @@  int i915_guc_submission_init(struct drm_device *dev)
 	memset(guc->doorbell_bitmap, 0, sizeof(guc->doorbell_bitmap));
 	guc->db_cacheline = 0;
 
+	guc_create_log(guc);
+
 	return 0;
 }