msm: kgsl: Make the GPU device aware of the next pending event
The adreno core needs to know what the next event pending for
any given context is so it can mark the interupt to be fired.
If this isn't done then some timestamps that don't have a
matching waittimestamp call won't fire an interrupt. This is
dangerous on the last interrupt/event before a context goes
away.
Change-Id: Ic0dedbad71f6de07b43b0656128c76509326d645
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index fa7b8c7..f3bcbc9 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2055,6 +2055,67 @@
return context_id;
}
+static void adreno_next_event(struct kgsl_device *device,
+ struct kgsl_event *event)
+{
+ int status;
+ unsigned int ref_ts, enableflag;
+ unsigned int context_id = _get_context_id(event->context);
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ status = kgsl_check_timestamp(device, event->context, event->timestamp);
+ if (!status) {
+ kgsl_sharedmem_readl(&device->memstore, &enableflag,
+ KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
+ /*
+ * Barrier is needed here to make sure the read from memstore
+ * has posted
+ */
+
+ mb();
+
+ if (enableflag) {
+ kgsl_sharedmem_readl(&device->memstore, &ref_ts,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ref_wait_ts));
+
+ /* Make sure the memstore read has posted */
+ mb();
+ if (timestamp_cmp(ref_ts, event->timestamp) >= 0) {
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ref_wait_ts), event->timestamp);
+ /* Make sure the memstore write is posted */
+ wmb();
+ }
+ } else {
+ unsigned int cmds[2];
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ref_wait_ts), event->timestamp);
+ enableflag = 1;
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ts_cmp_enable), enableflag);
+
+ /* Make sure the memstore write gets posted */
+ wmb();
+
+ /*
+ * submit a dummy packet so that even if all
+ * commands upto timestamp get executed we will still
+ * get an interrupt
+ */
+ cmds[0] = cp_type3_packet(CP_NOP, 1);
+ cmds[1] = 0;
+
+ if (adreno_dev->drawctxt_active)
+ adreno_ringbuffer_issuecmds_intr(device,
+ event->context, &cmds[0], 2);
+ }
+ }
+}
+
static int kgsl_check_interrupt_timestamp(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp)
{
@@ -2453,6 +2514,7 @@
.drawctxt_destroy = adreno_drawctxt_destroy,
.setproperty = adreno_setproperty,
.postmortem_dump = adreno_dump,
+ .next_event = adreno_next_event,
};
static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 4f99239..437207f 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -449,6 +449,22 @@
kfree(event);
}
+ /* Send the next pending event for each context to the device */
+ if (device->ftbl->next_event) {
+ unsigned int id = KGSL_MEMSTORE_GLOBAL;
+
+ list_for_each_entry(event, &device->events, list) {
+
+ if (!event->context)
+ continue;
+
+ if (event->context->id != id) {
+ device->ftbl->next_event(device, event);
+ id = event->context->id;
+ }
+ }
+ }
+
mutex_unlock(&device->mutex);
}
EXPORT_SYMBOL(kgsl_timestamp_expired);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 24eb630..f38885a 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -58,6 +58,7 @@
struct kgsl_device_private;
struct kgsl_context;
struct kgsl_power_stats;
+struct kgsl_event;
struct kgsl_functable {
/* Mandatory functions - these functions must be implemented
@@ -112,6 +113,8 @@
enum kgsl_property_type type, void *value,
unsigned int sizebytes);
int (*postmortem_dump) (struct kgsl_device *device, int manual);
+ void (*next_event)(struct kgsl_device *device,
+ struct kgsl_event *event);
};
/* MH register values */