msm: kgsl: Move events to context specific lists
Move the event accounting from a master list on the device to individual
context lists. This makes the management code more simple and reduces
the amount of extra cycles taken trying to walk a single largish list.
The new added code makes the event code slightly bigger than kgsl.c can
bear. As events become more commonplace this code will be more important
and it will be easier to maintain in a dedicated file so move all the event
related code into kgsl_events.c
Change-Id: Ic0dedbadf00b96eee53aea1d26acb195f1a916ce
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index c61da62..952676d 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -52,155 +52,6 @@
static struct ion_client *kgsl_ion_client;
-/**
- * kgsl_add_event - Add a new timstamp event for the KGSL device
- * @device - KGSL device for the new event
- * @ts - the timestamp to trigger the event on
- * @cb - callback function to call when the timestamp expires
- * @priv - private data for the specific event type
- * @owner - driver instance that owns this event
- *
- * @returns - 0 on success or error code on failure
- */
-
-int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
- void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
- void *owner)
-{
- struct kgsl_event *event;
- struct list_head *n;
- unsigned int cur_ts;
- struct kgsl_context *context = NULL;
-
- if (cb == NULL)
- return -EINVAL;
-
- if (id != KGSL_MEMSTORE_GLOBAL) {
- context = idr_find(&device->context_idr, id);
- if (context == NULL)
- return -EINVAL;
- }
- cur_ts = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
-
- /* Check to see if the requested timestamp has already fired */
-
- if (timestamp_cmp(cur_ts, ts) >= 0) {
- cb(device, priv, id, cur_ts);
- return 0;
- }
-
- event = kzalloc(sizeof(*event), GFP_KERNEL);
- if (event == NULL)
- return -ENOMEM;
-
- event->context = context;
- event->timestamp = ts;
- event->priv = priv;
- event->func = cb;
- event->owner = owner;
-
- /* inc refcount to avoid race conditions in cleanup */
- if (context)
- kgsl_context_get(context);
-
- /*
- * Add the event in order to the list. Order is by context id
- * first and then by timestamp for that context.
- */
-
- for (n = device->events.next ; n != &device->events; n = n->next) {
- struct kgsl_event *e =
- list_entry(n, struct kgsl_event, list);
-
- if (e->context != context)
- continue;
-
- if (timestamp_cmp(e->timestamp, ts) > 0) {
- list_add(&event->list, n->prev);
- break;
- }
- }
-
- if (n == &device->events)
- list_add_tail(&event->list, &device->events);
-
- queue_work(device->work_queue, &device->ts_expired_ws);
- return 0;
-}
-EXPORT_SYMBOL(kgsl_add_event);
-
-/**
- * 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 = kgsl_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);
-
- kgsl_context_put(context);
- 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
- *
- */
-void kgsl_cancel_events(struct kgsl_device *device,
- void *owner)
-{
- struct kgsl_event *event, *event_tmp;
- unsigned int id, cur;
-
- list_for_each_entry_safe(event, event_tmp, &device->events, list) {
- if (event->owner != owner)
- continue;
-
- cur = kgsl_readtimestamp(device, event->context,
- KGSL_TIMESTAMP_RETIRED);
-
- id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
- /*
- * "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);
-
- if (event->context)
- kgsl_context_put(event->context);
-
- list_del(&event->list);
- kfree(event);
- }
-}
-EXPORT_SYMBOL(kgsl_cancel_events);
-
/* kgsl_get_mem_entry - get the mem_entry structure for the specified object
* @device - Pointer to the device structure
* @ptbase - the pagetable base of the object
@@ -379,6 +230,25 @@
if (kgsl_sync_timeline_create(context)) {
idr_remove(&dev_priv->device->context_idr, id);
+ goto func_end;
+ }
+
+ /* Initialize the pending event list */
+ INIT_LIST_HEAD(&context->events);
+
+ /*
+ * Initialize the node that is used to maintain the master list of
+ * contexts with pending events in the device structure. Normally we
+ * wouldn't take the time to initalize a node but at event add time we
+ * call list_empty() on the node as a quick way of determining if the
+ * context is already in the master list so it needs to always be either
+ * active or in an unused but initialized state
+ */
+
+ INIT_LIST_HEAD(&context->events_list);
+
+func_end:
+ if (ret) {
kfree(context);
return NULL;
}
@@ -431,55 +301,6 @@
kfree(context);
}
-void kgsl_timestamp_expired(struct work_struct *work)
-{
- struct kgsl_device *device = container_of(work, struct kgsl_device,
- ts_expired_ws);
- struct kgsl_event *event, *event_tmp;
- uint32_t ts_processed;
- unsigned int id;
-
- mutex_lock(&device->mutex);
-
- /* Process expired events */
- list_for_each_entry_safe(event, event_tmp, &device->events, list) {
- ts_processed = kgsl_readtimestamp(device, event->context,
- KGSL_TIMESTAMP_RETIRED);
- if (timestamp_cmp(ts_processed, event->timestamp) < 0)
- continue;
-
- id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
-
- if (event->func)
- event->func(device, event->priv, id, ts_processed);
-
- if (event->context)
- kgsl_context_put(event->context);
-
- list_del(&event->list);
- 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);
-
static void kgsl_check_idle_locked(struct kgsl_device *device)
{
if (device->pwrctrl.nap_allowed == true &&