[PATCH 11/11] drm/i915: Use uncached(WC) mapping for acessing the GuC log buffer

akash.goel
2016-06-27T12:04:19Z

From: Akash Goel <akash.goel@intel.com>

Host needs to sample the GuC log buffer on every flush interrupt from GuC.
To ensure that we always get the up-to-date data from log buffer, its
better to access the buffer through an uncached CPU mapping. Also the way
buffer is accessed from GuC & Host side, manually doing cache flush may
not be effective always if cached CPU mapping is used.
Since the data to be read is less than 50 KB, there would not be any
performance implications.

Signed-off-by: Akash Goel <akash.goel@intel.com>
---
drivers/gpu/drm/i915/i915_guc_submission.c | 29 +++++++++++++++++++++++------
drivers/gpu/drm/i915/intel_guc.h | 1 +
2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 8c0fd83..71c626d 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -866,8 +866,7 @@ static void guc_read_update_log_buffer(struct drm_device *dev)
if (!guc->log_obj)
return;

- log_buffer_state = src_ptr =
- kmap_atomic(i915_gem_object_get_page(guc->log_obj, 0));
+ log_buffer_state = src_ptr = guc->log_buf_addr;

/* Get the pointer to local buffer to store the logs */
dst_ptr = log_buffer_copy_state = guc_get_write_buffer(guc);
@@ -897,14 +896,11 @@ static void guc_read_update_log_buffer(struct drm_device *dev)
log_buffer_copy_state++;
}

- kunmap_atomic(src_ptr);
-
/* Now copy the actual logs */
for (i=1; (i < guc->log_obj->base.size / PAGE_SIZE) && dst_ptr; i++) {
dst_ptr += PAGE_SIZE;
- src_ptr = kmap_atomic(i915_gem_object_get_page(guc->log_obj, i));
+ src_ptr += PAGE_SIZE;
memcpy(dst_ptr, src_ptr, PAGE_SIZE);
- kunmap_atomic(src_ptr);
}
}

@@ -1019,10 +1015,31 @@ static void guc_create_log_relay_file(struct intel_guc *guc)
static void guc_logging_fini(struct intel_guc *guc)
{
guc_remove_log_relay_file(guc);
+
+ if (guc->log_obj)
+ i915_gem_object_unpin_map(guc->log_obj);
+ guc->log_buf_addr = NULL;
}

static void guc_logging_init(struct intel_guc *guc)
{
+ void *vaddr;
+
+ /* Create a WC (Uncached for read) mapping so that we can
+ * directly get the data (up-to-date) from system memory.
+ */
+ vaddr = i915_gem_object_pin_map(guc->log_obj, true);
+ if (IS_ERR(vaddr)) {
+ DRM_DEBUG_DRIVER("Couldn't map log buffer pages(%ld)\n",
+ PTR_ERR(vaddr));
+ i915.guc_log_level = -1;
+ gem_release_guc_obj(guc->log_obj);
+ guc->log_obj = NULL;
+ return;
+ }
+
+ guc->log_buf_addr = vaddr;
+
guc_create_log_relay_file(guc);
}

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 01a1bb5..cf082fa 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -126,6 +126,7 @@ struct intel_guc {
struct intel_guc_fw guc_fw;
uint32_t log_flags;
struct drm_i915_gem_object *log_obj;
+ void *log_buf_addr;
struct rchan *log_relay_chan;
/*
* work, interrupts_enabled are protected by dev_priv->irq_lock
--
1.9.2