@@ -1011,8 +1011,9 @@ static void guc_read_update_log_buffer(struct intel_guc *guc)
struct guc_log_buffer_state *log_buffer_state, *log_buffer_snapshot_state;
struct guc_log_buffer_state log_buffer_state_local;
void *src_data_ptr, *dst_data_ptr;
- unsigned int buffer_size;
+ unsigned int buffer_size, read_offset, write_offset, bytes_to_copy;
enum guc_log_buffer_type type;
+ bool new_overflow;
if (WARN_ON(!guc->log.buf_addr))
return;
@@ -1035,11 +1036,14 @@ static void guc_read_update_log_buffer(struct intel_guc *guc)
memcpy(&log_buffer_state_local, log_buffer_state,
sizeof(struct guc_log_buffer_state));
buffer_size = guc_get_log_buffer_size(type);
+ read_offset = log_buffer_state_local.read_ptr;
+ write_offset = log_buffer_state_local.sampled_write_ptr;
/* Bookkeeping stuff */
guc->log.flush_count[type] += log_buffer_state_local.flush_to_file;
if (log_buffer_state_local.buffer_full_cnt !=
guc->log.prev_overflow_count[type]) {
+ new_overflow = 1;
guc->log.total_overflow_count[type] +=
(log_buffer_state_local.buffer_full_cnt -
guc->log.prev_overflow_count[type]);
@@ -1053,6 +1057,8 @@ static void guc_read_update_log_buffer(struct intel_guc *guc)
guc->log.prev_overflow_count[type] =
log_buffer_state_local.buffer_full_cnt;
DRM_ERROR_RATELIMITED("GuC log buffer overflow\n");
+ } else {
+ new_overflow = 0;
}
if (log_buffer_snapshot_state) {
@@ -1065,13 +1071,36 @@ static void guc_read_update_log_buffer(struct intel_guc *guc)
* for consistency set the write pointer value to same
* value of sampled_write_ptr in the snapshot buffer.
*/
- log_buffer_snapshot_state->write_ptr =
- log_buffer_snapshot_state->sampled_write_ptr;
+ log_buffer_snapshot_state->write_ptr = write_offset;
log_buffer_snapshot_state++;
/* Now copy the actual logs. */
- memcpy(dst_data_ptr, src_data_ptr, buffer_size);
+ if (unlikely(new_overflow)) {
+ /* copy the whole buffer in case of overflow */
+ read_offset = 0;
+ write_offset = buffer_size;
+ } else if (unlikely((read_offset > buffer_size) ||
+ (write_offset > buffer_size))) {
+ DRM_ERROR("invalid log buffer state\n");
+ /* copy whole buffer as offsets are unreliable */
+ read_offset = 0;
+ write_offset = buffer_size;
+ }
+
+ /* Just copy the newly written data */
+ if (read_offset <= write_offset) {
+ bytes_to_copy = write_offset - read_offset;
+ memcpy(dst_data_ptr + read_offset,
+ src_data_ptr + read_offset, bytes_to_copy);
+ } else {
+ bytes_to_copy = buffer_size - read_offset;
+ memcpy(dst_data_ptr + read_offset,
+ src_data_ptr + read_offset, bytes_to_copy);
+
+ bytes_to_copy = write_offset;
+ memcpy(dst_data_ptr, src_data_ptr, bytes_to_copy);
+ }
src_data_ptr += buffer_size;
dst_data_ptr += buffer_size;
@@ -1080,8 +1109,7 @@ static void guc_read_update_log_buffer(struct intel_guc *guc)
/* FIXME: invalidate/flush for log buffer needed */
/* Update the read pointer in the shared log buffer */
- log_buffer_state->read_ptr =
- log_buffer_state_local.sampled_write_ptr;
+ log_buffer_state->read_ptr = write_offset;
/* Clear the 'flush to file' flag */
log_buffer_state->flush_to_file = 0;