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;
 }