msm: kgsl: Cancel events of a context when destroying it

When a kgsl context is destroyed, make sure that its events are also
canceled. Not doing this may result in a kernel panic if the callback
is run on an invalid context.

Change-Id: Ic11119bffc88834c66d9985e19f15c32a3236256
Signed-off-by: Lynus Vaz <lvaz@codeaurora.org>
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 7e84692..5faff24 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -122,6 +122,40 @@
 }
 
 /**
+ * kgsl_cancel_events_ctxt - Cancel all events for a context
+ * @device - KGSL device for the events to cancel
+ * @ctxt - context whose events we want to cancel
+ *
+ */
+static void kgsl_cancel_events_ctxt(struct kgsl_device *device,
+	struct kgsl_context *context)
+{
+	struct kgsl_event *event, *event_tmp;
+	unsigned int id, cur;
+
+	cur = device->ftbl->readtimestamp(device, context,
+			KGSL_TIMESTAMP_RETIRED);
+	id = context->id;
+
+	list_for_each_entry_safe(event, event_tmp, &device->events, list) {
+		if (event->context != context)
+			continue;
+
+		/*
+		 * "cancel" the events by calling their callback.
+		 * Currently, events are used for lock and memory
+		 * management, so if the process is dying the right
+		 * thing to do is release or free.
+		 */
+		if (event->func)
+			event->func(device, event->priv, id, cur);
+
+		list_del(&event->list);
+		kfree(event);
+	}
+}
+
+/**
  * kgsl_cancel_events - Cancel all events for a process
  * @device - KGSL device for the events to cancel
  * @owner - driver instance that owns the events to cancel
@@ -1240,6 +1274,8 @@
 		goto done;
 	}
 
+	kgsl_cancel_events_ctxt(dev_priv->device, context);
+
 	if (dev_priv->device->ftbl->drawctxt_destroy)
 		dev_priv->device->ftbl->drawctxt_destroy(dev_priv->device,
 			context);