1 /**********************************************************************
3 * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
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.
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.
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.
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
21 * Contact Information:
22 * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23 * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
25 ******************************************************************************/
27 #ifndef AUTOCONF_INCLUDED
28 #include <linux/config.h>
31 #include <linux/version.h>
34 #include <asm/system.h>
36 #include <linux/pagemap.h>
37 #include <linux/hugetlb.h>
38 #include <linux/slab.h>
39 #include <linux/vmalloc.h>
40 #include <linux/delay.h>
41 #include <linux/pci.h>
43 #include <linux/string.h>
44 #include <linux/sched.h>
45 #include <linux/interrupt.h>
46 #include <linux/hardirq.h>
47 #include <linux/timer.h>
48 #include <linux/capability.h>
49 #include <linux/uaccess.h>
51 #include "img_types.h"
52 #include "services_headers.h"
61 #define EVENT_OBJECT_TIMEOUT_MS (100)
63 #define HOST_ALLOC_MEM_USING_KMALLOC ((void *)0)
64 #define HOST_ALLOC_MEM_USING_VMALLOC ((void *)1)
66 #define LINUX_KMALLOC_LIMIT PAGE_SIZE /* 4k */
68 #if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
69 enum PVRSRV_ERROR OSAllocMem(u32 ui32Flags, u32 ui32Size,
70 void **ppvCpuVAddr, void **phBlockAlloc)
72 enum PVRSRV_ERROR _OSAllocMem(u32 ui32Flags, u32 ui32Size,
73 void **ppvCpuVAddr, void **phBlockAlloc,
74 char *pszFilename, u32 ui32Line)
79 PVR_UNREFERENCED_PARAMETER(ui32Flags);
81 /* determine whether to go straight to vmalloc */
82 ui32Threshold = LINUX_KMALLOC_LIMIT;
84 if (ui32Size > ui32Threshold) {
85 #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
86 *ppvCpuVAddr = _VMallocWrapper(ui32Size, PVRSRV_HAP_CACHED,
87 pszFilename, ui32Line);
89 *ppvCpuVAddr = VMallocWrapper(ui32Size, PVRSRV_HAP_CACHED);
92 return PVRSRV_ERROR_OUT_OF_MEMORY;
95 *phBlockAlloc = HOST_ALLOC_MEM_USING_VMALLOC;
97 /* default - try kmalloc first */
99 #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
100 *ppvCpuVAddr = _KMallocWrapper(ui32Size, pszFilename, ui32Line);
102 *ppvCpuVAddr = KMallocWrapper(ui32Size);
106 return PVRSRV_ERROR_OUT_OF_MEMORY;
109 *phBlockAlloc = HOST_ALLOC_MEM_USING_KMALLOC;
116 #if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
117 void OSFreeMem(u32 ui32Flags, u32 ui32Size,
118 void *pvCpuVAddr, void *hBlockAlloc)
120 void _OSFreeMem(u32 ui32Flags, u32 ui32Size,
121 void *pvCpuVAddr, void *hBlockAlloc,
122 char *pszFilename, u32 ui32Line)
125 PVR_UNREFERENCED_PARAMETER(ui32Flags);
127 if (ui32Size > LINUX_KMALLOC_LIMIT) {
128 #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
129 _VFreeWrapper(pvCpuVAddr, pszFilename, ui32Line);
131 VFreeWrapper(pvCpuVAddr);
134 #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
135 _KFreeWrapper(pvCpuVAddr, pszFilename, ui32Line);
137 KFreeWrapper(pvCpuVAddr);
142 enum PVRSRV_ERROR OSAllocPages(u32 ui32AllocFlags,
144 void **ppvCpuVAddr, void **phOSMemHandle)
146 struct LinuxMemArea *psLinuxMemArea;
149 switch (ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK) {
150 case PVRSRV_HAP_KERNEL_ONLY:
153 NewVMallocLinuxMemArea(ui32Size, ui32AllocFlags);
155 return PVRSRV_ERROR_OUT_OF_MEMORY;
158 case PVRSRV_HAP_SINGLE_PROCESS:
162 NewAllocPagesLinuxMemArea(ui32Size, ui32AllocFlags);
164 return PVRSRV_ERROR_OUT_OF_MEMORY;
165 PVRMMapRegisterArea("Import Arena", psLinuxMemArea,
170 case PVRSRV_HAP_MULTI_PROCESS:
173 NewVMallocLinuxMemArea(ui32Size, ui32AllocFlags);
175 return PVRSRV_ERROR_OUT_OF_MEMORY;
176 PVRMMapRegisterArea("Import Arena", psLinuxMemArea,
181 PVR_DPF(PVR_DBG_ERROR, "OSAllocPages: invalid flags 0x%x\n",
184 *phOSMemHandle = (void *) 0;
185 return PVRSRV_ERROR_INVALID_PARAMS;
188 *ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea);
189 *phOSMemHandle = psLinuxMemArea;
191 LinuxMemAreaRegister(psLinuxMemArea);
196 enum PVRSRV_ERROR OSFreePages(u32 ui32AllocFlags, u32 ui32Bytes,
197 void *pvCpuVAddr, void *hOSMemHandle)
199 struct LinuxMemArea *psLinuxMemArea;
200 PVR_UNREFERENCED_PARAMETER(pvCpuVAddr);
202 psLinuxMemArea = (struct LinuxMemArea *)hOSMemHandle;
204 switch (ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK) {
205 case PVRSRV_HAP_KERNEL_ONLY:
207 case PVRSRV_HAP_SINGLE_PROCESS:
208 case PVRSRV_HAP_MULTI_PROCESS:
209 if (PVRMMapRemoveRegisteredArea(psLinuxMemArea) != PVRSRV_OK) {
210 PVR_DPF(PVR_DBG_ERROR,
211 "OSFreePages(ui32AllocFlags=0x%08X, "
213 "pvCpuVAddr=%p, hOSMemHandle=%p) FAILED!",
214 ui32AllocFlags, ui32Bytes, pvCpuVAddr,
216 return PVRSRV_ERROR_GENERIC;
220 PVR_DPF(PVR_DBG_ERROR, "%s: invalid flags 0x%x\n",
221 __func__, ui32AllocFlags);
222 return PVRSRV_ERROR_INVALID_PARAMS;
225 LinuxMemAreaDeepFree(psLinuxMemArea);
230 enum PVRSRV_ERROR OSGetSubMemHandle(void *hOSMemHandle,
233 u32 ui32Flags, void **phOSMemHandleRet)
235 struct LinuxMemArea *psParentLinuxMemArea, *psLinuxMemArea;
236 enum PVRSRV_ERROR eError = PVRSRV_OK;
238 psParentLinuxMemArea = (struct LinuxMemArea *)hOSMemHandle;
241 NewSubLinuxMemArea(psParentLinuxMemArea, ui32ByteOffset, ui32Bytes);
242 if (!psLinuxMemArea) {
243 *phOSMemHandleRet = NULL;
244 return PVRSRV_ERROR_OUT_OF_MEMORY;
246 *phOSMemHandleRet = psLinuxMemArea;
248 if (ui32Flags & PVRSRV_HAP_KERNEL_ONLY)
251 if (psParentLinuxMemArea->eAreaType == LINUX_MEM_AREA_IO) {
252 eError = PVRMMapRegisterArea("Physical", psLinuxMemArea, 0);
253 if (eError != PVRSRV_OK)
254 goto failed_register_area;
255 } else if (psParentLinuxMemArea->eAreaType ==
256 LINUX_MEM_AREA_ALLOC_PAGES) {
257 eError = PVRMMapRegisterArea("Import Arena", psLinuxMemArea, 0);
258 if (eError != PVRSRV_OK)
259 goto failed_register_area;
264 failed_register_area:
265 *phOSMemHandleRet = NULL;
266 LinuxMemAreaDeepFree(psLinuxMemArea);
270 enum PVRSRV_ERROR OSReleaseSubMemHandle(void *hOSMemHandle, u32 ui32Flags)
272 struct LinuxMemArea *psParentLinuxMemArea, *psLinuxMemArea;
273 enum PVRSRV_ERROR eError;
275 psLinuxMemArea = (struct LinuxMemArea *)hOSMemHandle;
276 PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC);
278 psParentLinuxMemArea =
279 psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea;
281 if (!(ui32Flags & PVRSRV_HAP_KERNEL_ONLY)
282 && (psParentLinuxMemArea->eAreaType == LINUX_MEM_AREA_IO
283 || psParentLinuxMemArea->eAreaType ==
284 LINUX_MEM_AREA_ALLOC_PAGES)
286 eError = PVRMMapRemoveRegisteredArea(psLinuxMemArea);
287 if (eError != PVRSRV_OK)
290 LinuxMemAreaDeepFree(psLinuxMemArea);
295 struct IMG_CPU_PHYADDR OSMemHandleToCpuPAddr(void *hOSMemHandle,
298 PVR_ASSERT(hOSMemHandle);
300 return LinuxMemAreaToCpuPAddr(hOSMemHandle, ui32ByteOffset);
303 void OSMemCopy(void *pvDst, void *pvSrc, u32 ui32Size)
305 memcpy(pvDst, pvSrc, ui32Size);
308 void OSMemSet(void *pvDest, u8 ui8Value, u32 ui32Size)
310 memset(pvDest, (int)ui8Value, (size_t) ui32Size);
313 char *OSStringCopy(char *pszDest, const char *pszSrc)
315 return strcpy(pszDest, pszSrc);
318 s32 OSSNPrintf(char *pStr, u32 ui32Size, const char *pszFormat, ...)
323 va_start(argList, pszFormat);
324 iCount = vsnprintf(pStr, (size_t) ui32Size, pszFormat, argList);
330 void OSBreakResourceLock(struct PVRSRV_RESOURCE *psResource, u32 ui32ID)
332 volatile u32 *pui32Access = (volatile u32 *)&psResource->ui32Lock;
335 if (psResource->ui32ID == ui32ID) {
336 psResource->ui32ID = 0;
339 PVR_DPF(PVR_DBG_MESSAGE, "OSBreakResourceLock: "
340 "Resource is not locked for this process.");
343 PVR_DPF(PVR_DBG_MESSAGE,
344 "OSBreakResourceLock: Resource is not locked");
347 enum PVRSRV_ERROR OSCreateResource(struct PVRSRV_RESOURCE *psResource)
349 psResource->ui32ID = 0;
350 psResource->ui32Lock = 0;
355 enum PVRSRV_ERROR OSDestroyResource(struct PVRSRV_RESOURCE *psResource)
357 OSBreakResourceLock(psResource, psResource->ui32ID);
362 enum PVRSRV_ERROR OSInitEnvData(void **ppvEnvSpecificData)
364 struct ENV_DATA *psEnvData;
366 if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct ENV_DATA),
367 (void *)&psEnvData, NULL) != PVRSRV_OK)
368 return PVRSRV_ERROR_GENERIC;
370 memset(psEnvData, 0, sizeof(*psEnvData));
372 if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
373 PVRSRV_MAX_BRIDGE_IN_SIZE + PVRSRV_MAX_BRIDGE_OUT_SIZE,
374 &psEnvData->pvBridgeData, NULL) != PVRSRV_OK) {
375 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct ENV_DATA),
377 return PVRSRV_ERROR_GENERIC;
380 psEnvData->bMISRInstalled = IMG_FALSE;
381 psEnvData->bLISRInstalled = IMG_FALSE;
383 *ppvEnvSpecificData = psEnvData;
388 enum PVRSRV_ERROR OSDeInitEnvData(void *pvEnvSpecificData)
390 struct ENV_DATA *psEnvData = (struct ENV_DATA *)pvEnvSpecificData;
392 PVR_ASSERT(!psEnvData->bMISRInstalled);
393 PVR_ASSERT(!psEnvData->bLISRInstalled);
395 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
396 PVRSRV_MAX_BRIDGE_IN_SIZE + PVRSRV_MAX_BRIDGE_OUT_SIZE,
397 psEnvData->pvBridgeData, NULL);
399 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct ENV_DATA),
400 pvEnvSpecificData, NULL);
405 void OSReleaseThreadQuanta(void)
412 unsigned long time, j = jiffies;
414 time = j * (1000000 / HZ);
419 void OSWaitus(u32 ui32Timeus)
424 u32 OSGetCurrentProcessIDKM(void)
428 return task_tgid_nr(current);
431 u32 OSGetPageSize(void)
436 static irqreturn_t DeviceISRWrapper(int irq, void *dev_id)
438 struct PVRSRV_DEVICE_NODE *psDeviceNode;
439 IMG_BOOL bStatus = IMG_FALSE;
441 psDeviceNode = (struct PVRSRV_DEVICE_NODE *)dev_id;
443 PVR_DPF(PVR_DBG_ERROR, "DeviceISRWrapper: invalid params\n");
447 bStatus = PVRSRVDeviceLISR(psDeviceNode);
450 struct SYS_DATA *psSysData = psDeviceNode->psSysData;
451 struct ENV_DATA *psEnvData =
452 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
454 queue_work(psEnvData->psMISRWorkqueue, &psEnvData->sMISRWork);
458 return bStatus ? IRQ_HANDLED : IRQ_NONE;
461 enum PVRSRV_ERROR OSInstallDeviceLISR(void *pvSysData,
463 char *pszISRName, void *pvDeviceNode)
465 struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
466 struct ENV_DATA *psEnvData =
467 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
469 if (psEnvData->bLISRInstalled) {
470 PVR_DPF(PVR_DBG_ERROR, "OSInstallDeviceLISR: "
471 "An ISR has already been installed: IRQ %d cookie %x",
472 psEnvData->ui32IRQ, psEnvData->pvISRCookie);
473 return PVRSRV_ERROR_GENERIC;
476 PVR_TRACE("Installing device LISR %s on IRQ %d with cookie %x",
477 pszISRName, ui32Irq, pvDeviceNode);
479 if (request_irq(ui32Irq, DeviceISRWrapper, IRQF_SHARED, pszISRName,
481 PVR_DPF(PVR_DBG_ERROR, "OSInstallDeviceLISR: "
482 "Couldn't install device LISR on IRQ %d",
485 return PVRSRV_ERROR_GENERIC;
488 psEnvData->ui32IRQ = ui32Irq;
489 psEnvData->pvISRCookie = pvDeviceNode;
490 psEnvData->bLISRInstalled = IMG_TRUE;
495 enum PVRSRV_ERROR OSUninstallDeviceLISR(void *pvSysData)
497 struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
498 struct ENV_DATA *psEnvData =
499 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
501 if (!psEnvData->bLISRInstalled) {
502 PVR_DPF(PVR_DBG_ERROR,
503 "OSUninstallDeviceLISR: No LISR has been installed");
504 return PVRSRV_ERROR_GENERIC;
507 PVR_TRACE("Uninstalling device LISR on IRQ %d with cookie %x",
508 psEnvData->ui32IRQ, psEnvData->pvISRCookie);
510 free_irq(psEnvData->ui32IRQ, psEnvData->pvISRCookie);
512 psEnvData->bLISRInstalled = IMG_FALSE;
517 static void MISRWrapper(struct work_struct *work)
519 struct ENV_DATA *psEnvData = container_of(work, struct ENV_DATA,
521 struct SYS_DATA *psSysData = (struct SYS_DATA *)psEnvData->pvSysData;
522 PVRSRVMISR(psSysData);
525 enum PVRSRV_ERROR OSInstallMISR(void *pvSysData)
527 struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
528 struct ENV_DATA *psEnvData =
529 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
531 if (psEnvData->bMISRInstalled) {
532 PVR_DPF(PVR_DBG_ERROR,
533 "OSInstallMISR: An MISR has already been installed");
534 return PVRSRV_ERROR_GENERIC;
537 PVR_TRACE("Installing MISR with cookie %x", pvSysData);
539 psEnvData->pvSysData = pvSysData;
540 psEnvData->psMISRWorkqueue = create_singlethread_workqueue("sgx_misr");
541 INIT_WORK(&psEnvData->sMISRWork, MISRWrapper);
543 psEnvData->bMISRInstalled = IMG_TRUE;
548 enum PVRSRV_ERROR OSUninstallMISR(void *pvSysData)
550 struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
551 struct ENV_DATA *psEnvData =
552 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
554 if (!psEnvData->bMISRInstalled) {
555 PVR_DPF(PVR_DBG_ERROR,
556 "OSUninstallMISR: No MISR has been installed");
557 return PVRSRV_ERROR_GENERIC;
560 PVR_TRACE("Uninstalling MISR");
562 flush_workqueue(psEnvData->psMISRWorkqueue);
563 destroy_workqueue(psEnvData->psMISRWorkqueue);
565 psEnvData->bMISRInstalled = IMG_FALSE;
570 enum PVRSRV_ERROR OSScheduleMISR(void *pvSysData)
572 struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
573 struct ENV_DATA *psEnvData =
574 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
576 if (psEnvData->bMISRInstalled)
577 queue_work(psEnvData->psMISRWorkqueue, &psEnvData->sMISRWork);
583 #define OS_TAS(p) xchg((p), 1)
584 enum PVRSRV_ERROR OSLockResource(struct PVRSRV_RESOURCE *psResource, u32 ui32ID)
586 enum PVRSRV_ERROR eError = PVRSRV_OK;
588 if (!OS_TAS(&psResource->ui32Lock))
589 psResource->ui32ID = ui32ID;
591 eError = PVRSRV_ERROR_GENERIC;
596 enum PVRSRV_ERROR OSUnlockResource(struct PVRSRV_RESOURCE *psResource,
599 volatile u32 *pui32Access = (volatile u32 *)&psResource->ui32Lock;
600 enum PVRSRV_ERROR eError = PVRSRV_OK;
603 if (psResource->ui32ID == ui32ID) {
604 psResource->ui32ID = 0;
607 PVR_DPF(PVR_DBG_ERROR, "OSUnlockResource: "
608 "Resource %p is not locked with expected value.",
610 PVR_DPF(PVR_DBG_MESSAGE, "Should be %x is actually %x",
611 ui32ID, psResource->ui32ID);
612 eError = PVRSRV_ERROR_GENERIC;
615 PVR_DPF(PVR_DBG_ERROR,
616 "OSUnlockResource: Resource %p is not locked",
618 eError = PVRSRV_ERROR_GENERIC;
624 struct IMG_CPU_PHYADDR OSMapLinToCPUPhys(void *pvLinAddr)
626 struct IMG_CPU_PHYADDR CpuPAddr;
628 CpuPAddr.uiAddr = (u32) VMallocToPhys(pvLinAddr);
633 void __iomem *OSMapPhysToLin(struct IMG_CPU_PHYADDR BasePAddr, u32 ui32Bytes,
634 u32 ui32MappingFlags, void **phOSMemHandle)
637 *phOSMemHandle = (void *) 0;
639 if (ui32MappingFlags & PVRSRV_HAP_KERNEL_ONLY) {
640 void __iomem *pvIORemapCookie;
642 IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags);
643 if (pvIORemapCookie == NULL)
645 return pvIORemapCookie;
647 PVR_DPF(PVR_DBG_ERROR,
648 "OSMapPhysToLin should only be used with "
649 "PVRSRV_HAP_KERNEL_ONLY "
650 "(Use OSReservePhys otherwise)");
651 *phOSMemHandle = (void *) 0;
660 OSUnMapPhysToLin(void __iomem *pvLinAddr, u32 ui32Bytes,
661 u32 ui32MappingFlags, void *hPageAlloc)
663 PVR_TRACE("%s: unmapping %d bytes from 0x%08x", __func__,
664 ui32Bytes, pvLinAddr);
666 PVR_UNREFERENCED_PARAMETER(hPageAlloc);
668 if (ui32MappingFlags & PVRSRV_HAP_KERNEL_ONLY) {
669 IOUnmapWrapper(pvLinAddr);
672 PVR_DPF(PVR_DBG_ERROR,
673 "OSUnMapPhysToLin should only be used with "
674 "PVRSRV_HAP_KERNEL_ONLY "
675 " (Use OSUnReservePhys otherwise)");
683 static enum PVRSRV_ERROR RegisterExternalMem(struct IMG_SYS_PHYADDR *pBasePAddr,
684 void *pvCPUVAddr, u32 ui32Bytes,
685 IMG_BOOL bPhysContig, u32 ui32MappingFlags,
686 void **phOSMemHandle)
688 struct LinuxMemArea *psLinuxMemArea;
690 switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) {
691 case PVRSRV_HAP_KERNEL_ONLY:
694 NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr,
695 ui32Bytes, bPhysContig,
699 return PVRSRV_ERROR_GENERIC;
702 case PVRSRV_HAP_SINGLE_PROCESS:
705 NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr,
706 ui32Bytes, bPhysContig,
710 return PVRSRV_ERROR_GENERIC;
711 PVRMMapRegisterArea("Physical", psLinuxMemArea,
715 case PVRSRV_HAP_MULTI_PROCESS:
718 NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr,
719 ui32Bytes, bPhysContig,
723 return PVRSRV_ERROR_GENERIC;
724 PVRMMapRegisterArea("Physical", psLinuxMemArea,
729 PVR_DPF(PVR_DBG_ERROR, "OSRegisterMem : invalid flags 0x%x\n",
731 *phOSMemHandle = (void *) 0;
732 return PVRSRV_ERROR_GENERIC;
735 *phOSMemHandle = (void *) psLinuxMemArea;
737 LinuxMemAreaRegister(psLinuxMemArea);
742 enum PVRSRV_ERROR OSRegisterMem(struct IMG_CPU_PHYADDR BasePAddr,
745 u32 ui32MappingFlags, void **phOSMemHandle)
747 struct IMG_SYS_PHYADDR SysPAddr = SysCpuPAddrToSysPAddr(BasePAddr);
749 return RegisterExternalMem(&SysPAddr, pvCPUVAddr, ui32Bytes, IMG_TRUE,
750 ui32MappingFlags, phOSMemHandle);
753 enum PVRSRV_ERROR OSRegisterDiscontigMem(struct IMG_SYS_PHYADDR *pBasePAddr,
754 void *pvCPUVAddr, u32 ui32Bytes,
755 u32 ui32MappingFlags,
756 void **phOSMemHandle)
758 return RegisterExternalMem(pBasePAddr, pvCPUVAddr, ui32Bytes,
759 IMG_FALSE, ui32MappingFlags, phOSMemHandle);
762 enum PVRSRV_ERROR OSUnRegisterMem(void *pvCpuVAddr,
764 u32 ui32MappingFlags, void *hOSMemHandle)
766 struct LinuxMemArea *psLinuxMemArea = (struct LinuxMemArea *)
769 PVR_UNREFERENCED_PARAMETER(pvCpuVAddr);
771 switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) {
772 case PVRSRV_HAP_KERNEL_ONLY:
774 case PVRSRV_HAP_SINGLE_PROCESS:
775 case PVRSRV_HAP_MULTI_PROCESS:
777 if (PVRMMapRemoveRegisteredArea(psLinuxMemArea) !=
779 PVR_DPF(PVR_DBG_ERROR,
780 "%s(%p, %d, 0x%08X, %p) FAILED!",
781 __func__, pvCpuVAddr, ui32Bytes,
782 ui32MappingFlags, hOSMemHandle);
783 return PVRSRV_ERROR_GENERIC;
789 PVR_DPF(PVR_DBG_ERROR,
790 "OSUnRegisterMem : invalid flags 0x%x",
792 return PVRSRV_ERROR_INVALID_PARAMS;
796 LinuxMemAreaDeepFree(psLinuxMemArea);
801 enum PVRSRV_ERROR OSUnRegisterDiscontigMem(void *pvCpuVAddr, u32 ui32Bytes,
802 u32 ui32Flags, void *hOSMemHandle)
804 return OSUnRegisterMem(pvCpuVAddr, ui32Bytes, ui32Flags, hOSMemHandle);
807 enum PVRSRV_ERROR OSReservePhys(struct IMG_CPU_PHYADDR BasePAddr,
808 u32 ui32Bytes, u32 ui32MappingFlags, void **ppvCpuVAddr,
809 void **phOSMemHandle)
811 struct LinuxMemArea *psLinuxMemArea;
813 switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) {
814 case PVRSRV_HAP_KERNEL_ONLY:
818 NewIORemapLinuxMemArea(BasePAddr, ui32Bytes,
821 return PVRSRV_ERROR_GENERIC;
824 case PVRSRV_HAP_SINGLE_PROCESS:
827 NewIOLinuxMemArea(BasePAddr, ui32Bytes,
830 return PVRSRV_ERROR_GENERIC;
831 PVRMMapRegisterArea("Physical", psLinuxMemArea,
835 case PVRSRV_HAP_MULTI_PROCESS:
838 NewIORemapLinuxMemArea(BasePAddr, ui32Bytes,
841 return PVRSRV_ERROR_GENERIC;
842 PVRMMapRegisterArea("Physical", psLinuxMemArea,
847 PVR_DPF(PVR_DBG_ERROR, "OSMapPhysToLin : invalid flags 0x%x\n",
850 *phOSMemHandle = (void *) 0;
851 return PVRSRV_ERROR_GENERIC;
854 *phOSMemHandle = (void *) psLinuxMemArea;
855 *ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea);
857 LinuxMemAreaRegister(psLinuxMemArea);
862 enum PVRSRV_ERROR OSUnReservePhys(void *pvCpuVAddr,
863 u32 ui32Bytes, u32 ui32MappingFlags, void *hOSMemHandle)
865 struct LinuxMemArea *psLinuxMemArea;
866 PVR_UNREFERENCED_PARAMETER(pvCpuVAddr);
868 psLinuxMemArea = (struct LinuxMemArea *)hOSMemHandle;
870 switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) {
871 case PVRSRV_HAP_KERNEL_ONLY:
873 case PVRSRV_HAP_SINGLE_PROCESS:
874 case PVRSRV_HAP_MULTI_PROCESS:
876 if (PVRMMapRemoveRegisteredArea(psLinuxMemArea) !=
878 PVR_DPF(PVR_DBG_ERROR,
879 "%s(%p, %d, 0x%08X, %p) FAILED!",
880 __func__, pvCpuVAddr, ui32Bytes,
881 ui32MappingFlags, hOSMemHandle);
882 return PVRSRV_ERROR_GENERIC;
888 PVR_DPF(PVR_DBG_ERROR,
889 "OSUnMapPhysToLin : invalid flags 0x%x",
891 return PVRSRV_ERROR_INVALID_PARAMS;
895 LinuxMemAreaDeepFree(psLinuxMemArea);
900 enum PVRSRV_ERROR OSBaseAllocContigMemory(u32 ui32Size, void **pvLinAddr,
901 struct IMG_CPU_PHYADDR *psPhysAddr)
903 PVR_UNREFERENCED_PARAMETER(ui32Size);
904 PVR_UNREFERENCED_PARAMETER(pvLinAddr);
905 PVR_UNREFERENCED_PARAMETER(psPhysAddr);
906 PVR_DPF(PVR_DBG_ERROR, "%s: Not available", __func__);
908 return PVRSRV_ERROR_OUT_OF_MEMORY;
911 enum PVRSRV_ERROR OSBaseFreeContigMemory(u32 ui32Size, void *pvLinAddr,
912 struct IMG_CPU_PHYADDR psPhysAddr)
914 PVR_UNREFERENCED_PARAMETER(ui32Size);
915 PVR_UNREFERENCED_PARAMETER(pvLinAddr);
916 PVR_UNREFERENCED_PARAMETER(psPhysAddr);
918 PVR_DPF(PVR_DBG_WARNING, "%s: Not available", __func__);
922 u32 OSReadHWReg(void __iomem *pvLinRegBaseAddr, u32 ui32Offset)
924 return (u32)readl(pvLinRegBaseAddr + ui32Offset);
927 void OSWriteHWReg(void __iomem *pvLinRegBaseAddr, u32 ui32Offset, u32 ui32Value)
929 writel(ui32Value, pvLinRegBaseAddr + ui32Offset);
932 struct TIMER_CALLBACK_DATA {
933 void (*pfnTimerFunc)(void *);
935 struct timer_list sTimer;
940 static void OSTimerCallbackWrapper(unsigned long ui32Data)
942 struct TIMER_CALLBACK_DATA *psTimerCBData =
943 (struct TIMER_CALLBACK_DATA *)ui32Data;
945 if (!psTimerCBData->bActive)
948 psTimerCBData->pfnTimerFunc(psTimerCBData->pvData);
950 mod_timer(&psTimerCBData->sTimer, psTimerCBData->ui32Delay + jiffies);
953 void *OSAddTimer(void (*pfnTimerFunc)(void *), void *pvData, u32 ui32MsTimeout)
955 struct TIMER_CALLBACK_DATA *psTimerCBData;
958 PVR_DPF(PVR_DBG_ERROR, "OSAddTimer: passed invalid callback");
962 if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
963 sizeof(struct TIMER_CALLBACK_DATA),
964 (void **) &psTimerCBData, NULL) != PVRSRV_OK) {
965 PVR_DPF(PVR_DBG_ERROR,
966 "OSAddTimer: failed to allocate memory");
970 psTimerCBData->pfnTimerFunc = pfnTimerFunc;
971 psTimerCBData->pvData = pvData;
972 psTimerCBData->bActive = IMG_FALSE;
974 psTimerCBData->ui32Delay = ((HZ * ui32MsTimeout) < 1000)
975 ? 1 : ((HZ * ui32MsTimeout) / 1000);
977 init_timer(&psTimerCBData->sTimer);
979 psTimerCBData->sTimer.function = OSTimerCallbackWrapper;
980 psTimerCBData->sTimer.data = (u32) psTimerCBData;
981 psTimerCBData->sTimer.expires = psTimerCBData->ui32Delay + jiffies;
983 return (void *)psTimerCBData;
986 enum PVRSRV_ERROR OSRemoveTimer(void *hTimer)
988 struct TIMER_CALLBACK_DATA *psTimerCBData =
989 (struct TIMER_CALLBACK_DATA *)hTimer;
991 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
992 sizeof(struct TIMER_CALLBACK_DATA),
993 psTimerCBData, NULL);
998 enum PVRSRV_ERROR OSEnableTimer(void *hTimer)
1000 struct TIMER_CALLBACK_DATA *psTimerCBData =
1001 (struct TIMER_CALLBACK_DATA *)hTimer;
1003 psTimerCBData->bActive = IMG_TRUE;
1005 psTimerCBData->sTimer.expires = psTimerCBData->ui32Delay + jiffies;
1006 add_timer(&psTimerCBData->sTimer);
1011 enum PVRSRV_ERROR OSDisableTimer(void *hTimer)
1013 struct TIMER_CALLBACK_DATA *psTimerCBData =
1014 (struct TIMER_CALLBACK_DATA *)hTimer;
1016 psTimerCBData->bActive = IMG_FALSE;
1018 del_timer_sync(&psTimerCBData->sTimer);
1023 enum PVRSRV_ERROR OSEventObjectCreate(const char *pszName,
1024 struct PVRSRV_EVENTOBJECT *psEventObject)
1026 enum PVRSRV_ERROR eError = PVRSRV_OK;
1028 if (psEventObject) {
1031 strncpy(psEventObject->szName, pszName,
1032 EVENTOBJNAME_MAXLENGTH);
1035 static u16 ui16NameIndex;
1036 snprintf(psEventObject->szName, EVENTOBJNAME_MAXLENGTH,
1037 "PVRSRV_EVENTOBJECT_%d", ui16NameIndex++);
1040 if (LinuxEventObjectListCreate(&psEventObject->hOSEventKM) !=
1042 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
1045 PVR_DPF(PVR_DBG_ERROR, "OSEventObjectCreate: "
1046 "psEventObject is not a valid pointer");
1047 eError = PVRSRV_ERROR_GENERIC;
1054 enum PVRSRV_ERROR OSEventObjectDestroy(struct PVRSRV_EVENTOBJECT *psEventObject)
1056 enum PVRSRV_ERROR eError = PVRSRV_OK;
1058 if (psEventObject) {
1059 if (psEventObject->hOSEventKM) {
1060 LinuxEventObjectListDestroy(psEventObject->hOSEventKM);
1062 PVR_DPF(PVR_DBG_ERROR, "OSEventObjectDestroy: "
1063 "hOSEventKM is not a valid pointer");
1064 eError = PVRSRV_ERROR_INVALID_PARAMS;
1067 PVR_DPF(PVR_DBG_ERROR, "OSEventObjectDestroy: "
1068 "psEventObject is not a valid pointer");
1069 eError = PVRSRV_ERROR_INVALID_PARAMS;
1075 enum PVRSRV_ERROR OSEventObjectWait(void *hOSEventKM)
1077 enum PVRSRV_ERROR eError = PVRSRV_OK;
1081 LinuxEventObjectWait(hOSEventKM, EVENT_OBJECT_TIMEOUT_MS);
1083 PVR_DPF(PVR_DBG_ERROR, "OSEventObjectWait: "
1084 "hOSEventKM is not a valid handle");
1085 eError = PVRSRV_ERROR_INVALID_PARAMS;
1091 enum PVRSRV_ERROR OSEventObjectOpen(struct PVRSRV_EVENTOBJECT *psEventObject,
1094 enum PVRSRV_ERROR eError = PVRSRV_OK;
1096 if (psEventObject) {
1097 if (LinuxEventObjectAdd(psEventObject->hOSEventKM, phOSEvent) !=
1099 PVR_DPF(PVR_DBG_ERROR, "LinuxEventObjectAdd: failed");
1100 eError = PVRSRV_ERROR_INVALID_PARAMS;
1104 PVR_DPF(PVR_DBG_ERROR, "OSEventObjectCreate: "
1105 "psEventObject is not a valid pointer");
1106 eError = PVRSRV_ERROR_INVALID_PARAMS;
1112 enum PVRSRV_ERROR OSEventObjectClose(struct PVRSRV_EVENTOBJECT *psEventObject,
1115 enum PVRSRV_ERROR eError = PVRSRV_OK;
1117 if (psEventObject) {
1118 if (LinuxEventObjectDelete
1119 (psEventObject->hOSEventKM, hOSEventKM) != PVRSRV_OK) {
1120 PVR_DPF(PVR_DBG_ERROR,
1121 "LinuxEventObjectDelete: failed");
1122 eError = PVRSRV_ERROR_INVALID_PARAMS;
1126 PVR_DPF(PVR_DBG_ERROR, "OSEventObjectDestroy: "
1127 "psEventObject is not a valid pointer");
1128 eError = PVRSRV_ERROR_INVALID_PARAMS;
1135 enum PVRSRV_ERROR OSEventObjectSignal(void *hOSEventKM)
1137 enum PVRSRV_ERROR eError = PVRSRV_OK;
1140 eError = LinuxEventObjectSignal(hOSEventKM);
1142 PVR_DPF(PVR_DBG_ERROR, "OSEventObjectSignal: "
1143 "hOSEventKM is not a valid handle");
1144 eError = PVRSRV_ERROR_INVALID_PARAMS;
1150 IMG_BOOL OSProcHasPrivSrvInit(void)
1152 return capable(CAP_SYS_MODULE) != 0;
1155 enum PVRSRV_ERROR OSCopyToUser(void *pvProcess, void __user *pvDest,
1156 const void *pvSrc, u32 ui32Bytes)
1158 PVR_UNREFERENCED_PARAMETER(pvProcess);
1160 if (copy_to_user(pvDest, pvSrc, ui32Bytes) == 0)
1163 return PVRSRV_ERROR_GENERIC;
1166 enum PVRSRV_ERROR OSCopyFromUser(void *pvProcess, void *pvDest,
1167 const void __user *pvSrc, u32 ui32Bytes)
1169 PVR_UNREFERENCED_PARAMETER(pvProcess);
1171 if (copy_from_user(pvDest, pvSrc, ui32Bytes) == 0)
1174 return PVRSRV_ERROR_GENERIC;
1177 IMG_BOOL OSAccessOK(enum IMG_VERIFY_TEST eVerification,
1178 const void __user *pvUserPtr, u32 ui32Bytes)
1182 if (eVerification == PVR_VERIFY_READ)
1183 linuxType = VERIFY_READ;
1184 else if (eVerification == PVR_VERIFY_WRITE)
1185 linuxType = VERIFY_WRITE;
1187 PVR_DPF(PVR_DBG_ERROR, "%s: Unknown eVerification", __func__);
1188 return PVRSRV_ERROR_GENERIC;
1190 return (IMG_BOOL)access_ok(linuxType, pvUserPtr, ui32Bytes);
1195 WRAP_TYPE_GET_USER_PAGES,
1196 WRAP_TYPE_FIND_VMA_PAGES,
1197 WRAP_TYPE_FIND_VMA_PFN
1200 struct sWrapMemInfo {
1201 enum eWrapMemType eType;
1203 struct page **ppsPages;
1204 struct IMG_SYS_PHYADDR *psPhysAddr;
1208 unsigned long ulStartAddr;
1209 unsigned long ulBeyondEndAddr;
1210 struct vm_area_struct *psVMArea;
1214 static void CheckPagesContiguous(struct sWrapMemInfo *psInfo)
1219 BUG_ON(psInfo == NULL);
1221 psInfo->iContiguous = 1;
1223 for (ui = 0, ui32AddrChk = psInfo->psPhysAddr[0].uiAddr;
1224 ui < psInfo->iNumPages; ui++, ui32AddrChk += PAGE_SIZE)
1225 if (psInfo->psPhysAddr[ui].uiAddr != ui32AddrChk) {
1226 psInfo->iContiguous = 0;
1231 static struct page *CPUVAddrToPage(struct vm_area_struct *psVMArea,
1232 unsigned long ulCPUVAddr)
1238 struct mm_struct *psMM = psVMArea->vm_mm;
1239 unsigned long ulPFN;
1240 spinlock_t *psPTLock;
1241 struct page *psPage;
1243 psPGD = pgd_offset(psMM, ulCPUVAddr);
1244 if (pgd_none(*psPGD) || pgd_bad(*psPGD))
1247 psPUD = pud_offset(psPGD, ulCPUVAddr);
1248 if (pud_none(*psPUD) || pud_bad(*psPUD))
1251 psPMD = pmd_offset(psPUD, ulCPUVAddr);
1252 if (pmd_none(*psPMD) || pmd_bad(*psPMD))
1257 psPTE = pte_offset_map_lock(psMM, psPMD, ulCPUVAddr, &psPTLock);
1258 if (pte_none(*psPTE) || !pte_present(*psPTE) || !pte_write(*psPTE))
1261 ulPFN = pte_pfn(*psPTE);
1262 if (!pfn_valid(ulPFN))
1265 psPage = pfn_to_page(ulPFN);
1270 pte_unmap_unlock(psPTE, psPTLock);
1275 enum PVRSRV_ERROR OSReleasePhysPageAddr(void *hOSWrapMem, IMG_BOOL bUseLock)
1277 struct sWrapMemInfo *psInfo = (struct sWrapMemInfo *)hOSWrapMem;
1280 BUG_ON(psInfo == NULL);
1283 switch (psInfo->eType) {
1284 case WRAP_TYPE_FIND_VMA_PAGES:
1286 case WRAP_TYPE_FIND_VMA_PFN:
1288 struct vm_area_struct *psVMArea;
1291 down_read(¤t->mm->mmap_sem);
1293 psVMArea = find_vma(current->mm, psInfo->ulStartAddr);
1294 if (psVMArea == NULL) {
1295 printk(KERN_WARNING ": OSCpuVToPageListRelease:"
1296 " Couldn't find memory region containing start address %lx",
1297 psInfo->ulStartAddr);
1300 up_read(¤t->mm->mmap_sem);
1305 if (psInfo->psVMArea != psVMArea)
1306 printk(KERN_WARNING ": OSCpuVToPageListRelease:"
1307 " vm_area_struct has a different "
1308 "address from the one used in "
1309 "ImportMem (%p != %p)",
1310 psVMArea, psInfo->psVMArea);
1312 if (psInfo->ulStartAddr < psVMArea->vm_start)
1313 printk(KERN_WARNING ": OSCpuVToPageListRelease:"
1314 " Start address %lx is outside of "
1315 "the region returned by find_vma",
1316 psInfo->ulStartAddr);
1318 if (psInfo->ulBeyondEndAddr > psVMArea->vm_end)
1319 printk(KERN_WARNING ": OSCpuVToPageListRelease:"
1320 " End address %lx is outside of the "
1321 "region returned by find_vma",
1322 psInfo->ulBeyondEndAddr);
1324 if ((psVMArea->vm_flags & (VM_IO | VM_RESERVED)) !=
1325 (VM_IO | VM_RESERVED))
1326 printk(KERN_WARNING ": OSCpuVToPageListRelease:"
1327 " Memory region does not represent "
1328 "memory mapped I/O (VMA flags: 0x%lx)",
1329 psVMArea->vm_flags);
1331 if ((psVMArea->vm_flags & (VM_READ | VM_WRITE)) !=
1332 (VM_READ | VM_WRITE))
1333 printk(KERN_WARNING ": OSCpuVToPageListRelease:"
1334 " OSWrapMemReleasePages: "
1335 "No read/write access to memory region "
1336 "(VMA flags: 0x%lx)",
1337 psVMArea->vm_flags);
1340 up_read(¤t->mm->mmap_sem);
1349 switch (psInfo->eType) {
1350 case WRAP_TYPE_CLEANUP:
1352 case WRAP_TYPE_FIND_VMA_PFN:
1354 case WRAP_TYPE_GET_USER_PAGES:
1356 for (ui = 0; ui < psInfo->iNumPages; ui++) {
1357 struct page *psPage = psInfo->ppsPages[ui];
1359 if (!PageReserved(psPage))
1362 SetPageDirty(psPage);
1364 page_cache_release(psPage);
1368 case WRAP_TYPE_FIND_VMA_PAGES:
1370 for (ui = 0; ui < psInfo->iNumPages; ui++)
1371 put_page_testzero(psInfo->ppsPages[ui]);
1376 printk(KERN_WARNING ": OSCpuVToPageListRelease: "
1377 "Unknown wrap type (%d)", psInfo->eType);
1378 return PVRSRV_ERROR_GENERIC;
1382 if (psInfo->ppsPages != NULL)
1383 kfree(psInfo->ppsPages);
1385 if (psInfo->psPhysAddr != NULL)
1386 kfree(psInfo->psPhysAddr);
1393 enum PVRSRV_ERROR OSAcquirePhysPageAddr(void *pvCPUVAddr,
1395 struct IMG_SYS_PHYADDR *psSysPAddr,
1399 unsigned long ulStartAddrOrig = (unsigned long)pvCPUVAddr;
1400 unsigned long ulAddrRangeOrig = (unsigned long)ui32Bytes;
1401 unsigned long ulBeyondEndAddrOrig = ulStartAddrOrig + ulAddrRangeOrig;
1402 unsigned long ulStartAddr;
1403 unsigned long ulAddrRange;
1404 unsigned long ulBeyondEndAddr;
1405 unsigned long ulAddr;
1406 int iNumPagesMapped;
1408 struct vm_area_struct *psVMArea;
1409 struct sWrapMemInfo *psInfo;
1411 ulStartAddr = ulStartAddrOrig & PAGE_MASK;
1412 ulBeyondEndAddr = PAGE_ALIGN(ulBeyondEndAddrOrig);
1413 ulAddrRange = ulBeyondEndAddr - ulStartAddr;
1415 psInfo = kmalloc(sizeof(*psInfo), GFP_KERNEL);
1416 if (psInfo == NULL) {
1417 printk(KERN_WARNING ": OSCpuVToPageList: "
1418 "Couldn't allocate information structure\n");
1419 return PVRSRV_ERROR_OUT_OF_MEMORY;
1421 memset(psInfo, 0, sizeof(*psInfo));
1424 psInfo->ulStartAddr = ulStartAddrOrig;
1425 psInfo->ulBeyondEndAddr = ulBeyondEndAddrOrig;
1428 psInfo->iNumPages = ulAddrRange >> PAGE_SHIFT;
1429 psInfo->iPageOffset = ulStartAddrOrig & ~PAGE_MASK;
1431 psInfo->psPhysAddr =
1432 kmalloc(psInfo->iNumPages * sizeof(*psInfo->psPhysAddr),
1434 if (psInfo->psPhysAddr == NULL) {
1436 ": OSCpuVToPageList: Couldn't allocate page array\n");
1441 kmalloc(psInfo->iNumPages * sizeof(*psInfo->ppsPages), GFP_KERNEL);
1442 if (psInfo->ppsPages == NULL) {
1444 ": OSCpuVToPageList: Couldn't allocate page array\n");
1449 down_read(¤t->mm->mmap_sem);
1452 get_user_pages(current, current->mm, ulStartAddr, psInfo->iNumPages,
1453 1, 0, psInfo->ppsPages, NULL);
1456 up_read(¤t->mm->mmap_sem);
1459 if (iNumPagesMapped >= 0) {
1461 if (iNumPagesMapped != psInfo->iNumPages) {
1462 printk(KERN_WARNING ": OSCpuVToPageList: Couldn't "
1463 "map all the pages needed "
1464 "(wanted: %d, got %d \n)",
1465 psInfo->iNumPages, iNumPagesMapped);
1467 for (ui = 0; ui < iNumPagesMapped; ui++)
1468 page_cache_release(psInfo->ppsPages[ui]);
1473 for (ui = 0; ui < psInfo->iNumPages; ui++) {
1474 struct IMG_CPU_PHYADDR CPUPhysAddr;
1476 CPUPhysAddr.uiAddr =
1477 page_to_pfn(psInfo->ppsPages[ui]) << PAGE_SHIFT;
1478 psInfo->psPhysAddr[ui] =
1479 SysCpuPAddrToSysPAddr(CPUPhysAddr);
1480 psSysPAddr[ui] = psInfo->psPhysAddr[ui];
1484 psInfo->eType = WRAP_TYPE_GET_USER_PAGES;
1489 printk(KERN_WARNING ": OSCpuVToPageList: get_user_pages failed (%d), "
1490 "trying something else \n",
1494 down_read(¤t->mm->mmap_sem);
1496 psVMArea = find_vma(current->mm, ulStartAddrOrig);
1497 if (psVMArea == NULL) {
1498 printk(KERN_WARNING ": OSCpuVToPageList: "
1499 "Couldn't find memory region containing "
1500 "start address %lx \n",
1503 goto error_release_mmap_sem;
1506 psInfo->psVMArea = psVMArea;
1509 if (ulStartAddrOrig < psVMArea->vm_start) {
1510 printk(KERN_WARNING ": OSCpuVToPageList: "
1511 "Start address %lx is outside of the "
1512 "region returned by find_vma\n",
1514 goto error_release_mmap_sem;
1517 if (ulBeyondEndAddrOrig > psVMArea->vm_end) {
1518 printk(KERN_WARNING ": OSCpuVToPageList: "
1519 "End address %lx is outside of the "
1520 "region returned by find_vma\n",
1521 ulBeyondEndAddrOrig);
1522 goto error_release_mmap_sem;
1525 if ((psVMArea->vm_flags & (VM_IO | VM_RESERVED)) !=
1526 (VM_IO | VM_RESERVED)) {
1527 printk(KERN_WARNING ": OSCpuVToPageList: "
1528 "Memory region does not represent "
1529 "memory mapped I/O (VMA flags: 0x%lx)\n",
1530 psVMArea->vm_flags);
1531 goto error_release_mmap_sem;
1534 if ((psVMArea->vm_flags & (VM_READ | VM_WRITE)) !=
1535 (VM_READ | VM_WRITE)) {
1536 printk(KERN_WARNING ": OSCpuVToPageList: "
1537 "No read/write access to memory region "
1538 "(VMA flags: 0x%lx)\n",
1539 psVMArea->vm_flags);
1540 goto error_release_mmap_sem;
1543 for (ulAddr = ulStartAddrOrig, ui = 0; ulAddr < ulBeyondEndAddrOrig;
1544 ulAddr += PAGE_SIZE, ui++) {
1545 struct page *psPage;
1547 BUG_ON(ui >= psInfo->iNumPages);
1549 psPage = CPUVAddrToPage(psVMArea, ulAddr);
1550 if (psPage == NULL) {
1553 printk(KERN_WARNING ": OSCpuVToPageList: "
1554 "Couldn't lookup page structure for "
1555 "address 0x%lx, trying something else\n",
1558 for (uj = 0; uj < ui; uj++)
1559 put_page_testzero(psInfo->ppsPages[uj]);
1563 psInfo->ppsPages[ui] = psPage;
1566 BUG_ON(ui > psInfo->iNumPages);
1567 if (ui == psInfo->iNumPages) {
1569 for (ui = 0; ui < psInfo->iNumPages; ui++) {
1570 struct page *psPage = psInfo->ppsPages[ui];
1571 struct IMG_CPU_PHYADDR CPUPhysAddr;
1573 CPUPhysAddr.uiAddr = page_to_pfn(psPage) << PAGE_SHIFT;
1575 psInfo->psPhysAddr[ui] =
1576 SysCpuPAddrToSysPAddr(CPUPhysAddr);
1577 psSysPAddr[ui] = psInfo->psPhysAddr[ui];
1580 psInfo->eType = WRAP_TYPE_FIND_VMA_PAGES;
1583 if ((psVMArea->vm_flags & VM_PFNMAP) == 0) {
1584 printk(KERN_WARNING ": OSCpuVToPageList: "
1585 "Region isn't a raw PFN mapping. Giving up.\n");
1586 goto error_release_mmap_sem;
1589 for (ulAddr = ulStartAddrOrig, ui = 0;
1590 ulAddr < ulBeyondEndAddrOrig; ulAddr += PAGE_SIZE, ui++) {
1591 struct IMG_CPU_PHYADDR CPUPhysAddr;
1593 CPUPhysAddr.uiAddr =
1594 ((ulAddr - psVMArea->vm_start) +
1595 (psVMArea->vm_pgoff << PAGE_SHIFT)) & PAGE_MASK;
1597 psInfo->psPhysAddr[ui] =
1598 SysCpuPAddrToSysPAddr(CPUPhysAddr);
1599 psSysPAddr[ui] = psInfo->psPhysAddr[ui];
1601 BUG_ON(ui != psInfo->iNumPages);
1603 psInfo->eType = WRAP_TYPE_FIND_VMA_PFN;
1606 ": OSCpuVToPageList: Region can't be locked down\n");
1610 up_read(¤t->mm->mmap_sem);
1613 CheckPagesContiguous(psInfo);
1615 *phOSWrapMem = (void *) psInfo;
1619 error_release_mmap_sem:
1621 up_read(¤t->mm->mmap_sem);
1624 psInfo->eType = WRAP_TYPE_CLEANUP;
1625 OSReleasePhysPageAddr((void *) psInfo, bUseLock);
1626 return PVRSRV_ERROR_GENERIC;