aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/pvr/event.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/pvr/event.c')
-rw-r--r--drivers/gpu/pvr/event.c274
1 files changed, 274 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/event.c b/drivers/gpu/pvr/event.c
new file mode 100644
index 00000000000..e2ef0d177ca
--- /dev/null
+++ b/drivers/gpu/pvr/event.c
@@ -0,0 +1,274 @@
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#ifndef AUTOCONF_INCLUDED
28 #include <linux/config.h>
29#endif
30
31#include <linux/version.h>
32#include <asm/io.h>
33#include <asm/page.h>
34#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
35#include <asm/system.h>
36#endif
37#include <linux/mm.h>
38#include <linux/slab.h>
39#include <linux/vmalloc.h>
40#include <linux/delay.h>
41#include <linux/pci.h>
42
43#include <linux/string.h>
44#include <linux/sched.h>
45#include <linux/interrupt.h>
46#include <asm/hardirq.h>
47#include <linux/timer.h>
48#include <linux/capability.h>
49#include <linux/sched.h>
50#include <asm/uaccess.h>
51
52#include "img_types.h"
53#include "services_headers.h"
54#include "mm.h"
55#include "pvrmmap.h"
56#include "mmap.h"
57#include "env_data.h"
58#include "proc.h"
59#include "mutex.h"
60#include "lock.h"
61#include "event.h"
62
63typedef struct PVRSRV_LINUX_EVENT_OBJECT_LIST_TAG
64{
65 rwlock_t sLock;
66 struct list_head sList;
67
68} PVRSRV_LINUX_EVENT_OBJECT_LIST;
69
70
71typedef struct PVRSRV_LINUX_EVENT_OBJECT_TAG
72{
73 atomic_t sTimeStamp;
74 IMG_UINT32 ui32TimeStampPrevious;
75#if defined(DEBUG)
76 IMG_UINT ui32Stats;
77#endif
78 wait_queue_head_t sWait;
79 struct list_head sList;
80 IMG_HANDLE hResItem;
81 PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList;
82} PVRSRV_LINUX_EVENT_OBJECT;
83
84PVRSRV_ERROR LinuxEventObjectListCreate(IMG_HANDLE *phEventObjectList)
85{
86 PVRSRV_LINUX_EVENT_OBJECT_LIST *psEvenObjectList;
87
88 if(OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT_LIST),
89 (IMG_VOID **)&psEvenObjectList, IMG_NULL,
90 "Linux Event Object List") != PVRSRV_OK)
91 {
92 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectCreate: failed to allocate memory for event list"));
93 return PVRSRV_ERROR_OUT_OF_MEMORY;
94 }
95
96 INIT_LIST_HEAD(&psEvenObjectList->sList);
97
98 rwlock_init(&psEvenObjectList->sLock);
99
100 *phEventObjectList = (IMG_HANDLE *) psEvenObjectList;
101
102 return PVRSRV_OK;
103}
104
105PVRSRV_ERROR LinuxEventObjectListDestroy(IMG_HANDLE hEventObjectList)
106{
107
108 PVRSRV_LINUX_EVENT_OBJECT_LIST *psEvenObjectList = (PVRSRV_LINUX_EVENT_OBJECT_LIST *) hEventObjectList ;
109
110 if(psEvenObjectList)
111 {
112 if (!list_empty(&psEvenObjectList->sList))
113 {
114 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectListDestroy: Event List is not empty"));
115 return PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT;
116 }
117 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT_LIST), psEvenObjectList, IMG_NULL);
118
119 }
120 return PVRSRV_OK;
121}
122
123
124PVRSRV_ERROR LinuxEventObjectDelete(IMG_HANDLE hOSEventObjectList, IMG_HANDLE hOSEventObject)
125{
126 if(hOSEventObjectList)
127 {
128 if(hOSEventObject)
129 {
130 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = (PVRSRV_LINUX_EVENT_OBJECT *)hOSEventObject;
131#if defined(DEBUG)
132 PVR_DPF((PVR_DBG_MESSAGE, "LinuxEventObjectListDelete: Event object waits: %u", psLinuxEventObject->ui32Stats));
133#endif
134 if(ResManFreeResByPtr(psLinuxEventObject->hResItem) != PVRSRV_OK)
135 {
136 return PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT;
137 }
138
139 return PVRSRV_OK;
140 }
141 }
142 return PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT;
143
144}
145
146static PVRSRV_ERROR LinuxEventObjectDeleteCallback(IMG_PVOID pvParam, IMG_UINT32 ui32Param)
147{
148 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = pvParam;
149 PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = psLinuxEventObject->psLinuxEventObjectList;
150
151 PVR_UNREFERENCED_PARAMETER(ui32Param);
152
153 write_lock_bh(&psLinuxEventObjectList->sLock);
154 list_del(&psLinuxEventObject->sList);
155 write_unlock_bh(&psLinuxEventObjectList->sLock);
156
157#if defined(DEBUG)
158 PVR_DPF((PVR_DBG_MESSAGE, "LinuxEventObjectDeleteCallback: Event object waits: %u", psLinuxEventObject->ui32Stats));
159#endif
160
161 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT), psLinuxEventObject, IMG_NULL);
162
163
164 return PVRSRV_OK;
165}
166PVRSRV_ERROR LinuxEventObjectAdd(IMG_HANDLE hOSEventObjectList, IMG_HANDLE *phOSEventObject)
167 {
168 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
169 PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = (PVRSRV_LINUX_EVENT_OBJECT_LIST*)hOSEventObjectList;
170 IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM();
171 PVRSRV_PER_PROCESS_DATA *psPerProc;
172
173 psPerProc = PVRSRVPerProcessData(ui32PID);
174 if (psPerProc == IMG_NULL)
175 {
176 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectAdd: Couldn't find per-process data"));
177 return PVRSRV_ERROR_OUT_OF_MEMORY;
178 }
179
180
181 if(OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT),
182 (IMG_VOID **)&psLinuxEventObject, IMG_NULL,
183 "Linux Event Object") != PVRSRV_OK)
184 {
185 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectAdd: failed to allocate memory "));
186 return PVRSRV_ERROR_OUT_OF_MEMORY;
187 }
188
189 INIT_LIST_HEAD(&psLinuxEventObject->sList);
190
191 atomic_set(&psLinuxEventObject->sTimeStamp, 0);
192 psLinuxEventObject->ui32TimeStampPrevious = 0;
193
194#if defined(DEBUG)
195 psLinuxEventObject->ui32Stats = 0;
196#endif
197 init_waitqueue_head(&psLinuxEventObject->sWait);
198
199 psLinuxEventObject->psLinuxEventObjectList = psLinuxEventObjectList;
200
201 psLinuxEventObject->hResItem = ResManRegisterRes(psPerProc->hResManContext,
202 RESMAN_TYPE_EVENT_OBJECT,
203 psLinuxEventObject,
204 0,
205 &LinuxEventObjectDeleteCallback);
206
207 write_lock_bh(&psLinuxEventObjectList->sLock);
208 list_add(&psLinuxEventObject->sList, &psLinuxEventObjectList->sList);
209 write_unlock_bh(&psLinuxEventObjectList->sLock);
210
211 *phOSEventObject = psLinuxEventObject;
212
213 return PVRSRV_OK;
214}
215
216PVRSRV_ERROR LinuxEventObjectSignal(IMG_HANDLE hOSEventObjectList)
217{
218 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
219 PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = (PVRSRV_LINUX_EVENT_OBJECT_LIST*)hOSEventObjectList;
220 struct list_head *psListEntry, *psListEntryTemp, *psList;
221 psList = &psLinuxEventObjectList->sList;
222
223 list_for_each_safe(psListEntry, psListEntryTemp, psList)
224 {
225
226 psLinuxEventObject = (PVRSRV_LINUX_EVENT_OBJECT *)list_entry(psListEntry, PVRSRV_LINUX_EVENT_OBJECT, sList);
227
228 atomic_inc(&psLinuxEventObject->sTimeStamp);
229 wake_up_interruptible(&psLinuxEventObject->sWait);
230 }
231
232 return PVRSRV_OK;
233
234}
235
236PVRSRV_ERROR LinuxEventObjectWait(IMG_HANDLE hOSEventObject, IMG_UINT32 ui32MSTimeout)
237{
238 IMG_UINT32 ui32TimeStamp;
239 DEFINE_WAIT(sWait);
240
241 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = (PVRSRV_LINUX_EVENT_OBJECT *) hOSEventObject;
242
243 IMG_UINT32 ui32TimeOutJiffies = msecs_to_jiffies(ui32MSTimeout);
244
245 do
246 {
247 prepare_to_wait(&psLinuxEventObject->sWait, &sWait, TASK_INTERRUPTIBLE);
248 ui32TimeStamp = (IMG_UINT32)atomic_read(&psLinuxEventObject->sTimeStamp);
249
250 if(psLinuxEventObject->ui32TimeStampPrevious != ui32TimeStamp)
251 {
252 break;
253 }
254
255 LinuxUnLockMutex(&gPVRSRVLock);
256
257 ui32TimeOutJiffies = (IMG_UINT32)schedule_timeout((IMG_INT32)ui32TimeOutJiffies);
258
259 LinuxLockMutex(&gPVRSRVLock);
260#if defined(DEBUG)
261 psLinuxEventObject->ui32Stats++;
262#endif
263
264
265 } while (ui32TimeOutJiffies);
266
267 finish_wait(&psLinuxEventObject->sWait, &sWait);
268
269 psLinuxEventObject->ui32TimeStampPrevious = ui32TimeStamp;
270
271 return ui32TimeOutJiffies ? PVRSRV_OK : PVRSRV_ERROR_TIMEOUT;
272
273}
274