RK3368 GPU: Rogue N Init.
[firefly-linux-kernel-4.4.55.git] / drivers / staging / imgtec / rogue / event.c
1 /*************************************************************************/ /*!
2 @File
3 @Title          Event Object
4 @Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @License        Dual MIT/GPLv2
6
7 The contents of this file are subject to the MIT license as set out below.
8
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 Alternatively, the contents of this file may be used under the terms of
20 the GNU General Public License Version 2 ("GPL") in which case the provisions
21 of GPL are applicable instead of those above.
22
23 If you wish to allow use of your version of this file only under the terms of
24 GPL, and not to allow others to use your version of this file under the terms
25 of the MIT license, indicate your decision by deleting the provisions above
26 and replace them with the notice and other provisions required by GPL as set
27 out in the file called "GPL-COPYING" included in this distribution. If you do
28 not delete the provisions above, a recipient may use your version of this file
29 under the terms of either the MIT license or GPL.
30
31 This License is also included in this distribution in the file called
32 "MIT-COPYING".
33
34 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
35 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
36 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
37 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
38 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
39 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 */ /**************************************************************************/
42
43 #include <asm/io.h>
44 #include <asm/page.h>
45 #include <linux/mm.h>
46 #include <linux/slab.h>
47 #include <linux/delay.h>
48 #include <linux/pci.h>
49
50 #include <linux/string.h>
51 #include <linux/sched.h>
52 #include <linux/interrupt.h>
53 #include <asm/hardirq.h>
54 #include <linux/timer.h>
55 #include <linux/capability.h>
56 #include <asm/uaccess.h>
57
58 #include "img_types.h"
59 #include "pvrsrv_error.h"
60 #include "allocmem.h"
61 #include "event.h"
62 #include "pvr_debug.h"
63 #include "pvrsrv.h"
64
65 #include "osfunc.h"
66
67 /* Returns pointer to task_struct that belongs to thread which acquired
68  * bridge lock. */
69 extern struct task_struct *BridgeLockGetOwner(void);
70 extern IMG_BOOL BridgeLockIsLocked(void);
71
72
73 typedef struct PVRSRV_LINUX_EVENT_OBJECT_LIST_TAG
74 {
75         rwlock_t sLock;
76         struct list_head sList;
77
78 } PVRSRV_LINUX_EVENT_OBJECT_LIST;
79
80
81 typedef struct PVRSRV_LINUX_EVENT_OBJECT_TAG
82 {
83         atomic_t sTimeStamp;
84         IMG_UINT32 ui32TimeStampPrevious;
85 #if defined(DEBUG)
86         IMG_UINT ui32Stats;
87 #endif
88         wait_queue_head_t sWait;
89         struct list_head sList;
90         PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList;
91 } PVRSRV_LINUX_EVENT_OBJECT;
92
93 /*!
94 ******************************************************************************
95
96  @Function      LinuxEventObjectListCreate
97
98  @Description
99
100  Linux wait object list creation
101
102  @Output    hOSEventKM : Pointer to the event object list handle
103
104  @Return   PVRSRV_ERROR  :  Error code
105
106 ******************************************************************************/
107 PVRSRV_ERROR LinuxEventObjectListCreate(IMG_HANDLE *phEventObjectList)
108 {
109         PVRSRV_LINUX_EVENT_OBJECT_LIST *psEvenObjectList;
110
111         psEvenObjectList = OSAllocMem(sizeof(*psEvenObjectList));
112         if (psEvenObjectList == NULL)
113         {
114                 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectCreate: failed to allocate memory for event list"));
115                 return PVRSRV_ERROR_OUT_OF_MEMORY;
116         }
117
118         INIT_LIST_HEAD(&psEvenObjectList->sList);
119
120         rwlock_init(&psEvenObjectList->sLock);
121
122         *phEventObjectList = (IMG_HANDLE *) psEvenObjectList;
123
124         return PVRSRV_OK;
125 }
126
127 /*!
128 ******************************************************************************
129
130  @Function      LinuxEventObjectListDestroy
131
132  @Description
133
134  Linux wait object list destruction
135
136  @Input    hOSEventKM : Event object list handle
137
138  @Return   PVRSRV_ERROR  :  Error code
139
140 ******************************************************************************/
141 PVRSRV_ERROR LinuxEventObjectListDestroy(IMG_HANDLE hEventObjectList)
142 {
143
144         PVRSRV_LINUX_EVENT_OBJECT_LIST *psEvenObjectList = (PVRSRV_LINUX_EVENT_OBJECT_LIST *) hEventObjectList ;
145
146         if(psEvenObjectList)
147         {
148                 if (!list_empty(&psEvenObjectList->sList))
149                 {
150                          PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectListDestroy: Event List is not empty"));
151                          return PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT;
152                 }
153                 OSFreeMem(psEvenObjectList);
154                 /*not nulling pointer, copy on stack*/
155         }
156         return PVRSRV_OK;
157 }
158
159
160 /*!
161 ******************************************************************************
162
163  @Function      LinuxEventObjectDelete
164
165  @Description
166
167  Linux wait object removal
168
169  @Input    hOSEventObject : Event object handle
170
171  @Return   PVRSRV_ERROR  :  Error code
172
173 ******************************************************************************/
174 PVRSRV_ERROR LinuxEventObjectDelete(IMG_HANDLE hOSEventObject)
175 {
176         if(hOSEventObject)
177         {
178                 PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = (PVRSRV_LINUX_EVENT_OBJECT *)hOSEventObject;
179                 PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = psLinuxEventObject->psLinuxEventObjectList;
180
181                 write_lock_bh(&psLinuxEventObjectList->sLock);
182                 list_del(&psLinuxEventObject->sList);
183                 write_unlock_bh(&psLinuxEventObjectList->sLock);
184
185 #if defined(DEBUG)
186 //              PVR_DPF((PVR_DBG_MESSAGE, "LinuxEventObjectDelete: Event object waits: %u", psLinuxEventObject->ui32Stats));
187 #endif
188
189                 OSFreeMem(psLinuxEventObject);
190                 /*not nulling pointer, copy on stack*/
191
192                 return PVRSRV_OK;
193         }
194         return PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT;
195 }
196
197 /*!
198 ******************************************************************************
199
200  @Function      LinuxEventObjectAdd
201
202  @Description
203
204  Linux wait object addition
205
206  @Input    hOSEventObjectList : Event object list handle
207  @Output   phOSEventObject : Pointer to the event object handle
208
209  @Return   PVRSRV_ERROR  :  Error code
210
211 ******************************************************************************/
212 PVRSRV_ERROR LinuxEventObjectAdd(IMG_HANDLE hOSEventObjectList, IMG_HANDLE *phOSEventObject)
213  {
214         PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
215         PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = (PVRSRV_LINUX_EVENT_OBJECT_LIST*)hOSEventObjectList;
216
217         /* allocate completion variable */
218         psLinuxEventObject = OSAllocMem(sizeof(*psLinuxEventObject));
219         if (psLinuxEventObject == NULL)
220         {
221                 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectAdd: failed to allocate memory "));
222                 return PVRSRV_ERROR_OUT_OF_MEMORY;
223         }
224
225         INIT_LIST_HEAD(&psLinuxEventObject->sList);
226
227         atomic_set(&psLinuxEventObject->sTimeStamp, 0);
228         psLinuxEventObject->ui32TimeStampPrevious = 0;
229
230 #if defined(DEBUG)
231         psLinuxEventObject->ui32Stats = 0;
232 #endif
233         init_waitqueue_head(&psLinuxEventObject->sWait);
234
235         psLinuxEventObject->psLinuxEventObjectList = psLinuxEventObjectList;
236
237         write_lock_bh(&psLinuxEventObjectList->sLock);
238         list_add(&psLinuxEventObject->sList, &psLinuxEventObjectList->sList);
239         write_unlock_bh(&psLinuxEventObjectList->sLock);
240
241         *phOSEventObject = psLinuxEventObject;
242
243         return PVRSRV_OK;
244 }
245
246 /*!
247 ******************************************************************************
248
249  @Function      LinuxEventObjectSignal
250
251  @Description
252
253  Linux wait object signaling function
254
255  @Input    hOSEventObjectList : Event object list handle
256
257  @Return   PVRSRV_ERROR  :  Error code
258
259 ******************************************************************************/
260 PVRSRV_ERROR LinuxEventObjectSignal(IMG_HANDLE hOSEventObjectList)
261 {
262         PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
263         PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = (PVRSRV_LINUX_EVENT_OBJECT_LIST*)hOSEventObjectList;
264         struct list_head *psListEntry, *psListEntryTemp, *psList;
265         psList = &psLinuxEventObjectList->sList;
266
267         read_lock_bh(&psLinuxEventObjectList->sLock);
268         list_for_each_safe(psListEntry, psListEntryTemp, psList)
269         {
270
271                 psLinuxEventObject = (PVRSRV_LINUX_EVENT_OBJECT *)list_entry(psListEntry, PVRSRV_LINUX_EVENT_OBJECT, sList);
272
273                 atomic_inc(&psLinuxEventObject->sTimeStamp);
274                 wake_up_interruptible(&psLinuxEventObject->sWait);
275         }
276         read_unlock_bh(&psLinuxEventObjectList->sLock);
277
278         return  PVRSRV_OK;
279
280 }
281
282 /*!
283 ******************************************************************************
284
285  @Function      LinuxEventObjectWait
286
287  @Description
288
289  Linux wait object routine
290
291  @Input    hOSEventObject : Event object handle
292
293  @Input   ui64Timeoutus : Time out value in usec
294
295  @Return   PVRSRV_ERROR  :  Error code
296
297 ******************************************************************************/
298 PVRSRV_ERROR LinuxEventObjectWait(IMG_HANDLE hOSEventObject, IMG_UINT64 ui64Timeoutus, IMG_BOOL bHoldBridgeLock)
299 {
300         IMG_UINT32 ui32TimeStamp;
301         IMG_BOOL bReleasePVRLock;
302         PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
303         IMG_UINT32 ui32Remainder;
304         long timeOutJiffies;
305         DEFINE_WAIT(sWait);
306
307         PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = (PVRSRV_LINUX_EVENT_OBJECT *) hOSEventObject;
308
309         /* Check if the driver is good shape */
310         if (psPVRSRVData->eServicesState != PVRSRV_SERVICES_STATE_OK)
311         {
312                 return PVRSRV_ERROR_TIMEOUT;
313         }
314
315         /* usecs_to_jiffies only takes an uint. So if our timeout is bigger than an
316          * uint use the msec version. With such a long timeout we really don't need
317          * the high resolution of usecs. */
318         if (ui64Timeoutus > 0xffffffffULL)
319                 timeOutJiffies = msecs_to_jiffies(OSDivide64(ui64Timeoutus, 1000, &ui32Remainder));
320         else
321                 timeOutJiffies = usecs_to_jiffies(ui64Timeoutus);
322
323         do
324         {
325                 prepare_to_wait(&psLinuxEventObject->sWait, &sWait, TASK_INTERRUPTIBLE);
326                 ui32TimeStamp = (IMG_UINT32)atomic_read(&psLinuxEventObject->sTimeStamp);
327
328                 if(psLinuxEventObject->ui32TimeStampPrevious != ui32TimeStamp)
329                 {
330                         break;
331                 }
332
333                 /* Check thread holds the current PVR/bridge lock before obeying the
334                  * 'release before deschedule' behaviour. Some threads choose not to
335                  * hold the bridge lock in their implementation.
336                  */
337                 bReleasePVRLock = (!bHoldBridgeLock && BridgeLockIsLocked() && current == BridgeLockGetOwner());
338                 if (bReleasePVRLock == IMG_TRUE)
339                 {
340                         OSReleaseBridgeLock();
341                 }
342
343                 timeOutJiffies = schedule_timeout(timeOutJiffies);
344
345                 if (bReleasePVRLock == IMG_TRUE)
346                 {
347                         OSAcquireBridgeLock();
348                 }
349
350 #if defined(DEBUG)
351                 psLinuxEventObject->ui32Stats++;
352 #endif
353
354
355         } while (timeOutJiffies);
356
357         finish_wait(&psLinuxEventObject->sWait, &sWait);
358
359         psLinuxEventObject->ui32TimeStampPrevious = ui32TimeStamp;
360
361         return timeOutJiffies ? PVRSRV_OK : PVRSRV_ERROR_TIMEOUT;
362
363 }