@@ -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);
@@ -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)
@@ -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);