6b945dfa2ac74a84a1411bfb158faf9146a16373
[sgx.git] / pvr / pvr_events.c
1
2 #include "pvr_events.h"
3 #include "servicesint.h"
4 #include "sgx_bridge.h"
5 #include "perproc.h"
6 #include "pvr_bridge_km.h"
7 #include "pvr_trace_cmd.h"
8
9 #include <linux/wait.h>
10 #include <linux/sched.h>
11 #include <linux/spinlock.h>
12 #include <linux/time.h>
13 #include <linux/uaccess.h>
14 #include <linux/fs.h>
15 #include <linux/notifier.h>
16 #include <linux/slab.h>
17
18 #include <plat/display.h>
19
20 static spinlock_t event_lock;
21 static struct list_head sync_wait_list;
22 static struct list_head flip_wait_list;
23 static struct notifier_block dss_nb;
24
25 static inline bool is_render_complete(const struct PVRSRV_SYNC_DATA *sync,
26                                       u32 write_ops_pending)
27 {
28         return (int)sync->ui32WriteOpsComplete - (int)write_ops_pending >= 0;
29 }
30
31 static void pvr_signal_sync_event(struct pvr_pending_sync_event *e,
32                                         const struct timeval *now)
33 {
34         e->event.tv_sec = now->tv_sec;
35         e->event.tv_usec = now->tv_usec;
36
37         list_move_tail(&e->base.link, &e->base.file_priv->event_list);
38
39         wake_up_interruptible(&e->base.file_priv->event_wait);
40 }
41
42 int pvr_sync_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv,
43                         const struct PVRSRV_KERNEL_SYNC_INFO *sync_info,
44                         u64 user_data)
45 {
46         struct pvr_pending_sync_event *e;
47         struct timeval now;
48         unsigned long flags;
49
50         e = kzalloc(sizeof(*e), GFP_KERNEL);
51         if (e == NULL)
52                 return -ENOMEM;
53
54         e->event.base.type = PVR_EVENT_SYNC;
55         e->event.base.length = sizeof(e->event);
56         e->event.sync_info = sync_info;
57         e->event.user_data = user_data;
58         e->base.event = &e->event.base;
59         e->base.file_priv = priv;
60         e->base.destroy = (void (*)(struct pvr_pending_event *))kfree;
61         e->base.write_ops_pending = sync_info->psSyncData->ui32WriteOpsPending;
62
63         do_gettimeofday(&now);
64         spin_lock_irqsave(&event_lock, flags);
65
66         if (priv->event_space < sizeof(e->event)) {
67                 spin_unlock_irqrestore(&event_lock, flags);
68                 kfree(e);
69                 return -ENOMEM;
70         }
71
72         priv->event_space -= sizeof(e->event);
73
74         list_add_tail(&e->base.link, &sync_wait_list);
75         if (is_render_complete(sync_info->psSyncData,
76                                e->base.write_ops_pending))
77                 pvr_signal_sync_event(e, &now);
78
79         spin_unlock_irqrestore(&event_lock, flags);
80
81         return 0;
82 }
83
84 static void pvr_signal_flip_event(struct pvr_pending_flip_event *e,
85                                         const struct timeval *now)
86 {
87         e->event.tv_sec = now->tv_sec;
88         e->event.tv_usec = now->tv_usec;
89
90         list_move_tail(&e->base.link, &e->base.file_priv->event_list);
91
92         wake_up_interruptible(&e->base.file_priv->event_wait);
93 }
94
95 int pvr_flip_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv,
96                          unsigned int overlay,
97                          enum pvr_sync_wait_seq_type type, u64 user_data)
98 {
99 #if 0
100         struct pvr_pending_flip_event *e;
101         struct timeval now;
102         unsigned long flags;
103
104         e = kzalloc(sizeof(*e), GFP_KERNEL);
105         if (e == NULL)
106                 return -ENOMEM;
107
108         switch (type) {
109         case _PVR_SYNC_WAIT_FLIP:
110                 e->event.base.type = PVR_EVENT_FLIP;
111                 e->dss_event = OMAP_DSS_NOTIFY_GO_OVL;
112                 break;
113         case _PVR_SYNC_WAIT_UPDATE:
114                 e->event.base.type = PVR_EVENT_UPDATE;
115                 e->dss_event = OMAP_DSS_NOTIFY_UPDATE_OVL;
116                 break;
117         default:
118                 BUG();
119         }
120         e->event.base.length = sizeof(e->event);
121         e->base.event = &e->event.base;
122         e->event.overlay = overlay;
123         e->event.user_data = user_data;
124         e->base.file_priv = priv;
125         e->base.destroy = (void (*)(struct pvr_pending_event *))kfree;
126
127         do_gettimeofday(&now);
128         spin_lock_irqsave(&event_lock, flags);
129
130         if (priv->event_space < sizeof(e->event)) {
131                 spin_unlock_irqrestore(&event_lock, flags);
132                 kfree(e);
133                 return -ENOMEM;
134         }
135
136         priv->event_space -= sizeof(e->event);
137
138         list_add_tail(&e->base.link, &flip_wait_list);
139
140         spin_unlock_irqrestore(&event_lock, flags);
141
142         return omap_dss_request_notify(e->dss_event, overlay);
143 #else
144         return -EFAULT;
145 #endif
146 }
147
148 static bool pvr_dequeue_event(struct PVRSRV_FILE_PRIVATE_DATA *priv,
149                 size_t total, size_t max, struct pvr_pending_event **out)
150 {
151         struct pvr_pending_event *e;
152         unsigned long flags;
153         bool ret = false;
154
155         spin_lock_irqsave(&event_lock, flags);
156
157         *out = NULL;
158         if (list_empty(&priv->event_list))
159                 goto err;
160
161         e = list_first_entry(&priv->event_list, struct pvr_pending_event, link);
162         if (e->event->length + total > max)
163                 goto err;
164
165         priv->event_space += e->event->length;
166         list_del(&e->link);
167         *out = e;
168         ret = true;
169
170 err:
171         spin_unlock_irqrestore(&event_lock, flags);
172
173         return ret;
174 }
175
176 static void trace_pvr_event(struct pvr_pending_event *e)
177 {
178         struct PVRSRV_PER_PROCESS_DATA *proc;
179
180         proc = e->file_priv->proc;
181         pvr_trcmd_lock();
182
183         switch (e->event->type) {
184         case PVR_EVENT_SYNC:
185         {
186                 struct pvr_event_sync *evsync;
187                 struct pvr_trcmd_syn *ts;
188
189                 evsync = (struct pvr_event_sync *)e->event;
190                 ts = pvr_trcmd_alloc(PVR_TRCMD_SGX_QBLT_SYNCOMP,
191                                      proc->ui32PID, proc->name, sizeof(*ts));
192                 pvr_trcmd_set_syn(ts, evsync->sync_info);
193                 break;
194         }
195         case PVR_EVENT_FLIP:
196                 pvr_trcmd_alloc(PVR_TRCMD_SGX_QBLT_FLPCOMP,
197                                 proc->ui32PID, proc->name, 0);
198                 break;
199         case PVR_EVENT_UPDATE:
200                 pvr_trcmd_alloc(PVR_TRCMD_SGX_QBLT_UPDCOMP,
201                                 proc->ui32PID, proc->name, 0);
202                 break;
203         default:
204                 __WARN();
205         }
206
207         pvr_trcmd_unlock();
208 }
209
210 ssize_t pvr_read(struct file *filp, char __user *buf, size_t count, loff_t *off)
211 {
212         struct PVRSRV_FILE_PRIVATE_DATA *priv = filp->private_data;
213         struct pvr_pending_event *e;
214         size_t total;
215         ssize_t ret;
216
217         ret = wait_event_interruptible(priv->event_wait,
218                                         !list_empty(&priv->event_list));
219
220         if (ret < 0)
221                 return ret;
222
223         total = 0;
224         while (pvr_dequeue_event(priv, total, count, &e)) {
225                 if (copy_to_user(buf + total, e->event, e->event->length)) {
226                         total = -EFAULT;
227                         break;
228                 }
229
230                 trace_pvr_event(e);
231
232                 total += e->event->length;
233                 e->destroy(e);
234         }
235
236         return total;
237 }
238
239 unsigned int pvr_poll(struct file *filp, struct poll_table_struct *wait)
240 {
241         struct PVRSRV_FILE_PRIVATE_DATA *priv = filp->private_data;
242         unsigned int mask = 0;
243
244         poll_wait(filp, &priv->event_wait, wait);
245
246         if (!list_empty(&priv->event_list))
247                 mask |= POLLIN | POLLRDNORM;
248
249         return mask;
250 }
251
252 void pvr_handle_sync_events(void)
253 {
254         struct pvr_pending_sync_event *e;
255         struct pvr_pending_sync_event *t;
256         struct timeval now;
257         unsigned long flags;
258
259         do_gettimeofday(&now);
260
261         spin_lock_irqsave(&event_lock, flags);
262
263         list_for_each_entry_safe(e, t, &sync_wait_list, base.link) {
264                 if (!is_render_complete(e->event.sync_info->psSyncData,
265                                         e->base.write_ops_pending))
266                         continue;
267
268                 pvr_signal_sync_event(e, &now);
269         }
270
271         spin_unlock_irqrestore(&event_lock, flags);
272 }
273
274 static int dss_notifier_callback(struct notifier_block *nb,
275                                  unsigned long event, void *data)
276 {
277         struct pvr_pending_flip_event *e;
278         struct pvr_pending_flip_event *t;
279         struct timeval now;
280         unsigned long flags;
281         long overlay = (long) data;
282
283         do_gettimeofday(&now);
284
285         spin_lock_irqsave(&event_lock, flags);
286
287         list_for_each_entry_safe(e, t, &flip_wait_list, base.link) {
288                 if (!(e->dss_event & event))
289                         continue;
290                 if (e->event.overlay != overlay)
291                         continue;
292
293                 pvr_signal_flip_event(e, &now);
294         }
295
296         spin_unlock_irqrestore(&event_lock, flags);
297
298         return 0;
299 }
300
301 void pvr_release_events(struct PVRSRV_FILE_PRIVATE_DATA *priv)
302 {
303         struct pvr_pending_event *w;
304         struct pvr_pending_event *z;
305         struct pvr_pending_sync_event *e;
306         struct pvr_pending_sync_event *t;
307         struct pvr_pending_flip_event *e2;
308         struct pvr_pending_flip_event *t2;
309         unsigned long flags;
310
311         spin_lock_irqsave(&event_lock, flags);
312
313         /* Remove pending waits */
314         list_for_each_entry_safe(e, t, &sync_wait_list, base.link)
315                 if (e->base.file_priv == priv) {
316                         list_del(&e->base.link);
317                         e->base.destroy(&e->base);
318                 }
319
320         list_for_each_entry_safe(e2, t2, &flip_wait_list, base.link)
321                 if (e2->base.file_priv == priv) {
322                         list_del(&e2->base.link);
323                         e2->base.destroy(&e2->base);
324                 }
325
326         /* Remove unconsumed events */
327         list_for_each_entry_safe(w, z, &priv->event_list, link)
328                 w->destroy(w);
329
330         spin_unlock_irqrestore(&event_lock, flags);
331 }
332
333 void pvr_init_events(void)
334 {
335         spin_lock_init(&event_lock);
336         INIT_LIST_HEAD(&sync_wait_list);
337         INIT_LIST_HEAD(&flip_wait_list);
338
339         dss_nb.notifier_call = dss_notifier_callback;
340 //      omap_dss_register_notifier(&dss_nb);
341 }
342
343 void pvr_exit_events(void)
344 {
345 //      omap_dss_unregister_notifier(&dss_nb);
346 }