msm: kgsl: Create a separate function to extract valid commands
Create a separate function that extracts valid commands from good
contexts and invalid commands from bad contexts during recovery
Change-Id: Icffe34821c1b70ca1a8c1a8e13a0b7e23d0ec193
Signed-off-by: Shubhraprakash Das <sadas@codeaurora.org>
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 8311e1f..c68de70 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -946,19 +946,97 @@
return 0;
}
+static void _copy_valid_rb_content(struct adreno_ringbuffer *rb,
+ unsigned int rb_rptr, unsigned int *temp_rb_buffer,
+ int *rb_size, unsigned int *bad_rb_buffer,
+ int *bad_rb_size,
+ int *last_valid_ctx_id)
+{
+ unsigned int good_rb_idx = 0, cmd_start_idx = 0;
+ unsigned int val1 = 0;
+ struct kgsl_context *k_ctxt;
+ struct adreno_context *a_ctxt;
+ unsigned int bad_rb_idx = 0;
+ int copy_rb_contents = 0;
+ unsigned int temp_rb_rptr;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int good_cmd_start_idx = 0;
+
+ /* Walk the rb from the context switch. Omit any commands
+ * for an invalid context. */
+ while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
+
+ if (KGSL_CMD_IDENTIFIER == val1) {
+ /* Start is the NOP dword that comes before
+ * KGSL_CMD_IDENTIFIER */
+ cmd_start_idx = bad_rb_idx - 1;
+ if (copy_rb_contents)
+ good_cmd_start_idx = good_rb_idx - 1;
+ }
+
+ /* check for context switch indicator */
+ if (val1 == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+ unsigned int temp_idx, val2;
+ /* increment by 3 to get to the context_id */
+ temp_rb_rptr = rb_rptr + (3 * sizeof(unsigned int)) %
+ size;
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
+ temp_rb_rptr);
+
+ /* if context switches to a context that did not cause
+ * hang then start saving the rb contents as those
+ * commands can be executed */
+ k_ctxt = idr_find(&rb->device->context_idr, val2);
+ if (k_ctxt) {
+ a_ctxt = k_ctxt->devctxt;
+
+ /* If we are changing to a good context and were not
+ * copying commands then copy over commands to the good
+ * context */
+ if (!copy_rb_contents && ((k_ctxt &&
+ !(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
+ !k_ctxt)) {
+ for (temp_idx = cmd_start_idx;
+ temp_idx < bad_rb_idx;
+ temp_idx++)
+ temp_rb_buffer[good_rb_idx++] =
+ bad_rb_buffer[temp_idx];
+ *last_valid_ctx_id = val2;
+ copy_rb_contents = 1;
+ } else if (copy_rb_contents && k_ctxt &&
+ (a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
+ /* If we are changing to bad context then remove
+ * the dwords we copied for this sequence from
+ * the good buffer */
+ good_rb_idx = good_cmd_start_idx;
+ copy_rb_contents = 0;
+ }
+ }
+ }
+
+ if (copy_rb_contents)
+ temp_rb_buffer[good_rb_idx++] = val1;
+ /* Copy both good and bad commands for replay to the bad
+ * buffer */
+ bad_rb_buffer[bad_rb_idx++] = val1;
+
+ rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
+ }
+ *rb_size = good_rb_idx;
+ *bad_rb_size = bad_rb_idx;
+}
+
int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
struct adreno_recovery_data *rec_data)
{
struct kgsl_device *device = rb->device;
unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
- unsigned int temp_idx = 0;
unsigned int value;
unsigned int val1;
unsigned int val2;
unsigned int val3;
- unsigned int copy_rb_contents = 0;
struct kgsl_context *context;
- unsigned int *temp_rb_buffer = rec_data->rb_buffer;
KGSL_DRV_ERR(device, "Last context id: %d\n", rec_data->context_id);
context = idr_find(&device->context_idr, rec_data->context_id);
@@ -1032,86 +1110,16 @@
" successful timestamp is overwritten\n");
return -EINVAL;
}
- /* rb_rptr is now pointing to the first dword of the command following
- * the last sucessfully executed command sequence. Assumption is that
- * GPU is hung in the command sequence pointed by rb_rptr */
- /* make sure the GPU is not hung in a command submitted by kgsl
- * itself */
- kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
- kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
- adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size));
- if (val1 == cp_nop_packet(1) && val2 == KGSL_CMD_IDENTIFIER) {
- KGSL_DRV_ERR(device,
- "GPU recovery from hang not possible because "
- "of hang in kgsl command\n");
- return -EINVAL;
- }
- while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
- kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
- /* check for context switch indicator */
- if (value == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
- kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
- BUG_ON(value != cp_type3_packet(CP_MEM_WRITE, 2));
- kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
- BUG_ON(val1 != (device->memstore.gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- current_context)));
- kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
-
- /*
- * If other context switches were already lost and
- * and the current context is the one that is hanging,
- * then we cannot recover. Print an error message
- * and leave.
- */
-
- if ((copy_rb_contents == 0) && (value ==
- rec_data->context_id)) {
- KGSL_DRV_ERR(device, "GPU recovery could not "
- "find the previous context\n");
- return -EINVAL;
- }
-
- /*
- * If we were copying the commands and got to this point
- * then we need to remove the 3 commands that appear
- * before KGSL_CONTEXT_TO_MEM_IDENTIFIER
- */
- if (temp_idx)
- temp_idx -= 3;
- /* if context switches to a context that did not cause
- * hang then start saving the rb contents as those
- * commands can be executed */
- if (value != rec_data->context_id) {
- copy_rb_contents = 1;
- temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
- temp_rb_buffer[temp_idx++] =
- KGSL_CMD_IDENTIFIER;
- temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
- temp_rb_buffer[temp_idx++] =
- KGSL_CONTEXT_TO_MEM_IDENTIFIER;
- temp_rb_buffer[temp_idx++] =
- cp_type3_packet(CP_MEM_WRITE, 2);
- temp_rb_buffer[temp_idx++] = val1;
- temp_rb_buffer[temp_idx++] = value;
- } else {
- copy_rb_contents = 0;
- }
- } else if (copy_rb_contents)
- temp_rb_buffer[temp_idx++] = value;
- }
-
- rec_data->rb_size = temp_idx;
+ KGSL_DRV_ERR(rb->device, "Hang recovery start: %x\n", rb_rptr / 4);
+ _copy_valid_rb_content(rb, rb_rptr, rec_data->rb_buffer,
+ &rec_data->rb_size,
+ rec_data->bad_rb_buffer,
+ &rec_data->bad_rb_size,
+ &rec_data->last_valid_ctx_id);
+ /* Do not replay bad commands until we change the code to
+ * handle this in adreno.c */
+ rec_data->bad_rb_size = 0;
return 0;
}