blob: 592894755a7b99ca17c5ed7315259998640c4879 [file] [log] [blame]
Jordan Crouseef3456c2013-01-04 16:46:51 -07001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/slab.h>
15#include <linux/list.h>
16#include <linux/module.h>
17#include <kgsl_device.h>
18
Jordan Crouse2c22e912013-02-28 13:40:56 -070019#include "kgsl_trace.h"
20
Jordan Crouseef3456c2013-01-04 16:46:51 -070021static void _add_event_to_list(struct list_head *head, struct kgsl_event *event)
22{
23 struct list_head *n;
24
25 for (n = head->next; n != head; n = n->next) {
26 struct kgsl_event *e =
27 list_entry(n, struct kgsl_event, list);
28
29 if (timestamp_cmp(e->timestamp, event->timestamp) > 0) {
30 list_add(&event->list, n->prev);
31 break;
32 }
33 }
34
35 if (n == head)
36 list_add_tail(&event->list, head);
37}
38
39/**
40 * kgsl_add_event - Add a new timstamp event for the KGSL device
41 * @device - KGSL device for the new event
42 * @id - the context ID that the event should be added to
43 * @ts - the timestamp to trigger the event on
44 * @cb - callback function to call when the timestamp expires
45 * @priv - private data for the specific event type
46 * @owner - driver instance that owns this event
47 *
48 * @returns - 0 on success or error code on failure
49 */
50int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
51 void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
52 void *owner)
53{
54 struct kgsl_event *event;
55 unsigned int cur_ts;
56 struct kgsl_context *context = NULL;
57
58 if (cb == NULL)
59 return -EINVAL;
60
61 if (id != KGSL_MEMSTORE_GLOBAL) {
62 context = idr_find(&device->context_idr, id);
63 if (context == NULL)
64 return -EINVAL;
65 }
66 cur_ts = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
67
Jordan Crousec77df992013-01-28 11:28:29 -070068 /*
69 * Check to see if the requested timestamp has already fired. If it
70 * did do the callback right away. Make sure to send the timestamp that
71 * the event expected instead of the current timestamp because sometimes
72 * the event handlers can get confused.
73 */
Jordan Crouseef3456c2013-01-04 16:46:51 -070074
75 if (timestamp_cmp(cur_ts, ts) >= 0) {
Jordan Crouse2c22e912013-02-28 13:40:56 -070076 trace_kgsl_fire_event(id, ts, 0);
Jordan Crousec77df992013-01-28 11:28:29 -070077 cb(device, priv, id, ts);
Jordan Crouseef3456c2013-01-04 16:46:51 -070078 return 0;
79 }
80
81 event = kzalloc(sizeof(*event), GFP_KERNEL);
82 if (event == NULL)
83 return -ENOMEM;
84
85 event->context = context;
86 event->timestamp = ts;
87 event->priv = priv;
88 event->func = cb;
89 event->owner = owner;
Jordan Crouse2c22e912013-02-28 13:40:56 -070090 event->created = jiffies;
91
92 trace_kgsl_register_event(id, ts);
Jordan Crouseef3456c2013-01-04 16:46:51 -070093
Carter Cooperecbb99a2013-01-08 11:41:02 -070094 /* inc refcount to avoid race conditions in cleanup */
95 if (context)
96 kgsl_context_get(context);
97
Jordan Crouseef3456c2013-01-04 16:46:51 -070098 /* Add the event to either the owning context or the global list */
99
100 if (context) {
101 _add_event_to_list(&context->events, event);
102
103 /*
104 * Add it to the master list of contexts with pending events if
105 * it isn't already there
106 */
107
108 if (list_empty(&context->events_list))
109 list_add_tail(&context->events_list,
110 &device->events_pending_list);
111
112 } else
113 _add_event_to_list(&device->events, event);
114
Jordan Crouseab601992013-03-05 11:18:20 -0700115 /*
116 * Increase the active count on the device to avoid going into power
117 * saving modes while events are pending
118 */
119
120 device->active_cnt++;
121
Jordan Crouseef3456c2013-01-04 16:46:51 -0700122 queue_work(device->work_queue, &device->ts_expired_ws);
123 return 0;
124}
125EXPORT_SYMBOL(kgsl_add_event);
126
127/**
128 * kgsl_cancel_events_ctxt - Cancel all events for a context
129 * @device - KGSL device for the events to cancel
130 * @context - context whose events we want to cancel
131 *
132 */
133void kgsl_cancel_events_ctxt(struct kgsl_device *device,
134 struct kgsl_context *context)
135{
136 struct kgsl_event *event, *event_tmp;
137 unsigned int id, cur;
138
139 cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
140 id = context->id;
141
142 list_for_each_entry_safe(event, event_tmp, &context->events, list) {
143 /*
144 * "cancel" the events by calling their callback.
145 * Currently, events are used for lock and memory
146 * management, so if the process is dying the right
147 * thing to do is release or free.
Jordan Crousec77df992013-01-28 11:28:29 -0700148 *
149 * Send the current timestamp so the event knows how far the
150 * system got before the event was canceled
Jordan Crouseef3456c2013-01-04 16:46:51 -0700151 */
Lynus Vazf5e67a22013-03-04 18:38:33 +0530152 list_del(&event->list);
Jordan Crousec77df992013-01-28 11:28:29 -0700153
Jordan Crouse2c22e912013-02-28 13:40:56 -0700154 trace_kgsl_fire_event(id, cur, jiffies - event->created);
155
Jordan Crouseef3456c2013-01-04 16:46:51 -0700156 if (event->func)
157 event->func(device, event->priv, id, cur);
158
Carter Cooperecbb99a2013-01-08 11:41:02 -0700159 kgsl_context_put(context);
Jordan Crouseef3456c2013-01-04 16:46:51 -0700160 kfree(event);
Jordan Crouseab601992013-03-05 11:18:20 -0700161
162 kgsl_active_count_put(device);
Jordan Crouseef3456c2013-01-04 16:46:51 -0700163 }
164
165 /* Remove ourselves from the master pending list */
166 list_del_init(&context->events_list);
167}
168
169/**
170 * kgsl_cancel_events - Cancel all generic events for a process
171 * @device - KGSL device for the events to cancel
172 * @owner - driver instance that owns the events to cancel
173 *
174 */
175void kgsl_cancel_events(struct kgsl_device *device,
176 void *owner)
177{
178 struct kgsl_event *event, *event_tmp;
179 unsigned int cur;
180
181 cur = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
182
183 list_for_each_entry_safe(event, event_tmp, &device->events, list) {
184 if (event->owner != owner)
185 continue;
186
187 /*
188 * "cancel" the events by calling their callback.
189 * Currently, events are used for lock and memory
190 * management, so if the process is dying the right
Jordan Crousec77df992013-01-28 11:28:29 -0700191 * thing to do is release or free. Send the current timestamp so
192 * the callback knows how far the GPU made it before things went
193 * explosion
Jordan Crouseef3456c2013-01-04 16:46:51 -0700194 */
Lynus Vazf5e67a22013-03-04 18:38:33 +0530195 list_del(&event->list);
Jordan Crouse2c22e912013-02-28 13:40:56 -0700196
197 trace_kgsl_fire_event(KGSL_MEMSTORE_GLOBAL, cur,
198 jiffies - event->created);
199
Jordan Crouseef3456c2013-01-04 16:46:51 -0700200 if (event->func)
201 event->func(device, event->priv, KGSL_MEMSTORE_GLOBAL,
202 cur);
203
Carter Cooperecbb99a2013-01-08 11:41:02 -0700204 if (event->context)
205 kgsl_context_put(event->context);
Jordan Crouseef3456c2013-01-04 16:46:51 -0700206 kfree(event);
Jordan Crouseab601992013-03-05 11:18:20 -0700207
208 kgsl_active_count_put(device);
Jordan Crouseef3456c2013-01-04 16:46:51 -0700209 }
210}
211EXPORT_SYMBOL(kgsl_cancel_events);
212
213static void _process_event_list(struct kgsl_device *device,
214 struct list_head *head, unsigned int timestamp)
215{
216 struct kgsl_event *event, *tmp;
217 unsigned int id;
218
219 list_for_each_entry_safe(event, tmp, head, list) {
220 if (timestamp_cmp(timestamp, event->timestamp) < 0)
221 break;
222
223 id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
224
Jordan Crousec77df992013-01-28 11:28:29 -0700225 /*
226 * Send the timestamp of the expired event, not the current
227 * timestamp. This prevents the event handlers from getting
228 * confused if they don't bother comparing the current timetamp
229 * to the timestamp they wanted
230 */
Lynus Vazf5e67a22013-03-04 18:38:33 +0530231 list_del(&event->list);
Jordan Crousec77df992013-01-28 11:28:29 -0700232
Jordan Crouse2c22e912013-02-28 13:40:56 -0700233 trace_kgsl_fire_event(id, event->timestamp,
234 jiffies - event->created);
235
Jordan Crouseef3456c2013-01-04 16:46:51 -0700236 if (event->func)
Jordan Crousec77df992013-01-28 11:28:29 -0700237 event->func(device, event->priv, id, event->timestamp);
Jordan Crouseef3456c2013-01-04 16:46:51 -0700238
Carter Cooperecbb99a2013-01-08 11:41:02 -0700239 if (event->context)
240 kgsl_context_put(event->context);
Jordan Crouseef3456c2013-01-04 16:46:51 -0700241 kfree(event);
Jordan Crouseab601992013-03-05 11:18:20 -0700242
243 kgsl_active_count_put(device);
Jordan Crouseef3456c2013-01-04 16:46:51 -0700244 }
245}
246
Jordan Crouseed8c2dd2013-01-28 16:58:45 -0700247static inline int _mark_next_event(struct kgsl_device *device,
Jordan Crouseef3456c2013-01-04 16:46:51 -0700248 struct list_head *head)
249{
250 struct kgsl_event *event;
251
252 if (!list_empty(head)) {
253 event = list_first_entry(head, struct kgsl_event, list);
Jordan Crouseed8c2dd2013-01-28 16:58:45 -0700254
255 /*
256 * Next event will return 0 if the event was marked or 1 if the
257 * timestamp on the event has passed - return that up a layer
258 */
259
Hareesh Gunduf1ab1642013-05-13 20:25:53 +0530260 if (device->ftbl->next_event)
261 return device->ftbl->next_event(device, event);
Jordan Crouseef3456c2013-01-04 16:46:51 -0700262 }
Jordan Crouseed8c2dd2013-01-28 16:58:45 -0700263
264 return 0;
Jordan Crouseef3456c2013-01-04 16:46:51 -0700265}
266
267static int kgsl_process_context_events(struct kgsl_device *device,
268 struct kgsl_context *context)
269{
Jordan Crouseed8c2dd2013-01-28 16:58:45 -0700270 while (1) {
271 unsigned int timestamp = kgsl_readtimestamp(device, context,
272 KGSL_TIMESTAMP_RETIRED);
Jordan Crouseef3456c2013-01-04 16:46:51 -0700273
Jordan Crouseed8c2dd2013-01-28 16:58:45 -0700274 _process_event_list(device, &context->events, timestamp);
Jordan Crouseef3456c2013-01-04 16:46:51 -0700275
Jordan Crouseed8c2dd2013-01-28 16:58:45 -0700276 /*
277 * _mark_next event will return 1 as long as the next event
278 * timestamp has expired - this is to cope with an unavoidable
279 * race condition with the GPU that is still processing events.
280 */
281
282 if (!_mark_next_event(device, &context->events))
283 break;
284 }
Jordan Crouseef3456c2013-01-04 16:46:51 -0700285
286 /*
287 * Return 0 if the list is empty so the calling function can remove the
288 * context from the pending list
289 */
290
291 return list_empty(&context->events) ? 0 : 1;
292}
293
294void kgsl_process_events(struct work_struct *work)
295{
296 struct kgsl_device *device = container_of(work, struct kgsl_device,
297 ts_expired_ws);
298 struct kgsl_context *context, *tmp;
299 uint32_t timestamp;
300
301 mutex_lock(&device->mutex);
302
303 /* Process expired global events */
304 timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
305 _process_event_list(device, &device->events, timestamp);
306 _mark_next_event(device, &device->events);
307
308 /* Now process all of the pending contexts */
309 list_for_each_entry_safe(context, tmp, &device->events_pending_list,
310 events_list) {
311
312 /*
313 * If kgsl_timestamp_expired_context returns 0 then it no longer
314 * has any pending events and can be removed from the list
315 */
316
317 if (kgsl_process_context_events(device, context) == 0)
318 list_del_init(&context->events_list);
319 }
320
321 mutex_unlock(&device->mutex);
322}
323EXPORT_SYMBOL(kgsl_process_events);