diff mbox

[14/14] drm/i915: Optimization to reduce the sampling time of GuC log buffer

Message ID 1467485491-17247-15-git-send-email-akash.goel@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

akash.goel@intel.com July 2, 2016, 6:51 p.m. UTC
From: Akash Goel <akash.goel@intel.com>

GuC firmware sends an interrupt to flush the log buffer when it becomes
half full, so Driver doesn't really need to sample the complete buffer
and can just copy only the newly written data by GuC into the local
buffer, i.e. as per the read & write pointer values.
Moreover the flush interrupt would generally come for one type of log
buffer, when it becomes half full, so at that time the other 2 types of
log buffer would comparatively have much lesser unread data in them.
In case of overflow reported by GuC, Driver do need to copy the entire
buffer as the whole buffer would contain the unread data.

Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 68 +++++++++++++++++++++---------
 drivers/gpu/drm/i915/i915_irq.c            |  3 +-
 drivers/gpu/drm/i915/intel_guc.h           |  2 +-
 3 files changed, 51 insertions(+), 22 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 2a192d4..9514645 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -866,32 +866,35 @@  static void* guc_get_write_buffer(struct intel_guc *guc)
 	return relay_reserve(guc->log.relay_chan, guc->log.obj->base.size);
 }
 
-static void guc_read_update_log_buffer(struct drm_device *dev, bool capture_all)
+static void guc_read_update_log_buffer(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_guc *guc = &dev_priv->guc;
 	struct guc_log_buffer_state *log_buffer_state;
 	struct guc_log_buffer_state *log_buffer_copy_state;
 	void *src_ptr, *dst_ptr;
-	u32 num_pages_to_copy;
-	int i;
+	bool new_overflow;
+	u32 i, buffer_size, read_offset, write_offset, bytes_to_copy;
 
 	if (!guc->log.obj || !guc->log.buf_addr)
 		return;
 
-	num_pages_to_copy = guc->log.obj->base.size / PAGE_SIZE;
-	/* Don't really need to copy crash buffer area in regular cases as there
-	 * won't be any unread data there.
-	 */
-	if (!capture_all)
-		num_pages_to_copy -= (GUC_LOG_CRASH_PAGES + 1);
-
 	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);
 
+	/* Actual logs are present from the 2nd page */
+	src_ptr += PAGE_SIZE;
+	dst_ptr += PAGE_SIZE;
+
 	for (i = 0; i < GUC_MAX_LOG_BUFFER; i++) {
+		buffer_size = log_buffer_state->size;
+		read_offset = log_buffer_state->read_ptr;
+		write_offset = log_buffer_state->sampled_write_ptr;
+		new_overflow = 0;
+
+		/* First copy the state structure */
 		if (log_buffer_copy_state) {
 			memcpy(log_buffer_copy_state, log_buffer_state,
 					sizeof(struct guc_log_buffer_state));
@@ -907,6 +910,10 @@  static void guc_read_update_log_buffer(struct drm_device *dev, bool capture_all)
 			log_buffer_copy_state++;
 		}
 
+		if (log_buffer_state->buffer_full_cnt !=
+					guc->log.overflow_count[i])
+			new_overflow = 1;
+
 		guc->log.overflow_count[i] = log_buffer_state->buffer_full_cnt;
 		guc->log.flush_count[i] += log_buffer_state->flush_to_file;
 
@@ -917,13 +924,36 @@  static void guc_read_update_log_buffer(struct drm_device *dev, bool capture_all)
 		/* Clear the 'flush to file' flag */
 		log_buffer_state->flush_to_file = 0;
 		log_buffer_state++;
-	}
 
-	/* Now copy the actual logs */
-	for (i=1; (i < num_pages_to_copy) && dst_ptr; i++) {
-		dst_ptr += PAGE_SIZE;
-		src_ptr += PAGE_SIZE;
-		memcpy(dst_ptr, src_ptr, PAGE_SIZE);
+		if (!log_buffer_copy_state)
+			continue;
+
+		/* Now copy the actual logs */
+		if ((read_offset > buffer_size) || (write_offset > buffer_size)) {
+			DRM_ERROR("invalid log buffer state\n");
+			/* copy the whole buffer, as offsets are unreliable */
+			memcpy(dst_ptr, src_ptr, buffer_size);
+		} else if (new_overflow) {
+			/* Need to copy the whole buffer in case of overflow */
+			memcpy(dst_ptr, src_ptr, buffer_size);
+		} else {
+			/* Just copy the new data */
+			if (read_offset <= write_offset) {
+				bytes_to_copy = write_offset - read_offset;
+				memcpy(dst_ptr + read_offset,
+					src_ptr + read_offset, bytes_to_copy);
+			} else {
+				bytes_to_copy = buffer_size - read_offset;
+				memcpy(dst_ptr + read_offset,
+					src_ptr + read_offset, bytes_to_copy);
+
+				bytes_to_copy = write_offset;
+				memcpy(dst_ptr, src_ptr, bytes_to_copy);
+			}
+		}
+
+		src_ptr += buffer_size;
+		dst_ptr += buffer_size;
 	}
 }
 
@@ -1370,11 +1400,11 @@  int intel_guc_resume(struct drm_device *dev)
 	return host2guc_action(guc, data, ARRAY_SIZE(data));
 }
 
-void i915_guc_capture_logs(struct drm_device *dev, bool capture_all)
+void i915_guc_capture_logs(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	guc_read_update_log_buffer(dev, capture_all);
+	guc_read_update_log_buffer(dev);
 
 	host2guc_logbuffer_flush_complete(&dev_priv->guc);
 }
@@ -1395,7 +1425,7 @@  void i915_guc_capture_logs_on_reset(struct drm_device *dev)
 	host2guc_force_logbuffer_flush(&dev_priv->guc);
 
 	/* GuC would have updated the log buffer by now, so capture it */
-	i915_guc_capture_logs(dev, true);
+	i915_guc_capture_logs(dev);
 
 end:
 	mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index e2cbe1e..99af3b5 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1255,8 +1255,7 @@  static void gen9_guc2host_events_work(struct work_struct *work)
 	msg = I915_READ(SOFT_SCRATCH(15));
 	if (msg & (GUC2HOST_MSG_CRASH_DUMP_POSTED |
 		   GUC2HOST_MSG_FLUSH_LOG_BUFFER)) {
-		i915_guc_capture_logs(dev_priv->dev,
-			msg & GUC2HOST_MSG_CRASH_DUMP_POSTED);
+		i915_guc_capture_logs(dev_priv->dev);
 
 		/* Clear GuC to Host msg bits that are handled */
 		if (msg & GUC2HOST_MSG_FLUSH_LOG_BUFFER)
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index bd299d3..d9f50be 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -182,7 +182,7 @@  int i915_guc_wq_check_space(struct drm_i915_gem_request *rq);
 int i915_guc_submit(struct drm_i915_gem_request *rq);
 void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
 void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
-void i915_guc_capture_logs(struct drm_device *dev, bool capture_all);
+void i915_guc_capture_logs(struct drm_device *dev);
 void i915_guc_capture_logs_on_reset(struct drm_device *dev);
 void i915_guc_register(struct drm_device *dev);
 void i915_guc_unregister(struct drm_device *dev);