1.3.13.1607/3_00_00_08+flat+Lindent
[sgx.git] / pvr / osfunc.c
1 /**********************************************************************
2  *
3  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4  * 
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  * 
9  * This program is distributed in the hope it will be useful but, except 
10  * as otherwise stated in writing, without any warranty; without even the 
11  * implied warranty of merchantability or fitness for a particular purpose. 
12  * See the GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17  * 
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
24  *
25  ******************************************************************************/
26
27 #ifndef AUTOCONF_INCLUDED
28 #include <linux/config.h>
29 #endif
30
31 #include <linux/version.h>
32 #include <asm/io.h>
33 #include <asm/page.h>
34 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
35 #include <asm/system.h>
36 #endif
37 #include <linux/mm.h>
38 #include <linux/pagemap.h>
39 #include <linux/hugetlb.h>
40 #include <linux/slab.h>
41 #include <linux/vmalloc.h>
42 #include <linux/delay.h>
43 #include <linux/pci.h>
44
45 #include <linux/string.h>
46 #include <linux/sched.h>
47 #include <linux/interrupt.h>
48 #include <asm/hardirq.h>
49 #include <linux/timer.h>
50 #include <linux/capability.h>
51 #include <asm/uaccess.h>
52
53 #include "img_types.h"
54 #include "services_headers.h"
55 #include "mm.h"
56 #include "pvrmmap.h"
57 #include "mmap.h"
58 #include "env_data.h"
59 #include "proc.h"
60 #include "mutex.h"
61 #include "event.h"
62
63 #define EVENT_OBJECT_TIMEOUT_MS         (100)
64
65 extern PVRSRV_LINUX_MUTEX gPVRSRVLock;
66
67 #define HOST_ALLOC_MEM_USING_KMALLOC ((IMG_HANDLE)0)
68 #define HOST_ALLOC_MEM_USING_VMALLOC ((IMG_HANDLE)1)
69
70 #if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
71 PVRSRV_ERROR OSAllocMem(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size,
72                         IMG_PVOID * ppvCpuVAddr, IMG_HANDLE * phBlockAlloc)
73 #else
74 PVRSRV_ERROR _OSAllocMem(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size,
75                          IMG_PVOID * ppvCpuVAddr, IMG_HANDLE * phBlockAlloc,
76                          IMG_CHAR * pszFilename, IMG_UINT32 ui32Line)
77 #endif
78 {
79         PVR_UNREFERENCED_PARAMETER(ui32Flags);
80
81 #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
82         *ppvCpuVAddr = _KMallocWrapper(ui32Size, pszFilename, ui32Line);
83 #else
84         *ppvCpuVAddr = KMallocWrapper(ui32Size);
85 #endif
86         if (*ppvCpuVAddr) {
87                 if (phBlockAlloc) {
88
89                         *phBlockAlloc = HOST_ALLOC_MEM_USING_KMALLOC;
90                 }
91         } else {
92                 if (!phBlockAlloc) {
93                         return PVRSRV_ERROR_OUT_OF_MEMORY;
94                 }
95
96 #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
97                 *ppvCpuVAddr =
98                     _VMallocWrapper(ui32Size, PVRSRV_HAP_CACHED, pszFilename,
99                                     ui32Line);
100 #else
101                 *ppvCpuVAddr = VMallocWrapper(ui32Size, PVRSRV_HAP_CACHED);
102 #endif
103                 if (!*ppvCpuVAddr) {
104                         return PVRSRV_ERROR_OUT_OF_MEMORY;
105                 }
106
107                 *phBlockAlloc = HOST_ALLOC_MEM_USING_VMALLOC;
108         }
109
110         return PVRSRV_OK;
111 }
112
113 #if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
114 PVRSRV_ERROR OSFreeMem(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size,
115                        IMG_PVOID pvCpuVAddr, IMG_HANDLE hBlockAlloc)
116 #else
117 PVRSRV_ERROR _OSFreeMem(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size,
118                         IMG_PVOID pvCpuVAddr, IMG_HANDLE hBlockAlloc,
119                         IMG_CHAR * pszFilename, IMG_UINT32 ui32Line)
120 #endif
121 {
122         PVR_UNREFERENCED_PARAMETER(ui32Flags);
123         PVR_UNREFERENCED_PARAMETER(ui32Size);
124
125         if (hBlockAlloc == HOST_ALLOC_MEM_USING_VMALLOC) {
126 #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
127                 _VFreeWrapper(pvCpuVAddr, pszFilename, ui32Line);
128 #else
129                 VFreeWrapper(pvCpuVAddr);
130 #endif
131         } else {
132 #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
133                 _KFreeWrapper(pvCpuVAddr, pszFilename, ui32Line);
134 #else
135                 KFreeWrapper(pvCpuVAddr);
136 #endif
137         }
138
139         return PVRSRV_OK;
140 }
141
142 PVRSRV_ERROR
143 OSAllocPages(IMG_UINT32 ui32AllocFlags,
144              IMG_UINT32 ui32Size,
145              IMG_VOID ** ppvCpuVAddr, IMG_HANDLE * phOSMemHandle)
146 {
147         LinuxMemArea *psLinuxMemArea;
148
149 #if 0
150
151         if (ui32AllocFlags & PVRSRV_HAP_SINGLE_PROCESS) {
152                 ui32AllocFlags &= ~PVRSRV_HAP_SINGLE_PROCESS;
153                 ui32AllocFlags |= PVRSRV_HAP_MULTI_PROCESS;
154         }
155 #endif
156
157         switch (ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK) {
158         case PVRSRV_HAP_KERNEL_ONLY:
159                 {
160                         psLinuxMemArea =
161                             NewVMallocLinuxMemArea(ui32Size, ui32AllocFlags);
162                         if (!psLinuxMemArea) {
163                                 return PVRSRV_ERROR_OUT_OF_MEMORY;
164                         }
165                         break;
166                 }
167         case PVRSRV_HAP_SINGLE_PROCESS:
168                 {
169
170                         psLinuxMemArea =
171                             NewAllocPagesLinuxMemArea(ui32Size, ui32AllocFlags);
172                         if (!psLinuxMemArea) {
173                                 return PVRSRV_ERROR_OUT_OF_MEMORY;
174                         }
175                         PVRMMapRegisterArea("Import Arena", psLinuxMemArea,
176                                             ui32AllocFlags);
177                         break;
178                 }
179
180         case PVRSRV_HAP_MULTI_PROCESS:
181                 {
182
183 #if defined(VIVT_CACHE) || defined(__sh__)
184
185                         ui32AllocFlags &= ~PVRSRV_HAP_CACHED;
186 #endif
187                         psLinuxMemArea =
188                             NewVMallocLinuxMemArea(ui32Size, ui32AllocFlags);
189                         if (!psLinuxMemArea) {
190                                 return PVRSRV_ERROR_OUT_OF_MEMORY;
191                         }
192                         PVRMMapRegisterArea("Import Arena", psLinuxMemArea,
193                                             ui32AllocFlags);
194                         break;
195                 }
196         default:
197                 PVR_DPF((PVR_DBG_ERROR, "OSAllocPages: invalid flags 0x%x\n",
198                          ui32AllocFlags));
199                 *ppvCpuVAddr = NULL;
200                 *phOSMemHandle = (IMG_HANDLE) 0;
201                 return PVRSRV_ERROR_INVALID_PARAMS;
202         }
203
204         *ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea);
205         *phOSMemHandle = psLinuxMemArea;
206
207         LinuxMemAreaRegister(psLinuxMemArea);
208
209         return PVRSRV_OK;
210 }
211
212 PVRSRV_ERROR
213 OSFreePages(IMG_UINT32 ui32AllocFlags, IMG_UINT32 ui32Bytes,
214             IMG_VOID * pvCpuVAddr, IMG_HANDLE hOSMemHandle)
215 {
216         LinuxMemArea *psLinuxMemArea;
217         PVR_UNREFERENCED_PARAMETER(pvCpuVAddr);
218
219         psLinuxMemArea = (LinuxMemArea *) hOSMemHandle;
220
221         switch (ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK) {
222         case PVRSRV_HAP_KERNEL_ONLY:
223                 break;
224         case PVRSRV_HAP_SINGLE_PROCESS:
225         case PVRSRV_HAP_MULTI_PROCESS:
226                 if (PVRMMapRemoveRegisteredArea(psLinuxMemArea) != PVRSRV_OK) {
227                         PVR_DPF((PVR_DBG_ERROR,
228                                  "OSFreePages(ui32AllocFlags=0x%08X, ui32Bytes=%ld, "
229                                  "pvCpuVAddr=%p, hOSMemHandle=%p) FAILED!",
230                                  ui32AllocFlags, ui32Bytes, pvCpuVAddr,
231                                  hOSMemHandle));
232                         return PVRSRV_ERROR_GENERIC;
233                 }
234                 break;
235         default:
236                 PVR_DPF((PVR_DBG_ERROR, "%s: invalid flags 0x%x\n",
237                          __FUNCTION__, ui32AllocFlags));
238                 return PVRSRV_ERROR_INVALID_PARAMS;
239         }
240
241         LinuxMemAreaDeepFree(psLinuxMemArea);
242
243         return PVRSRV_OK;
244 }
245
246 PVRSRV_ERROR
247 OSGetSubMemHandle(IMG_HANDLE hOSMemHandle,
248                   IMG_UINT32 ui32ByteOffset,
249                   IMG_UINT32 ui32Bytes,
250                   IMG_UINT32 ui32Flags, IMG_HANDLE * phOSMemHandleRet)
251 {
252         LinuxMemArea *psParentLinuxMemArea, *psLinuxMemArea;
253         PVRSRV_ERROR eError = PVRSRV_OK;
254
255         psParentLinuxMemArea = (LinuxMemArea *) hOSMemHandle;
256
257         psLinuxMemArea =
258             NewSubLinuxMemArea(psParentLinuxMemArea, ui32ByteOffset, ui32Bytes);
259         if (!psLinuxMemArea) {
260                 *phOSMemHandleRet = NULL;
261                 return PVRSRV_ERROR_OUT_OF_MEMORY;
262         }
263         *phOSMemHandleRet = psLinuxMemArea;
264
265         if (ui32Flags & PVRSRV_HAP_KERNEL_ONLY) {
266                 return PVRSRV_OK;
267         }
268
269         if (psParentLinuxMemArea->eAreaType == LINUX_MEM_AREA_IO) {
270                 eError = PVRMMapRegisterArea("Physical", psLinuxMemArea, 0);
271                 if (eError != PVRSRV_OK) {
272                         goto failed_register_area;
273                 }
274         } else if (psParentLinuxMemArea->eAreaType ==
275                    LINUX_MEM_AREA_ALLOC_PAGES) {
276                 eError = PVRMMapRegisterArea("Import Arena", psLinuxMemArea, 0);
277                 if (eError != PVRSRV_OK) {
278                         goto failed_register_area;
279                 }
280         }
281
282         return PVRSRV_OK;
283
284 failed_register_area:
285         *phOSMemHandleRet = NULL;
286         LinuxMemAreaDeepFree(psLinuxMemArea);
287         return eError;
288 }
289
290 PVRSRV_ERROR
291 OSReleaseSubMemHandle(IMG_VOID * hOSMemHandle, IMG_UINT32 ui32Flags)
292 {
293         LinuxMemArea *psParentLinuxMemArea, *psLinuxMemArea;
294         PVRSRV_ERROR eError;
295
296         psLinuxMemArea = (LinuxMemArea *) hOSMemHandle;
297         PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC);
298
299         psParentLinuxMemArea =
300             psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea;
301
302         if (!(ui32Flags & PVRSRV_HAP_KERNEL_ONLY)
303             && (psParentLinuxMemArea->eAreaType == LINUX_MEM_AREA_IO
304                 || psParentLinuxMemArea->eAreaType ==
305                 LINUX_MEM_AREA_ALLOC_PAGES)
306             ) {
307                 eError = PVRMMapRemoveRegisteredArea(psLinuxMemArea);
308                 if (eError != PVRSRV_OK) {
309                         return eError;
310                 }
311         }
312         LinuxMemAreaDeepFree(psLinuxMemArea);
313
314         return PVRSRV_OK;
315 }
316
317 IMG_CPU_PHYADDR
318 OSMemHandleToCpuPAddr(IMG_VOID * hOSMemHandle, IMG_UINT32 ui32ByteOffset)
319 {
320         PVR_ASSERT(hOSMemHandle);
321
322         return LinuxMemAreaToCpuPAddr(hOSMemHandle, ui32ByteOffset);
323 }
324
325 IMG_VOID OSMemCopy(IMG_VOID * pvDst, IMG_VOID * pvSrc, IMG_UINT32 ui32Size)
326 {
327 #if defined(USE_UNOPTIMISED_MEMCPY)
328         unsigned char *Src, *Dst;
329         int i;
330
331         Src = (unsigned char *)pvSrc;
332         Dst = (unsigned char *)pvDst;
333         for (i = 0; i < ui32Size; i++) {
334                 Dst[i] = Src[i];
335         }
336 #else
337         memcpy(pvDst, pvSrc, ui32Size);
338 #endif
339 }
340
341 IMG_VOID OSMemSet(IMG_VOID * pvDest, IMG_UINT8 ui8Value, IMG_UINT32 ui32Size)
342 {
343 #if defined(USE_UNOPTIMISED_MEMSET)
344         unsigned char *Buff;
345         int i;
346
347         Buff = (unsigned char *)pvDest;
348         for (i = 0; i < ui32Size; i++) {
349                 Buff[i] = ui8Value;
350         }
351 #else
352         memset(pvDest, (int)ui8Value, (size_t) ui32Size);
353 #endif
354 }
355
356 IMG_CHAR *OSStringCopy(IMG_CHAR * pszDest, const IMG_CHAR * pszSrc)
357 {
358         return (strcpy(pszDest, pszSrc));
359 }
360
361 IMG_INT32 OSSNPrintf(IMG_CHAR * pStr, IMG_UINT32 ui32Size,
362                      const IMG_CHAR * pszFormat, ...)
363 {
364         va_list argList;
365         IMG_INT32 iCount;
366
367         va_start(argList, pszFormat);
368         iCount = vsnprintf(pStr, (size_t) ui32Size, pszFormat, argList);
369         va_end(argList);
370
371         return iCount;
372 }
373
374 IMG_VOID OSBreakResourceLock(PVRSRV_RESOURCE * psResource, IMG_UINT32 ui32ID)
375 {
376         volatile IMG_UINT32 *pui32Access =
377             (volatile IMG_UINT32 *)&psResource->ui32Lock;
378
379         if (*pui32Access) {
380                 if (psResource->ui32ID == ui32ID) {
381                         psResource->ui32ID = 0;
382                         *pui32Access = 0;
383                 } else {
384                         PVR_DPF((PVR_DBG_MESSAGE,
385                                  "OSBreakResourceLock: Resource is not locked for this process."));
386                 }
387         } else {
388                 PVR_DPF((PVR_DBG_MESSAGE,
389                          "OSBreakResourceLock: Resource is not locked"));
390         }
391 }
392
393 PVRSRV_ERROR OSCreateResource(PVRSRV_RESOURCE * psResource)
394 {
395         psResource->ui32ID = 0;
396         psResource->ui32Lock = 0;
397
398         return PVRSRV_OK;
399 }
400
401 PVRSRV_ERROR OSDestroyResource(PVRSRV_RESOURCE * psResource)
402 {
403         OSBreakResourceLock(psResource, psResource->ui32ID);
404
405         return PVRSRV_OK;
406 }
407
408 PVRSRV_ERROR OSInitEnvData(IMG_PVOID * ppvEnvSpecificData)
409 {
410         ENV_DATA *psEnvData;
411
412         if (OSAllocMem
413             (PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA),
414              (IMG_VOID *) & psEnvData, IMG_NULL) != PVRSRV_OK) {
415                 return PVRSRV_ERROR_GENERIC;
416         }
417
418         if (OSAllocMem
419             (PVRSRV_OS_PAGEABLE_HEAP,
420              PVRSRV_MAX_BRIDGE_IN_SIZE + PVRSRV_MAX_BRIDGE_OUT_SIZE,
421              &psEnvData->pvBridgeData, IMG_NULL) != PVRSRV_OK) {
422                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), psEnvData,
423                           IMG_NULL);
424                 return PVRSRV_ERROR_GENERIC;
425         }
426
427         psEnvData->bMISRInstalled = IMG_FALSE;
428         psEnvData->bLISRInstalled = IMG_FALSE;
429
430         *ppvEnvSpecificData = psEnvData;
431
432         return PVRSRV_OK;
433 }
434
435 PVRSRV_ERROR OSDeInitEnvData(IMG_PVOID pvEnvSpecificData)
436 {
437         ENV_DATA *psEnvData = (ENV_DATA *) pvEnvSpecificData;
438
439         PVR_ASSERT(!psEnvData->bMISRInstalled);
440         PVR_ASSERT(!psEnvData->bLISRInstalled);
441
442         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, 0x1000, psEnvData->pvBridgeData,
443                   IMG_NULL);
444
445         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), pvEnvSpecificData,
446                   IMG_NULL);
447
448         return PVRSRV_OK;
449 }
450
451 IMG_VOID OSReleaseThreadQuanta(IMG_VOID)
452 {
453         schedule();
454 }
455
456 IMG_UINT32 OSClockus(IMG_VOID)
457 {
458         unsigned long time, j = jiffies;
459
460         time = j * (1000000 / HZ);
461
462         return time;
463 }
464
465 IMG_VOID OSWaitus(IMG_UINT32 ui32Timeus)
466 {
467         udelay(ui32Timeus);
468 }
469
470 IMG_UINT32 OSGetCurrentProcessIDKM(IMG_VOID)
471 {
472         if (in_interrupt()) {
473                 return KERNEL_ID;
474         }
475 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
476         return current->pgrp;
477 #else
478 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
479         return task_tgid_nr(current);
480 #else
481         return current->tgid;
482 #endif
483 #endif
484 }
485
486 IMG_UINT32 OSGetPageSize(IMG_VOID)
487 {
488 #if defined(__sh__)
489         IMG_UINT32 ui32ReturnValue = PAGE_SIZE;
490
491         return (ui32ReturnValue);
492 #else
493         return PAGE_SIZE;
494 #endif
495 }
496
497 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
498 static irqreturn_t DeviceISRWrapper(int irq, void *dev_id
499 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
500                                     , struct pt_regs *regs
501 #endif
502     )
503 {
504         PVRSRV_DEVICE_NODE *psDeviceNode;
505         IMG_BOOL bStatus = IMG_FALSE;
506
507 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
508         PVR_UNREFERENCED_PARAMETER(regs);
509 #endif
510         psDeviceNode = (PVRSRV_DEVICE_NODE *) dev_id;
511         if (!psDeviceNode) {
512                 PVR_DPF((PVR_DBG_ERROR, "DeviceISRWrapper: invalid params\n"));
513                 goto out;
514         }
515
516         bStatus = PVRSRVDeviceLISR(psDeviceNode);
517
518         if (bStatus) {
519                 SYS_DATA *psSysData = psDeviceNode->psSysData;
520                 ENV_DATA *psEnvData = (ENV_DATA *) psSysData->pvEnvSpecificData;
521
522                 tasklet_schedule(&psEnvData->sMISRTasklet);
523         }
524
525 out:
526 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
527         return bStatus ? IRQ_HANDLED : IRQ_NONE;
528 #endif
529 }
530
531 static irqreturn_t SystemISRWrapper(int irq, void *dev_id
532 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
533                                     , struct pt_regs *regs
534 #endif
535     )
536 {
537         SYS_DATA *psSysData;
538         IMG_BOOL bStatus = IMG_FALSE;
539
540 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
541         PVR_UNREFERENCED_PARAMETER(regs);
542 #endif
543         psSysData = (SYS_DATA *) dev_id;
544         if (!psSysData) {
545                 PVR_DPF((PVR_DBG_ERROR, "SystemISRWrapper: invalid params\n"));
546                 goto out;
547         }
548
549         bStatus = PVRSRVSystemLISR(psSysData);
550
551         if (bStatus) {
552                 ENV_DATA *psEnvData = (ENV_DATA *) psSysData->pvEnvSpecificData;
553
554                 tasklet_schedule(&psEnvData->sMISRTasklet);
555         }
556
557 out:
558 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
559         return bStatus ? IRQ_HANDLED : IRQ_NONE;
560 #endif
561 }
562
563 PVRSRV_ERROR OSInstallDeviceLISR(IMG_VOID * pvSysData,
564                                  IMG_UINT32 ui32Irq,
565                                  IMG_CHAR * pszISRName, IMG_VOID * pvDeviceNode)
566 {
567         SYS_DATA *psSysData = (SYS_DATA *) pvSysData;
568         ENV_DATA *psEnvData = (ENV_DATA *) psSysData->pvEnvSpecificData;
569
570         if (psEnvData->bLISRInstalled) {
571                 PVR_DPF((PVR_DBG_ERROR,
572                          "OSInstallDeviceLISR: An ISR has already been installed: IRQ %d cookie %x",
573                          psEnvData->ui32IRQ, psEnvData->pvISRCookie));
574                 return PVRSRV_ERROR_GENERIC;
575         }
576
577         PVR_TRACE(("Installing device LISR %s on IRQ %d with cookie %x",
578                    pszISRName, ui32Irq, pvDeviceNode));
579
580         if (request_irq(ui32Irq, DeviceISRWrapper,
581 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
582                         SA_SHIRQ
583 #else
584                         IRQF_SHARED
585 #endif
586                         , pszISRName, pvDeviceNode)) {
587                 PVR_DPF((PVR_DBG_ERROR,
588                          "OSInstallDeviceLISR: Couldn't install device LISR on IRQ %d",
589                          ui32Irq));
590
591                 return PVRSRV_ERROR_GENERIC;
592         }
593
594         psEnvData->ui32IRQ = ui32Irq;
595         psEnvData->pvISRCookie = pvDeviceNode;
596         psEnvData->bLISRInstalled = IMG_TRUE;
597
598         return PVRSRV_OK;
599 }
600
601 PVRSRV_ERROR OSUninstallDeviceLISR(IMG_VOID * pvSysData)
602 {
603         SYS_DATA *psSysData = (SYS_DATA *) pvSysData;
604         ENV_DATA *psEnvData = (ENV_DATA *) psSysData->pvEnvSpecificData;
605
606         if (!psEnvData->bLISRInstalled) {
607                 PVR_DPF((PVR_DBG_ERROR,
608                          "OSUninstallDeviceLISR: No LISR has been installed"));
609                 return PVRSRV_ERROR_GENERIC;
610         }
611
612         PVR_TRACE(("Uninstalling device LISR on IRQ %d with cookie %x",
613                    psEnvData->ui32IRQ, psEnvData->pvISRCookie));
614
615         free_irq(psEnvData->ui32IRQ, psEnvData->pvISRCookie);
616
617         psEnvData->bLISRInstalled = IMG_FALSE;
618
619         return PVRSRV_OK;
620 }
621
622 PVRSRV_ERROR OSInstallSystemLISR(IMG_VOID * pvSysData, IMG_UINT32 ui32Irq)
623 {
624         SYS_DATA *psSysData = (SYS_DATA *) pvSysData;
625         ENV_DATA *psEnvData = (ENV_DATA *) psSysData->pvEnvSpecificData;
626
627         if (psEnvData->bLISRInstalled) {
628                 PVR_DPF((PVR_DBG_ERROR,
629                          "OSInstallSystemLISR: An LISR has already been installed: IRQ %d cookie %x",
630                          psEnvData->ui32IRQ, psEnvData->pvISRCookie));
631                 return PVRSRV_ERROR_GENERIC;
632         }
633
634         PVR_TRACE(("Installing system LISR on IRQ %d with cookie %x", ui32Irq,
635                    pvSysData));
636
637         if (request_irq(ui32Irq, SystemISRWrapper,
638 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
639                         SA_SHIRQ
640 #else
641                         IRQF_SHARED
642 #endif
643                         , "PowerVR", pvSysData)) {
644                 PVR_DPF((PVR_DBG_ERROR,
645                          "OSInstallSystemLISR: Couldn't install system LISR on IRQ %d",
646                          ui32Irq));
647
648                 return PVRSRV_ERROR_GENERIC;
649         }
650
651         psEnvData->ui32IRQ = ui32Irq;
652         psEnvData->pvISRCookie = pvSysData;
653         psEnvData->bLISRInstalled = IMG_TRUE;
654
655         return PVRSRV_OK;
656 }
657
658 PVRSRV_ERROR OSUninstallSystemLISR(IMG_VOID * pvSysData)
659 {
660         SYS_DATA *psSysData = (SYS_DATA *) pvSysData;
661         ENV_DATA *psEnvData = (ENV_DATA *) psSysData->pvEnvSpecificData;
662
663         if (!psEnvData->bLISRInstalled) {
664                 PVR_DPF((PVR_DBG_ERROR,
665                          "OSUninstallSystemLISR: No LISR has been installed"));
666                 return PVRSRV_ERROR_GENERIC;
667         }
668
669         PVR_TRACE(("Uninstalling system LISR on IRQ %d with cookie %x",
670                    psEnvData->ui32IRQ, psEnvData->pvISRCookie));
671
672         free_irq(psEnvData->ui32IRQ, psEnvData->pvISRCookie);
673
674         psEnvData->bLISRInstalled = IMG_FALSE;
675
676         return PVRSRV_OK;
677 }
678
679 static void MISRWrapper(unsigned long data)
680 {
681         SYS_DATA *psSysData;
682
683         psSysData = (SYS_DATA *) data;
684
685         PVRSRVMISR(psSysData);
686 }
687
688 PVRSRV_ERROR OSInstallMISR(IMG_VOID * pvSysData)
689 {
690         SYS_DATA *psSysData = (SYS_DATA *) pvSysData;
691         ENV_DATA *psEnvData = (ENV_DATA *) psSysData->pvEnvSpecificData;
692
693         if (psEnvData->bMISRInstalled) {
694                 PVR_DPF((PVR_DBG_ERROR,
695                          "OSInstallMISR: An MISR has already been installed"));
696                 return PVRSRV_ERROR_GENERIC;
697         }
698
699         PVR_TRACE(("Installing MISR with cookie %x", pvSysData));
700
701         tasklet_init(&psEnvData->sMISRTasklet, MISRWrapper,
702                      (unsigned long)pvSysData);
703
704         psEnvData->bMISRInstalled = IMG_TRUE;
705
706         return PVRSRV_OK;
707 }
708
709 PVRSRV_ERROR OSUninstallMISR(IMG_VOID * pvSysData)
710 {
711         SYS_DATA *psSysData = (SYS_DATA *) pvSysData;
712         ENV_DATA *psEnvData = (ENV_DATA *) psSysData->pvEnvSpecificData;
713
714         if (!psEnvData->bMISRInstalled) {
715                 PVR_DPF((PVR_DBG_ERROR,
716                          "OSUninstallMISR: No MISR has been installed"));
717                 return PVRSRV_ERROR_GENERIC;
718         }
719
720         PVR_TRACE(("Uninstalling MISR"));
721
722         tasklet_kill(&psEnvData->sMISRTasklet);
723
724         psEnvData->bMISRInstalled = IMG_FALSE;
725
726         return PVRSRV_OK;
727 }
728
729 PVRSRV_ERROR OSScheduleMISR(IMG_VOID * pvSysData)
730 {
731         SYS_DATA *psSysData = (SYS_DATA *) pvSysData;
732         ENV_DATA *psEnvData = (ENV_DATA *) psSysData->pvEnvSpecificData;
733
734         if (psEnvData->bMISRInstalled) {
735                 tasklet_schedule(&psEnvData->sMISRTasklet);
736         }
737
738         return PVRSRV_OK;
739 }
740
741 #endif
742
743 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
744 #define OS_TAS(p)       xchg((p), 1)
745 #else
746 #define OS_TAS(p)       tas(p)
747 #endif
748 PVRSRV_ERROR OSLockResource(PVRSRV_RESOURCE * psResource, IMG_UINT32 ui32ID)
749 {
750         PVRSRV_ERROR eError = PVRSRV_OK;
751
752         if (!OS_TAS(&psResource->ui32Lock))
753                 psResource->ui32ID = ui32ID;
754         else
755                 eError = PVRSRV_ERROR_GENERIC;
756
757         return eError;
758 }
759
760 PVRSRV_ERROR OSUnlockResource(PVRSRV_RESOURCE * psResource, IMG_UINT32 ui32ID)
761 {
762         volatile IMG_UINT32 *pui32Access =
763             (volatile IMG_UINT32 *)&psResource->ui32Lock;
764         PVRSRV_ERROR eError = PVRSRV_OK;
765
766         if (*pui32Access) {
767                 if (psResource->ui32ID == ui32ID) {
768                         psResource->ui32ID = 0;
769                         *pui32Access = 0;
770                 } else {
771                         PVR_DPF((PVR_DBG_ERROR,
772                                  "OSUnlockResource: Resource %p is not locked with expected value.",
773                                  psResource));
774                         PVR_DPF((PVR_DBG_MESSAGE, "Should be %x is actually %x",
775                                  ui32ID, psResource->ui32ID));
776                         eError = PVRSRV_ERROR_GENERIC;
777                 }
778         } else {
779                 PVR_DPF((PVR_DBG_ERROR,
780                          "OSUnlockResource: Resource %p is not locked",
781                          psResource));
782                 eError = PVRSRV_ERROR_GENERIC;
783         }
784
785         return eError;
786 }
787
788 IMG_BOOL OSIsResourceLocked(PVRSRV_RESOURCE * psResource, IMG_UINT32 ui32ID)
789 {
790         volatile IMG_UINT32 *pui32Access =
791             (volatile IMG_UINT32 *)&psResource->ui32Lock;
792
793         return (*(volatile IMG_UINT32 *)pui32Access == 1)
794             && (psResource->ui32ID == ui32ID)
795             ? IMG_TRUE : IMG_FALSE;
796 }
797
798 IMG_CPU_PHYADDR OSMapLinToCPUPhys(IMG_VOID * pvLinAddr)
799 {
800         IMG_CPU_PHYADDR CpuPAddr;
801
802         CpuPAddr.uiAddr = (IMG_UINTPTR_T) VMallocToPhys(pvLinAddr);
803
804         return CpuPAddr;
805 }
806
807 IMG_VOID *OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr,
808                          IMG_UINT32 ui32Bytes,
809                          IMG_UINT32 ui32MappingFlags,
810                          IMG_HANDLE * phOSMemHandle)
811 {
812         if (phOSMemHandle) {
813                 *phOSMemHandle = (IMG_HANDLE) 0;
814         }
815
816         if (ui32MappingFlags & PVRSRV_HAP_KERNEL_ONLY) {
817                 IMG_VOID *pvIORemapCookie;
818                 pvIORemapCookie =
819                     IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags);
820                 if (pvIORemapCookie == IMG_NULL) {
821                         return NULL;
822                 }
823                 return pvIORemapCookie;
824         } else {
825                 PVR_DPF((PVR_DBG_ERROR,
826                          "OSMapPhysToLin should only be used with PVRSRV_HAP_KERNEL_ONLY "
827                          " (Use OSReservePhys otherwise)"));
828                 *phOSMemHandle = (IMG_HANDLE) 0;
829                 return NULL;
830         }
831
832         PVR_ASSERT(0);
833         return NULL;
834 }
835
836 IMG_BOOL
837 OSUnMapPhysToLin(IMG_VOID * pvLinAddr, IMG_UINT32 ui32Bytes,
838                  IMG_UINT32 ui32MappingFlags, IMG_HANDLE hPageAlloc)
839 {
840         PVR_TRACE(("%s: unmapping %d bytes from 0x%08x", __FUNCTION__,
841                    ui32Bytes, pvLinAddr));
842
843         PVR_UNREFERENCED_PARAMETER(hPageAlloc);
844
845         if (ui32MappingFlags & PVRSRV_HAP_KERNEL_ONLY) {
846                 IOUnmapWrapper(pvLinAddr);
847                 return IMG_TRUE;
848         } else {
849                 PVR_DPF((PVR_DBG_ERROR,
850                          "OSUnMapPhysToLin should only be used with PVRSRV_HAP_KERNEL_ONLY "
851                          " (Use OSUnReservePhys otherwise)"));
852                 return IMG_FALSE;
853         }
854
855         PVR_ASSERT(0);
856         return IMG_FALSE;
857 }
858
859 static PVRSRV_ERROR
860 RegisterExternalMem(IMG_SYS_PHYADDR * pBasePAddr,
861                     IMG_VOID * pvCPUVAddr,
862                     IMG_UINT32 ui32Bytes,
863                     IMG_BOOL bPhysContig,
864                     IMG_UINT32 ui32MappingFlags, IMG_HANDLE * phOSMemHandle)
865 {
866         LinuxMemArea *psLinuxMemArea;
867
868         switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) {
869         case PVRSRV_HAP_KERNEL_ONLY:
870                 {
871                         psLinuxMemArea =
872                             NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr,
873                                                       ui32Bytes, bPhysContig,
874                                                       ui32MappingFlags);
875
876                         if (!psLinuxMemArea) {
877                                 return PVRSRV_ERROR_GENERIC;
878                         }
879                         break;
880                 }
881         case PVRSRV_HAP_SINGLE_PROCESS:
882                 {
883                         psLinuxMemArea =
884                             NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr,
885                                                       ui32Bytes, bPhysContig,
886                                                       ui32MappingFlags);
887
888                         if (!psLinuxMemArea) {
889                                 return PVRSRV_ERROR_GENERIC;
890                         }
891                         PVRMMapRegisterArea("Physical", psLinuxMemArea,
892                                             ui32MappingFlags);
893                         break;
894                 }
895         case PVRSRV_HAP_MULTI_PROCESS:
896                 {
897
898 #if defined(VIVT_CACHE) || defined(__sh__)
899
900                         ui32MappingFlags &= ~PVRSRV_HAP_CACHED;
901 #endif
902                         psLinuxMemArea =
903                             NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr,
904                                                       ui32Bytes, bPhysContig,
905                                                       ui32MappingFlags);
906
907                         if (!psLinuxMemArea) {
908                                 return PVRSRV_ERROR_GENERIC;
909                         }
910                         PVRMMapRegisterArea("Physical", psLinuxMemArea,
911                                             ui32MappingFlags);
912                         break;
913                 }
914         default:
915                 PVR_DPF((PVR_DBG_ERROR, "OSRegisterMem : invalid flags 0x%x\n",
916                          ui32MappingFlags));
917                 *phOSMemHandle = (IMG_HANDLE) 0;
918                 return PVRSRV_ERROR_GENERIC;
919         }
920
921         *phOSMemHandle = (IMG_HANDLE) psLinuxMemArea;
922
923         LinuxMemAreaRegister(psLinuxMemArea);
924
925         return PVRSRV_OK;
926 }
927
928 PVRSRV_ERROR
929 OSRegisterMem(IMG_CPU_PHYADDR BasePAddr,
930               IMG_VOID * pvCPUVAddr,
931               IMG_UINT32 ui32Bytes,
932               IMG_UINT32 ui32MappingFlags, IMG_HANDLE * phOSMemHandle)
933 {
934         IMG_SYS_PHYADDR SysPAddr = SysCpuPAddrToSysPAddr(BasePAddr);
935
936         return RegisterExternalMem(&SysPAddr, pvCPUVAddr, ui32Bytes, IMG_TRUE,
937                                    ui32MappingFlags, phOSMemHandle);
938 }
939
940 PVRSRV_ERROR OSRegisterDiscontigMem(IMG_SYS_PHYADDR * pBasePAddr,
941                                     IMG_VOID * pvCPUVAddr, IMG_UINT32 ui32Bytes,
942                                     IMG_UINT32 ui32MappingFlags,
943                                     IMG_HANDLE * phOSMemHandle)
944 {
945         return RegisterExternalMem(pBasePAddr, pvCPUVAddr, ui32Bytes, IMG_FALSE,
946                                    ui32MappingFlags, phOSMemHandle);
947 }
948
949 PVRSRV_ERROR
950 OSUnRegisterMem(IMG_VOID * pvCpuVAddr,
951                 IMG_UINT32 ui32Bytes,
952                 IMG_UINT32 ui32MappingFlags, IMG_HANDLE hOSMemHandle)
953 {
954         LinuxMemArea *psLinuxMemArea = (LinuxMemArea *) hOSMemHandle;
955
956         PVR_UNREFERENCED_PARAMETER(pvCpuVAddr);
957
958         switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) {
959         case PVRSRV_HAP_KERNEL_ONLY:
960                 break;
961         case PVRSRV_HAP_SINGLE_PROCESS:
962         case PVRSRV_HAP_MULTI_PROCESS:
963                 {
964                         if (PVRMMapRemoveRegisteredArea(psLinuxMemArea) !=
965                             PVRSRV_OK) {
966                                 PVR_DPF((PVR_DBG_ERROR,
967                                          "%s(%p, %d, 0x%08X, %p) FAILED!",
968                                          __FUNCTION__, pvCpuVAddr, ui32Bytes,
969                                          ui32MappingFlags, hOSMemHandle));
970                                 return PVRSRV_ERROR_GENERIC;
971                         }
972                         break;
973                 }
974         default:
975                 {
976                         PVR_DPF((PVR_DBG_ERROR,
977                                  "OSUnRegisterMem : invalid flags 0x%x",
978                                  ui32MappingFlags));
979                         return PVRSRV_ERROR_INVALID_PARAMS;
980                 }
981         }
982
983         LinuxMemAreaDeepFree(psLinuxMemArea);
984
985         return PVRSRV_OK;
986 }
987
988 PVRSRV_ERROR OSUnRegisterDiscontigMem(IMG_VOID * pvCpuVAddr,
989                                       IMG_UINT32 ui32Bytes,
990                                       IMG_UINT32 ui32Flags,
991                                       IMG_HANDLE hOSMemHandle)
992 {
993         return OSUnRegisterMem(pvCpuVAddr, ui32Bytes, ui32Flags, hOSMemHandle);
994 }
995
996 PVRSRV_ERROR
997 OSReservePhys(IMG_CPU_PHYADDR BasePAddr,
998               IMG_UINT32 ui32Bytes,
999               IMG_UINT32 ui32MappingFlags,
1000               IMG_VOID ** ppvCpuVAddr, IMG_HANDLE * phOSMemHandle)
1001 {
1002         LinuxMemArea *psLinuxMemArea;
1003
1004 #if 0
1005
1006         if (ui32MappingFlags & PVRSRV_HAP_SINGLE_PROCESS) {
1007                 ui32MappingFlags &= ~PVRSRV_HAP_SINGLE_PROCESS;
1008                 ui32MappingFlags |= PVRSRV_HAP_MULTI_PROCESS;
1009         }
1010 #endif
1011
1012         switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) {
1013         case PVRSRV_HAP_KERNEL_ONLY:
1014                 {
1015
1016                         psLinuxMemArea =
1017                             NewIORemapLinuxMemArea(BasePAddr, ui32Bytes,
1018                                                    ui32MappingFlags);
1019                         if (!psLinuxMemArea) {
1020                                 return PVRSRV_ERROR_GENERIC;
1021                         }
1022                         break;
1023                 }
1024         case PVRSRV_HAP_SINGLE_PROCESS:
1025                 {
1026
1027                         psLinuxMemArea =
1028                             NewIOLinuxMemArea(BasePAddr, ui32Bytes,
1029                                               ui32MappingFlags);
1030                         if (!psLinuxMemArea) {
1031                                 return PVRSRV_ERROR_GENERIC;
1032                         }
1033                         PVRMMapRegisterArea("Physical", psLinuxMemArea,
1034                                             ui32MappingFlags);
1035                         break;
1036                 }
1037         case PVRSRV_HAP_MULTI_PROCESS:
1038                 {
1039
1040 #if defined(VIVT_CACHE) || defined(__sh__)
1041
1042                         ui32MappingFlags &= ~PVRSRV_HAP_CACHED;
1043 #endif
1044                         psLinuxMemArea =
1045                             NewIORemapLinuxMemArea(BasePAddr, ui32Bytes,
1046                                                    ui32MappingFlags);
1047                         if (!psLinuxMemArea) {
1048                                 return PVRSRV_ERROR_GENERIC;
1049                         }
1050                         PVRMMapRegisterArea("Physical", psLinuxMemArea,
1051                                             ui32MappingFlags);
1052                         break;
1053                 }
1054         default:
1055                 PVR_DPF((PVR_DBG_ERROR, "OSMapPhysToLin : invalid flags 0x%x\n",
1056                          ui32MappingFlags));
1057                 *ppvCpuVAddr = NULL;
1058                 *phOSMemHandle = (IMG_HANDLE) 0;
1059                 return PVRSRV_ERROR_GENERIC;
1060         }
1061
1062         *phOSMemHandle = (IMG_HANDLE) psLinuxMemArea;
1063         *ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea);
1064
1065         LinuxMemAreaRegister(psLinuxMemArea);
1066
1067         return PVRSRV_OK;
1068 }
1069
1070 PVRSRV_ERROR
1071 OSUnReservePhys(IMG_VOID * pvCpuVAddr,
1072                 IMG_UINT32 ui32Bytes,
1073                 IMG_UINT32 ui32MappingFlags, IMG_HANDLE hOSMemHandle)
1074 {
1075         LinuxMemArea *psLinuxMemArea;
1076         PVR_UNREFERENCED_PARAMETER(pvCpuVAddr);
1077
1078         psLinuxMemArea = (LinuxMemArea *) hOSMemHandle;
1079
1080         switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) {
1081         case PVRSRV_HAP_KERNEL_ONLY:
1082                 break;
1083         case PVRSRV_HAP_SINGLE_PROCESS:
1084         case PVRSRV_HAP_MULTI_PROCESS:
1085                 {
1086                         if (PVRMMapRemoveRegisteredArea(psLinuxMemArea) !=
1087                             PVRSRV_OK) {
1088                                 PVR_DPF((PVR_DBG_ERROR,
1089                                          "%s(%p, %d, 0x%08X, %p) FAILED!",
1090                                          __FUNCTION__, pvCpuVAddr, ui32Bytes,
1091                                          ui32MappingFlags, hOSMemHandle));
1092                                 return PVRSRV_ERROR_GENERIC;
1093                         }
1094                         break;
1095                 }
1096         default:
1097                 {
1098                         PVR_DPF((PVR_DBG_ERROR,
1099                                  "OSUnMapPhysToLin : invalid flags 0x%x",
1100                                  ui32MappingFlags));
1101                         return PVRSRV_ERROR_INVALID_PARAMS;
1102                 }
1103         }
1104
1105         LinuxMemAreaDeepFree(psLinuxMemArea);
1106
1107         return PVRSRV_OK;
1108 }
1109
1110 PVRSRV_ERROR OSBaseAllocContigMemory(IMG_UINT32 ui32Size,
1111                                      IMG_CPU_VIRTADDR * pvLinAddr,
1112                                      IMG_CPU_PHYADDR * psPhysAddr)
1113 {
1114 #if !defined(NO_HARDWARE)
1115         PVR_UNREFERENCED_PARAMETER(ui32Size);
1116         PVR_UNREFERENCED_PARAMETER(pvLinAddr);
1117         PVR_UNREFERENCED_PARAMETER(psPhysAddr);
1118         PVR_DPF((PVR_DBG_ERROR, "%s: Not available", __FUNCTION__));
1119
1120         return PVRSRV_ERROR_OUT_OF_MEMORY;
1121 #else
1122         void *pvKernLinAddr;
1123
1124 #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
1125         pvKernLinAddr = _KMallocWrapper(ui32Size, __FILE__, __LINE__);
1126 #else
1127         pvKernLinAddr = KMallocWrapper(ui32Size);
1128 #endif
1129         if (!pvKernLinAddr) {
1130                 return PVRSRV_ERROR_OUT_OF_MEMORY;
1131         }
1132
1133         *pvLinAddr = pvKernLinAddr;
1134
1135         psPhysAddr->uiAddr = virt_to_phys(pvKernLinAddr);
1136
1137         return PVRSRV_OK;
1138 #endif
1139 }
1140
1141 PVRSRV_ERROR OSBaseFreeContigMemory(IMG_UINT32 ui32Size,
1142                                     IMG_CPU_VIRTADDR pvLinAddr,
1143                                     IMG_CPU_PHYADDR psPhysAddr)
1144 {
1145 #if !defined(NO_HARDWARE)
1146         PVR_UNREFERENCED_PARAMETER(ui32Size);
1147         PVR_UNREFERENCED_PARAMETER(pvLinAddr);
1148         PVR_UNREFERENCED_PARAMETER(psPhysAddr);
1149
1150         PVR_DPF((PVR_DBG_WARNING, "%s: Not available", __FUNCTION__));
1151 #else
1152         PVR_UNREFERENCED_PARAMETER(ui32Size);
1153         PVR_UNREFERENCED_PARAMETER(psPhysAddr);
1154
1155         KFreeWrapper(pvLinAddr);
1156 #endif
1157         return PVRSRV_OK;
1158 }
1159
1160 IMG_UINT32 OSReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset)
1161 {
1162 #if !defined(NO_HARDWARE)
1163         return (IMG_UINT32) readl(pvLinRegBaseAddr + ui32Offset);
1164 #else
1165         return *(IMG_UINT32 *) (pvLinRegBaseAddr + ui32Offset);
1166 #endif
1167 }
1168
1169 IMG_VOID OSWriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset,
1170                       IMG_UINT32 ui32Value)
1171 {
1172 #if !defined(NO_HARDWARE)
1173         writel(ui32Value, pvLinRegBaseAddr + ui32Offset);
1174 #else
1175         *(IMG_UINT32 *) (pvLinRegBaseAddr + ui32Offset) = ui32Value;
1176 #endif
1177 }
1178
1179 #if defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14))
1180
1181 PVRSRV_PCI_DEV_HANDLE OSPCISetDev(IMG_VOID * pvPCICookie,
1182                                   HOST_PCI_INIT_FLAGS eFlags)
1183 {
1184         int err;
1185         IMG_UINT32 i;
1186         PVR_PCI_DEV *psPVRPCI;
1187
1188         PVR_TRACE(("OSPCISetDev"));
1189
1190         if (OSAllocMem
1191             (PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psPVRPCI),
1192              (IMG_VOID *) & psPVRPCI, IMG_NULL) != PVRSRV_OK) {
1193                 PVR_DPF((PVR_DBG_ERROR,
1194                          "OSPCISetDev: Couldn't allocate PVR PCI structure"));
1195                 return IMG_NULL;
1196         }
1197
1198         psPVRPCI->psPCIDev = (struct pci_dev *)pvPCICookie;
1199         psPVRPCI->ePCIFlags = eFlags;
1200
1201         err = pci_enable_device(psPVRPCI->psPCIDev);
1202         if (err != 0) {
1203                 PVR_DPF((PVR_DBG_ERROR,
1204                          "OSPCISetDev: Couldn't enable device (%d)", err));
1205                 return IMG_NULL;
1206         }
1207
1208         if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER)
1209                 pci_set_master(psPVRPCI->psPCIDev);
1210
1211         for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
1212                 psPVRPCI->abPCIResourceInUse[i] = IMG_FALSE;
1213         }
1214
1215         return (PVRSRV_PCI_DEV_HANDLE) psPVRPCI;
1216 }
1217
1218 PVRSRV_PCI_DEV_HANDLE OSPCIAcquireDev(IMG_UINT16 ui16VendorID,
1219                                       IMG_UINT16 ui16DeviceID,
1220                                       HOST_PCI_INIT_FLAGS eFlags)
1221 {
1222         struct pci_dev *psPCIDev;
1223
1224         psPCIDev = pci_get_device(ui16VendorID, ui16DeviceID, NULL);
1225         if (psPCIDev == NULL) {
1226                 PVR_DPF((PVR_DBG_ERROR,
1227                          "OSPCIAcquireDev: Couldn't acquire device"));
1228                 return IMG_NULL;
1229         }
1230
1231         return OSPCISetDev((IMG_VOID *) psPCIDev, eFlags);
1232 }
1233
1234 PVRSRV_ERROR OSPCIIRQ(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 * pui32IRQ)
1235 {
1236         PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *) hPVRPCI;
1237
1238         *pui32IRQ = psPVRPCI->psPCIDev->irq;
1239
1240         return PVRSRV_OK;
1241 }
1242
1243 enum HOST_PCI_ADDR_RANGE_FUNC {
1244         HOST_PCI_ADDR_RANGE_FUNC_LEN,
1245         HOST_PCI_ADDR_RANGE_FUNC_START,
1246         HOST_PCI_ADDR_RANGE_FUNC_END,
1247         HOST_PCI_ADDR_RANGE_FUNC_REQUEST,
1248         HOST_PCI_ADDR_RANGE_FUNC_RELEASE
1249 };
1250
1251 static IMG_UINT32 OSPCIAddrRangeFunc(enum HOST_PCI_ADDR_RANGE_FUNC eFunc,
1252                                      PVRSRV_PCI_DEV_HANDLE hPVRPCI,
1253                                      IMG_UINT32 ui32Index)
1254 {
1255         PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *) hPVRPCI;
1256
1257         if (ui32Index >= DEVICE_COUNT_RESOURCE) {
1258                 PVR_DPF((PVR_DBG_ERROR,
1259                          "OSPCIAddrRangeFunc: Index out of range"));
1260                 return 0;
1261
1262         }
1263
1264         switch (eFunc) {
1265         case HOST_PCI_ADDR_RANGE_FUNC_LEN:
1266                 return pci_resource_len(psPVRPCI->psPCIDev, ui32Index);
1267         case HOST_PCI_ADDR_RANGE_FUNC_START:
1268                 return pci_resource_start(psPVRPCI->psPCIDev, ui32Index);
1269         case HOST_PCI_ADDR_RANGE_FUNC_END:
1270                 return pci_resource_end(psPVRPCI->psPCIDev, ui32Index);
1271         case HOST_PCI_ADDR_RANGE_FUNC_REQUEST:
1272                 {
1273                         int err;
1274
1275                         err =
1276                             pci_request_region(psPVRPCI->psPCIDev, ui32Index,
1277                                                "PowerVR");
1278                         if (err != 0) {
1279                                 PVR_DPF((PVR_DBG_ERROR,
1280                                          "OSPCIAddrRangeFunc: pci_request_region_failed (%d)",
1281                                          err));
1282                                 return 0;
1283                         }
1284                         psPVRPCI->abPCIResourceInUse[ui32Index] = IMG_TRUE;
1285                         return 1;
1286                 }
1287         case HOST_PCI_ADDR_RANGE_FUNC_RELEASE:
1288                 if (psPVRPCI->abPCIResourceInUse[ui32Index]) {
1289                         pci_release_region(psPVRPCI->psPCIDev, ui32Index);
1290                         psPVRPCI->abPCIResourceInUse[ui32Index] = IMG_FALSE;
1291                 }
1292                 return 1;
1293         default:
1294                 PVR_DPF((PVR_DBG_ERROR,
1295                          "OSPCIAddrRangeFunc: Unknown function"));
1296                 break;
1297         }
1298
1299         return 0;
1300 }
1301
1302 IMG_UINT32 OSPCIAddrRangeLen(PVRSRV_PCI_DEV_HANDLE hPVRPCI,
1303                              IMG_UINT32 ui32Index)
1304 {
1305         return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_LEN, hPVRPCI,
1306                                   ui32Index);
1307 }
1308
1309 IMG_UINT32 OSPCIAddrRangeStart(PVRSRV_PCI_DEV_HANDLE hPVRPCI,
1310                                IMG_UINT32 ui32Index)
1311 {
1312         return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_START, hPVRPCI,
1313                                   ui32Index);
1314 }
1315
1316 IMG_UINT32 OSPCIAddrRangeEnd(PVRSRV_PCI_DEV_HANDLE hPVRPCI,
1317                              IMG_UINT32 ui32Index)
1318 {
1319         return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_END, hPVRPCI,
1320                                   ui32Index);
1321 }
1322
1323 PVRSRV_ERROR OSPCIRequestAddrRange(PVRSRV_PCI_DEV_HANDLE hPVRPCI,
1324                                    IMG_UINT32 ui32Index)
1325 {
1326         return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_REQUEST, hPVRPCI,
1327                                   ui32Index) ==
1328             0 ? PVRSRV_ERROR_GENERIC : PVRSRV_OK;
1329 }
1330
1331 PVRSRV_ERROR OSPCIReleaseAddrRange(PVRSRV_PCI_DEV_HANDLE hPVRPCI,
1332                                    IMG_UINT32 ui32Index)
1333 {
1334         return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_RELEASE, hPVRPCI,
1335                                   ui32Index) ==
1336             0 ? PVRSRV_ERROR_GENERIC : PVRSRV_OK;
1337 }
1338
1339 PVRSRV_ERROR OSPCIReleaseDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
1340 {
1341         PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *) hPVRPCI;
1342         int i;
1343
1344         PVR_TRACE(("OSPCIReleaseDev"));
1345
1346         for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
1347                 if (psPVRPCI->abPCIResourceInUse[i]) {
1348                         PVR_TRACE(("OSPCIReleaseDev: Releasing Address range %d", i));
1349                         pci_release_region(psPVRPCI->psPCIDev, i);
1350                         psPVRPCI->abPCIResourceInUse[i] = IMG_FALSE;
1351                 }
1352         }
1353
1354         pci_disable_device(psPVRPCI->psPCIDev);
1355
1356         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psPVRPCI),
1357                   (IMG_VOID *) psPVRPCI, IMG_NULL);
1358
1359         return PVRSRV_OK;
1360 }
1361
1362 PVRSRV_ERROR OSPCISuspendDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
1363 {
1364         PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *) hPVRPCI;
1365         int i;
1366         int err;
1367
1368         PVR_TRACE(("OSPCISuspendDev"));
1369
1370         for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
1371                 if (psPVRPCI->abPCIResourceInUse[i]) {
1372                         pci_release_region(psPVRPCI->psPCIDev, i);
1373                 }
1374         }
1375
1376         err = pci_save_state(psPVRPCI->psPCIDev);
1377         if (err != 0) {
1378                 PVR_DPF((PVR_DBG_ERROR,
1379                          "OSPCISuspendDev: pci_save_state_failed (%d)", err));
1380                 return PVRSRV_ERROR_GENERIC;
1381         }
1382
1383         pci_disable_device(psPVRPCI->psPCIDev);
1384
1385         err =
1386             pci_set_power_state(psPVRPCI->psPCIDev,
1387                                 pci_choose_state(psPVRPCI->psPCIDev,
1388                                                  PMSG_SUSPEND));
1389         switch (err) {
1390         case 0:
1391                 break;
1392         case -EIO:
1393                 PVR_DPF((PVR_DBG_WARNING,
1394                          "OSPCISuspendDev: device doesn't support PCI PM"));
1395                 break;
1396         case -EINVAL:
1397                 PVR_DPF((PVR_DBG_ERROR,
1398                          "OSPCISuspendDev: can't enter requested power state"));
1399                 break;
1400         default:
1401                 PVR_DPF((PVR_DBG_ERROR,
1402                          "OSPCISuspendDev: pci_set_power_state failed (%d)",
1403                          err));
1404                 break;
1405         }
1406
1407         return PVRSRV_OK;
1408 }
1409
1410 PVRSRV_ERROR OSPCIResumeDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
1411 {
1412         PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *) hPVRPCI;
1413         int err;
1414         int i;
1415
1416         PVR_TRACE(("OSPCIResumeDev"));
1417
1418         err =
1419             pci_set_power_state(psPVRPCI->psPCIDev,
1420                                 pci_choose_state(psPVRPCI->psPCIDev, PMSG_ON));
1421         switch (err) {
1422         case 0:
1423                 break;
1424         case -EIO:
1425                 PVR_DPF((PVR_DBG_WARNING,
1426                          "OSPCIResumeDev: device doesn't support PCI PM"));
1427                 break;
1428         case -EINVAL:
1429                 PVR_DPF((PVR_DBG_ERROR,
1430                          "OSPCIResumeDev: can't enter requested power state"));
1431                 return PVRSRV_ERROR_GENERIC;
1432         default:
1433                 PVR_DPF((PVR_DBG_ERROR,
1434                          "OSPCIResumeDev: pci_set_power_state failed (%d)",
1435                          err));
1436                 return PVRSRV_ERROR_GENERIC;
1437         }
1438
1439         err = pci_restore_state(psPVRPCI->psPCIDev);
1440         if (err != 0) {
1441                 PVR_DPF((PVR_DBG_ERROR,
1442                          "OSPCIResumeDev: pci_restore_state failed (%d)", err));
1443                 return PVRSRV_ERROR_GENERIC;
1444         }
1445
1446         err = pci_enable_device(psPVRPCI->psPCIDev);
1447         if (err != 0) {
1448                 PVR_DPF((PVR_DBG_ERROR,
1449                          "OSPCIResumeDev: Couldn't enable device (%d)", err));
1450                 return PVRSRV_ERROR_GENERIC;
1451         }
1452
1453         if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER)
1454                 pci_set_master(psPVRPCI->psPCIDev);
1455
1456         for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
1457                 if (psPVRPCI->abPCIResourceInUse[i]) {
1458                         err =
1459                             pci_request_region(psPVRPCI->psPCIDev, i,
1460                                                "PowerVR");
1461                         if (err != 0) {
1462                                 PVR_DPF((PVR_DBG_ERROR,
1463                                          "OSPCIResumeDev: pci_request_region_failed (region %d, error %d)",
1464                                          i, err));
1465                         }
1466                 }
1467
1468         }
1469
1470         return PVRSRV_OK;
1471 }
1472
1473 #endif
1474
1475 typedef struct TIMER_CALLBACK_DATA_TAG {
1476         PFN_TIMER_FUNC pfnTimerFunc;
1477         IMG_VOID *pvData;
1478         struct timer_list sTimer;
1479         IMG_UINT32 ui32Delay;
1480         IMG_BOOL bActive;
1481 } TIMER_CALLBACK_DATA;
1482
1483 static IMG_VOID OSTimerCallbackWrapper(IMG_UINT32 ui32Data)
1484 {
1485         TIMER_CALLBACK_DATA *psTimerCBData = (TIMER_CALLBACK_DATA *) ui32Data;
1486
1487         if (!psTimerCBData->bActive)
1488                 return;
1489
1490         psTimerCBData->pfnTimerFunc(psTimerCBData->pvData);
1491
1492         mod_timer(&psTimerCBData->sTimer, psTimerCBData->ui32Delay + jiffies);
1493 }
1494
1495 IMG_HANDLE OSAddTimer(PFN_TIMER_FUNC pfnTimerFunc, IMG_VOID * pvData,
1496                       IMG_UINT32 ui32MsTimeout)
1497 {
1498         TIMER_CALLBACK_DATA *psTimerCBData;
1499
1500         if (!pfnTimerFunc) {
1501                 PVR_DPF((PVR_DBG_ERROR, "OSAddTimer: passed invalid callback"));
1502                 return IMG_NULL;
1503         }
1504
1505         if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
1506                        sizeof(TIMER_CALLBACK_DATA),
1507                        (IMG_VOID **) & psTimerCBData, IMG_NULL) != PVRSRV_OK) {
1508                 PVR_DPF((PVR_DBG_ERROR,
1509                          "OSAddTimer: failed to allocate memory for TIMER_CALLBACK_DATA"));
1510                 return IMG_NULL;
1511         }
1512
1513         psTimerCBData->pfnTimerFunc = pfnTimerFunc;
1514         psTimerCBData->pvData = pvData;
1515         psTimerCBData->bActive = IMG_FALSE;
1516
1517         psTimerCBData->ui32Delay = ((HZ * ui32MsTimeout) < 1000)
1518             ? 1 : ((HZ * ui32MsTimeout) / 1000);
1519
1520         init_timer(&psTimerCBData->sTimer);
1521
1522         psTimerCBData->sTimer.function = OSTimerCallbackWrapper;
1523         psTimerCBData->sTimer.data = (IMG_UINT32) psTimerCBData;
1524         psTimerCBData->sTimer.expires = psTimerCBData->ui32Delay + jiffies;
1525
1526         return (IMG_HANDLE) psTimerCBData;
1527 }
1528
1529 PVRSRV_ERROR OSRemoveTimer(IMG_HANDLE hTimer)
1530 {
1531         TIMER_CALLBACK_DATA *psTimerCBData = (TIMER_CALLBACK_DATA *) hTimer;
1532
1533         OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(TIMER_CALLBACK_DATA),
1534                   psTimerCBData, IMG_NULL);
1535
1536         return PVRSRV_OK;
1537 }
1538
1539 PVRSRV_ERROR OSEnableTimer(IMG_HANDLE hTimer)
1540 {
1541         TIMER_CALLBACK_DATA *psTimerCBData = (TIMER_CALLBACK_DATA *) hTimer;
1542
1543         psTimerCBData->bActive = IMG_TRUE;
1544
1545         add_timer(&psTimerCBData->sTimer);
1546
1547         return PVRSRV_OK;
1548 }
1549
1550 PVRSRV_ERROR OSDisableTimer(IMG_HANDLE hTimer)
1551 {
1552         TIMER_CALLBACK_DATA *psTimerCBData = (TIMER_CALLBACK_DATA *) hTimer;
1553
1554         psTimerCBData->bActive = IMG_FALSE;
1555
1556         del_timer_sync(&psTimerCBData->sTimer);
1557
1558         return PVRSRV_OK;
1559 }
1560
1561 PVRSRV_ERROR OSEventObjectCreate(const IMG_CHAR * pszName,
1562                                  PVRSRV_EVENTOBJECT * psEventObject)
1563 {
1564
1565         PVRSRV_ERROR eError = PVRSRV_OK;
1566
1567         if (psEventObject) {
1568                 if (pszName) {
1569
1570                         strncpy(psEventObject->szName, pszName,
1571                                 EVENTOBJNAME_MAXLENGTH);
1572                 } else {
1573
1574                         static IMG_UINT16 ui16NameIndex = 0;
1575                         snprintf(psEventObject->szName, EVENTOBJNAME_MAXLENGTH,
1576                                  "PVRSRV_EVENTOBJECT_%d", ui16NameIndex++);
1577                 }
1578
1579                 if (LinuxEventObjectListCreate(&psEventObject->hOSEventKM) !=
1580                     PVRSRV_OK) {
1581                         eError = PVRSRV_ERROR_OUT_OF_MEMORY;
1582                 }
1583
1584         } else {
1585                 PVR_DPF((PVR_DBG_ERROR,
1586                          "OSEventObjectCreate: psEventObject is not a valid pointer"));
1587                 eError = PVRSRV_ERROR_GENERIC;
1588         }
1589
1590         return eError;
1591
1592 }
1593
1594 PVRSRV_ERROR OSEventObjectDestroy(PVRSRV_EVENTOBJECT * psEventObject)
1595 {
1596         PVRSRV_ERROR eError = PVRSRV_OK;
1597
1598         if (psEventObject) {
1599                 if (psEventObject->hOSEventKM) {
1600                         LinuxEventObjectListDestroy(psEventObject->hOSEventKM);
1601                 } else {
1602                         PVR_DPF((PVR_DBG_ERROR,
1603                                  "OSEventObjectDestroy: hOSEventKM is not a valid pointer"));
1604                         eError = PVRSRV_ERROR_INVALID_PARAMS;
1605                 }
1606         } else {
1607                 PVR_DPF((PVR_DBG_ERROR,
1608                          "OSEventObjectDestroy: psEventObject is not a valid pointer"));
1609                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1610         }
1611
1612         return eError;
1613 }
1614
1615 PVRSRV_ERROR OSEventObjectWait(IMG_HANDLE hOSEventKM)
1616 {
1617         PVRSRV_ERROR eError = PVRSRV_OK;
1618
1619         if (hOSEventKM) {
1620                 eError =
1621                     LinuxEventObjectWait(hOSEventKM, EVENT_OBJECT_TIMEOUT_MS);
1622         } else {
1623                 PVR_DPF((PVR_DBG_ERROR,
1624                          "OSEventObjectWait: hOSEventKM is not a valid handle"));
1625                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1626         }
1627
1628         return eError;
1629 }
1630
1631 PVRSRV_ERROR OSEventObjectOpen(PVRSRV_EVENTOBJECT * psEventObject,
1632                                IMG_HANDLE * phOSEvent)
1633 {
1634         PVRSRV_ERROR eError = PVRSRV_OK;
1635
1636         if (psEventObject) {
1637                 if (LinuxEventObjectAdd(psEventObject->hOSEventKM, phOSEvent) !=
1638                     PVRSRV_OK) {
1639                         PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectAdd: failed"));
1640                         eError = PVRSRV_ERROR_INVALID_PARAMS;
1641                 }
1642
1643         } else {
1644                 PVR_DPF((PVR_DBG_ERROR,
1645                          "OSEventObjectCreate: psEventObject is not a valid pointer"));
1646                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1647         }
1648
1649         return eError;
1650 }
1651
1652 PVRSRV_ERROR OSEventObjectClose(PVRSRV_EVENTOBJECT * psEventObject,
1653                                 IMG_HANDLE hOSEventKM)
1654 {
1655         PVRSRV_ERROR eError = PVRSRV_OK;
1656
1657         if (psEventObject) {
1658                 if (LinuxEventObjectDelete
1659                     (psEventObject->hOSEventKM, hOSEventKM) != PVRSRV_OK) {
1660                         PVR_DPF((PVR_DBG_ERROR,
1661                                  "LinuxEventObjectDelete: failed"));
1662                         eError = PVRSRV_ERROR_INVALID_PARAMS;
1663                 }
1664
1665         } else {
1666                 PVR_DPF((PVR_DBG_ERROR,
1667                          "OSEventObjectDestroy: psEventObject is not a valid pointer"));
1668                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1669         }
1670
1671         return eError;
1672
1673 }
1674
1675 PVRSRV_ERROR OSEventObjectSignal(IMG_HANDLE hOSEventKM)
1676 {
1677         PVRSRV_ERROR eError = PVRSRV_OK;
1678
1679         if (hOSEventKM) {
1680                 eError = LinuxEventObjectSignal(hOSEventKM);
1681         } else {
1682                 PVR_DPF((PVR_DBG_ERROR,
1683                          "OSEventObjectSignal: hOSEventKM is not a valid handle"));
1684                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1685         }
1686
1687         return eError;
1688 }
1689
1690 IMG_BOOL OSProcHasPrivSrvInit(IMG_VOID)
1691 {
1692         return capable(CAP_SYS_MODULE) != 0;
1693 }
1694
1695 PVRSRV_ERROR OSCopyToUser(IMG_PVOID pvProcess,
1696                           IMG_VOID * pvDest,
1697                           IMG_VOID * pvSrc, IMG_UINT32 ui32Bytes)
1698 {
1699         PVR_UNREFERENCED_PARAMETER(pvProcess);
1700
1701         if (copy_to_user(pvDest, pvSrc, ui32Bytes) == 0)
1702                 return PVRSRV_OK;
1703         else
1704                 return PVRSRV_ERROR_GENERIC;
1705 }
1706
1707 PVRSRV_ERROR OSCopyFromUser(IMG_PVOID pvProcess,
1708                             IMG_VOID * pvDest,
1709                             IMG_VOID * pvSrc, IMG_UINT32 ui32Bytes)
1710 {
1711         PVR_UNREFERENCED_PARAMETER(pvProcess);
1712
1713         if (copy_from_user(pvDest, pvSrc, ui32Bytes) == 0)
1714                 return PVRSRV_OK;
1715         else
1716                 return PVRSRV_ERROR_GENERIC;
1717 }
1718
1719 IMG_BOOL OSAccessOK(IMG_VERIFY_TEST eVerification, IMG_VOID * pvUserPtr,
1720                     IMG_UINT32 ui32Bytes)
1721 {
1722         int linuxType;
1723
1724         if (eVerification == PVR_VERIFY_READ)
1725                 linuxType = VERIFY_READ;
1726         else if (eVerification == PVR_VERIFY_WRITE)
1727                 linuxType = VERIFY_WRITE;
1728         else {
1729                 PVR_DPF((PVR_DBG_ERROR, "%s: Unknown eVerification",
1730                          __FUNCTION__));
1731                 return PVRSRV_ERROR_GENERIC;
1732         }
1733         return (IMG_BOOL) access_ok(linuxType, pvUserPtr, ui32Bytes);
1734 }
1735
1736 typedef enum _eWrapMemType_ {
1737         WRAP_TYPE_CLEANUP,
1738         WRAP_TYPE_GET_USER_PAGES,
1739         WRAP_TYPE_FIND_VMA_PAGES,
1740         WRAP_TYPE_FIND_VMA_PFN
1741 } eWrapMemType;
1742
1743 typedef struct _sWrapMemInfo_ {
1744         eWrapMemType eType;
1745         int iNumPages;
1746         struct page **ppsPages;
1747         IMG_SYS_PHYADDR *psPhysAddr;
1748         int iPageOffset;
1749         int iContiguous;
1750 #if defined(DEBUG)
1751         unsigned long ulStartAddr;
1752         unsigned long ulBeyondEndAddr;
1753         struct vm_area_struct *psVMArea;
1754 #endif
1755 } sWrapMemInfo;
1756
1757 static void CheckPagesContiguous(sWrapMemInfo * psInfo)
1758 {
1759         unsigned ui;
1760         IMG_UINT32 ui32AddrChk;
1761
1762         BUG_ON(psInfo == IMG_NULL);
1763
1764         psInfo->iContiguous = 1;
1765
1766         for (ui = 0, ui32AddrChk = psInfo->psPhysAddr[0].uiAddr;
1767              ui < psInfo->iNumPages; ui++, ui32AddrChk += PAGE_SIZE) {
1768                 if (psInfo->psPhysAddr[ui].uiAddr != ui32AddrChk) {
1769                         psInfo->iContiguous = 0;
1770                         break;
1771                 }
1772         }
1773 }
1774
1775 static struct page *CPUVAddrToPage(struct vm_area_struct *psVMArea,
1776                                    unsigned long ulCPUVAddr)
1777 {
1778 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10))
1779         pgd_t *psPGD;
1780         pud_t *psPUD;
1781         pmd_t *psPMD;
1782         pte_t *psPTE;
1783         struct mm_struct *psMM = psVMArea->vm_mm;
1784         unsigned long ulPFN;
1785         spinlock_t *psPTLock;
1786         struct page *psPage;
1787
1788         psPGD = pgd_offset(psMM, ulCPUVAddr);
1789         if (pgd_none(*psPGD) || pgd_bad(*psPGD))
1790                 return NULL;
1791
1792         psPUD = pud_offset(psPGD, ulCPUVAddr);
1793         if (pud_none(*psPUD) || pud_bad(*psPUD))
1794                 return NULL;
1795
1796         psPMD = pmd_offset(psPUD, ulCPUVAddr);
1797         if (pmd_none(*psPMD) || pmd_bad(*psPMD))
1798                 return NULL;
1799
1800         psPage = NULL;
1801
1802         psPTE = pte_offset_map_lock(psMM, psPMD, ulCPUVAddr, &psPTLock);
1803         if (pte_none(*psPTE) || !pte_present(*psPTE) || !pte_write(*psPTE))
1804                 goto exit_unlock;
1805
1806         ulPFN = pte_pfn(*psPTE);
1807         if (!pfn_valid(ulPFN))
1808                 goto exit_unlock;
1809
1810         psPage = pfn_to_page(ulPFN);
1811
1812         get_page(psPage);
1813
1814 exit_unlock:
1815         pte_unmap_unlock(psPTE, psPTLock);
1816
1817         return psPage;
1818 #else
1819         return NULL;
1820 #endif
1821 }
1822
1823 PVRSRV_ERROR OSReleasePhysPageAddr(IMG_HANDLE hOSWrapMem)
1824 {
1825         sWrapMemInfo *psInfo = (sWrapMemInfo *) hOSWrapMem;
1826         unsigned ui;
1827
1828         BUG_ON(psInfo == IMG_NULL);
1829
1830 #if defined(DEBUG)
1831         switch (psInfo->eType) {
1832         case WRAP_TYPE_FIND_VMA_PAGES:
1833
1834         case WRAP_TYPE_FIND_VMA_PFN:
1835                 {
1836                         struct vm_area_struct *psVMArea;
1837
1838                         down_read(&current->mm->mmap_sem);
1839
1840                         psVMArea = find_vma(current->mm, psInfo->ulStartAddr);
1841                         if (psVMArea == NULL) {
1842                                 printk(KERN_WARNING
1843                                        ": OSCpuVToPageListRelease: Couldn't find memory region containing start address %lx",
1844                                        psInfo->ulStartAddr);
1845
1846                                 up_read(&current->mm->mmap_sem);
1847                                 break;
1848                         }
1849
1850                         if (psInfo->psVMArea != psVMArea) {
1851                                 printk(KERN_WARNING
1852                                        ": OSCpuVToPageListRelease: vm_area_struct has a different address from the one used in ImportMem (%p != %p)",
1853                                        psVMArea, psInfo->psVMArea);
1854                         }
1855
1856                         if (psInfo->ulStartAddr < psVMArea->vm_start) {
1857                                 printk(KERN_WARNING
1858                                        ": OSCpuVToPageListRelease: Start address %lx is outside of the region returned by find_vma",
1859                                        psInfo->ulStartAddr);
1860                         }
1861
1862                         if (psInfo->ulBeyondEndAddr > psVMArea->vm_end) {
1863                                 printk(KERN_WARNING
1864                                        ": OSCpuVToPageListRelease: End address %lx is outside of the region returned by find_vma",
1865                                        psInfo->ulBeyondEndAddr);
1866                         }
1867
1868                         if ((psVMArea->vm_flags & (VM_IO | VM_RESERVED)) !=
1869                             (VM_IO | VM_RESERVED)) {
1870                                 printk(KERN_WARNING
1871                                        ": OSCpuVToPageListRelease: Memory region does not represent memory mapped I/O (VMA flags: 0x%lx)",
1872                                        psVMArea->vm_flags);
1873                         }
1874
1875                         if ((psVMArea->vm_flags & (VM_READ | VM_WRITE)) !=
1876                             (VM_READ | VM_WRITE)) {
1877                                 printk(KERN_WARNING
1878                                        ": OSCpuVToPageListRelease: OSWrapMemReleasePages: No read/write access to memory region (VMA flags: 0x%lx)",
1879                                        psVMArea->vm_flags);
1880                         }
1881
1882                         up_read(&current->mm->mmap_sem);
1883                         break;
1884                 }
1885         default:
1886                 break;
1887         }
1888 #endif
1889
1890         switch (psInfo->eType) {
1891         case WRAP_TYPE_CLEANUP:
1892                 break;
1893         case WRAP_TYPE_FIND_VMA_PFN:
1894                 break;
1895         case WRAP_TYPE_GET_USER_PAGES:
1896                 {
1897                         for (ui = 0; ui < psInfo->iNumPages; ui++) {
1898                                 struct page *psPage = psInfo->ppsPages[ui];
1899
1900                                 if (!PageReserved(psPage)) ;
1901                                 {
1902                                         SetPageDirty(psPage);
1903                                 }
1904                                 page_cache_release(psPage);
1905                         }
1906                         break;
1907                 }
1908         case WRAP_TYPE_FIND_VMA_PAGES:
1909                 {
1910                         for (ui = 0; ui < psInfo->iNumPages; ui++) {
1911                                 put_page_testzero(psInfo->ppsPages[ui]);
1912                         }
1913                         break;
1914                 }
1915         default:
1916                 {
1917                         printk(KERN_WARNING
1918                                ": OSCpuVToPageListRelease: Unknown wrap type (%d)",
1919                                psInfo->eType);
1920                         return PVRSRV_ERROR_GENERIC;
1921                 }
1922         }
1923
1924         if (psInfo->ppsPages != IMG_NULL) {
1925                 kfree(psInfo->ppsPages);
1926         }
1927
1928         if (psInfo->psPhysAddr != IMG_NULL) {
1929                 kfree(psInfo->psPhysAddr);
1930         }
1931
1932         kfree(psInfo);
1933
1934         return PVRSRV_OK;
1935 }
1936
1937 PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID * pvCPUVAddr,
1938                                    IMG_UINT32 ui32Bytes,
1939                                    IMG_SYS_PHYADDR * psSysPAddr,
1940                                    IMG_HANDLE * phOSWrapMem)
1941 {
1942         unsigned long ulStartAddrOrig = (unsigned long)pvCPUVAddr;
1943         unsigned long ulAddrRangeOrig = (unsigned long)ui32Bytes;
1944         unsigned long ulBeyondEndAddrOrig = ulStartAddrOrig + ulAddrRangeOrig;
1945         unsigned long ulStartAddr;
1946         unsigned long ulAddrRange;
1947         unsigned long ulBeyondEndAddr;
1948         unsigned long ulAddr;
1949         int iNumPagesMapped;
1950         unsigned ui;
1951         struct vm_area_struct *psVMArea;
1952         sWrapMemInfo *psInfo;
1953
1954         ulStartAddr = ulStartAddrOrig & PAGE_MASK;
1955         ulBeyondEndAddr = PAGE_ALIGN(ulBeyondEndAddrOrig);
1956         ulAddrRange = ulBeyondEndAddr - ulStartAddr;
1957
1958         psInfo = kmalloc(sizeof(*psInfo), GFP_KERNEL);
1959         if (psInfo == NULL) {
1960                 printk(KERN_WARNING
1961                        ": OSCpuVToPageList: Couldn't allocate information structure");
1962                 return PVRSRV_ERROR_OUT_OF_MEMORY;
1963         }
1964         memset(psInfo, 0, sizeof(*psInfo));
1965
1966 #if defined(DEBUG)
1967         psInfo->ulStartAddr = ulStartAddrOrig;
1968         psInfo->ulBeyondEndAddr = ulBeyondEndAddrOrig;
1969 #endif
1970
1971         psInfo->iNumPages = ulAddrRange >> PAGE_SHIFT;
1972         psInfo->iPageOffset = ulStartAddrOrig & ~PAGE_MASK;
1973
1974         psInfo->psPhysAddr =
1975             kmalloc(psInfo->iNumPages * sizeof(*psInfo->psPhysAddr),
1976                     GFP_KERNEL);
1977         if (psInfo->psPhysAddr == NULL) {
1978                 printk(KERN_WARNING
1979                        ": OSCpuVToPageList: Couldn't allocate page array");
1980                 goto error_free;
1981         }
1982
1983         psInfo->ppsPages =
1984             kmalloc(psInfo->iNumPages * sizeof(*psInfo->ppsPages), GFP_KERNEL);
1985         if (psInfo->ppsPages == NULL) {
1986                 printk(KERN_WARNING
1987                        ": OSCpuVToPageList: Couldn't allocate page array");
1988                 goto error_free;
1989         }
1990
1991         down_read(&current->mm->mmap_sem);
1992         iNumPagesMapped =
1993             get_user_pages(current, current->mm, ulStartAddr, psInfo->iNumPages,
1994                            1, 0, psInfo->ppsPages, NULL);
1995         up_read(&current->mm->mmap_sem);
1996
1997         if (iNumPagesMapped >= 0) {
1998
1999                 if (iNumPagesMapped != psInfo->iNumPages) {
2000                         printk(KERN_WARNING
2001                                ": OSCpuVToPageList: Couldn't map all the pages needed (wanted: %d, got %d)",
2002                                psInfo->iNumPages, iNumPagesMapped);
2003
2004                         for (ui = 0; ui < iNumPagesMapped; ui++) {
2005                                 page_cache_release(psInfo->ppsPages[ui]);
2006
2007                         }
2008                         goto error_free;
2009                 }
2010
2011                 for (ui = 0; ui < psInfo->iNumPages; ui++) {
2012                         IMG_CPU_PHYADDR CPUPhysAddr;
2013
2014                         CPUPhysAddr.uiAddr =
2015                             page_to_pfn(psInfo->ppsPages[ui]) << PAGE_SHIFT;
2016                         psInfo->psPhysAddr[ui] =
2017                             SysCpuPAddrToSysPAddr(CPUPhysAddr);
2018                         psSysPAddr[ui] = psInfo->psPhysAddr[ui];
2019
2020                 }
2021
2022                 psInfo->eType = WRAP_TYPE_GET_USER_PAGES;
2023
2024                 goto exit_check;
2025         }
2026
2027         printk(KERN_WARNING
2028                ": OSCpuVToPageList: get_user_pages failed (%d), trying something else",
2029                iNumPagesMapped);
2030
2031         down_read(&current->mm->mmap_sem);
2032
2033         psVMArea = find_vma(current->mm, ulStartAddrOrig);
2034         if (psVMArea == NULL) {
2035                 printk(KERN_WARNING
2036                        ": OSCpuVToPageList: Couldn't find memory region containing start address %lx",
2037                        ulStartAddrOrig);
2038
2039                 goto error_release_mmap_sem;
2040         }
2041 #if defined(DEBUG)
2042         psInfo->psVMArea = psVMArea;
2043 #endif
2044
2045         if (ulStartAddrOrig < psVMArea->vm_start) {
2046                 printk(KERN_WARNING
2047                        ": OSCpuVToPageList: Start address %lx is outside of the region returned by find_vma",
2048                        ulStartAddrOrig);
2049                 goto error_release_mmap_sem;
2050         }
2051
2052         if (ulBeyondEndAddrOrig > psVMArea->vm_end) {
2053                 printk(KERN_WARNING
2054                        ": OSCpuVToPageList: End address %lx is outside of the region returned by find_vma",
2055                        ulBeyondEndAddrOrig);
2056                 goto error_release_mmap_sem;
2057         }
2058
2059         if ((psVMArea->vm_flags & (VM_IO | VM_RESERVED)) !=
2060             (VM_IO | VM_RESERVED)) {
2061                 printk(KERN_WARNING
2062                        ": OSCpuVToPageList: Memory region does not represent memory mapped I/O (VMA flags: 0x%lx)",
2063                        psVMArea->vm_flags);
2064                 goto error_release_mmap_sem;
2065         }
2066
2067         if ((psVMArea->vm_flags & (VM_READ | VM_WRITE)) != (VM_READ | VM_WRITE)) {
2068                 printk(KERN_WARNING
2069                        ": OSCpuVToPageList: No read/write access to memory region (VMA flags: 0x%lx)",
2070                        psVMArea->vm_flags);
2071                 goto error_release_mmap_sem;
2072         }
2073
2074         for (ulAddr = ulStartAddrOrig, ui = 0; ulAddr < ulBeyondEndAddrOrig;
2075              ulAddr += PAGE_SIZE, ui++) {
2076                 struct page *psPage;
2077
2078                 BUG_ON(ui >= psInfo->iNumPages);
2079
2080                 psPage = CPUVAddrToPage(psVMArea, ulAddr);
2081                 if (psPage == NULL) {
2082                         unsigned uj;
2083
2084                         printk(KERN_WARNING
2085                                ": OSCpuVToPageList: Couldn't lookup page structure for address 0x%lx, trying something else",
2086                                ulAddr);
2087
2088                         for (uj = 0; uj < ui; uj++) {
2089                                 put_page_testzero(psInfo->ppsPages[uj]);
2090                         }
2091                         break;
2092                 }
2093
2094                 psInfo->ppsPages[ui] = psPage;
2095         }
2096
2097         BUG_ON(ui > psInfo->iNumPages);
2098         if (ui == psInfo->iNumPages) {
2099
2100                 for (ui = 0; ui < psInfo->iNumPages; ui++) {
2101                         struct page *psPage = psInfo->ppsPages[ui];
2102                         IMG_CPU_PHYADDR CPUPhysAddr;
2103
2104                         CPUPhysAddr.uiAddr = page_to_pfn(psPage) << PAGE_SHIFT;
2105
2106                         psInfo->psPhysAddr[ui] =
2107                             SysCpuPAddrToSysPAddr(CPUPhysAddr);
2108                         psSysPAddr[ui] = psInfo->psPhysAddr[ui];
2109                 }
2110
2111                 psInfo->eType = WRAP_TYPE_FIND_VMA_PAGES;
2112         } else {
2113 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10))
2114
2115                 if ((psVMArea->vm_flags & VM_PFNMAP) == 0) {
2116                         printk(KERN_WARNING
2117                                ": OSCpuVToPageList: Region isn't a raw PFN mapping.  Giving up.");
2118                         goto error_release_mmap_sem;
2119                 }
2120
2121                 for (ulAddr = ulStartAddrOrig, ui = 0;
2122                      ulAddr < ulBeyondEndAddrOrig; ulAddr += PAGE_SIZE, ui++) {
2123                         IMG_CPU_PHYADDR CPUPhysAddr;
2124
2125                         CPUPhysAddr.uiAddr =
2126                             ((ulAddr - psVMArea->vm_start) +
2127                              (psVMArea->vm_pgoff << PAGE_SHIFT)) & PAGE_MASK;
2128
2129                         psInfo->psPhysAddr[ui] =
2130                             SysCpuPAddrToSysPAddr(CPUPhysAddr);
2131                         psSysPAddr[ui] = psInfo->psPhysAddr[ui];
2132                 }
2133                 BUG_ON(ui != psInfo->iNumPages);
2134
2135                 psInfo->eType = WRAP_TYPE_FIND_VMA_PFN;
2136
2137                 printk(KERN_WARNING
2138                        ": OSCpuVToPageList: Region can't be locked down");
2139 #else
2140                 printk(KERN_WARNING
2141                        ": OSCpuVToPageList: Raw PFN mappings not supported.  Giving up.");
2142                 goto error_release_mmap_sem;
2143 #endif
2144         }
2145
2146         up_read(&current->mm->mmap_sem);
2147
2148 exit_check:
2149         CheckPagesContiguous(psInfo);
2150
2151         *phOSWrapMem = (IMG_HANDLE) psInfo;
2152
2153         return PVRSRV_OK;
2154
2155 error_release_mmap_sem:
2156         up_read(&current->mm->mmap_sem);
2157 error_free:
2158         psInfo->eType = WRAP_TYPE_CLEANUP;
2159         OSReleasePhysPageAddr((IMG_HANDLE) psInfo);
2160         return PVRSRV_ERROR_GENERIC;
2161 }