diff mbox

[17/18] drm/i915: Early creation of relay channel for capturing boot time logs

Message ID 1476289484-13682-18-git-send-email-akash.goel@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

akash.goel@intel.com Oct. 12, 2016, 4:24 p.m. UTC
From: Akash Goel <akash.goel@intel.com>

As per the current i915 Driver load sequence, debugfs registration is done
at the end and so the relay channel debugfs file is also created after that
but the GuC firmware is loaded much earlier in the sequence.
As a result Driver could miss capturing the boot-time logs of GuC firmware
if there are flush interrupts from the GuC side.
Relay has a provision to support early logging where initially only relay
channel can be created, to have buffers for storing logs, and later on
channel can be associated with a debugfs file at appropriate time.
Have availed that, which allows Driver to capture boot time logs also,
which can be collected once Userspace comes up.

v2:
- Remove the couple of FIXMEs, as now the relay channel will be created
  early before enabling the flush interrupts, so no possibility of relay
  channel pointer being modified & read at the same time from 2 different
  execution contexts.
- Rebase.

v3:
- Add a comment to justiy setting 'is_global' before the NULL check on the
  parent directory dentry pointer.

Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Akash Goel <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 71 ++++++++++++++++++++----------
 1 file changed, 47 insertions(+), 24 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 24d356d..43de16f 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -915,15 +915,16 @@  static struct dentry *create_buf_file_callback(const char *filename,
 {
 	struct dentry *buf_file;
 
-	if (!parent)
-		return NULL;
-
 	/* This to enable the use of a single buffer for the relay channel and
 	 * correspondingly have a single file exposed to User, through which
 	 * it can collect the logs in order without any post-processing.
+	 * Need to set 'is_global' even if parent is NULL for early logging.
 	 */
 	*is_global = 1;
 
+	if (!parent)
+		return NULL;
+
 	/* Not using the channel filename passed as an argument, since for each
 	 * channel relay appends the corresponding CPU number to the filename
 	 * passed in relay_open(). This should be fine as relay just needs a
@@ -956,13 +957,40 @@  static void guc_log_remove_relay_file(struct intel_guc *guc)
 	relay_close(guc->log.relay_chan);
 }
 
-static int guc_log_create_relay_file(struct intel_guc *guc)
+static int guc_log_create_relay_channel(struct intel_guc *guc)
 {
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
 	struct rchan *guc_log_relay_chan;
-	struct dentry *log_dir;
 	size_t n_subbufs, subbuf_size;
 
+	/* Keep the size of sub buffers same as shared log buffer */
+	subbuf_size = guc->log.vma->obj->base.size;
+
+	/* Store up to 8 snapshots, which is large enough to buffer sufficient
+	 * boot time logs and provides enough leeway to User, in terms of
+	 * latency, for consuming the logs from relay. Also doesn't take
+	 * up too much memory.
+	 */
+	n_subbufs = 8;
+
+	guc_log_relay_chan = relay_open(NULL, NULL, subbuf_size,
+					n_subbufs, &relay_callbacks, dev_priv);
+	if (!guc_log_relay_chan) {
+		DRM_ERROR("Couldn't create relay chan for GuC logging\n");
+		return -ENOMEM;
+	}
+
+	GEM_BUG_ON(guc_log_relay_chan->subbuf_size < subbuf_size);
+	guc->log.relay_chan = guc_log_relay_chan;
+	return 0;
+}
+
+static int guc_log_create_relay_file(struct intel_guc *guc)
+{
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	struct dentry *log_dir;
+	int ret;
+
 	/* For now create the log file in /sys/kernel/debug/dri/0 dir */
 	log_dir = dev_priv->drm.primary->debugfs_root;
 
@@ -982,26 +1010,12 @@  static int guc_log_create_relay_file(struct intel_guc *guc)
 		return -ENODEV;
 	}
 
-	/* Keep the size of sub buffers same as shared log buffer */
-	subbuf_size = guc->log.vma->obj->base.size;
-
-	/* Store up to 8 snapshots, which is large enough to buffer sufficient
-	 * boot time logs and provides enough leeway to User, in terms of
-	 * latency, for consuming the logs from relay. Also doesn't take
-	 * up too much memory.
-	 */
-	n_subbufs = 8;
-
-	guc_log_relay_chan = relay_open("guc_log", log_dir, subbuf_size,
-					n_subbufs, &relay_callbacks, dev_priv);
-	if (!guc_log_relay_chan) {
-		DRM_ERROR("Couldn't create relay chan for GuC logging\n");
-		return -ENOMEM;
+	ret = relay_late_setup_files(guc->log.relay_chan, "guc_log", log_dir);
+	if (ret) {
+		DRM_ERROR("Couldn't associate relay chan with file %d\n", ret);
+		return ret;
 	}
 
-	GEM_BUG_ON(guc_log_relay_chan->subbuf_size < subbuf_size);
-	/* FIXME: Cover the update under a lock ? */
-	guc->log.relay_chan = guc_log_relay_chan;
 	return 0;
 }
 
@@ -1021,7 +1035,6 @@  static void guc_move_to_next_buf(struct intel_guc *guc)
 
 static void *guc_get_write_buffer(struct intel_guc *guc)
 {
-	/* FIXME: Cover the check under a lock ? */
 	if (!guc->log.relay_chan)
 		return NULL;
 
@@ -1231,6 +1244,16 @@  static int guc_log_create_extras(struct intel_guc *guc)
 		guc->log.buf_addr = vaddr;
 	}
 
+	if (!guc->log.relay_chan) {
+		/* Create a relay channel, so that we have buffers for storing
+		 * the GuC firmware logs, the channel will be linked with a file
+		 * later on when debugfs is registered.
+		 */
+		ret = guc_log_create_relay_channel(guc);
+		if (ret)
+			return ret;
+	}
+
 	if (!guc->log.flush_wq) {
 		INIT_WORK(&guc->log.flush_work, guc_capture_logs_work);