RK3368 GPU version Rogue M 1.28
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / rogue_m / services / server / env / linux / osfunc.c
1 /*************************************************************************/ /*!
2 @File
3 @Title          Environment related functions
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 <linux/version.h>
44 #include <asm/io.h>
45 #include <asm/page.h>
46 #include <asm/div64.h>
47 #include <linux/mm.h>
48 #include <linux/pagemap.h>
49 #include <linux/hugetlb.h> 
50 #include <linux/slab.h>
51 #include <linux/vmalloc.h>
52 #include <linux/delay.h>
53 #include <linux/genalloc.h>
54
55 #include <linux/string.h>
56 #include <linux/sched.h>
57 #include <linux/interrupt.h>
58 #include <asm/hardirq.h>
59 #include <asm/tlbflush.h>
60 #include <asm/page.h>
61 #include <linux/timer.h>
62 #include <linux/capability.h>
63 #include <asm/uaccess.h>
64 #include <linux/spinlock.h>
65 #if defined(PVR_LINUX_MISR_USING_WORKQUEUE) || \
66         defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE) || \
67         defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || \
68         defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE) || \
69         defined(PVR_LINUX_USING_WORKQUEUES)
70 #include <linux/workqueue.h>
71 #endif
72 #include <linux/kthread.h>
73 #include <asm/atomic.h>
74
75 #include "osfunc.h"
76 #include "img_types.h"
77 #include "mm.h"
78 #include "allocmem.h"
79 #include "env_data.h"
80 #include "pvr_debugfs.h"
81 #include "event.h"
82 #include "linkage.h"
83 #include "pvr_uaccess.h"
84 #include "pvr_debug.h"
85 #include "driverlock.h"
86 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
87 #include "process_stats.h"
88 #endif
89 #if defined(SUPPORT_SYSTEM_INTERRUPT_HANDLING)
90 #include "syscommon.h"
91 #endif
92 #include "physmem_osmem_linux.h"
93
94 #if defined(VIRTUAL_PLATFORM)
95 #define EVENT_OBJECT_TIMEOUT_MS         (120000)
96 #else
97 #if defined(EMULATOR)
98 #define EVENT_OBJECT_TIMEOUT_MS         (2000)
99 #else
100 #define EVENT_OBJECT_TIMEOUT_MS         (100)
101 #endif /* EMULATOR */
102 #endif
103
104 /* Use a pool for PhysContigPages on x86 32bit so we avoid virtual address space fragmentation by vm_map_ram.
105  * ARM does not have the function to invalidate TLB entries so they have to use the kernel functions directly. */
106 #if defined(CONFIG_GENERIC_ALLOCATOR) \
107         && defined(CONFIG_X86) \
108         && !defined(CONFIG_64BIT) \
109         && (LINUX_VERSION_CODE > KERNEL_VERSION(3,0,0))
110 #define OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL 1
111 #endif
112
113 static void *g_pvBridgeBuffers = IMG_NULL;
114 static atomic_t g_DriverSuspended;
115
116 struct task_struct *OSGetBridgeLockOwner(void);
117
118 /*
119         Create a 4MB pool which should be more then enough in most cases,
120         if it becomes full then the calling code will fall back to
121         vm_map_ram.
122 */
123
124 #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL)
125 #define POOL_SIZE       (4*1024*1024)
126 static struct gen_pool *pvrsrv_pool_writecombine = NULL;
127 static char *pool_start;
128
129 static void deinit_pvr_pool(void)
130 {
131         gen_pool_destroy(pvrsrv_pool_writecombine);
132         pvrsrv_pool_writecombine = NULL;
133         vfree(pool_start);
134         pool_start = NULL;
135 }
136
137 static void init_pvr_pool(void)
138 {
139         struct vm_struct *tmp_area;
140         int ret = -1;
141
142         /* Create the pool to allocate vm space from */
143         pvrsrv_pool_writecombine = gen_pool_create(PAGE_SHIFT, -1);
144         if (!pvrsrv_pool_writecombine) {
145                 printk(KERN_ERR "%s: create pvrsrv_pool failed\n", __func__);
146                 return;
147         }
148
149         /* Reserve space in the vmalloc vm range */
150         tmp_area = __get_vm_area(POOL_SIZE, VM_ALLOC,
151                         VMALLOC_START, VMALLOC_END);
152         if (!tmp_area) {
153                 printk(KERN_ERR "%s: __get_vm_area failed\n", __func__);
154                 gen_pool_destroy(pvrsrv_pool_writecombine);
155                 pvrsrv_pool_writecombine = NULL;
156                 return;
157         }
158
159         pool_start = tmp_area->addr;
160
161         if (!pool_start) {
162                 printk(KERN_ERR "%s:No vm space to create POOL\n",
163                                 __func__);
164                 gen_pool_destroy(pvrsrv_pool_writecombine);
165                 pvrsrv_pool_writecombine = NULL;
166                 return;
167         } else {
168                 /* Add our reserved space into the pool */
169                 ret = gen_pool_add(pvrsrv_pool_writecombine,
170                         (unsigned long) pool_start, POOL_SIZE, -1);
171                 if (ret) {
172                         printk(KERN_ERR "%s:could not remainder pool\n",
173                                         __func__);
174                         deinit_pvr_pool();
175                         return;
176                 }
177         }
178         return;
179 }
180
181 static inline IMG_BOOL vmap_from_pool(void *pvCPUVAddr)
182 {
183         IMG_CHAR *pcTmp = pvCPUVAddr;
184         if ((pcTmp >= pool_start) && (pcTmp <= (pool_start + POOL_SIZE)))
185         {
186                 return IMG_TRUE;
187         }
188         return IMG_FALSE;
189 }
190 #endif  /* #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL) */
191
192 PVRSRV_ERROR OSMMUPxAlloc(PVRSRV_DEVICE_NODE *psDevNode, IMG_SIZE_T uiSize,
193                                                         Px_HANDLE *psMemHandle, IMG_DEV_PHYADDR *psDevPAddr)
194 {
195         IMG_CPU_PHYADDR sCpuPAddr;
196         struct page *psPage;
197
198         /*
199                 Check that we're not doing multiple pages worth of
200                 import as it's not supported a.t.m.
201         */
202         PVR_ASSERT(uiSize == PAGE_SIZE);
203
204         psPage = alloc_page(GFP_KERNEL);
205         if (psPage == NULL)
206         {
207                 return PVRSRV_ERROR_OUT_OF_MEMORY;
208         }
209
210 #if defined (CONFIG_X86)
211         {
212                 IMG_PVOID pvPageVAddr = page_address(psPage);
213                 int ret;
214                 ret = set_memory_wc((unsigned long)pvPageVAddr, 1);
215
216                 if (ret)
217                 {
218                         __free_page(psPage);
219                         return PVRSRV_ERROR_UNABLE_TO_SET_CACHE_MODE;
220                 }
221         }
222 #endif
223 #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined (CONFIG_METAG)
224         {
225                 IMG_CPU_PHYADDR sCPUPhysAddrStart, sCPUPhysAddrEnd;
226                 IMG_PVOID pvPageVAddr = kmap(psPage);
227
228                 sCPUPhysAddrStart.uiAddr = IMG_CAST_TO_CPUPHYADDR_UINT(page_to_phys(psPage));
229                 sCPUPhysAddrEnd.uiAddr = sCPUPhysAddrStart.uiAddr + PAGE_SIZE;
230
231                 OSInvalidateCPUCacheRangeKM(pvPageVAddr,
232                                                                         pvPageVAddr + PAGE_SIZE,
233                                                                         sCPUPhysAddrStart,
234                                                                         sCPUPhysAddrEnd);
235         }
236 #endif
237
238         psMemHandle->u.pvHandle = psPage;
239         sCpuPAddr.uiAddr = IMG_CAST_TO_CPUPHYADDR_UINT(page_to_phys(psPage));
240
241         PhysHeapCpuPAddrToDevPAddr(psDevNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_CPU_LOCAL], 1, psDevPAddr, &sCpuPAddr);
242
243 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
244 #if !defined(PVRSRV_ENABLE_MEMORY_STATS)
245             PVRSRVStatsIncrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA, PAGE_SIZE);
246 #else
247         PVRSRVStatsAddMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA,
248                                                                  psPage,
249                                                                  sCpuPAddr,
250                                                                  PAGE_SIZE,
251                                                                  IMG_NULL);
252 #endif
253 #endif
254
255         return PVRSRV_OK;
256 }
257
258 void OSMMUPxFree(PVRSRV_DEVICE_NODE *psDevNode, Px_HANDLE *psMemHandle)
259 {
260         struct page *psPage = (struct page*) psMemHandle->u.pvHandle;
261
262 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
263 #if !defined(PVRSRV_ENABLE_MEMORY_STATS)
264             PVRSRVStatsDecrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA, PAGE_SIZE);
265 #else
266         PVRSRVStatsRemoveMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA, (IMG_UINT64)(IMG_UINTPTR_T)psPage);
267 #endif
268 #endif
269
270 #if defined (CONFIG_X86)
271         {
272                 IMG_PVOID pvPageVAddr;
273                 int ret;
274
275                 pvPageVAddr = page_address(psPage);
276                 ret = set_memory_wb((unsigned long) pvPageVAddr, 1);
277                 if (ret)
278                 {
279                         PVR_DPF((PVR_DBG_ERROR, "%s: Failed to reset page attribute", __FUNCTION__));
280                 }
281         }
282 #endif
283         __free_page(psPage);
284 }
285
286 PVRSRV_ERROR OSMMUPxMap(PVRSRV_DEVICE_NODE *psDevNode, Px_HANDLE *psMemHandle,
287                                                 IMG_SIZE_T uiSize, IMG_DEV_PHYADDR *psDevPAddr,
288                                                 void **pvPtr)
289 {
290         struct page **ppsPage = (struct page **) &psMemHandle->u.pvHandle;
291         IMG_UINTPTR_T uiCPUVAddr;
292         pgprot_t prot = PAGE_KERNEL;
293         PVR_UNREFERENCED_PARAMETER(psDevNode);
294
295         prot = pgprot_writecombine(prot);
296
297 #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL)
298         uiCPUVAddr = gen_pool_alloc(pvrsrv_pool_writecombine, PAGE_SIZE);
299
300         if (uiCPUVAddr) {
301                 int ret = 0;
302                 struct vm_struct tmp_area;
303
304                 /* vmalloc and friends expect a guard page so we need to take that into account */
305                 tmp_area.addr = (void *)uiCPUVAddr;
306                 tmp_area.size =  2 * PAGE_SIZE;
307 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3,17,0))
308                 ret = map_vm_area(&tmp_area, prot, ppsPage);
309 #else
310                 ret = map_vm_area(&tmp_area, prot, & ppsPage);
311 #endif
312                 if (ret) {
313                         gen_pool_free(pvrsrv_pool_writecombine, uiCPUVAddr, PAGE_SIZE);
314                         PVR_DPF((PVR_DBG_ERROR,
315                                          "%s: Cannot map page to pool",
316                                          __func__));
317                         /* Failed the pool alloc so fall back to the vm_map path */
318                         uiCPUVAddr = 0;
319                 }
320         }
321
322         /* Not else as if the poll alloc fails it resets uiCPUVAddr to 0 */
323         if (uiCPUVAddr == 0)
324 #endif  /* #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL) */
325         {
326 #if !defined(CONFIG_64BIT) || defined(PVRSRV_FORCE_SLOWER_VMAP_ON_64BIT_BUILDS)
327                 uiCPUVAddr = (IMG_UINTPTR_T) vmap(ppsPage, 1, VM_READ | VM_WRITE, prot);
328 #else
329                 uiCPUVAddr = (IMG_UINTPTR_T) vm_map_ram(ppsPage,
330                                                                                                 1,
331                                                                                                 -1,
332                                                                                                 prot);
333 #endif
334         }
335
336         /* Check that one of the above methods got us an address */
337         if (((void *)uiCPUVAddr) == IMG_NULL)
338         {
339                 return PVRSRV_ERROR_FAILED_TO_MAP_KERNELVIRTUAL;
340         }
341
342         *pvPtr = (void *) ((uiCPUVAddr & (~OSGetPageMask())) |
343                                                         ((IMG_UINTPTR_T) (psDevPAddr->uiAddr & OSGetPageMask())));
344
345 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
346 #if !defined(PVRSRV_ENABLE_MEMORY_STATS)
347         /* Mapping is done a page at a time */
348         PVRSRVStatsIncrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA, PAGE_SIZE);
349 #else
350         {
351                 IMG_CPU_PHYADDR sCpuPAddr;
352                 sCpuPAddr.uiAddr = 0;
353
354                 PVRSRVStatsAddMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA,
355                                                                          (void *)uiCPUVAddr,
356                                                                          sCpuPAddr,
357                                                                          uiSize,
358                                                                          IMG_NULL);
359         }
360 #endif
361 #endif
362
363         return PVRSRV_OK;
364 }
365
366 void OSMMUPxUnmap(PVRSRV_DEVICE_NODE *psDevNode, Px_HANDLE *psMemHandle, void *pvPtr)
367 {
368         PVR_UNREFERENCED_PARAMETER(psDevNode);
369         PVR_UNREFERENCED_PARAMETER(psMemHandle);
370
371 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
372 #if !defined(PVRSRV_ENABLE_MEMORY_STATS)
373         /* Mapping is done a page at a time */
374         PVRSRVStatsDecrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA, PAGE_SIZE);
375 #else
376         PVRSRVStatsRemoveMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA, (IMG_UINT64)(IMG_UINTPTR_T)pvPtr);
377 #endif
378 #endif
379
380 #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL)
381         if (vmap_from_pool(pvPtr))
382         {
383                 unsigned long addr = (unsigned long)pvPtr;
384
385                 /* Flush the data cache */
386                 flush_cache_vunmap(addr, addr + PAGE_SIZE);
387                 /* Unmap the page */
388                 unmap_kernel_range_noflush(addr, PAGE_SIZE);
389                 /* Flush the TLB */
390                 __flush_tlb_single(addr);
391                 /* Free the page back to the pool */
392                 gen_pool_free(pvrsrv_pool_writecombine, addr, PAGE_SIZE);
393         }
394         else
395 #endif  /*#if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL) */
396         {
397 #if !defined(CONFIG_64BIT) || defined(PVRSRV_FORCE_SLOWER_VMAP_ON_64BIT_BUILDS)
398                 vunmap(pvPtr);
399 #else
400                 vm_unmap_ram(pvPtr, 1);
401 #endif
402         }
403 }
404
405 IMG_INT OSMemCmp(void *pvBufA, void *pvBufB, IMG_SIZE_T uiLen)
406 {
407         return (IMG_INT) memcmp(pvBufA, pvBufB, uiLen);
408 }
409
410 /*************************************************************************/ /*!
411 @Function       OSStringNCopy
412 @Description    strcpy
413 */ /**************************************************************************/
414 IMG_CHAR *OSStringNCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc, IMG_SIZE_T uSize)
415 {
416         return strncpy(pszDest, pszSrc, uSize);
417 }
418
419 /*************************************************************************/ /*!
420 @Function       OSSNPrintf
421 @Description    snprintf
422 @Return         the chars written or -1 on error
423 */ /**************************************************************************/
424 IMG_INT32 OSSNPrintf(IMG_CHAR *pStr, IMG_SIZE_T ui32Size, const IMG_CHAR *pszFormat, ...)
425 {
426         va_list argList;
427         IMG_INT32 iCount;
428
429         va_start(argList, pszFormat);
430         iCount = vsnprintf(pStr, (size_t)ui32Size, pszFormat, argList);
431         va_end(argList);
432
433         return iCount;
434 }
435
436 IMG_SIZE_T OSStringLength(const IMG_CHAR *pStr)
437 {
438         return strlen(pStr);
439 }
440
441 IMG_SIZE_T OSStringNLength(const IMG_CHAR *pStr, IMG_SIZE_T uiCount)
442 {
443         return strnlen(pStr, uiCount);
444 }
445
446 IMG_INT32 OSStringCompare(const IMG_CHAR *pStr1, const IMG_CHAR *pStr2)
447 {
448         return strcmp(pStr1, pStr2);
449 }
450
451 /*************************************************************************/ /*!
452 @Function       OSInitEnvData
453 @Description    Allocates space for env specific data
454 @Input          ppvEnvSpecificData   Pointer to pointer in which to return
455                                      allocated data.
456 @Input          ui32MMUMode          MMU mode.
457 @Return         PVRSRV_OK
458 */ /**************************************************************************/
459 PVRSRV_ERROR OSInitEnvData(void)
460 {
461         /* allocate memory for the bridge buffers to be used during an ioctl */
462         g_pvBridgeBuffers = OSAllocMem(PVRSRV_MAX_BRIDGE_IN_SIZE + PVRSRV_MAX_BRIDGE_OUT_SIZE);
463         if (g_pvBridgeBuffers == IMG_NULL)
464         {
465                 return PVRSRV_ERROR_OUT_OF_MEMORY;
466         }
467
468         atomic_set(&g_DriverSuspended, 0);
469
470 #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL)
471         /*
472                 vm_ram_ram works with 2MB blocks to avoid excessive
473                 TLB flushing but our allocations are always small and have
474                 a long lifetime which then leads to fragmentation of vmalloc space.
475                 To workaround this we create a virtual address pool in the vmap range
476                 for mapping our page tables into so we don't fragment vmalloc space.
477         */
478         if (!pvrsrv_pool_writecombine)
479         {
480                 init_pvr_pool();
481         }
482 #endif  /* #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL) */
483
484         LinuxInitPagePool();
485
486         return PVRSRV_OK;
487 }
488
489
490 /*************************************************************************/ /*!
491 @Function       OSDeInitEnvData
492 @Description    frees env specific data memory
493 @Input          pvEnvSpecificData   Pointer to private structure
494 @Return         PVRSRV_OK on success else PVRSRV_ERROR_OUT_OF_MEMORY
495 */ /**************************************************************************/
496 void OSDeInitEnvData(void)
497 {
498
499         LinuxDeinitPagePool();
500
501 #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL)
502         if (pvrsrv_pool_writecombine)
503         {
504                 deinit_pvr_pool();
505         }
506 #endif
507         if (g_pvBridgeBuffers)
508         {
509                 /* free-up the memory allocated for bridge buffers */
510                 OSFreeMem(g_pvBridgeBuffers);
511                 g_pvBridgeBuffers = IMG_NULL;
512         }
513 }
514
515 PVRSRV_ERROR OSGetGlobalBridgeBuffers(IMG_VOID **ppvBridgeInBuffer,
516                                                         IMG_UINT32 *pui32BridgeInBufferSize,
517                                                         IMG_VOID **ppvBridgeOutBuffer,
518                                                         IMG_UINT32 *pui32BridgeOutBufferSize)
519 {
520         PVR_ASSERT (ppvBridgeInBuffer && ppvBridgeOutBuffer);
521         PVR_ASSERT (pui32BridgeInBufferSize && pui32BridgeOutBufferSize);
522
523         *ppvBridgeInBuffer = g_pvBridgeBuffers;
524         *pui32BridgeInBufferSize = PVRSRV_MAX_BRIDGE_IN_SIZE;
525
526         *ppvBridgeOutBuffer = *ppvBridgeInBuffer + *pui32BridgeInBufferSize;
527         *pui32BridgeOutBufferSize = PVRSRV_MAX_BRIDGE_OUT_SIZE;
528
529         return PVRSRV_OK;
530 }
531
532 IMG_BOOL OSSetDriverSuspended(void)
533 {
534         int suspend_level = atomic_inc_return(&g_DriverSuspended);
535         return (1 != suspend_level)? IMG_FALSE: IMG_TRUE;
536 }
537
538 IMG_BOOL OSClearDriverSuspended(void)
539 {
540         int suspend_level = atomic_dec_return(&g_DriverSuspended);
541         return (0 != suspend_level)? IMG_FALSE: IMG_TRUE;
542 }
543
544 IMG_BOOL OSGetDriverSuspended(void)
545 {
546         return (0 < atomic_read(&g_DriverSuspended))? IMG_TRUE: IMG_FALSE;
547 }
548
549 /*************************************************************************/ /*!
550 @Function       OSReleaseThreadQuanta
551 @Description    Releases thread quanta
552 */ /**************************************************************************/ 
553 void OSReleaseThreadQuanta(void)
554 {
555         schedule();
556 }
557
558
559 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
560 static inline IMG_UINT32 Clockus(void)
561 {
562         return (jiffies * (1000000 / HZ));
563 }
564 #else
565 /* Not matching/aligning this API to the Clockus() API above to avoid necessary
566  * multiplication/division operations in calling code.
567  */
568 static inline IMG_UINT64 Clockns64(void)
569 {
570         IMG_UINT64 timenow;
571
572         /* Kernel thread preempt protection. Some architecture implementations 
573          * (ARM) of sched_clock are not preempt safe when the kernel is configured 
574          * as such e.g. CONFIG_PREEMPT and others.
575          */
576         preempt_disable();
577
578         /* Using sched_clock instead of ktime_get since we need a time stamp that
579          * correlates with that shown in kernel logs and trace data not one that
580          * is a bit behind. */
581         timenow = sched_clock();
582
583         preempt_enable();
584
585         return timenow;
586 }
587 #endif
588
589 /*************************************************************************/ /*!
590  @Function OSClockns64
591  @Description
592         This function returns the clock in nanoseconds. Unlike OSClockus,
593         OSClockus64 has a near 64-bit range
594 */ /**************************************************************************/
595 IMG_UINT64 OSClockns64(void)
596 {
597 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
598         return Clockns64();     
599 #else
600         return ((IMG_UINT64)Clockus()) * 1000ULL;
601 #endif
602 }
603
604 /*************************************************************************/ /*!
605  @Function OSClockus64
606  @Description
607         This function returns the clock in microseconds. Unlike OSClockus,
608         OSClockus64 has a near 64-bit range
609 */ /**************************************************************************/
610 IMG_UINT64 OSClockus64(void)
611 {
612 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
613         IMG_UINT64 timenow = Clockns64();
614         IMG_UINT32 remainder;
615         return OSDivide64r64(timenow, 1000, &remainder);
616 #else
617         return ((IMG_UINT64)Clockus());
618 #endif
619 }
620
621
622 /*************************************************************************/ /*!
623 @Function       OSClockus
624 @Description    This function returns the clock in microseconds
625 @Return         clock (us)
626 */ /**************************************************************************/ 
627 IMG_UINT32 OSClockus(void)
628 {
629 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
630         return (IMG_UINT32) OSClockus64();
631 #else
632         return Clockus();
633 #endif
634 }
635
636
637 /*************************************************************************/ /*!
638 @Function       OSClockms
639 @Description    This function returns the clock in milliseconds
640 @Return         clock (ms)
641 */ /**************************************************************************/ 
642 IMG_UINT32 OSClockms(void)
643 {
644 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
645         IMG_UINT64 timenow = Clockns64();
646         IMG_UINT32 remainder;
647
648         return OSDivide64(timenow, 1000000, &remainder);
649 #else
650         IMG_UINT64 time, j = (IMG_UINT32)jiffies;
651
652         time = j * (((1 << 16) * 1000) / HZ);
653         time >>= 16;
654
655         return (IMG_UINT32)time;
656 #endif
657 }
658
659
660 /*
661         OSWaitus
662 */
663 void OSWaitus(IMG_UINT32 ui32Timeus)
664 {
665         udelay(ui32Timeus);
666 }
667
668
669 /*
670         OSSleepms
671 */
672 void OSSleepms(IMG_UINT32 ui32Timems)
673 {
674         msleep(ui32Timems);
675 }
676
677
678 /*************************************************************************/ /*!
679 @Function       OSGetCurrentProcessID
680 @Description    Returns ID of current process (thread group)
681 @Return         ID of current process
682 *****************************************************************************/
683 IMG_PID OSGetCurrentProcessID(void)
684 {
685         if (in_interrupt())
686         {
687                 return KERNEL_ID;
688         }
689
690 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
691         return (IMG_PID)current->pgrp;
692 #else
693 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
694         return (IMG_PID)task_tgid_nr(current);
695 #else
696         return (IMG_PID)current->tgid;
697 #endif
698 #endif
699 }
700
701 /*************************************************************************/ /*!
702 @Function       OSGetCurrentProcessName
703 @Description    gets name of current process
704 @Return         process name
705 *****************************************************************************/
706 IMG_CHAR *OSGetCurrentProcessName(void)
707 {
708         return current->comm;
709 }
710
711 /*************************************************************************/ /*!
712 @Function       OSGetCurrentThreadID
713 @Description    Returns ID for current thread
714 @Return         ID of current thread
715 *****************************************************************************/
716 IMG_UINTPTR_T OSGetCurrentThreadID(void)
717 {
718         if (in_interrupt())
719         {
720                 return KERNEL_ID;
721         }
722
723         return current->pid;
724 }
725
726 /*************************************************************************/ /*!
727 @Function       OSGetPageSize
728 @Description    gets page size
729 @Return         page size
730 */ /**************************************************************************/
731 IMG_SIZE_T OSGetPageSize(void)
732 {
733         return PAGE_SIZE;
734 }
735
736 /*************************************************************************/ /*!
737 @Function       OSGetPageShift
738 @Description    gets page size
739 @Return         page size
740 */ /**************************************************************************/
741 IMG_SIZE_T OSGetPageShift(void)
742 {
743         return PAGE_SHIFT;
744 }
745
746 /*************************************************************************/ /*!
747 @Function       OSGetPageMask
748 @Description    gets page mask
749 @Return         page size
750 */ /**************************************************************************/
751 IMG_SIZE_T OSGetPageMask(void)
752 {
753         return (OSGetPageSize()-1);
754 }
755
756 #if !defined (SUPPORT_SYSTEM_INTERRUPT_HANDLING)
757 typedef struct _LISR_DATA_ {
758         PFN_LISR pfnLISR;
759         void *pvData;
760         IMG_UINT32 ui32IRQ;
761 } LISR_DATA;
762
763 /*
764         DeviceISRWrapper
765 */
766 static irqreturn_t DeviceISRWrapper(int irq, void *dev_id)
767 {
768         LISR_DATA *psLISRData = (LISR_DATA *) dev_id;
769         IMG_BOOL bStatus = IMG_FALSE;
770
771         PVR_UNREFERENCED_PARAMETER(irq);
772
773         bStatus = psLISRData->pfnLISR(psLISRData->pvData);
774
775         return bStatus ? IRQ_HANDLED : IRQ_NONE;
776 }
777 #endif
778
779 /*
780         OSInstallDeviceLISR
781 */
782 PVRSRV_ERROR OSInstallDeviceLISR(PVRSRV_DEVICE_CONFIG *psDevConfig,
783                                  IMG_HANDLE *hLISRData, 
784                                  PFN_LISR pfnLISR,
785                                  void *pvData)
786 {
787 #if defined(SUPPORT_SYSTEM_INTERRUPT_HANDLING)
788         return SysInstallDeviceLISR(psDevConfig->ui32IRQ,
789                                         psDevConfig->pszName,
790                                         pfnLISR,
791                                         pvData,
792                                         hLISRData);
793 #else
794         LISR_DATA *psLISRData;
795         unsigned long flags = 0;
796
797         psLISRData = OSAllocMem(sizeof(LISR_DATA));
798
799         psLISRData->pfnLISR = pfnLISR;
800         psLISRData->pvData = pvData;
801         psLISRData->ui32IRQ = psDevConfig->ui32IRQ;
802
803         if (psDevConfig->bIRQIsShared)
804         {
805                 flags |= IRQF_SHARED;
806         }
807
808         if (psDevConfig->eIRQActiveLevel == PVRSRV_DEVICE_IRQ_ACTIVE_HIGH)
809         {
810                 flags |= IRQF_TRIGGER_HIGH;
811         }
812         else if (psDevConfig->eIRQActiveLevel == PVRSRV_DEVICE_IRQ_ACTIVE_LOW)
813         {
814                 flags |= IRQF_TRIGGER_LOW;
815         }
816
817         PVR_TRACE(("Installing device LISR %s on IRQ %d with cookie %p", psDevConfig->pszName, psDevConfig->ui32IRQ, pvData));
818
819         if(request_irq(psDevConfig->ui32IRQ, DeviceISRWrapper,
820                 flags, psDevConfig->pszName, psLISRData))
821         {
822                 PVR_DPF((PVR_DBG_ERROR,"OSInstallDeviceLISR: Couldn't install device LISR on IRQ %d", psDevConfig->ui32IRQ));
823
824                 return PVRSRV_ERROR_UNABLE_TO_INSTALL_ISR;
825         }
826
827         *hLISRData = (IMG_HANDLE) psLISRData;
828
829         return PVRSRV_OK;
830 #endif
831 }
832
833 /*
834         OSUninstallDeviceLISR
835 */
836 PVRSRV_ERROR OSUninstallDeviceLISR(IMG_HANDLE hLISRData)
837 {
838 #if defined (SUPPORT_SYSTEM_INTERRUPT_HANDLING)
839         return SysUninstallDeviceLISR(hLISRData);
840 #else
841         LISR_DATA *psLISRData = (LISR_DATA *) hLISRData;
842
843         PVR_TRACE(("Uninstalling device LISR on IRQ %d with cookie %p", psLISRData->ui32IRQ,  psLISRData->pvData));
844
845         free_irq(psLISRData->ui32IRQ, psLISRData);
846         OSFreeMem(psLISRData);
847
848         return PVRSRV_OK;
849 #endif
850 }
851
852 #if defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE)
853 typedef struct  _MISR_DATA_ {
854         struct workqueue_struct *psWorkQueue;
855         struct work_struct sMISRWork;
856         PFN_MISR pfnMISR;
857         void *hData;
858 } MISR_DATA;
859
860 /*
861         MISRWrapper
862 */
863 static void MISRWrapper(struct work_struct *data)
864 {
865         MISR_DATA *psMISRData = container_of(data, MISR_DATA, sMISRWork);
866
867         psMISRData->pfnMISR(psMISRData->hData);
868 }
869
870 /*
871         OSInstallMISR
872 */
873 PVRSRV_ERROR OSInstallMISR(IMG_HANDLE *hMISRData, PFN_MISR pfnMISR,
874                                                         void *hData)
875 {
876         MISR_DATA *psMISRData;
877
878         psMISRData = OSAllocMem(sizeof(MISR_DATA));
879         if (psMISRData == NULL)
880         {
881                 return PVRSRV_ERROR_OUT_OF_MEMORY;
882         }
883
884         psMISRData->hData = hData;
885         psMISRData->pfnMISR = pfnMISR;
886
887         PVR_TRACE(("Installing MISR with cookie %p", psMISRData));
888
889         psMISRData->psWorkQueue = create_singlethread_workqueue("pvr_workqueue");
890
891         if (psMISRData->psWorkQueue == IMG_NULL)
892         {
893                 PVR_DPF((PVR_DBG_ERROR, "OSInstallMISR: create_singlethreaded_workqueue failed"));
894                 OSFreeMem(psMISRData);
895                 return PVRSRV_ERROR_UNABLE_TO_CREATE_THREAD;
896         }
897
898         INIT_WORK(&psMISRData->sMISRWork, MISRWrapper);
899
900         *hMISRData = (IMG_HANDLE) psMISRData;
901
902         return PVRSRV_OK;
903 }
904
905 /*
906         OSUninstallMISR
907 */
908 PVRSRV_ERROR OSUninstallMISR(IMG_HANDLE hMISRData)
909 {
910         MISR_DATA *psMISRData = (MISR_DATA *) hMISRData;
911
912         PVR_TRACE(("Uninstalling MISR"));
913
914         destroy_workqueue(psMISRData->psWorkQueue);
915         OSFreeMem(psMISRData);
916
917         return PVRSRV_OK;
918 }
919
920 /*
921         OSScheduleMISR
922 */
923 PVRSRV_ERROR OSScheduleMISR(IMG_HANDLE hMISRData)
924 {
925         MISR_DATA *psMISRData = (MISR_DATA *) hMISRData;
926
927         /*
928                 Note:
929
930                 In the case of NO_HARDWARE we want the driver to be synchronous so
931                 that we don't have to worry about waiting for previous operations
932                 to complete
933         */
934 #if defined(NO_HARDWARE)
935         psMISRData->pfnMISR(psMISRData->hData);
936 #else
937         queue_work(psMISRData->psWorkQueue, &psMISRData->sMISRWork);
938 #endif
939         return PVRSRV_OK;
940 }
941 #else   /* defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE) */
942 #if defined(PVR_LINUX_MISR_USING_WORKQUEUE)
943 typedef struct  _MISR_DATA_ {
944         struct work_struct sMISRWork;
945         PFN_MISR pfnMISR;
946         void *hData;
947 } MISR_DATA;
948
949 /*
950         MISRWrapper
951 */
952 static void MISRWrapper(struct work_struct *data)
953 {
954         MISR_DATA *psMISRData = container_of(data, MISR_DATA, sMISRWork);
955
956         psMISRData->pfnMISR(psMISRData->hData);
957 }
958
959 /*
960         OSInstallMISR
961 */
962 PVRSRV_ERROR OSInstallMISR(IMG_HANDLE *hMISRData, PFN_MISR pfnMISR, void *hData)
963 {
964         MISR_DATA *psMISRData;
965
966         psMISRData = OSAllocMem(sizeof(MISR_DATA));
967         if (psMISRData == NULL)
968         {
969                 return PVRSRV_ERROR_OUT_OF_MEMORY;
970         }
971
972         psMISRData->hData = hData;
973         psMISRData->pfnMISR = pfnMISR;
974
975         PVR_TRACE(("Installing MISR with cookie %p", psMISRData));
976
977         INIT_WORK(&psMISRData->sMISRWork, MISRWrapper);
978
979         *hMISRData = (IMG_HANDLE) psMISRData;
980
981         return PVRSRV_OK;
982 }
983
984
985 /*
986         OSUninstallMISR
987 */
988 PVRSRV_ERROR OSUninstallMISR(IMG_HANDLE hMISRData)
989 {
990         PVR_TRACE(("Uninstalling MISR"));
991
992         flush_scheduled_work();
993
994         OSFreeMem(hMISRData);
995
996         return PVRSRV_OK;
997 }
998
999 /*
1000         OSScheduleMISR
1001 */
1002 PVRSRV_ERROR OSScheduleMISR(IMG_HANDLE hMISRData)
1003 {
1004         MISR_DATA *psMISRData = hMISRData;
1005 #if defined(NO_HARDWARE)
1006         psMISRData->pfnMISR(psMISRData->hData);
1007 #else
1008         schedule_work(&psMISRData->sMISRWork);
1009 #endif
1010         return PVRSRV_OK;
1011 }
1012
1013 #else   /* #if defined(PVR_LINUX_MISR_USING_WORKQUEUE) */
1014 typedef struct _MISR_DATA_ {
1015         struct tasklet_struct sMISRTasklet;
1016         PFN_MISR pfnMISR;
1017         void *hData;
1018 } MISR_DATA;
1019
1020 /*
1021         MISRWrapper
1022 */
1023 static void MISRWrapper(unsigned long data)
1024 {
1025         MISR_DATA *psMISRData = (MISR_DATA *) data;
1026
1027         psMISRData->pfnMISR(psMISRData->hData);
1028 }
1029
1030 /*
1031         OSInstallMISR
1032 */
1033 PVRSRV_ERROR OSInstallMISR(IMG_HANDLE *hMISRData, PFN_MISR pfnMISR, void *hData)
1034 {
1035         MISR_DATA *psMISRData;
1036
1037         psMISRData = OSAllocMem(sizeof(MISR_DATA));
1038         if (psMISRData == NULL)
1039         {
1040                 return PVRSRV_ERROR_OUT_OF_MEMORY;
1041         }
1042
1043         psMISRData->hData = hData;
1044         psMISRData->pfnMISR = pfnMISR;
1045
1046         PVR_TRACE(("Installing MISR with cookie %p", psMISRData));
1047
1048         tasklet_init(&psMISRData->sMISRTasklet, MISRWrapper, (unsigned long)psMISRData);
1049
1050         *hMISRData = (IMG_HANDLE) psMISRData;
1051
1052         return PVRSRV_OK;
1053 }
1054
1055 /*
1056         OSUninstallMISR
1057 */
1058 PVRSRV_ERROR OSUninstallMISR(IMG_HANDLE hMISRData)
1059 {
1060         MISR_DATA *psMISRData = (MISR_DATA *) hMISRData;
1061
1062         PVR_TRACE(("Uninstalling MISR"));
1063
1064         tasklet_kill(&psMISRData->sMISRTasklet);
1065
1066         return PVRSRV_OK;
1067 }
1068
1069 /*
1070         OSScheduleMISR
1071 */
1072 PVRSRV_ERROR OSScheduleMISR(IMG_HANDLE hMISRData)
1073 {
1074         MISR_DATA *psMISRData = (MISR_DATA *) hMISRData;
1075
1076 #if defined(NO_HARDWARE)
1077         psMISRData->pfnMISR(psMISRData->hData);
1078 #else
1079         tasklet_schedule(&psMISRData->sMISRTasklet);
1080 #endif
1081         return PVRSRV_OK;
1082 }
1083
1084 #endif /* #if defined(PVR_LINUX_MISR_USING_WORKQUEUE) */
1085 #endif /* #if defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE) */
1086
1087 /* OS specific values for thread priority */
1088 const IMG_INT32 ai32OSPriorityValues[LAST_PRIORITY] = { -20, /* HIGHEST_PRIORITY */
1089                                                         -10, /* HIGH_PRIRIOTY */
1090                                                           0, /* NORMAL_PRIORITY */
1091                                                           9, /* LOW_PRIORITY */
1092                                                          19, /* LOWEST_PRIORITY */
1093                                                         -22};/* NOSET_PRIORITY */
1094
1095 typedef struct {
1096         struct task_struct *kthread;
1097         PFN_THREAD pfnThread;
1098         void *hData;
1099         OS_THREAD_LEVEL eThreadPriority;
1100 } OSThreadData;
1101
1102 static int OSThreadRun(void *data)
1103 {
1104         OSThreadData *psOSThreadData = data;
1105
1106         /* If i32NiceValue is acceptable, set the nice value for the new thread */
1107         if (psOSThreadData->eThreadPriority != NOSET_PRIORITY &&
1108                  psOSThreadData->eThreadPriority < LAST_PRIORITY)
1109                 set_user_nice(current, ai32OSPriorityValues[psOSThreadData->eThreadPriority]);
1110
1111         /* Call the client's kernel thread with the client's data pointer */
1112         psOSThreadData->pfnThread(psOSThreadData->hData);
1113
1114         /* Wait for OSThreadDestroy() to call kthread_stop() */
1115         while (!kthread_should_stop())
1116         {
1117                  schedule();
1118         }
1119
1120         return 0;
1121 }
1122
1123 PVRSRV_ERROR OSThreadCreate(IMG_HANDLE *phThread,
1124                                                         IMG_CHAR *pszThreadName,
1125                                                         PFN_THREAD pfnThread,
1126                                                         void *hData)
1127 {
1128         return OSThreadCreatePriority(phThread, pszThreadName, pfnThread, hData, NOSET_PRIORITY);
1129 }
1130
1131 PVRSRV_ERROR OSThreadCreatePriority(IMG_HANDLE *phThread,
1132                                     IMG_CHAR *pszThreadName,
1133                                     PFN_THREAD pfnThread,
1134                                     void *hData,
1135                                     OS_THREAD_LEVEL eThreadPriority)
1136 {
1137         OSThreadData *psOSThreadData;
1138         PVRSRV_ERROR eError;
1139
1140         psOSThreadData = OSAllocMem(sizeof(OSThreadData));
1141         if (psOSThreadData == IMG_NULL)
1142         {
1143                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
1144                 goto fail_alloc;
1145         }
1146
1147         psOSThreadData->pfnThread = pfnThread;
1148         psOSThreadData->hData = hData;
1149         psOSThreadData->eThreadPriority= eThreadPriority;
1150         psOSThreadData->kthread = kthread_run(OSThreadRun, psOSThreadData, pszThreadName);
1151
1152         if (IS_ERR(psOSThreadData->kthread))
1153         {
1154                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
1155                 goto fail_kthread;
1156         }
1157
1158         *phThread = psOSThreadData;
1159
1160         return PVRSRV_OK;
1161
1162 fail_kthread:
1163         OSFreeMem(psOSThreadData);
1164 fail_alloc:
1165         PVR_ASSERT(eError != PVRSRV_OK);
1166         return eError;
1167 }
1168
1169 PVRSRV_ERROR OSThreadDestroy(IMG_HANDLE hThread)
1170 {
1171         OSThreadData *psOSThreadData = hThread;
1172         int ret;
1173
1174         /* Let the thread know we are ready for it to end and wait for it. */
1175         ret = kthread_stop(psOSThreadData->kthread);
1176         PVR_ASSERT(ret == 0);
1177         OSFreeMem(psOSThreadData);
1178
1179         return PVRSRV_OK;
1180 }
1181
1182 void OSPanic(void)
1183 {
1184         BUG();
1185
1186 #if defined(__KLOCWORK__)
1187         /* Klocworks does not understand that BUG is terminal... */
1188         abort();
1189 #endif
1190 }
1191
1192 /*************************************************************************/ /*!
1193 @Function       OSMapPhysToLin
1194 @Description    Maps the physical memory into linear addr range
1195 @Input          BasePAddr       Physical cpu address
1196 @Input          ui32Bytes       Bytes to map
1197 @Input          ui32CacheType   Cache type
1198 @Return         Linear addr of mapping on success, else NULL
1199  */ /**************************************************************************/
1200 void *
1201 OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr,
1202                IMG_SIZE_T ui32Bytes,
1203                IMG_UINT32 ui32MappingFlags)
1204 {
1205         void *pvIORemapCookie;
1206
1207         pvIORemapCookie = IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags);
1208         if(pvIORemapCookie == IMG_NULL)
1209         {
1210                 PVR_ASSERT(0);
1211                 return IMG_NULL;
1212         }
1213
1214         return pvIORemapCookie;
1215 }
1216
1217
1218 /*************************************************************************/ /*!
1219 @Function       OSUnMapPhysToLin
1220 @Description    Unmaps memory that was mapped with OSMapPhysToLin
1221 @Input          pvLinAddr
1222 @Input          ui32Bytes
1223 @Return         TRUE on success, else FALSE
1224 */ /**************************************************************************/
1225 IMG_BOOL
1226 OSUnMapPhysToLin(void *pvLinAddr, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32MappingFlags)
1227 {
1228         PVR_UNREFERENCED_PARAMETER(ui32Bytes);
1229
1230         IOUnmapWrapper(pvLinAddr);
1231
1232         return IMG_TRUE;
1233 }
1234
1235 /*
1236         OSReadHWReg8
1237 */
1238 IMG_UINT8 OSReadHWReg8(IMG_PVOID        pvLinRegBaseAddr,
1239                                                 IMG_UINT32      ui32Offset)
1240 {
1241 #if !defined(NO_HARDWARE)
1242         return (IMG_UINT8) readb((IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1243 #else
1244         return 0x4e;    /* FIXME: OSReadHWReg should not exist in no hardware builds */
1245 #endif
1246 }
1247
1248 /*
1249         OSReadHWReg16
1250 */
1251 IMG_UINT16 OSReadHWReg16(IMG_PVOID      pvLinRegBaseAddr,
1252                                                  IMG_UINT32     ui32Offset)
1253 {
1254 #if !defined(NO_HARDWARE)
1255         return (IMG_UINT16) readw((IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1256 #else
1257         return 0x3a4e;  /* FIXME: OSReadHWReg should not exist in no hardware builds */
1258 #endif
1259 }
1260
1261 /*
1262         OSReadHWReg32
1263 */
1264 IMG_UINT32 OSReadHWReg32(IMG_PVOID      pvLinRegBaseAddr,
1265                                                  IMG_UINT32     ui32Offset)
1266 {
1267 #if !defined(NO_HARDWARE)
1268         return (IMG_UINT32) readl((IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1269 #else
1270         return 0x30f73a4e;      /* FIXME: OSReadHWReg should not exist in no hardware builds */
1271 #endif
1272 }
1273
1274
1275 /*
1276         OSReadHWReg64
1277 */
1278 IMG_UINT64 OSReadHWReg64(IMG_PVOID      pvLinRegBaseAddr,
1279                                                  IMG_UINT32     ui32Offset)
1280 {
1281         IMG_UINT64      ui64Result;
1282
1283         ui64Result = OSReadHWReg32(pvLinRegBaseAddr, ui32Offset + 4);
1284         ui64Result <<= 32;
1285         ui64Result |= (IMG_UINT64)OSReadHWReg32(pvLinRegBaseAddr, ui32Offset);
1286
1287         return ui64Result;
1288 }
1289
1290 /*
1291         OSReadHWRegBank
1292 */
1293 IMG_DEVMEM_SIZE_T OSReadHWRegBank(IMG_PVOID pvLinRegBaseAddr,
1294                                   IMG_UINT32 ui32Offset,
1295                                   IMG_UINT8 *pui8DstBuf,
1296                                   IMG_DEVMEM_SIZE_T uiDstBufLen)
1297 {
1298 #if !defined(NO_HARDWARE)
1299         IMG_DEVMEM_SIZE_T uiCounter;
1300
1301         /* FIXME: optimize this */
1302
1303         for(uiCounter = 0; uiCounter < uiDstBufLen; uiCounter++) {
1304                 *(pui8DstBuf + uiCounter) =
1305                   readb(pvLinRegBaseAddr + ui32Offset + uiCounter);
1306         }
1307
1308         return uiCounter;
1309 #else
1310         return uiDstBufLen;
1311 #endif
1312 }
1313
1314 /*
1315         OSWriteHWReg8
1316 */
1317 void OSWriteHWReg8(void                 *pvLinRegBaseAddr,
1318                                    IMG_UINT32   ui32Offset,
1319                                    IMG_UINT8    ui8Value)
1320 {
1321 #if !defined(NO_HARDWARE)
1322         writeb(ui8Value, (IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1323 #endif
1324 }
1325
1326 /*
1327         OSWriteHWReg16
1328 */
1329 void OSWriteHWReg16(void                *pvLinRegBaseAddr,
1330                                         IMG_UINT32      ui32Offset,
1331                                         IMG_UINT16      ui16Value)
1332 {
1333 #if !defined(NO_HARDWARE)
1334         writew(ui16Value, (IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1335 #endif
1336 }
1337
1338 /*
1339         OSWriteHWReg32
1340 */
1341 void OSWriteHWReg32(void                *pvLinRegBaseAddr,
1342                                         IMG_UINT32      ui32Offset,
1343                                         IMG_UINT32      ui32Value)
1344 {
1345 #if !defined(NO_HARDWARE)
1346         writel(ui32Value, (IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1347 #endif
1348 }
1349
1350
1351 /*
1352         OSWriteHWReg64
1353 */
1354 void OSWriteHWReg64(void                *pvLinRegBaseAddr,
1355                                         IMG_UINT32      ui32Offset,
1356                                         IMG_UINT64      ui64Value)
1357 {
1358 #if !defined(NO_HARDWARE)
1359         IMG_UINT32 ui32ValueLow, ui32ValueHigh;
1360
1361         ui32ValueLow = ui64Value & 0xffffffff;
1362         ui32ValueHigh = ((IMG_UINT64) (ui64Value >> 32)) & 0xffffffff;
1363
1364         writel(ui32ValueLow, pvLinRegBaseAddr + ui32Offset);
1365         writel(ui32ValueHigh, pvLinRegBaseAddr + ui32Offset + 4);
1366 #endif
1367 }
1368
1369 IMG_DEVMEM_SIZE_T OSWriteHWRegBank(void *pvLinRegBaseAddr,
1370                                                                    IMG_UINT32 ui32Offset,
1371                                                                    IMG_UINT8 *pui8SrcBuf,
1372                                                                    IMG_DEVMEM_SIZE_T uiSrcBufLen)
1373 {
1374 #if !defined(NO_HARDWARE)
1375         IMG_DEVMEM_SIZE_T uiCounter;
1376
1377         /* FIXME: optimize this */
1378
1379         for(uiCounter = 0; uiCounter < uiSrcBufLen; uiCounter++) {
1380                 writeb(*(pui8SrcBuf + uiCounter),
1381                        pvLinRegBaseAddr + ui32Offset + uiCounter);
1382         }
1383
1384         return uiCounter;
1385 #else
1386         return uiSrcBufLen;
1387 #endif
1388 }
1389
1390 #define OS_MAX_TIMERS   8
1391
1392 /* Timer callback strucure used by OSAddTimer */
1393 typedef struct TIMER_CALLBACK_DATA_TAG
1394 {
1395         IMG_BOOL                        bInUse;
1396         PFN_TIMER_FUNC          pfnTimerFunc;
1397         void                            *pvData;
1398         struct timer_list       sTimer;
1399         IMG_UINT32                      ui32Delay;
1400         IMG_BOOL                        bActive;
1401 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1402         struct work_struct      sWork;
1403 #endif
1404 }TIMER_CALLBACK_DATA;
1405
1406 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1407 static struct workqueue_struct  *psTimerWorkQueue;
1408 #endif
1409
1410 static TIMER_CALLBACK_DATA sTimers[OS_MAX_TIMERS];
1411
1412 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1413 DEFINE_MUTEX(sTimerStructLock);
1414 #else
1415 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
1416 /* The lock is used to control access to sTimers */
1417 static spinlock_t sTimerStructLock = SPIN_LOCK_UNLOCKED;
1418 #else
1419 static DEFINE_SPINLOCK(sTimerStructLock);
1420 #endif
1421 #endif
1422
1423 static void OSTimerCallbackBody(TIMER_CALLBACK_DATA *psTimerCBData)
1424 {
1425         if (!psTimerCBData->bActive)
1426                 return;
1427
1428         /* call timer callback */
1429         psTimerCBData->pfnTimerFunc(psTimerCBData->pvData);
1430
1431         /* reset timer */
1432         mod_timer(&psTimerCBData->sTimer, psTimerCBData->ui32Delay + jiffies);
1433 }
1434
1435
1436 /*************************************************************************/ /*!
1437 @Function       OSTimerCallbackWrapper
1438 @Description    OS specific timer callback wrapper function
1439 @Input          uData    Timer callback data
1440 */ /**************************************************************************/
1441 static void OSTimerCallbackWrapper(IMG_UINTPTR_T uData)
1442 {
1443         TIMER_CALLBACK_DATA     *psTimerCBData = (TIMER_CALLBACK_DATA*)uData;
1444
1445 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1446         int res;
1447
1448 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1449         res = queue_work(psTimerWorkQueue, &psTimerCBData->sWork);
1450 #else
1451         res = schedule_work(&psTimerCBData->sWork);
1452 #endif
1453         if (res == 0)
1454         {
1455                 PVR_DPF((PVR_DBG_WARNING, "OSTimerCallbackWrapper: work already queued"));
1456         }
1457 #else
1458         OSTimerCallbackBody(psTimerCBData);
1459 #endif
1460 }
1461
1462
1463 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1464 static void OSTimerWorkQueueCallBack(struct work_struct *psWork)
1465 {
1466         TIMER_CALLBACK_DATA *psTimerCBData = container_of(psWork, TIMER_CALLBACK_DATA, sWork);
1467
1468         OSTimerCallbackBody(psTimerCBData);
1469 }
1470 #endif
1471
1472 /*************************************************************************/ /*!
1473 @Function       OSAddTimer
1474 @Description    OS specific function to install a timer callback
1475 @Input          pfnTimerFunc    Timer callback
1476 @Input         *pvData          Callback data
1477 @Input          ui32MsTimeout   Callback period
1478 @Return         Valid handle success, NULL failure
1479 */ /**************************************************************************/
1480 IMG_HANDLE OSAddTimer(PFN_TIMER_FUNC pfnTimerFunc, void *pvData, IMG_UINT32 ui32MsTimeout)
1481 {
1482         TIMER_CALLBACK_DATA     *psTimerCBData;
1483         IMG_UINT32              ui32i;
1484 #if !(defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE))
1485         unsigned long           ulLockFlags;
1486 #endif
1487
1488         /* check callback */
1489         if(!pfnTimerFunc)
1490         {
1491                 PVR_DPF((PVR_DBG_ERROR, "OSAddTimer: passed invalid callback"));
1492                 return IMG_NULL;
1493         }
1494
1495         /* Allocate timer callback data structure */
1496 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1497         mutex_lock(&sTimerStructLock);
1498 #else
1499         spin_lock_irqsave(&sTimerStructLock, ulLockFlags);
1500 #endif
1501         for (ui32i = 0; ui32i < OS_MAX_TIMERS; ui32i++)
1502         {
1503                 psTimerCBData = &sTimers[ui32i];
1504                 if (!psTimerCBData->bInUse)
1505                 {
1506                         psTimerCBData->bInUse = IMG_TRUE;
1507                         break;
1508                 }
1509         }
1510 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1511         mutex_unlock(&sTimerStructLock);
1512 #else
1513         spin_unlock_irqrestore(&sTimerStructLock, ulLockFlags);
1514 #endif
1515         if (ui32i >= OS_MAX_TIMERS)
1516         {
1517                 PVR_DPF((PVR_DBG_ERROR, "OSAddTimer: all timers are in use"));
1518                 return IMG_NULL;
1519         }
1520
1521         psTimerCBData->pfnTimerFunc = pfnTimerFunc;
1522         psTimerCBData->pvData = pvData;
1523         psTimerCBData->bActive = IMG_FALSE;
1524
1525         /*
1526                 HZ = ticks per second
1527                 ui32MsTimeout = required ms delay
1528                 ticks = (Hz * ui32MsTimeout) / 1000
1529         */
1530         psTimerCBData->ui32Delay = ((HZ * ui32MsTimeout) < 1000)
1531                                                                 ?       1
1532                                                                 :       ((HZ * ui32MsTimeout) / 1000);
1533         /* initialise object */
1534         init_timer(&psTimerCBData->sTimer);
1535
1536         /* setup timer object */
1537         psTimerCBData->sTimer.function = (void *)OSTimerCallbackWrapper;
1538         psTimerCBData->sTimer.data = (IMG_UINTPTR_T)psTimerCBData;
1539
1540         return (IMG_HANDLE)(IMG_UINTPTR_T)(ui32i + 1);
1541 }
1542
1543
1544 static inline TIMER_CALLBACK_DATA *GetTimerStructure(IMG_HANDLE hTimer)
1545 {
1546         IMG_UINT32 ui32i = (IMG_UINT32)((IMG_UINTPTR_T)hTimer) - 1;
1547
1548         PVR_ASSERT(ui32i < OS_MAX_TIMERS);
1549
1550         return &sTimers[ui32i];
1551 }
1552
1553 /*************************************************************************/ /*!
1554 @Function       OSRemoveTimer
1555 @Description    OS specific function to remove a timer callback
1556 @Input          hTimer : timer handle
1557 @Return         PVRSRV_ERROR
1558 */ /**************************************************************************/
1559 PVRSRV_ERROR OSRemoveTimer (IMG_HANDLE hTimer)
1560 {
1561         TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
1562
1563         PVR_ASSERT(psTimerCBData->bInUse);
1564         PVR_ASSERT(!psTimerCBData->bActive);
1565
1566         /* free timer callback data struct */
1567         psTimerCBData->bInUse = IMG_FALSE;
1568
1569         return PVRSRV_OK;
1570 }
1571
1572
1573 /*************************************************************************/ /*!
1574 @Function       OSEnableTimer
1575 @Description    OS specific function to enable a timer callback
1576 @Input          hTimer    Timer handle
1577 @Return         PVRSRV_ERROR
1578 */ /**************************************************************************/
1579 PVRSRV_ERROR OSEnableTimer (IMG_HANDLE hTimer)
1580 {
1581         TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
1582
1583         PVR_ASSERT(psTimerCBData->bInUse);
1584         PVR_ASSERT(!psTimerCBData->bActive);
1585
1586         /* Start timer arming */
1587         psTimerCBData->bActive = IMG_TRUE;
1588
1589         /* set the expire time */
1590         psTimerCBData->sTimer.expires = psTimerCBData->ui32Delay + jiffies;
1591
1592         /* Add the timer to the list */
1593         add_timer(&psTimerCBData->sTimer);
1594
1595         return PVRSRV_OK;
1596 }
1597
1598
1599 /*************************************************************************/ /*!
1600 @Function       OSDisableTimer
1601 @Description    OS specific function to disable a timer callback
1602 @Input          hTimer    Timer handle
1603 @Return         PVRSRV_ERROR
1604 */ /**************************************************************************/
1605 PVRSRV_ERROR OSDisableTimer (IMG_HANDLE hTimer)
1606 {
1607         TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
1608
1609         PVR_ASSERT(psTimerCBData->bInUse);
1610         PVR_ASSERT(psTimerCBData->bActive);
1611
1612         /* Stop timer from arming */
1613         psTimerCBData->bActive = IMG_FALSE;
1614         smp_mb();
1615
1616 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1617         flush_workqueue(psTimerWorkQueue);
1618 #endif
1619 #if defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1620         flush_scheduled_work();
1621 #endif
1622
1623         /* remove timer */
1624         del_timer_sync(&psTimerCBData->sTimer);
1625
1626 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1627         /*
1628          * This second flush is to catch the case where the timer ran
1629          * before we managed to delete it, in which case, it will have
1630          * queued more work for the workqueue.  Since the bActive flag
1631          * has been cleared, this second flush won't result in the
1632          * timer being rearmed.
1633          */
1634         flush_workqueue(psTimerWorkQueue);
1635 #endif
1636 #if defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1637         flush_scheduled_work();
1638 #endif
1639
1640         return PVRSRV_OK;
1641 }
1642
1643
1644 /*************************************************************************/ /*!
1645 @Function       OSEventObjectCreate
1646 @Description    OS specific function to create an event object
1647 @Input          pszName      Globally unique event object name (if null name must be autogenerated)
1648 @Output         hEventObject OS event object info structure
1649 @Return         PVRSRV_ERROR
1650 */ /**************************************************************************/
1651 PVRSRV_ERROR OSEventObjectCreate(const IMG_CHAR *pszName, IMG_HANDLE *hEventObject)
1652 {
1653         PVRSRV_ERROR eError = PVRSRV_OK;
1654         PVR_UNREFERENCED_PARAMETER(pszName);
1655
1656         if(hEventObject)
1657         {
1658                 if(LinuxEventObjectListCreate(hEventObject) != PVRSRV_OK)
1659                 {
1660                          eError = PVRSRV_ERROR_OUT_OF_MEMORY;
1661                 }
1662
1663         }
1664         else
1665         {
1666                 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectCreate: hEventObject is not a valid pointer"));
1667                 eError = PVRSRV_ERROR_UNABLE_TO_CREATE_EVENT;
1668         }
1669
1670         return eError;
1671 }
1672
1673
1674 /*************************************************************************/ /*!
1675 @Function       OSEventObjectDestroy
1676 @Description    OS specific function to destroy an event object
1677 @Input          hEventObject   OS event object info structure
1678 @Return         PVRSRV_ERROR
1679 */ /**************************************************************************/
1680 PVRSRV_ERROR OSEventObjectDestroy(IMG_HANDLE hEventObject)
1681 {
1682         PVRSRV_ERROR eError = PVRSRV_OK;
1683
1684         if(hEventObject)
1685         {
1686                 LinuxEventObjectListDestroy(hEventObject);
1687         }
1688         else
1689         {
1690                 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectDestroy: hEventObject is not a valid pointer"));
1691                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1692         }
1693
1694         return eError;
1695 }
1696
1697 /*
1698  * EventObjectWaitTimeout()
1699  */
1700 static PVRSRV_ERROR EventObjectWaitTimeout(IMG_HANDLE hOSEventKM,
1701                                            IMG_UINT32 uiTimeoutMs,
1702                                            IMG_BOOL bHoldBridgeLock)
1703 {
1704     PVRSRV_ERROR eError;
1705
1706         if(hOSEventKM && uiTimeoutMs > 0)
1707         {
1708                 eError = LinuxEventObjectWait(hOSEventKM, uiTimeoutMs, bHoldBridgeLock);
1709         }
1710         else
1711         {
1712                 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectWait: invalid arguments %p, %d", hOSEventKM, uiTimeoutMs ));
1713                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1714         }
1715
1716         return eError;
1717 }
1718
1719 /*************************************************************************/ /*!
1720 @Function       OSEventObjectWaitTimeout
1721 @Description    Wait for an event with timeout as supplied. Called from client
1722 @Input          hOSEventKM    OS and kernel specific handle to event object
1723 @Input          uiTimeoutMs   Non zero time period in milliseconds to wait
1724 @Return         PVRSRV_ERROR_TIMEOUT : Wait reached wait limit and timed out
1725 @Return         PVRSRV_ERROR         : any other system error code
1726 */ /**************************************************************************/
1727 PVRSRV_ERROR OSEventObjectWaitTimeout(IMG_HANDLE hOSEventKM, IMG_UINT32 uiTimeoutMs)
1728 {
1729     return EventObjectWaitTimeout(hOSEventKM, uiTimeoutMs, IMG_FALSE);
1730 }
1731
1732 /*************************************************************************/ /*!
1733 @Function       OSEventObjectWait
1734 @Description    OS specific function to wait for an event object. Called
1735                                 from client. Uses a default wait with 100ms timeout.
1736 @Input          hOSEventKM    OS and kernel specific handle to event object
1737 @Return         PVRSRV_ERROR_TIMEOUT  : Reached wait limit and timed out
1738 @Return         PVRSRV_ERROR  : any other system error code
1739 */ /**************************************************************************/
1740 PVRSRV_ERROR OSEventObjectWait(IMG_HANDLE hOSEventKM)
1741 {
1742         return OSEventObjectWaitTimeout(hOSEventKM, EVENT_OBJECT_TIMEOUT_MS);
1743 }
1744
1745 /*************************************************************************/ /*!
1746 @Function       OSEventObjectWaitTimeoutAndHoldBridgeLock
1747 @Description    Wait for an event with timeout as supplied. Called from client
1748                 NOTE: Holds bridge lock during wait.
1749 @Input          hOSEventKM    OS and kernel specific handle to event object
1750 @Input          uiTimeoutMs   Non zero time period in milliseconds to wait
1751 @Return         PVRSRV_ERROR_TIMEOUT : Wait reached wait limit and timed out
1752 @Return         PVRSRV_ERROR         : any other system error code
1753 */ /**************************************************************************/
1754 PVRSRV_ERROR OSEventObjectWaitTimeoutAndHoldBridgeLock(IMG_HANDLE hOSEventKM, IMG_UINT32 uiTimeoutMs)
1755 {
1756         return EventObjectWaitTimeout(hOSEventKM, uiTimeoutMs, IMG_TRUE);
1757 }
1758
1759 /*************************************************************************/ /*!
1760 @Function       OSEventObjectWaitAndHoldBridgeLock
1761 @Description    OS specific function to wait for an event object. Called
1762                                 from client. Uses a default wait with 100ms timeout.
1763                 NOTE: Holds bridge lock during wait.
1764 @Input          hOSEventKM    OS and kernel specific handle to event object
1765 @Return         PVRSRV_ERROR_TIMEOUT  : Reached wait limit and timed out
1766 @Return         PVRSRV_ERROR  : any other system error code
1767 */ /**************************************************************************/
1768 PVRSRV_ERROR OSEventObjectWaitAndHoldBridgeLock(IMG_HANDLE hOSEventKM)
1769 {
1770         return OSEventObjectWaitTimeoutAndHoldBridgeLock(hOSEventKM, EVENT_OBJECT_TIMEOUT_MS);
1771 }
1772
1773 /*************************************************************************/ /*!
1774 @Function       OSEventObjectOpen
1775 @Description    OS specific function to open an event object.  Called from client
1776 @Input          hEventObject  Pointer to an event object
1777 @Output         phOSEvent     OS and kernel specific handle to event object
1778 @Return         PVRSRV_ERROR
1779 */ /**************************************************************************/
1780 PVRSRV_ERROR OSEventObjectOpen(IMG_HANDLE hEventObject,
1781                                                                                         IMG_HANDLE *phOSEvent)
1782 {
1783         PVRSRV_ERROR eError = PVRSRV_OK;
1784
1785         if(hEventObject)
1786         {
1787                 if(LinuxEventObjectAdd(hEventObject, phOSEvent) != PVRSRV_OK)
1788                 {
1789                         PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectAdd: failed"));
1790                         eError = PVRSRV_ERROR_INVALID_PARAMS;
1791                 }
1792         }
1793         else
1794         {
1795                 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectOpen: hEventObject is not a valid pointer"));
1796                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1797         }
1798
1799         return eError;
1800 }
1801
1802 /*************************************************************************/ /*!
1803 @Function       OSEventObjectClose
1804 @Description    OS specific function to close an event object.  Called from client
1805 @Input          hOSEventKM    OS and kernel specific handle to event object
1806 @Return         PVRSRV_ERROR  :
1807 */ /**************************************************************************/
1808 PVRSRV_ERROR OSEventObjectClose(IMG_HANDLE hOSEventKM)
1809 {
1810         PVRSRV_ERROR eError = PVRSRV_OK;
1811
1812         if(hOSEventKM)
1813         {
1814                 if(LinuxEventObjectDelete(hOSEventKM) != PVRSRV_OK)
1815                 {
1816                         PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectDelete: failed"));
1817                         eError = PVRSRV_ERROR_INVALID_PARAMS;
1818                 }
1819
1820         }
1821         else
1822         {
1823                 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectDestroy: hEventObject is not a valid pointer"));
1824                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1825         }
1826
1827         return eError;
1828 }
1829
1830 /*************************************************************************/ /*!
1831 @Function       OSEventObjectSignal
1832 @Description    OS specific function to 'signal' an event object.  Called from L/MISR
1833 @Input          hOSEventKM   OS and kernel specific handle to event object
1834 @Return         PVRSRV_ERROR
1835 */ /**************************************************************************/
1836 PVRSRV_ERROR OSEventObjectSignal(IMG_HANDLE hEventObject)
1837 {
1838         PVRSRV_ERROR eError;
1839
1840         if(hEventObject)
1841         {
1842                 eError = LinuxEventObjectSignal(hEventObject);
1843         }
1844         else
1845         {
1846                 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectSignal: hOSEventKM is not a valid handle"));
1847                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1848         }
1849
1850         return eError;
1851 }
1852
1853 /*************************************************************************/ /*!
1854 @Function       OSProcHasPrivSrvInit
1855 @Description    Does the process have sufficient privileges to initialise services?
1856 @Return         IMG_BOOL
1857 */ /**************************************************************************/
1858 IMG_BOOL OSProcHasPrivSrvInit(void)
1859 {
1860         return capable(CAP_SYS_ADMIN) != 0;
1861 }
1862
1863 /*************************************************************************/ /*!
1864 @Function       OSCopyToUser
1865 @Description    Copy a block of data into user space
1866 @Input          pvSrc
1867 @Output         pvDest
1868 @Input          ui32Bytes
1869 @Return   PVRSRV_ERROR  :
1870 */ /**************************************************************************/
1871 PVRSRV_ERROR OSCopyToUser(IMG_PVOID pvProcess,
1872                           void *pvDest,
1873                           const void *pvSrc,
1874                           IMG_SIZE_T ui32Bytes)
1875 {
1876         PVR_UNREFERENCED_PARAMETER(pvProcess);
1877
1878         if(pvr_copy_to_user(pvDest, pvSrc, ui32Bytes)==0)
1879                 return PVRSRV_OK;
1880         else
1881                 return PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY;
1882 }
1883
1884 /*************************************************************************/ /*!
1885 @Function       OSCopyFromUser
1886 @Description    Copy a block of data from the user space
1887 @Output         pvDest
1888 @Input          pvSrc
1889 @Input          ui32Bytes
1890 @Return         PVRSRV_ERROR  :
1891 */ /**************************************************************************/
1892 PVRSRV_ERROR OSCopyFromUser(IMG_PVOID pvProcess,
1893                             void *pvDest,
1894                             const void *pvSrc,
1895                             IMG_SIZE_T ui32Bytes)
1896 {
1897         PVR_UNREFERENCED_PARAMETER(pvProcess);
1898
1899         if(pvr_copy_from_user(pvDest, pvSrc, ui32Bytes)==0)
1900                 return PVRSRV_OK;
1901         else
1902                 return PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY;
1903 }
1904
1905 /*************************************************************************/ /*!
1906 @Function       OSAccessOK
1907 @Description    Checks if a user space pointer is valide
1908 @Input          eVerification
1909 @Input          pvUserPtr
1910 @Input          ui32Bytes
1911 @Return         IMG_BOOL :
1912 */ /**************************************************************************/
1913 IMG_BOOL OSAccessOK(IMG_VERIFY_TEST eVerification, void *pvUserPtr, IMG_SIZE_T ui32Bytes)
1914 {
1915         IMG_INT linuxType;
1916
1917         if (eVerification == PVR_VERIFY_READ)
1918         {
1919                 linuxType = VERIFY_READ;
1920         }
1921         else
1922         {
1923                 PVR_ASSERT(eVerification == PVR_VERIFY_WRITE);
1924                 linuxType = VERIFY_WRITE;
1925         }
1926
1927         return access_ok(linuxType, pvUserPtr, ui32Bytes);
1928 }
1929
1930
1931 void OSWriteMemoryBarrier(void)
1932 {
1933         wmb();
1934 }
1935
1936
1937 void OSMemoryBarrier(void)
1938 {
1939         mb();
1940 }
1941
1942 IMG_UINT64 OSDivide64r64(IMG_UINT64 ui64Divident, IMG_UINT32 ui32Divisor, IMG_UINT32 *pui32Remainder)
1943 {
1944         *pui32Remainder = do_div(ui64Divident, ui32Divisor);
1945
1946         return ui64Divident;
1947 }
1948
1949 IMG_UINT32 OSDivide64(IMG_UINT64 ui64Divident, IMG_UINT32 ui32Divisor, IMG_UINT32 *pui32Remainder)
1950 {
1951         *pui32Remainder = do_div(ui64Divident, ui32Divisor);
1952
1953         return (IMG_UINT32) ui64Divident;
1954 }
1955
1956 /* One time osfunc initialisation */
1957 PVRSRV_ERROR PVROSFuncInit(void)
1958 {
1959 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1960         {
1961                 PVR_ASSERT(!psTimerWorkQueue);
1962
1963                 psTimerWorkQueue = create_workqueue("pvr_timer");
1964                 if (psTimerWorkQueue == NULL)
1965                 {
1966                         PVR_DPF((PVR_DBG_ERROR, "%s: couldn't create timer workqueue", __FUNCTION__));
1967                         return PVRSRV_ERROR_UNABLE_TO_CREATE_THREAD;
1968                 }
1969         }
1970 #endif
1971
1972 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1973         {
1974                 IMG_UINT32 ui32i;
1975
1976                 for (ui32i = 0; ui32i < OS_MAX_TIMERS; ui32i++)
1977                 {
1978                         TIMER_CALLBACK_DATA *psTimerCBData = &sTimers[ui32i];
1979
1980                         INIT_WORK(&psTimerCBData->sWork, OSTimerWorkQueueCallBack);
1981                 }
1982         }
1983 #endif
1984         return PVRSRV_OK;
1985 }
1986
1987 /*
1988  * Osfunc deinitialisation.
1989  * Note that PVROSFuncInit may not have been called
1990  */
1991 void PVROSFuncDeInit(void)
1992 {
1993 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1994         if (psTimerWorkQueue != NULL)
1995         {
1996                 destroy_workqueue(psTimerWorkQueue);
1997                 psTimerWorkQueue = NULL;
1998         }
1999 #endif
2000 }
2001
2002 void OSDumpStack(void)
2003 {
2004         dump_stack();
2005 }
2006
2007 static struct task_struct *gsOwner;
2008
2009 void OSAcquireBridgeLock(void)
2010 {
2011         mutex_lock(&gPVRSRVLock);
2012         gsOwner = current;
2013 }
2014
2015 void OSReleaseBridgeLock(void)
2016 {
2017         gsOwner = NULL;
2018         mutex_unlock(&gPVRSRVLock);
2019 }
2020
2021 struct task_struct *OSGetBridgeLockOwner(void)
2022 {
2023         return gsOwner;
2024 }
2025
2026
2027 /*************************************************************************/ /*!
2028 @Function       OSCreateStatisticEntry
2029 @Description    Create a statistic entry in the specified folder.
2030 @Input          pszName        String containing the name for the entry.
2031 @Input          pvFolder       Reference from OSCreateStatisticFolder() of the
2032                                folder to create the entry in, or IMG_NULL for the
2033                                root.
2034 @Input          pfnStatsPrint  Pointer to function that can be used to print the
2035                                values of all the statistics.
2036 @Input          pfnIncMemRefCt Pointer to function that can be used to take a
2037                                reference on the memory backing the statistic
2038                                                            entry.
2039 @Input          pfnDecMemRefCt Pointer to function that can be used to drop a
2040                                reference on the memory backing the statistic
2041                                                            entry.
2042 @Input          pvData         OS specific reference that can be used by
2043                                pfnGetElement.
2044 @Return         Pointer void reference to the entry created, which can be
2045                 passed to OSRemoveStatisticEntry() to remove the entry.
2046 */ /**************************************************************************/
2047 IMG_PVOID OSCreateStatisticEntry(IMG_CHAR* pszName, IMG_PVOID pvFolder,
2048                                  OS_STATS_PRINT_FUNC* pfnStatsPrint,
2049                                                              OS_INC_STATS_MEM_REFCOUNT_FUNC* pfnIncMemRefCt,
2050                                                              OS_DEC_STATS_MEM_REFCOUNT_FUNC* pfnDecMemRefCt,
2051                                  IMG_PVOID pvData)
2052 {
2053         return (IMG_PVOID)PVRDebugFSCreateStatisticEntry(pszName, (PVR_DEBUGFS_DIR_DATA *)pvFolder, pfnStatsPrint, pfnIncMemRefCt, pfnDecMemRefCt, pvData);
2054 } /* OSCreateStatisticEntry */
2055
2056
2057 /*************************************************************************/ /*!
2058 @Function       OSRemoveStatisticEntry
2059 @Description    Removes a statistic entry.
2060 @Input          pvEntry  Pointer void reference to the entry created by
2061                          OSCreateStatisticEntry().
2062 */ /**************************************************************************/
2063 void OSRemoveStatisticEntry(IMG_PVOID pvEntry)
2064 {
2065         PVRDebugFSRemoveStatisticEntry((PVR_DEBUGFS_DRIVER_STAT *)pvEntry);
2066 } /* OSRemoveStatisticEntry */
2067
2068
2069 /*************************************************************************/ /*!
2070 @Function       OSCreateStatisticFolder
2071 @Description    Create a statistic folder to hold statistic entries.
2072 @Input          pszName   String containing the name for the folder.
2073 @Input          pvFolder  Reference from OSCreateStatisticFolder() of the folder
2074                           to create the folder in, or IMG_NULL for the root.
2075 @Return         Pointer void reference to the folder created, which can be
2076                 passed to OSRemoveStatisticFolder() to remove the folder.
2077 */ /**************************************************************************/
2078 IMG_PVOID OSCreateStatisticFolder(IMG_CHAR *pszName, IMG_PVOID pvFolder)
2079 {
2080         PVR_DEBUGFS_DIR_DATA *psNewStatFolder = IMG_NULL;
2081         int iResult;
2082
2083         iResult = PVRDebugFSCreateEntryDir(pszName, (PVR_DEBUGFS_DIR_DATA *)pvFolder, &psNewStatFolder);
2084         return (iResult == 0) ? (void *)psNewStatFolder : IMG_NULL;
2085 } /* OSCreateStatisticFolder */
2086
2087
2088 /*************************************************************************/ /*!
2089 @Function       OSRemoveStatisticFolder
2090 @Description    Removes a statistic folder.
2091 @Input          pvFolder  Reference from OSCreateStatisticFolder() of the
2092                           folder that should be removed.
2093 */ /**************************************************************************/
2094 void OSRemoveStatisticFolder(IMG_PVOID pvFolder)
2095 {
2096         PVRDebugFSRemoveEntryDir((PVR_DEBUGFS_DIR_DATA *)pvFolder);
2097 } /* OSRemoveStatisticFolder */