msm: kgsl: Fix snapshot dump for hangs involving legacy context switch

The IBs stored by legacy context switch are not stored as part of the
nominal mem_entry accounting that the rest of the process has.  As a
result we cannot freeze the legacy context switch IBs for dump.  Instead,
dump them into the snapshot as IB sections.  Also, store the offset for
the frozen objects to avoid trying to read the gpuaddr of the memdesc after
it had been freed.

Change-Id: Ic0dedbadda43a3025f938b31140d5be19c4706b2
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index c76bfd0..83f402b 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -988,17 +988,47 @@
 	return status;
 }
 
+/* Find a memory structure attached to an adreno context */
+
+struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device,
+	unsigned int pt_base, unsigned int gpuaddr, unsigned int size)
+{
+	struct kgsl_context *context;
+	struct adreno_context *adreno_context = NULL;
+	int next = 0;
+
+	while (1) {
+		context = idr_get_next(&device->context_idr, &next);
+		if (context == NULL)
+			break;
+
+		adreno_context = (struct adreno_context *)context->devctxt;
+
+		if (kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base)) {
+			struct kgsl_memdesc *desc;
+
+			desc = &adreno_context->gpustate;
+			if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size))
+				return desc;
+
+			desc = &adreno_context->context_gmem_shadow.gmemshadow;
+			if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size))
+				return desc;
+		}
+		next = next + 1;
+	}
+
+	return NULL;
+}
+
 struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
 						unsigned int pt_base,
 						unsigned int gpuaddr,
 						unsigned int size)
 {
-	struct kgsl_memdesc *result = NULL;
 	struct kgsl_mem_entry *entry;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *ringbuffer = &adreno_dev->ringbuffer;
-	struct kgsl_context *context;
-	int next = 0;
 
 	if (kgsl_gpuaddr_in_memdesc(&ringbuffer->buffer_desc, gpuaddr, size))
 		return &ringbuffer->buffer_desc;
@@ -1018,34 +1048,7 @@
 	if (entry)
 		return &entry->memdesc;
 
-	while (1) {
-		struct adreno_context *adreno_context = NULL;
-		context = idr_get_next(&device->context_idr, &next);
-		if (context == NULL)
-			break;
-
-		adreno_context = (struct adreno_context *)context->devctxt;
-
-		if (kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base)) {
-			struct kgsl_memdesc *desc;
-
-			desc = &adreno_context->gpustate;
-			if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size)) {
-				result = desc;
-				return result;
-			}
-
-			desc = &adreno_context->context_gmem_shadow.gmemshadow;
-			if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size)) {
-				result = desc;
-				return result;
-			}
-		}
-		next = next + 1;
-	}
-
-	return NULL;
-
+	return adreno_find_ctxtmem(device, pt_base, gpuaddr, size);
 }
 
 uint8_t *adreno_convertaddr(struct kgsl_device *device, unsigned int pt_base,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 4885312..48e70c8 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -128,6 +128,9 @@
 uint8_t *adreno_convertaddr(struct kgsl_device *device,
 	unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
 
+struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device,
+	unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
+
 void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
 		int hang);
 
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index bca7040..e8cb734 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -657,17 +657,31 @@
 			parse_ibs = 0;
 
 		if (parse_ibs && adreno_cmd_is_ib(rbptr[index])) {
+			unsigned int ibaddr = rbptr[index + 1];
+			unsigned int ibsize = rbptr[index + 2];
+
 			/*
-			 * The IB from CP_IB1_BASE goes into the snapshot, all
+			 * This will return non NULL if the IB happens to be
+			 * part of the context memory (i.e - context switch
+			 * command buffers)
+			 */
+
+			struct kgsl_memdesc *memdesc =
+				adreno_find_ctxtmem(device, ptbase, ibaddr,
+					ibsize);
+
+			/*
+			 * The IB from CP_IB1_BASE and the IBs for legacy
+			 * context switch go into the snapshot all
 			 * others get marked at GPU objects
 			 */
-			if (rbptr[index + 1] == ibbase)
+
+			if (ibaddr == ibbase || memdesc != NULL)
 				push_object(device, SNAPSHOT_OBJ_TYPE_IB,
-					ptbase, rbptr[index + 1],
-					rbptr[index + 2]);
+					ptbase, ibaddr, ibsize);
 			else
-				ib_add_gpu_object(device, ptbase,
-					rbptr[index + 1], rbptr[index + 2]);
+				ib_add_gpu_object(device, ptbase, ibaddr,
+					ibsize);
 		}
 
 		index = index + 1;
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index c24576d..553dc60 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -28,6 +28,7 @@
 	unsigned int gpuaddr;
 	unsigned int ptbase;
 	unsigned int size;
+	unsigned int offset;
 	int type;
 	struct kgsl_mem_entry *entry;
 	struct list_head node;
@@ -229,7 +230,7 @@
 		 * then offset the source pointer
 		 */
 
-		offset = obj->gpuaddr - obj->entry->memdesc.gpuaddr;
+		offset = obj->offset;
 
 		/*
 		 * Then  adjust it to account for the offset for the output
@@ -348,6 +349,7 @@
 	obj->gpuaddr = gpuaddr;
 	obj->ptbase = ptbase;
 	obj->size = size;
+	obj->offset = offset;
 
 	list_add(&obj->node, &device->snapshot_obj_list);