[android-sdk/device-ti-proprietary-open.git] / omap5 / sgx_src / eurasia_km / services4 / srvkm / env / linux / event.c
1 /*************************************************************************/ /*!
2 @Title Event Object
3 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
4 @License Dual MIT/GPLv2
6 The contents of this file are subject to the MIT license as set out below.
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
18 Alternatively, the contents of this file may be used under the terms of
19 the GNU General Public License Version 2 ("GPL") in which case the provisions
20 of GPL are applicable instead of those above.
22 If you wish to allow use of your version of this file only under the terms of
23 GPL, and not to allow others to use your version of this file under the terms
24 of the MIT license, indicate your decision by deleting the provisions above
25 and replace them with the notice and other provisions required by GPL as set
26 out in the file called "GPL-COPYING" included in this distribution. If you do
27 not delete the provisions above, a recipient may use your version of this file
28 under the terms of either the MIT license or GPL.
30 This License is also included in this distribution in the file called
31 "MIT-COPYING".
33 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
34 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
35 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
37 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
38 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 */ /**************************************************************************/
42 #include <linux/version.h>
44 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))
45 #ifndef AUTOCONF_INCLUDED
46 #include <linux/config.h>
47 #endif
48 #endif
50 #include <asm/io.h>
51 #include <asm/page.h>
52 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
53 #include <asm/system.h>
54 #endif
55 #include <linux/mm.h>
56 #include <linux/slab.h>
57 #include <linux/vmalloc.h>
58 #include <linux/delay.h>
59 #include <linux/pci.h>
61 #include <linux/string.h>
62 #include <linux/sched.h>
63 #include <linux/interrupt.h>
64 #include <asm/hardirq.h>
65 #include <linux/spinlock.h>
66 #include <linux/timer.h>
67 #include <linux/capability.h>
68 #include <linux/sched.h>
69 #include <asm/uaccess.h>
71 #include "img_types.h"
72 #include "services_headers.h"
73 #include "mm.h"
74 #include "pvrmmap.h"
75 #include "mmap.h"
76 #include "env_data.h"
77 #include "proc.h"
78 #include "mutex.h"
79 #include "lock.h"
80 #include "event.h"
82 typedef struct PVRSRV_LINUX_EVENT_OBJECT_LIST_TAG
83 {
84 rwlock_t sLock;
85 struct list_head sList;
87 } PVRSRV_LINUX_EVENT_OBJECT_LIST;
90 typedef struct PVRSRV_LINUX_EVENT_OBJECT_TAG
91 {
92 atomic_t sTimeStamp;
93 IMG_UINT32 ui32TimeStampPrevious;
94 #if defined(DEBUG)
95 IMG_UINT ui32Stats;
96 #endif
97 wait_queue_head_t sWait;
98 struct list_head sList;
99 IMG_HANDLE hResItem;
100 PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList;
101 } PVRSRV_LINUX_EVENT_OBJECT;
103 /*!
104 ******************************************************************************
106 @Function LinuxEventObjectListCreate
108 @Description
110 Linux wait object list creation
112 @Output hOSEventKM : Pointer to the event object list handle
114 @Return PVRSRV_ERROR : Error code
116 ******************************************************************************/
117 PVRSRV_ERROR LinuxEventObjectListCreate(IMG_HANDLE *phEventObjectList)
118 {
119 PVRSRV_LINUX_EVENT_OBJECT_LIST *psEventObjectList;
121 if(OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT_LIST),
122 (IMG_VOID **)&psEventObjectList, IMG_NULL,
123 "Linux Event Object List") != PVRSRV_OK)
124 {
125 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectCreate: failed to allocate memory for event list"));
126 return PVRSRV_ERROR_OUT_OF_MEMORY;
127 }
129 INIT_LIST_HEAD(&psEventObjectList->sList);
131 rwlock_init(&psEventObjectList->sLock);
133 *phEventObjectList = (IMG_HANDLE *) psEventObjectList;
135 return PVRSRV_OK;
136 }
138 /*!
139 ******************************************************************************
141 @Function LinuxEventObjectListDestroy
143 @Description
145 Linux wait object list destruction
147 @Input hOSEventKM : Event object list handle
149 @Return PVRSRV_ERROR : Error code
151 ******************************************************************************/
152 PVRSRV_ERROR LinuxEventObjectListDestroy(IMG_HANDLE hEventObjectList)
153 {
155 PVRSRV_LINUX_EVENT_OBJECT_LIST *psEventObjectList = (PVRSRV_LINUX_EVENT_OBJECT_LIST *) hEventObjectList ;
157 if(psEventObjectList)
158 {
159 IMG_BOOL bListEmpty;
161 read_lock(&psEventObjectList->sLock);
162 bListEmpty = list_empty(&psEventObjectList->sList);
163 read_unlock(&psEventObjectList->sLock);
165 if (!bListEmpty)
166 {
167 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectListDestroy: Event List is not empty"));
168 return PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT;
169 }
171 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT_LIST), psEventObjectList, IMG_NULL);
172 /*not nulling pointer, copy on stack*/
173 }
175 return PVRSRV_OK;
176 }
179 /*!
180 ******************************************************************************
182 @Function LinuxEventObjectDelete
184 @Description
186 Linux wait object removal
188 @Input hOSEventObjectList : Event object list handle
189 @Input hOSEventObject : Event object handle
190 @Input bResManCallback : Called from the resman
192 @Return PVRSRV_ERROR : Error code
194 ******************************************************************************/
195 PVRSRV_ERROR LinuxEventObjectDelete(IMG_HANDLE hOSEventObjectList, IMG_HANDLE hOSEventObject)
196 {
197 if(hOSEventObjectList)
198 {
199 if(hOSEventObject)
200 {
201 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = (PVRSRV_LINUX_EVENT_OBJECT *)hOSEventObject;
202 #if defined(DEBUG)
203 PVR_DPF((PVR_DBG_MESSAGE, "LinuxEventObjectListDelete: Event object waits: %u", psLinuxEventObject->ui32Stats));
204 #endif
205 if(ResManFreeResByPtr(psLinuxEventObject->hResItem, CLEANUP_WITH_POLL) != PVRSRV_OK)
206 {
207 return PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT;
208 }
210 return PVRSRV_OK;
211 }
212 }
213 return PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT;
215 }
217 /*!
218 ******************************************************************************
220 @Function LinuxEventObjectDeleteCallback
222 @Description
224 Linux wait object removal
226 @Input hOSEventObject : Event object handle
228 @Return PVRSRV_ERROR : Error code
230 ******************************************************************************/
231 static PVRSRV_ERROR LinuxEventObjectDeleteCallback(IMG_PVOID pvParam, IMG_UINT32 ui32Param, IMG_BOOL bForceCleanup)
232 {
233 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = pvParam;
234 PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = psLinuxEventObject->psLinuxEventObjectList;
235 unsigned long ulLockFlags;
237 PVR_UNREFERENCED_PARAMETER(ui32Param);
238 PVR_UNREFERENCED_PARAMETER(bForceCleanup);
240 write_lock_irqsave(&psLinuxEventObjectList->sLock, ulLockFlags);
241 list_del(&psLinuxEventObject->sList);
242 write_unlock_irqrestore(&psLinuxEventObjectList->sLock, ulLockFlags);
244 #if defined(DEBUG)
245 PVR_DPF((PVR_DBG_MESSAGE, "LinuxEventObjectDeleteCallback: Event object waits: %u", psLinuxEventObject->ui32Stats));
246 #endif
248 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT), psLinuxEventObject, IMG_NULL);
249 /*not nulling pointer, copy on stack*/
251 return PVRSRV_OK;
252 }
253 /*!
254 ******************************************************************************
256 @Function LinuxEventObjectAdd
258 @Description
260 Linux wait object addition
262 @Input hOSEventObjectList : Event object list handle
263 @Output phOSEventObject : Pointer to the event object handle
265 @Return PVRSRV_ERROR : Error code
267 ******************************************************************************/
268 PVRSRV_ERROR LinuxEventObjectAdd(IMG_HANDLE hOSEventObjectList, IMG_HANDLE *phOSEventObject)
269 {
270 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
271 PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = (PVRSRV_LINUX_EVENT_OBJECT_LIST*)hOSEventObjectList;
272 IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM();
273 PVRSRV_PER_PROCESS_DATA *psPerProc;
274 unsigned long ulLockFlags;
276 psPerProc = PVRSRVPerProcessData(ui32PID);
277 if (psPerProc == IMG_NULL)
278 {
279 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectAdd: Couldn't find per-process data"));
280 return PVRSRV_ERROR_OUT_OF_MEMORY;
281 }
283 /* allocate completion variable */
284 if(OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT),
285 (IMG_VOID **)&psLinuxEventObject, IMG_NULL,
286 "Linux Event Object") != PVRSRV_OK)
287 {
288 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectAdd: failed to allocate memory "));
289 return PVRSRV_ERROR_OUT_OF_MEMORY;
290 }
292 INIT_LIST_HEAD(&psLinuxEventObject->sList);
294 atomic_set(&psLinuxEventObject->sTimeStamp, 0);
295 psLinuxEventObject->ui32TimeStampPrevious = 0;
297 #if defined(DEBUG)
298 psLinuxEventObject->ui32Stats = 0;
299 #endif
300 init_waitqueue_head(&psLinuxEventObject->sWait);
302 psLinuxEventObject->psLinuxEventObjectList = psLinuxEventObjectList;
304 psLinuxEventObject->hResItem = ResManRegisterRes(psPerProc->hResManContext,
305 RESMAN_TYPE_EVENT_OBJECT,
306 psLinuxEventObject,
307 0,
308 &LinuxEventObjectDeleteCallback);
310 write_lock_irqsave(&psLinuxEventObjectList->sLock, ulLockFlags);
311 list_add(&psLinuxEventObject->sList, &psLinuxEventObjectList->sList);
312 write_unlock_irqrestore(&psLinuxEventObjectList->sLock, ulLockFlags);
314 *phOSEventObject = psLinuxEventObject;
316 return PVRSRV_OK;
317 }
319 /*!
320 ******************************************************************************
322 @Function LinuxEventObjectSignal
324 @Description
326 Linux wait object signaling function
328 @Input hOSEventObjectList : Event object list handle
330 @Return PVRSRV_ERROR : Error code
332 ******************************************************************************/
333 PVRSRV_ERROR LinuxEventObjectSignal(IMG_HANDLE hOSEventObjectList)
334 {
335 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
336 PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = (PVRSRV_LINUX_EVENT_OBJECT_LIST*)hOSEventObjectList;
337 struct list_head *psListEntry, *psList;
339 psList = &psLinuxEventObjectList->sList;
341 /*
342 * We don't take the write lock in interrupt context, so we don't
343 * need to use read_lock_irqsave.
344 */
345 read_lock(&psLinuxEventObjectList->sLock);
346 list_for_each(psListEntry, psList)
347 {
349 psLinuxEventObject = (PVRSRV_LINUX_EVENT_OBJECT *)list_entry(psListEntry, PVRSRV_LINUX_EVENT_OBJECT, sList);
351 atomic_inc(&psLinuxEventObject->sTimeStamp);
352 wake_up_interruptible(&psLinuxEventObject->sWait);
353 }
354 read_unlock(&psLinuxEventObjectList->sLock);
356 return PVRSRV_OK;
358 }
360 /*!
361 ******************************************************************************
363 @Function LinuxEventObjectWait
365 @Description
367 Linux wait object routine
369 @Input hOSEventObject : Event object handle
371 @Input ui32MSTimeout : Time out value in msec
373 @Return PVRSRV_ERROR : Error code
375 ******************************************************************************/
376 PVRSRV_ERROR LinuxEventObjectWait(IMG_HANDLE hOSEventObject, IMG_UINT32 ui32MSTimeout)
377 {
378 IMG_UINT32 ui32TimeStamp;
379 DEFINE_WAIT(sWait);
381 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = (PVRSRV_LINUX_EVENT_OBJECT *) hOSEventObject;
383 IMG_UINT32 ui32TimeOutJiffies = msecs_to_jiffies(ui32MSTimeout);
385 do
386 {
387 prepare_to_wait(&psLinuxEventObject->sWait, &sWait, TASK_INTERRUPTIBLE);
388 ui32TimeStamp = (IMG_UINT32)atomic_read(&psLinuxEventObject->sTimeStamp);
390 if(psLinuxEventObject->ui32TimeStampPrevious != ui32TimeStamp)
391 {
392 break;
393 }
395 LinuxUnLockMutex(&gPVRSRVLock);
397 ui32TimeOutJiffies = (IMG_UINT32)schedule_timeout((IMG_INT32)ui32TimeOutJiffies);
399 LinuxLockMutex(&gPVRSRVLock);
400 #if defined(DEBUG)
401 psLinuxEventObject->ui32Stats++;
402 #endif
405 } while (ui32TimeOutJiffies);
407 finish_wait(&psLinuxEventObject->sWait, &sWait);
409 psLinuxEventObject->ui32TimeStampPrevious = ui32TimeStamp;
411 return ui32TimeOutJiffies ? PVRSRV_OK : PVRSRV_ERROR_TIMEOUT;
413 }