[Intel-gfx] [PATCH 17/18] drm/i915: Early creation of relay channel for capturing boot time logs
akash.goel at intel.com
akash.goel at intel.com
Thu Sep 8 10:39:17 UTC 2016
From: Akash Goel <akash.goel at 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 at chris-wilson.co.uk>
Signed-off-by: Akash Goel <akash.goel at intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
---
drivers/gpu/drm/i915/i915_guc_submission.c | 75 ++++++++++++++++++++----------
1 file changed, 51 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 9ca9e0d..b9fede0 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -894,15 +894,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
@@ -935,13 +936,40 @@ static void guc_remove_log_relay_file(struct intel_guc *guc)
relay_close(guc->log.relay_chan);
}
-static int guc_create_log_relay_file(struct intel_guc *guc)
+static int guc_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_create_log_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;
@@ -961,26 +989,12 @@ static int guc_create_log_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;
}
@@ -1000,7 +1014,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;
@@ -1210,6 +1223,16 @@ static int guc_create_log_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_create_relay_channel(guc);
+ if (ret)
+ return ret;
+ }
+
if (!guc->log.flush_wq) {
INIT_WORK(&guc->log.flush_work, guc_capture_logs_work);
@@ -1298,6 +1321,10 @@ static int guc_log_late_setup(struct intel_guc *guc)
if (ret)
goto err;
+ /* Parent debugfs dir should be available by now, associate the already
+ * opened relay channel with a debugfs file, which will then allow User
+ * to pull the logs.
+ */
ret = guc_create_log_relay_file(guc);
if (ret)
goto err;
--
1.9.2
More information about the Intel-gfx
mailing list