1 /*************************************************************************/ /*!
3 @Title Environment related functions
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @License Dual MIT/GPLv2
7 The contents of this file are subject to the MIT license as set out below.
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:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
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.
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.
31 This License is also included in this distribution in the file called
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 */ /**************************************************************************/
43 #include <linux/version.h>
46 #include <asm/div64.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>
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>
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>
72 #include <linux/kthread.h>
73 #include <asm/atomic.h>
76 #include "img_types.h"
80 #include "pvr_debugfs.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"
89 #if defined(SUPPORT_SYSTEM_INTERRUPT_HANDLING)
90 #include "syscommon.h"
92 #include "physmem_osmem_linux.h"
94 #if defined(VIRTUAL_PLATFORM)
95 #define EVENT_OBJECT_TIMEOUT_MS (120000)
98 #define EVENT_OBJECT_TIMEOUT_MS (2000)
100 #define EVENT_OBJECT_TIMEOUT_MS (100)
101 #endif /* EMULATOR */
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
113 static void *g_pvBridgeBuffers = IMG_NULL;
114 static atomic_t g_DriverSuspended;
116 struct task_struct *OSGetBridgeLockOwner(void);
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
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;
129 static void deinit_pvr_pool(void)
131 gen_pool_destroy(pvrsrv_pool_writecombine);
132 pvrsrv_pool_writecombine = NULL;
137 static void init_pvr_pool(void)
139 struct vm_struct *tmp_area;
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__);
149 /* Reserve space in the vmalloc vm range */
150 tmp_area = __get_vm_area(POOL_SIZE, VM_ALLOC,
151 VMALLOC_START, VMALLOC_END);
153 printk(KERN_ERR "%s: __get_vm_area failed\n", __func__);
154 gen_pool_destroy(pvrsrv_pool_writecombine);
155 pvrsrv_pool_writecombine = NULL;
159 pool_start = tmp_area->addr;
162 printk(KERN_ERR "%s:No vm space to create POOL\n",
164 gen_pool_destroy(pvrsrv_pool_writecombine);
165 pvrsrv_pool_writecombine = NULL;
168 /* Add our reserved space into the pool */
169 ret = gen_pool_add(pvrsrv_pool_writecombine,
170 (unsigned long) pool_start, POOL_SIZE, -1);
172 printk(KERN_ERR "%s:could not remainder pool\n",
181 static inline IMG_BOOL vmap_from_pool(void *pvCPUVAddr)
183 IMG_CHAR *pcTmp = pvCPUVAddr;
184 if ((pcTmp >= pool_start) && (pcTmp <= (pool_start + POOL_SIZE)))
190 #endif /* #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL) */
192 PVRSRV_ERROR OSMMUPxAlloc(PVRSRV_DEVICE_NODE *psDevNode, IMG_SIZE_T uiSize,
193 Px_HANDLE *psMemHandle, IMG_DEV_PHYADDR *psDevPAddr)
195 IMG_CPU_PHYADDR sCpuPAddr;
199 Check that we're not doing multiple pages worth of
200 import as it's not supported a.t.m.
202 PVR_ASSERT(uiSize == PAGE_SIZE);
204 psPage = alloc_page(GFP_KERNEL);
207 return PVRSRV_ERROR_OUT_OF_MEMORY;
210 #if defined (CONFIG_X86)
212 IMG_PVOID pvPageVAddr = page_address(psPage);
214 ret = set_memory_wc((unsigned long)pvPageVAddr, 1);
219 return PVRSRV_ERROR_UNABLE_TO_SET_CACHE_MODE;
223 #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined (CONFIG_METAG)
225 IMG_CPU_PHYADDR sCPUPhysAddrStart, sCPUPhysAddrEnd;
226 IMG_PVOID pvPageVAddr = kmap(psPage);
228 sCPUPhysAddrStart.uiAddr = IMG_CAST_TO_CPUPHYADDR_UINT(page_to_phys(psPage));
229 sCPUPhysAddrEnd.uiAddr = sCPUPhysAddrStart.uiAddr + PAGE_SIZE;
231 OSInvalidateCPUCacheRangeKM(pvPageVAddr,
232 pvPageVAddr + PAGE_SIZE,
238 psMemHandle->u.pvHandle = psPage;
239 sCpuPAddr.uiAddr = IMG_CAST_TO_CPUPHYADDR_UINT(page_to_phys(psPage));
241 PhysHeapCpuPAddrToDevPAddr(psDevNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_CPU_LOCAL], 1, psDevPAddr, &sCpuPAddr);
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);
247 PVRSRVStatsAddMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA,
258 void OSMMUPxFree(PVRSRV_DEVICE_NODE *psDevNode, Px_HANDLE *psMemHandle)
260 struct page *psPage = (struct page*) psMemHandle->u.pvHandle;
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);
266 PVRSRVStatsRemoveMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_UMA, (IMG_UINT64)(IMG_UINTPTR_T)psPage);
270 #if defined (CONFIG_X86)
272 IMG_PVOID pvPageVAddr;
275 pvPageVAddr = page_address(psPage);
276 ret = set_memory_wb((unsigned long) pvPageVAddr, 1);
279 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to reset page attribute", __FUNCTION__));
286 PVRSRV_ERROR OSMMUPxMap(PVRSRV_DEVICE_NODE *psDevNode, Px_HANDLE *psMemHandle,
287 IMG_SIZE_T uiSize, IMG_DEV_PHYADDR *psDevPAddr,
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);
295 prot = pgprot_writecombine(prot);
297 #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL)
298 uiCPUVAddr = gen_pool_alloc(pvrsrv_pool_writecombine, PAGE_SIZE);
302 struct vm_struct tmp_area;
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);
310 ret = map_vm_area(&tmp_area, prot, & ppsPage);
313 gen_pool_free(pvrsrv_pool_writecombine, uiCPUVAddr, PAGE_SIZE);
314 PVR_DPF((PVR_DBG_ERROR,
315 "%s: Cannot map page to pool",
317 /* Failed the pool alloc so fall back to the vm_map path */
322 /* Not else as if the poll alloc fails it resets uiCPUVAddr to 0 */
324 #endif /* #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL) */
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);
329 uiCPUVAddr = (IMG_UINTPTR_T) vm_map_ram(ppsPage,
336 /* Check that one of the above methods got us an address */
337 if (((void *)uiCPUVAddr) == IMG_NULL)
339 return PVRSRV_ERROR_FAILED_TO_MAP_KERNELVIRTUAL;
342 *pvPtr = (void *) ((uiCPUVAddr & (~OSGetPageMask())) |
343 ((IMG_UINTPTR_T) (psDevPAddr->uiAddr & OSGetPageMask())));
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);
351 IMG_CPU_PHYADDR sCpuPAddr;
352 sCpuPAddr.uiAddr = 0;
354 PVRSRVStatsAddMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA,
366 void OSMMUPxUnmap(PVRSRV_DEVICE_NODE *psDevNode, Px_HANDLE *psMemHandle, void *pvPtr)
368 PVR_UNREFERENCED_PARAMETER(psDevNode);
369 PVR_UNREFERENCED_PARAMETER(psMemHandle);
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);
376 PVRSRVStatsRemoveMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_VMAP_PT_UMA, (IMG_UINT64)(IMG_UINTPTR_T)pvPtr);
380 #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL)
381 if (vmap_from_pool(pvPtr))
383 unsigned long addr = (unsigned long)pvPtr;
385 /* Flush the data cache */
386 flush_cache_vunmap(addr, addr + PAGE_SIZE);
388 unmap_kernel_range_noflush(addr, PAGE_SIZE);
390 __flush_tlb_single(addr);
391 /* Free the page back to the pool */
392 gen_pool_free(pvrsrv_pool_writecombine, addr, PAGE_SIZE);
395 #endif /*#if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL) */
397 #if !defined(CONFIG_64BIT) || defined(PVRSRV_FORCE_SLOWER_VMAP_ON_64BIT_BUILDS)
400 vm_unmap_ram(pvPtr, 1);
405 IMG_INT OSMemCmp(void *pvBufA, void *pvBufB, IMG_SIZE_T uiLen)
407 return (IMG_INT) memcmp(pvBufA, pvBufB, uiLen);
410 /*************************************************************************/ /*!
411 @Function OSStringNCopy
413 */ /**************************************************************************/
414 IMG_CHAR *OSStringNCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc, IMG_SIZE_T uSize)
416 return strncpy(pszDest, pszSrc, uSize);
419 /*************************************************************************/ /*!
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, ...)
429 va_start(argList, pszFormat);
430 iCount = vsnprintf(pStr, (size_t)ui32Size, pszFormat, argList);
436 IMG_SIZE_T OSStringLength(const IMG_CHAR *pStr)
441 IMG_SIZE_T OSStringNLength(const IMG_CHAR *pStr, IMG_SIZE_T uiCount)
443 return strnlen(pStr, uiCount);
446 IMG_INT32 OSStringCompare(const IMG_CHAR *pStr1, const IMG_CHAR *pStr2)
448 return strcmp(pStr1, pStr2);
451 /*************************************************************************/ /*!
452 @Function OSInitEnvData
453 @Description Allocates space for env specific data
454 @Input ppvEnvSpecificData Pointer to pointer in which to return
456 @Input ui32MMUMode MMU mode.
458 */ /**************************************************************************/
459 PVRSRV_ERROR OSInitEnvData(void)
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)
465 return PVRSRV_ERROR_OUT_OF_MEMORY;
468 atomic_set(&g_DriverSuspended, 0);
470 #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL)
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.
478 if (!pvrsrv_pool_writecombine)
482 #endif /* #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL) */
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)
499 LinuxDeinitPagePool();
501 #if defined(OSFUNC_USE_PHYS_CONTIG_PAGES_MAP_POOL)
502 if (pvrsrv_pool_writecombine)
507 if (g_pvBridgeBuffers)
509 /* free-up the memory allocated for bridge buffers */
510 OSFreeMem(g_pvBridgeBuffers);
511 g_pvBridgeBuffers = IMG_NULL;
515 PVRSRV_ERROR OSGetGlobalBridgeBuffers(IMG_VOID **ppvBridgeInBuffer,
516 IMG_UINT32 *pui32BridgeInBufferSize,
517 IMG_VOID **ppvBridgeOutBuffer,
518 IMG_UINT32 *pui32BridgeOutBufferSize)
520 PVR_ASSERT (ppvBridgeInBuffer && ppvBridgeOutBuffer);
521 PVR_ASSERT (pui32BridgeInBufferSize && pui32BridgeOutBufferSize);
523 *ppvBridgeInBuffer = g_pvBridgeBuffers;
524 *pui32BridgeInBufferSize = PVRSRV_MAX_BRIDGE_IN_SIZE;
526 *ppvBridgeOutBuffer = *ppvBridgeInBuffer + *pui32BridgeInBufferSize;
527 *pui32BridgeOutBufferSize = PVRSRV_MAX_BRIDGE_OUT_SIZE;
532 IMG_BOOL OSSetDriverSuspended(void)
534 int suspend_level = atomic_inc_return(&g_DriverSuspended);
535 return (1 != suspend_level)? IMG_FALSE: IMG_TRUE;
538 IMG_BOOL OSClearDriverSuspended(void)
540 int suspend_level = atomic_dec_return(&g_DriverSuspended);
541 return (0 != suspend_level)? IMG_FALSE: IMG_TRUE;
544 IMG_BOOL OSGetDriverSuspended(void)
546 return (0 < atomic_read(&g_DriverSuspended))? IMG_TRUE: IMG_FALSE;
549 /*************************************************************************/ /*!
550 @Function OSReleaseThreadQuanta
551 @Description Releases thread quanta
552 */ /**************************************************************************/
553 void OSReleaseThreadQuanta(void)
559 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
560 static inline IMG_UINT32 Clockus(void)
562 return (jiffies * (1000000 / HZ));
565 /* Not matching/aligning this API to the Clockus() API above to avoid necessary
566 * multiplication/division operations in calling code.
568 static inline IMG_UINT64 Clockns64(void)
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.
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();
589 /*************************************************************************/ /*!
590 @Function OSClockns64
592 This function returns the clock in nanoseconds. Unlike OSClockus,
593 OSClockus64 has a near 64-bit range
594 */ /**************************************************************************/
595 IMG_UINT64 OSClockns64(void)
597 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
600 return ((IMG_UINT64)Clockus()) * 1000ULL;
604 /*************************************************************************/ /*!
605 @Function OSClockus64
607 This function returns the clock in microseconds. Unlike OSClockus,
608 OSClockus64 has a near 64-bit range
609 */ /**************************************************************************/
610 IMG_UINT64 OSClockus64(void)
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);
617 return ((IMG_UINT64)Clockus());
622 /*************************************************************************/ /*!
624 @Description This function returns the clock in microseconds
626 */ /**************************************************************************/
627 IMG_UINT32 OSClockus(void)
629 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
630 return (IMG_UINT32) OSClockus64();
637 /*************************************************************************/ /*!
639 @Description This function returns the clock in milliseconds
641 */ /**************************************************************************/
642 IMG_UINT32 OSClockms(void)
644 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
645 IMG_UINT64 timenow = Clockns64();
646 IMG_UINT32 remainder;
648 return OSDivide64(timenow, 1000000, &remainder);
650 IMG_UINT64 time, j = (IMG_UINT32)jiffies;
652 time = j * (((1 << 16) * 1000) / HZ);
655 return (IMG_UINT32)time;
663 void OSWaitus(IMG_UINT32 ui32Timeus)
672 void OSSleepms(IMG_UINT32 ui32Timems)
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)
690 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
691 return (IMG_PID)current->pgrp;
693 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
694 return (IMG_PID)task_tgid_nr(current);
696 return (IMG_PID)current->tgid;
701 /*************************************************************************/ /*!
702 @Function OSGetCurrentProcessName
703 @Description gets name of current process
705 *****************************************************************************/
706 IMG_CHAR *OSGetCurrentProcessName(void)
708 return current->comm;
711 /*************************************************************************/ /*!
712 @Function OSGetCurrentThreadID
713 @Description Returns ID for current thread
714 @Return ID of current thread
715 *****************************************************************************/
716 IMG_UINTPTR_T OSGetCurrentThreadID(void)
726 /*************************************************************************/ /*!
727 @Function OSGetPageSize
728 @Description gets page size
730 */ /**************************************************************************/
731 IMG_SIZE_T OSGetPageSize(void)
736 /*************************************************************************/ /*!
737 @Function OSGetPageShift
738 @Description gets page size
740 */ /**************************************************************************/
741 IMG_SIZE_T OSGetPageShift(void)
746 /*************************************************************************/ /*!
747 @Function OSGetPageMask
748 @Description gets page mask
750 */ /**************************************************************************/
751 IMG_SIZE_T OSGetPageMask(void)
753 return (OSGetPageSize()-1);
756 #if !defined (SUPPORT_SYSTEM_INTERRUPT_HANDLING)
757 typedef struct _LISR_DATA_ {
766 static irqreturn_t DeviceISRWrapper(int irq, void *dev_id)
768 LISR_DATA *psLISRData = (LISR_DATA *) dev_id;
769 IMG_BOOL bStatus = IMG_FALSE;
771 PVR_UNREFERENCED_PARAMETER(irq);
773 bStatus = psLISRData->pfnLISR(psLISRData->pvData);
775 return bStatus ? IRQ_HANDLED : IRQ_NONE;
782 PVRSRV_ERROR OSInstallDeviceLISR(PVRSRV_DEVICE_CONFIG *psDevConfig,
783 IMG_HANDLE *hLISRData,
787 #if defined(SUPPORT_SYSTEM_INTERRUPT_HANDLING)
788 return SysInstallDeviceLISR(psDevConfig->ui32IRQ,
789 psDevConfig->pszName,
794 LISR_DATA *psLISRData;
795 unsigned long flags = 0;
797 psLISRData = OSAllocMem(sizeof(LISR_DATA));
799 psLISRData->pfnLISR = pfnLISR;
800 psLISRData->pvData = pvData;
801 psLISRData->ui32IRQ = psDevConfig->ui32IRQ;
803 if (psDevConfig->bIRQIsShared)
805 flags |= IRQF_SHARED;
808 if (psDevConfig->eIRQActiveLevel == PVRSRV_DEVICE_IRQ_ACTIVE_HIGH)
810 flags |= IRQF_TRIGGER_HIGH;
812 else if (psDevConfig->eIRQActiveLevel == PVRSRV_DEVICE_IRQ_ACTIVE_LOW)
814 flags |= IRQF_TRIGGER_LOW;
817 PVR_TRACE(("Installing device LISR %s on IRQ %d with cookie %p", psDevConfig->pszName, psDevConfig->ui32IRQ, pvData));
819 if(request_irq(psDevConfig->ui32IRQ, DeviceISRWrapper,
820 flags, psDevConfig->pszName, psLISRData))
822 PVR_DPF((PVR_DBG_ERROR,"OSInstallDeviceLISR: Couldn't install device LISR on IRQ %d", psDevConfig->ui32IRQ));
824 return PVRSRV_ERROR_UNABLE_TO_INSTALL_ISR;
827 *hLISRData = (IMG_HANDLE) psLISRData;
834 OSUninstallDeviceLISR
836 PVRSRV_ERROR OSUninstallDeviceLISR(IMG_HANDLE hLISRData)
838 #if defined (SUPPORT_SYSTEM_INTERRUPT_HANDLING)
839 return SysUninstallDeviceLISR(hLISRData);
841 LISR_DATA *psLISRData = (LISR_DATA *) hLISRData;
843 PVR_TRACE(("Uninstalling device LISR on IRQ %d with cookie %p", psLISRData->ui32IRQ, psLISRData->pvData));
845 free_irq(psLISRData->ui32IRQ, psLISRData);
846 OSFreeMem(psLISRData);
852 #if defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE)
853 typedef struct _MISR_DATA_ {
854 struct workqueue_struct *psWorkQueue;
855 struct work_struct sMISRWork;
863 static void MISRWrapper(struct work_struct *data)
865 MISR_DATA *psMISRData = container_of(data, MISR_DATA, sMISRWork);
867 psMISRData->pfnMISR(psMISRData->hData);
873 PVRSRV_ERROR OSInstallMISR(IMG_HANDLE *hMISRData, PFN_MISR pfnMISR,
876 MISR_DATA *psMISRData;
878 psMISRData = OSAllocMem(sizeof(MISR_DATA));
879 if (psMISRData == NULL)
881 return PVRSRV_ERROR_OUT_OF_MEMORY;
884 psMISRData->hData = hData;
885 psMISRData->pfnMISR = pfnMISR;
887 PVR_TRACE(("Installing MISR with cookie %p", psMISRData));
889 psMISRData->psWorkQueue = create_singlethread_workqueue("pvr_workqueue");
891 if (psMISRData->psWorkQueue == IMG_NULL)
893 PVR_DPF((PVR_DBG_ERROR, "OSInstallMISR: create_singlethreaded_workqueue failed"));
894 OSFreeMem(psMISRData);
895 return PVRSRV_ERROR_UNABLE_TO_CREATE_THREAD;
898 INIT_WORK(&psMISRData->sMISRWork, MISRWrapper);
900 *hMISRData = (IMG_HANDLE) psMISRData;
908 PVRSRV_ERROR OSUninstallMISR(IMG_HANDLE hMISRData)
910 MISR_DATA *psMISRData = (MISR_DATA *) hMISRData;
912 PVR_TRACE(("Uninstalling MISR"));
914 destroy_workqueue(psMISRData->psWorkQueue);
915 OSFreeMem(psMISRData);
923 PVRSRV_ERROR OSScheduleMISR(IMG_HANDLE hMISRData)
925 MISR_DATA *psMISRData = (MISR_DATA *) hMISRData;
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
934 #if defined(NO_HARDWARE)
935 psMISRData->pfnMISR(psMISRData->hData);
937 queue_work(psMISRData->psWorkQueue, &psMISRData->sMISRWork);
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;
952 static void MISRWrapper(struct work_struct *data)
954 MISR_DATA *psMISRData = container_of(data, MISR_DATA, sMISRWork);
956 psMISRData->pfnMISR(psMISRData->hData);
962 PVRSRV_ERROR OSInstallMISR(IMG_HANDLE *hMISRData, PFN_MISR pfnMISR, void *hData)
964 MISR_DATA *psMISRData;
966 psMISRData = OSAllocMem(sizeof(MISR_DATA));
967 if (psMISRData == NULL)
969 return PVRSRV_ERROR_OUT_OF_MEMORY;
972 psMISRData->hData = hData;
973 psMISRData->pfnMISR = pfnMISR;
975 PVR_TRACE(("Installing MISR with cookie %p", psMISRData));
977 INIT_WORK(&psMISRData->sMISRWork, MISRWrapper);
979 *hMISRData = (IMG_HANDLE) psMISRData;
988 PVRSRV_ERROR OSUninstallMISR(IMG_HANDLE hMISRData)
990 PVR_TRACE(("Uninstalling MISR"));
992 flush_scheduled_work();
994 OSFreeMem(hMISRData);
1002 PVRSRV_ERROR OSScheduleMISR(IMG_HANDLE hMISRData)
1004 MISR_DATA *psMISRData = hMISRData;
1005 #if defined(NO_HARDWARE)
1006 psMISRData->pfnMISR(psMISRData->hData);
1008 schedule_work(&psMISRData->sMISRWork);
1013 #else /* #if defined(PVR_LINUX_MISR_USING_WORKQUEUE) */
1014 typedef struct _MISR_DATA_ {
1015 struct tasklet_struct sMISRTasklet;
1023 static void MISRWrapper(unsigned long data)
1025 MISR_DATA *psMISRData = (MISR_DATA *) data;
1027 psMISRData->pfnMISR(psMISRData->hData);
1033 PVRSRV_ERROR OSInstallMISR(IMG_HANDLE *hMISRData, PFN_MISR pfnMISR, void *hData)
1035 MISR_DATA *psMISRData;
1037 psMISRData = OSAllocMem(sizeof(MISR_DATA));
1038 if (psMISRData == NULL)
1040 return PVRSRV_ERROR_OUT_OF_MEMORY;
1043 psMISRData->hData = hData;
1044 psMISRData->pfnMISR = pfnMISR;
1046 PVR_TRACE(("Installing MISR with cookie %p", psMISRData));
1048 tasklet_init(&psMISRData->sMISRTasklet, MISRWrapper, (unsigned long)psMISRData);
1050 *hMISRData = (IMG_HANDLE) psMISRData;
1058 PVRSRV_ERROR OSUninstallMISR(IMG_HANDLE hMISRData)
1060 MISR_DATA *psMISRData = (MISR_DATA *) hMISRData;
1062 PVR_TRACE(("Uninstalling MISR"));
1064 tasklet_kill(&psMISRData->sMISRTasklet);
1072 PVRSRV_ERROR OSScheduleMISR(IMG_HANDLE hMISRData)
1074 MISR_DATA *psMISRData = (MISR_DATA *) hMISRData;
1076 #if defined(NO_HARDWARE)
1077 psMISRData->pfnMISR(psMISRData->hData);
1079 tasklet_schedule(&psMISRData->sMISRTasklet);
1084 #endif /* #if defined(PVR_LINUX_MISR_USING_WORKQUEUE) */
1085 #endif /* #if defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE) */
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 */
1096 struct task_struct *kthread;
1097 PFN_THREAD pfnThread;
1099 OS_THREAD_LEVEL eThreadPriority;
1102 static int OSThreadRun(void *data)
1104 OSThreadData *psOSThreadData = data;
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]);
1111 /* Call the client's kernel thread with the client's data pointer */
1112 psOSThreadData->pfnThread(psOSThreadData->hData);
1114 /* Wait for OSThreadDestroy() to call kthread_stop() */
1115 while (!kthread_should_stop())
1123 PVRSRV_ERROR OSThreadCreate(IMG_HANDLE *phThread,
1124 IMG_CHAR *pszThreadName,
1125 PFN_THREAD pfnThread,
1128 return OSThreadCreatePriority(phThread, pszThreadName, pfnThread, hData, NOSET_PRIORITY);
1131 PVRSRV_ERROR OSThreadCreatePriority(IMG_HANDLE *phThread,
1132 IMG_CHAR *pszThreadName,
1133 PFN_THREAD pfnThread,
1135 OS_THREAD_LEVEL eThreadPriority)
1137 OSThreadData *psOSThreadData;
1138 PVRSRV_ERROR eError;
1140 psOSThreadData = OSAllocMem(sizeof(OSThreadData));
1141 if (psOSThreadData == IMG_NULL)
1143 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
1147 psOSThreadData->pfnThread = pfnThread;
1148 psOSThreadData->hData = hData;
1149 psOSThreadData->eThreadPriority= eThreadPriority;
1150 psOSThreadData->kthread = kthread_run(OSThreadRun, psOSThreadData, pszThreadName);
1152 if (IS_ERR(psOSThreadData->kthread))
1154 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
1158 *phThread = psOSThreadData;
1163 OSFreeMem(psOSThreadData);
1165 PVR_ASSERT(eError != PVRSRV_OK);
1169 PVRSRV_ERROR OSThreadDestroy(IMG_HANDLE hThread)
1171 OSThreadData *psOSThreadData = hThread;
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);
1186 #if defined(__KLOCWORK__)
1187 /* Klocworks does not understand that BUG is terminal... */
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 */ /**************************************************************************/
1201 OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr,
1202 IMG_SIZE_T ui32Bytes,
1203 IMG_UINT32 ui32MappingFlags)
1205 void *pvIORemapCookie;
1207 pvIORemapCookie = IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags);
1208 if(pvIORemapCookie == IMG_NULL)
1214 return pvIORemapCookie;
1218 /*************************************************************************/ /*!
1219 @Function OSUnMapPhysToLin
1220 @Description Unmaps memory that was mapped with OSMapPhysToLin
1223 @Return TRUE on success, else FALSE
1224 */ /**************************************************************************/
1226 OSUnMapPhysToLin(void *pvLinAddr, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32MappingFlags)
1228 PVR_UNREFERENCED_PARAMETER(ui32Bytes);
1230 IOUnmapWrapper(pvLinAddr);
1238 IMG_UINT8 OSReadHWReg8(IMG_PVOID pvLinRegBaseAddr,
1239 IMG_UINT32 ui32Offset)
1241 #if !defined(NO_HARDWARE)
1242 return (IMG_UINT8) readb((IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1244 return 0x4e; /* FIXME: OSReadHWReg should not exist in no hardware builds */
1251 IMG_UINT16 OSReadHWReg16(IMG_PVOID pvLinRegBaseAddr,
1252 IMG_UINT32 ui32Offset)
1254 #if !defined(NO_HARDWARE)
1255 return (IMG_UINT16) readw((IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1257 return 0x3a4e; /* FIXME: OSReadHWReg should not exist in no hardware builds */
1264 IMG_UINT32 OSReadHWReg32(IMG_PVOID pvLinRegBaseAddr,
1265 IMG_UINT32 ui32Offset)
1267 #if !defined(NO_HARDWARE)
1268 return (IMG_UINT32) readl((IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1270 return 0x30f73a4e; /* FIXME: OSReadHWReg should not exist in no hardware builds */
1278 IMG_UINT64 OSReadHWReg64(IMG_PVOID pvLinRegBaseAddr,
1279 IMG_UINT32 ui32Offset)
1281 IMG_UINT64 ui64Result;
1283 ui64Result = OSReadHWReg32(pvLinRegBaseAddr, ui32Offset + 4);
1285 ui64Result |= (IMG_UINT64)OSReadHWReg32(pvLinRegBaseAddr, ui32Offset);
1293 IMG_DEVMEM_SIZE_T OSReadHWRegBank(IMG_PVOID pvLinRegBaseAddr,
1294 IMG_UINT32 ui32Offset,
1295 IMG_UINT8 *pui8DstBuf,
1296 IMG_DEVMEM_SIZE_T uiDstBufLen)
1298 #if !defined(NO_HARDWARE)
1299 IMG_DEVMEM_SIZE_T uiCounter;
1301 /* FIXME: optimize this */
1303 for(uiCounter = 0; uiCounter < uiDstBufLen; uiCounter++) {
1304 *(pui8DstBuf + uiCounter) =
1305 readb(pvLinRegBaseAddr + ui32Offset + uiCounter);
1317 void OSWriteHWReg8(void *pvLinRegBaseAddr,
1318 IMG_UINT32 ui32Offset,
1321 #if !defined(NO_HARDWARE)
1322 writeb(ui8Value, (IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1329 void OSWriteHWReg16(void *pvLinRegBaseAddr,
1330 IMG_UINT32 ui32Offset,
1331 IMG_UINT16 ui16Value)
1333 #if !defined(NO_HARDWARE)
1334 writew(ui16Value, (IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1341 void OSWriteHWReg32(void *pvLinRegBaseAddr,
1342 IMG_UINT32 ui32Offset,
1343 IMG_UINT32 ui32Value)
1345 #if !defined(NO_HARDWARE)
1346 writel(ui32Value, (IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1354 void OSWriteHWReg64(void *pvLinRegBaseAddr,
1355 IMG_UINT32 ui32Offset,
1356 IMG_UINT64 ui64Value)
1358 #if !defined(NO_HARDWARE)
1359 IMG_UINT32 ui32ValueLow, ui32ValueHigh;
1361 ui32ValueLow = ui64Value & 0xffffffff;
1362 ui32ValueHigh = ((IMG_UINT64) (ui64Value >> 32)) & 0xffffffff;
1364 writel(ui32ValueLow, pvLinRegBaseAddr + ui32Offset);
1365 writel(ui32ValueHigh, pvLinRegBaseAddr + ui32Offset + 4);
1369 IMG_DEVMEM_SIZE_T OSWriteHWRegBank(void *pvLinRegBaseAddr,
1370 IMG_UINT32 ui32Offset,
1371 IMG_UINT8 *pui8SrcBuf,
1372 IMG_DEVMEM_SIZE_T uiSrcBufLen)
1374 #if !defined(NO_HARDWARE)
1375 IMG_DEVMEM_SIZE_T uiCounter;
1377 /* FIXME: optimize this */
1379 for(uiCounter = 0; uiCounter < uiSrcBufLen; uiCounter++) {
1380 writeb(*(pui8SrcBuf + uiCounter),
1381 pvLinRegBaseAddr + ui32Offset + uiCounter);
1390 #define OS_MAX_TIMERS 8
1392 /* Timer callback strucure used by OSAddTimer */
1393 typedef struct TIMER_CALLBACK_DATA_TAG
1396 PFN_TIMER_FUNC pfnTimerFunc;
1398 struct timer_list sTimer;
1399 IMG_UINT32 ui32Delay;
1401 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1402 struct work_struct sWork;
1404 }TIMER_CALLBACK_DATA;
1406 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1407 static struct workqueue_struct *psTimerWorkQueue;
1410 static TIMER_CALLBACK_DATA sTimers[OS_MAX_TIMERS];
1412 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1413 DEFINE_MUTEX(sTimerStructLock);
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;
1419 static DEFINE_SPINLOCK(sTimerStructLock);
1423 static void OSTimerCallbackBody(TIMER_CALLBACK_DATA *psTimerCBData)
1425 if (!psTimerCBData->bActive)
1428 /* call timer callback */
1429 psTimerCBData->pfnTimerFunc(psTimerCBData->pvData);
1432 mod_timer(&psTimerCBData->sTimer, psTimerCBData->ui32Delay + jiffies);
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)
1443 TIMER_CALLBACK_DATA *psTimerCBData = (TIMER_CALLBACK_DATA*)uData;
1445 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1448 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1449 res = queue_work(psTimerWorkQueue, &psTimerCBData->sWork);
1451 res = schedule_work(&psTimerCBData->sWork);
1455 PVR_DPF((PVR_DBG_WARNING, "OSTimerCallbackWrapper: work already queued"));
1458 OSTimerCallbackBody(psTimerCBData);
1463 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1464 static void OSTimerWorkQueueCallBack(struct work_struct *psWork)
1466 TIMER_CALLBACK_DATA *psTimerCBData = container_of(psWork, TIMER_CALLBACK_DATA, sWork);
1468 OSTimerCallbackBody(psTimerCBData);
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)
1482 TIMER_CALLBACK_DATA *psTimerCBData;
1484 #if !(defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE))
1485 unsigned long ulLockFlags;
1488 /* check callback */
1491 PVR_DPF((PVR_DBG_ERROR, "OSAddTimer: passed invalid callback"));
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);
1499 spin_lock_irqsave(&sTimerStructLock, ulLockFlags);
1501 for (ui32i = 0; ui32i < OS_MAX_TIMERS; ui32i++)
1503 psTimerCBData = &sTimers[ui32i];
1504 if (!psTimerCBData->bInUse)
1506 psTimerCBData->bInUse = IMG_TRUE;
1510 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1511 mutex_unlock(&sTimerStructLock);
1513 spin_unlock_irqrestore(&sTimerStructLock, ulLockFlags);
1515 if (ui32i >= OS_MAX_TIMERS)
1517 PVR_DPF((PVR_DBG_ERROR, "OSAddTimer: all timers are in use"));
1521 psTimerCBData->pfnTimerFunc = pfnTimerFunc;
1522 psTimerCBData->pvData = pvData;
1523 psTimerCBData->bActive = IMG_FALSE;
1526 HZ = ticks per second
1527 ui32MsTimeout = required ms delay
1528 ticks = (Hz * ui32MsTimeout) / 1000
1530 psTimerCBData->ui32Delay = ((HZ * ui32MsTimeout) < 1000)
1532 : ((HZ * ui32MsTimeout) / 1000);
1533 /* initialise object */
1534 init_timer(&psTimerCBData->sTimer);
1536 /* setup timer object */
1537 psTimerCBData->sTimer.function = (void *)OSTimerCallbackWrapper;
1538 psTimerCBData->sTimer.data = (IMG_UINTPTR_T)psTimerCBData;
1540 return (IMG_HANDLE)(IMG_UINTPTR_T)(ui32i + 1);
1544 static inline TIMER_CALLBACK_DATA *GetTimerStructure(IMG_HANDLE hTimer)
1546 IMG_UINT32 ui32i = (IMG_UINT32)((IMG_UINTPTR_T)hTimer) - 1;
1548 PVR_ASSERT(ui32i < OS_MAX_TIMERS);
1550 return &sTimers[ui32i];
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)
1561 TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
1563 PVR_ASSERT(psTimerCBData->bInUse);
1564 PVR_ASSERT(!psTimerCBData->bActive);
1566 /* free timer callback data struct */
1567 psTimerCBData->bInUse = IMG_FALSE;
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)
1581 TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
1583 PVR_ASSERT(psTimerCBData->bInUse);
1584 PVR_ASSERT(!psTimerCBData->bActive);
1586 /* Start timer arming */
1587 psTimerCBData->bActive = IMG_TRUE;
1589 /* set the expire time */
1590 psTimerCBData->sTimer.expires = psTimerCBData->ui32Delay + jiffies;
1592 /* Add the timer to the list */
1593 add_timer(&psTimerCBData->sTimer);
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)
1607 TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
1609 PVR_ASSERT(psTimerCBData->bInUse);
1610 PVR_ASSERT(psTimerCBData->bActive);
1612 /* Stop timer from arming */
1613 psTimerCBData->bActive = IMG_FALSE;
1616 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1617 flush_workqueue(psTimerWorkQueue);
1619 #if defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1620 flush_scheduled_work();
1624 del_timer_sync(&psTimerCBData->sTimer);
1626 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
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.
1634 flush_workqueue(psTimerWorkQueue);
1636 #if defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1637 flush_scheduled_work();
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)
1653 PVRSRV_ERROR eError = PVRSRV_OK;
1654 PVR_UNREFERENCED_PARAMETER(pszName);
1658 if(LinuxEventObjectListCreate(hEventObject) != PVRSRV_OK)
1660 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
1666 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectCreate: hEventObject is not a valid pointer"));
1667 eError = PVRSRV_ERROR_UNABLE_TO_CREATE_EVENT;
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)
1682 PVRSRV_ERROR eError = PVRSRV_OK;
1686 LinuxEventObjectListDestroy(hEventObject);
1690 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectDestroy: hEventObject is not a valid pointer"));
1691 eError = PVRSRV_ERROR_INVALID_PARAMS;
1698 * EventObjectWaitTimeout()
1700 static PVRSRV_ERROR EventObjectWaitTimeout(IMG_HANDLE hOSEventKM,
1701 IMG_UINT32 uiTimeoutMs,
1702 IMG_BOOL bHoldBridgeLock)
1704 PVRSRV_ERROR eError;
1706 if(hOSEventKM && uiTimeoutMs > 0)
1708 eError = LinuxEventObjectWait(hOSEventKM, uiTimeoutMs, bHoldBridgeLock);
1712 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectWait: invalid arguments %p, %d", hOSEventKM, uiTimeoutMs ));
1713 eError = PVRSRV_ERROR_INVALID_PARAMS;
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)
1729 return EventObjectWaitTimeout(hOSEventKM, uiTimeoutMs, IMG_FALSE);
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)
1742 return OSEventObjectWaitTimeout(hOSEventKM, EVENT_OBJECT_TIMEOUT_MS);
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)
1756 return EventObjectWaitTimeout(hOSEventKM, uiTimeoutMs, IMG_TRUE);
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)
1770 return OSEventObjectWaitTimeoutAndHoldBridgeLock(hOSEventKM, EVENT_OBJECT_TIMEOUT_MS);
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)
1783 PVRSRV_ERROR eError = PVRSRV_OK;
1787 if(LinuxEventObjectAdd(hEventObject, phOSEvent) != PVRSRV_OK)
1789 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectAdd: failed"));
1790 eError = PVRSRV_ERROR_INVALID_PARAMS;
1795 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectOpen: hEventObject is not a valid pointer"));
1796 eError = PVRSRV_ERROR_INVALID_PARAMS;
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)
1810 PVRSRV_ERROR eError = PVRSRV_OK;
1814 if(LinuxEventObjectDelete(hOSEventKM) != PVRSRV_OK)
1816 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectDelete: failed"));
1817 eError = PVRSRV_ERROR_INVALID_PARAMS;
1823 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectDestroy: hEventObject is not a valid pointer"));
1824 eError = PVRSRV_ERROR_INVALID_PARAMS;
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)
1838 PVRSRV_ERROR eError;
1842 eError = LinuxEventObjectSignal(hEventObject);
1846 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectSignal: hOSEventKM is not a valid handle"));
1847 eError = PVRSRV_ERROR_INVALID_PARAMS;
1853 /*************************************************************************/ /*!
1854 @Function OSProcHasPrivSrvInit
1855 @Description Does the process have sufficient privileges to initialise services?
1857 */ /**************************************************************************/
1858 IMG_BOOL OSProcHasPrivSrvInit(void)
1860 return capable(CAP_SYS_ADMIN) != 0;
1863 /*************************************************************************/ /*!
1864 @Function OSCopyToUser
1865 @Description Copy a block of data into user space
1869 @Return PVRSRV_ERROR :
1870 */ /**************************************************************************/
1871 PVRSRV_ERROR OSCopyToUser(IMG_PVOID pvProcess,
1874 IMG_SIZE_T ui32Bytes)
1876 PVR_UNREFERENCED_PARAMETER(pvProcess);
1878 if(pvr_copy_to_user(pvDest, pvSrc, ui32Bytes)==0)
1881 return PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY;
1884 /*************************************************************************/ /*!
1885 @Function OSCopyFromUser
1886 @Description Copy a block of data from the user space
1890 @Return PVRSRV_ERROR :
1891 */ /**************************************************************************/
1892 PVRSRV_ERROR OSCopyFromUser(IMG_PVOID pvProcess,
1895 IMG_SIZE_T ui32Bytes)
1897 PVR_UNREFERENCED_PARAMETER(pvProcess);
1899 if(pvr_copy_from_user(pvDest, pvSrc, ui32Bytes)==0)
1902 return PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY;
1905 /*************************************************************************/ /*!
1906 @Function OSAccessOK
1907 @Description Checks if a user space pointer is valide
1908 @Input eVerification
1912 */ /**************************************************************************/
1913 IMG_BOOL OSAccessOK(IMG_VERIFY_TEST eVerification, void *pvUserPtr, IMG_SIZE_T ui32Bytes)
1917 if (eVerification == PVR_VERIFY_READ)
1919 linuxType = VERIFY_READ;
1923 PVR_ASSERT(eVerification == PVR_VERIFY_WRITE);
1924 linuxType = VERIFY_WRITE;
1927 return access_ok(linuxType, pvUserPtr, ui32Bytes);
1931 void OSWriteMemoryBarrier(void)
1937 void OSMemoryBarrier(void)
1942 IMG_UINT64 OSDivide64r64(IMG_UINT64 ui64Divident, IMG_UINT32 ui32Divisor, IMG_UINT32 *pui32Remainder)
1944 *pui32Remainder = do_div(ui64Divident, ui32Divisor);
1946 return ui64Divident;
1949 IMG_UINT32 OSDivide64(IMG_UINT64 ui64Divident, IMG_UINT32 ui32Divisor, IMG_UINT32 *pui32Remainder)
1951 *pui32Remainder = do_div(ui64Divident, ui32Divisor);
1953 return (IMG_UINT32) ui64Divident;
1956 /* One time osfunc initialisation */
1957 PVRSRV_ERROR PVROSFuncInit(void)
1959 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1961 PVR_ASSERT(!psTimerWorkQueue);
1963 psTimerWorkQueue = create_workqueue("pvr_timer");
1964 if (psTimerWorkQueue == NULL)
1966 PVR_DPF((PVR_DBG_ERROR, "%s: couldn't create timer workqueue", __FUNCTION__));
1967 return PVRSRV_ERROR_UNABLE_TO_CREATE_THREAD;
1972 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
1976 for (ui32i = 0; ui32i < OS_MAX_TIMERS; ui32i++)
1978 TIMER_CALLBACK_DATA *psTimerCBData = &sTimers[ui32i];
1980 INIT_WORK(&psTimerCBData->sWork, OSTimerWorkQueueCallBack);
1988 * Osfunc deinitialisation.
1989 * Note that PVROSFuncInit may not have been called
1991 void PVROSFuncDeInit(void)
1993 #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1994 if (psTimerWorkQueue != NULL)
1996 destroy_workqueue(psTimerWorkQueue);
1997 psTimerWorkQueue = NULL;
2002 void OSDumpStack(void)
2007 static struct task_struct *gsOwner;
2009 void OSAcquireBridgeLock(void)
2011 mutex_lock(&gPVRSRVLock);
2015 void OSReleaseBridgeLock(void)
2018 mutex_unlock(&gPVRSRVLock);
2021 struct task_struct *OSGetBridgeLockOwner(void)
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
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
2039 @Input pfnDecMemRefCt Pointer to function that can be used to drop a
2040 reference on the memory backing the statistic
2042 @Input pvData OS specific reference that can be used by
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,
2053 return (IMG_PVOID)PVRDebugFSCreateStatisticEntry(pszName, (PVR_DEBUGFS_DIR_DATA *)pvFolder, pfnStatsPrint, pfnIncMemRefCt, pfnDecMemRefCt, pvData);
2054 } /* OSCreateStatisticEntry */
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)
2065 PVRDebugFSRemoveStatisticEntry((PVR_DEBUGFS_DRIVER_STAT *)pvEntry);
2066 } /* OSRemoveStatisticEntry */
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)
2080 PVR_DEBUGFS_DIR_DATA *psNewStatFolder = IMG_NULL;
2083 iResult = PVRDebugFSCreateEntryDir(pszName, (PVR_DEBUGFS_DIR_DATA *)pvFolder, &psNewStatFolder);
2084 return (iResult == 0) ? (void *)psNewStatFolder : IMG_NULL;
2085 } /* OSCreateStatisticFolder */
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)
2096 PVRDebugFSRemoveEntryDir((PVR_DEBUGFS_DIR_DATA *)pvFolder);
2097 } /* OSRemoveStatisticFolder */