fixes for bc_cat
[sgx.git] / pvr / event.c
1 /**********************************************************************
2  *
3  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful but, except
10  * as otherwise stated in writing, without any warranty; without even the
11  * implied warranty of merchantability or fitness for a particular purpose.
12  * See the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
24  *
25  ******************************************************************************/
26
27 #include <linux/version.h>
28 #include <linux/io.h>
29 #include <asm/page.h>
30 #include <asm/system.h>
31 #include <linux/mm.h>
32 #include <linux/slab.h>
33 #include <linux/vmalloc.h>
34 #include <linux/delay.h>
35 #include <linux/pci.h>
36
37 #include <linux/string.h>
38 #include <linux/sched.h>
39 #include <linux/interrupt.h>
40 #include <linux/hardirq.h>
41 #include <linux/timer.h>
42 #include <linux/capability.h>
43 #include <linux/sched.h>
44 #include <linux/uaccess.h>
45
46 #include "img_types.h"
47 #include "services_headers.h"
48 #include "mm.h"
49 #include "pvrmmap.h"
50 #include "mmap.h"
51 #include "env_data.h"
52 #include "proc.h"
53 #include "event.h"
54 #include "pvr_bridge_km.h"
55
56 struct PVRSRV_LINUX_EVENT_OBJECT_LIST {
57         rwlock_t sLock;
58         struct list_head sList;
59
60 };
61
62 struct PVRSRV_LINUX_EVENT_OBJECT {
63         atomic_t sTimeStamp;
64         u32 ui32TimeStampPrevious;
65 #if defined(CONFIG_PVR_DEBUG_EXTRA)
66         unsigned ui32Stats;
67 #endif
68         wait_queue_head_t sWait;
69         struct list_head sList;
70         void *hResItem;
71         struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList;
72 };
73
74 enum PVRSRV_ERROR LinuxEventObjectListCreate(void **phEventObjectList)
75 {
76         struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psEvenObjectList;
77
78         if (OSAllocMem
79             (PVRSRV_OS_NON_PAGEABLE_HEAP,
80              sizeof(struct PVRSRV_LINUX_EVENT_OBJECT_LIST),
81              (void **) &psEvenObjectList, NULL) != PVRSRV_OK) {
82                 PVR_DPF(PVR_DBG_ERROR, "LinuxEventObjectCreate: "
83                                 "failed to allocate memory for event list");
84                 return PVRSRV_ERROR_OUT_OF_MEMORY;
85         }
86
87         INIT_LIST_HEAD(&psEvenObjectList->sList);
88
89         rwlock_init(&psEvenObjectList->sLock);
90
91         *phEventObjectList = (void **) psEvenObjectList;
92
93         return PVRSRV_OK;
94 }
95
96 enum PVRSRV_ERROR LinuxEventObjectListDestroy(void *hEventObjectList)
97 {
98         struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psEvenObjectList =
99             (struct PVRSRV_LINUX_EVENT_OBJECT_LIST *)hEventObjectList;
100
101         if (psEvenObjectList) {
102                 if (!list_empty(&psEvenObjectList->sList)) {
103                         PVR_DPF(PVR_DBG_ERROR,
104                         "LinuxEventObjectListDestroy: Event List is not empty");
105                         return PVRSRV_ERROR_GENERIC;
106                 }
107                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
108                           sizeof(struct PVRSRV_LINUX_EVENT_OBJECT_LIST),
109                           psEvenObjectList, NULL);
110         }
111         return PVRSRV_OK;
112 }
113
114 enum PVRSRV_ERROR LinuxEventObjectDelete(void *hOSEventObjectList,
115                                     void *hOSEventObject)
116 {
117         if (hOSEventObjectList)
118                 if (hOSEventObject) {
119                         struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject =
120                             (struct PVRSRV_LINUX_EVENT_OBJECT *)hOSEventObject;
121 #if defined(CONFIG_PVR_DEBUG_EXTRA)
122                         PVR_DPF(PVR_DBG_MESSAGE,
123                         "LinuxEventObjectListDelete: Event object waits: %lu",
124                                  psLinuxEventObject->ui32Stats);
125 #endif
126                         ResManFreeResByPtr(psLinuxEventObject->hResItem);
127
128                         return PVRSRV_OK;
129                 }
130         return PVRSRV_ERROR_GENERIC;
131
132 }
133
134 static enum PVRSRV_ERROR LinuxEventObjectDeleteCallback(void *pvParam,
135                                                         u32 ui32Param)
136 {
137         struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = pvParam;
138         struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList =
139             psLinuxEventObject->psLinuxEventObjectList;
140
141         PVR_UNREFERENCED_PARAMETER(ui32Param);
142
143         write_lock_bh(&psLinuxEventObjectList->sLock);
144         list_del(&psLinuxEventObject->sList);
145         write_unlock_bh(&psLinuxEventObjectList->sLock);
146
147 #if defined(CONFIG_PVR_DEBUG_EXTRA)
148         PVR_DPF(PVR_DBG_MESSAGE,
149                  "LinuxEventObjectDeleteCallback: Event object waits: %lu",
150                  psLinuxEventObject->ui32Stats);
151 #endif
152
153         OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
154                   sizeof(struct PVRSRV_LINUX_EVENT_OBJECT), psLinuxEventObject,
155                   NULL);
156
157         return PVRSRV_OK;
158 }
159
160 enum PVRSRV_ERROR LinuxEventObjectAdd(void *hOSEventObjectList,
161                                  void **phOSEventObject)
162 {
163         struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
164         struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList =
165             (struct PVRSRV_LINUX_EVENT_OBJECT_LIST *)hOSEventObjectList;
166         u32 ui32PID = OSGetCurrentProcessIDKM();
167         struct PVRSRV_PER_PROCESS_DATA *psPerProc;
168
169         psPerProc = PVRSRVPerProcessData(ui32PID);
170         if (psPerProc == NULL) {
171                 PVR_DPF(PVR_DBG_ERROR,
172                          "LinuxEventObjectAdd: Couldn't find per-process data");
173                 return PVRSRV_ERROR_OUT_OF_MEMORY;
174         }
175
176         if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
177              sizeof(struct PVRSRV_LINUX_EVENT_OBJECT),
178              (void **) &psLinuxEventObject, NULL) != PVRSRV_OK) {
179                 PVR_DPF(PVR_DBG_ERROR,
180                          "LinuxEventObjectAdd: failed to allocate memory ");
181                 return PVRSRV_ERROR_OUT_OF_MEMORY;
182         }
183
184         INIT_LIST_HEAD(&psLinuxEventObject->sList);
185
186         atomic_set(&psLinuxEventObject->sTimeStamp, 0);
187         psLinuxEventObject->ui32TimeStampPrevious = 0;
188
189 #if defined(CONFIG_PVR_DEBUG_EXTRA)
190         psLinuxEventObject->ui32Stats = 0;
191 #endif
192         init_waitqueue_head(&psLinuxEventObject->sWait);
193
194         psLinuxEventObject->psLinuxEventObjectList = psLinuxEventObjectList;
195
196         psLinuxEventObject->hResItem =
197             ResManRegisterRes(psPerProc->hResManContext,
198                               RESMAN_TYPE_EVENT_OBJECT, psLinuxEventObject, 0,
199                               &LinuxEventObjectDeleteCallback);
200
201         write_lock_bh(&psLinuxEventObjectList->sLock);
202         list_add(&psLinuxEventObject->sList, &psLinuxEventObjectList->sList);
203         write_unlock_bh(&psLinuxEventObjectList->sLock);
204
205         *phOSEventObject = psLinuxEventObject;
206
207         return PVRSRV_OK;
208 }
209
210 enum PVRSRV_ERROR LinuxEventObjectSignal(void *hOSEventObjectList)
211 {
212         struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
213         struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList =
214             (struct PVRSRV_LINUX_EVENT_OBJECT_LIST *)hOSEventObjectList;
215         struct list_head *psListEntry, *psListEntryTemp, *psList;
216         psList = &psLinuxEventObjectList->sList;
217
218         list_for_each_safe(psListEntry, psListEntryTemp, psList) {
219
220                 psLinuxEventObject =
221                     (struct PVRSRV_LINUX_EVENT_OBJECT *)list_entry(psListEntry,
222                                         struct PVRSRV_LINUX_EVENT_OBJECT,
223                                         sList);
224
225                 atomic_inc(&psLinuxEventObject->sTimeStamp);
226                 wake_up_interruptible(&psLinuxEventObject->sWait);
227         }
228
229         return PVRSRV_OK;
230
231 }
232
233 enum PVRSRV_ERROR LinuxEventObjectWait(void *hOSEventObject, u32 ui32MSTimeout)
234 {
235         u32 ui32TimeStamp;
236         DEFINE_WAIT(sWait);
237
238         struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject =
239             (struct PVRSRV_LINUX_EVENT_OBJECT *)hOSEventObject;
240
241         u32 ui32TimeOutJiffies = msecs_to_jiffies(ui32MSTimeout);
242
243         do {
244                 prepare_to_wait(&psLinuxEventObject->sWait, &sWait,
245                                 TASK_INTERRUPTIBLE);
246                 ui32TimeStamp = atomic_read(&psLinuxEventObject->sTimeStamp);
247
248                 if (psLinuxEventObject->ui32TimeStampPrevious != ui32TimeStamp)
249                         break;
250
251                 pvr_unlock();
252
253                 ui32TimeOutJiffies =
254                     (u32) schedule_timeout((s32) ui32TimeOutJiffies);
255
256                 pvr_lock();
257
258                 if (pvr_is_disabled()) {
259                         ui32TimeOutJiffies = 1;
260                         break;
261                 }
262 #if defined(CONFIG_PVR_DEBUG_EXTRA)
263                 psLinuxEventObject->ui32Stats++;
264 #endif
265
266         } while (ui32TimeOutJiffies);
267
268         finish_wait(&psLinuxEventObject->sWait, &sWait);
269
270         psLinuxEventObject->ui32TimeStampPrevious = ui32TimeStamp;
271
272         return ui32TimeOutJiffies ? PVRSRV_OK : PVRSRV_ERROR_TIMEOUT;
273
274 }