1 /**********************************************************************
2 Copyright (c) Imagination Technologies Ltd.
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 ******************************************************************************/
23 #include <linux/version.h>
25 #include <linux/module.h>
26 #include <linux/vmalloc.h>
27 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
28 #include <linux/wrapper.h>
30 #include <linux/slab.h>
33 #include <asm/shmparam.h>
34 #include <asm/pgtable.h>
35 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
36 #include <linux/sched.h>
37 #include <asm/current.h>
39 #if defined(SUPPORT_DRI_DRM)
45 #include "servicesint.h"
50 #include "pvr_debug.h"
56 #include "env_perproc.h"
57 #include "bridged_support.h"
58 #if defined(SUPPORT_DRI_DRM)
62 #if !defined(PVR_SECURE_HANDLES)
63 #error "The mmap code requires PVR_SECURE_HANDLES"
66 static struct mutex g_sMMapMutex;
68 static LinuxKMemCache *g_psMemmapCache = NULL;
69 static LIST_HEAD(g_sMMapAreaList);
70 static LIST_HEAD(g_sMMapOffsetStructList);
71 #if defined(DEBUG_LINUX_MMAP_AREAS)
72 static IMG_UINT32 g_ui32RegisteredAreas = 0;
73 static IMG_UINT32 g_ui32TotalByteSize = 0;
77 #if defined(PVR_PROC_USE_SEQ_FILE) && defined(DEBUG_LINUX_MMAP_AREAS)
78 static struct proc_dir_entry *g_ProcMMap;
81 #define FIRST_PHYSICAL_PFN 0
82 #define LAST_PHYSICAL_PFN 0x7fffffffUL
83 #define FIRST_SPECIAL_PFN (LAST_PHYSICAL_PFN + 1)
84 #define LAST_SPECIAL_PFN 0xffffffffUL
86 #define MAX_MMAP_HANDLE 0x7fffffffUL
88 static inline IMG_BOOL
89 PFNIsPhysical(IMG_UINT32 pfn)
92 return ((pfn >= FIRST_PHYSICAL_PFN) && (pfn <= LAST_PHYSICAL_PFN)) ? IMG_TRUE : IMG_FALSE;
95 static inline IMG_BOOL
96 PFNIsSpecial(IMG_UINT32 pfn)
99 return ((pfn >= FIRST_SPECIAL_PFN) && (pfn <= LAST_SPECIAL_PFN)) ? IMG_TRUE : IMG_FALSE;
102 static inline IMG_HANDLE
103 MMapOffsetToHandle(IMG_UINT32 pfn)
105 if (PFNIsPhysical(pfn))
107 PVR_ASSERT(PFNIsPhysical(pfn));
111 return (IMG_HANDLE)(pfn - FIRST_SPECIAL_PFN);
114 static inline IMG_UINT32
115 HandleToMMapOffset(IMG_HANDLE hHandle)
117 IMG_UINT32 ulHandle = (IMG_UINT32)hHandle;
119 if (PFNIsSpecial(ulHandle))
121 PVR_ASSERT(PFNIsSpecial(ulHandle));
125 return ulHandle + FIRST_SPECIAL_PFN;
128 static inline IMG_BOOL
129 LinuxMemAreaUsesPhysicalMap(LinuxMemArea *psLinuxMemArea)
131 return LinuxMemAreaPhysIsContig(psLinuxMemArea);
134 static inline IMG_UINT32
135 GetCurrentThreadID(IMG_VOID)
138 return (IMG_UINT32)current->pid;
141 static PKV_OFFSET_STRUCT
142 CreateOffsetStruct(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32Offset, IMG_UINT32 ui32RealByteSize)
144 PKV_OFFSET_STRUCT psOffsetStruct;
145 #if defined(DEBUG) || defined(DEBUG_LINUX_MMAP_AREAS)
146 const IMG_CHAR *pszName = LinuxMemAreaTypeToString(LinuxMemAreaRootType(psLinuxMemArea));
149 #if defined(DEBUG) || defined(DEBUG_LINUX_MMAP_AREAS)
150 PVR_DPF((PVR_DBG_MESSAGE,
151 "%s(%s, psLinuxMemArea: 0x%p, ui32AllocFlags: 0x%8lx)",
152 __FUNCTION__, pszName, psLinuxMemArea, psLinuxMemArea->ui32AreaFlags));
155 PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC || LinuxMemAreaRoot(psLinuxMemArea)->eAreaType != LINUX_MEM_AREA_SUB_ALLOC);
157 PVR_ASSERT(psLinuxMemArea->bMMapRegistered);
159 psOffsetStruct = KMemCacheAllocWrapper(g_psMemmapCache, GFP_KERNEL);
160 if(psOffsetStruct == IMG_NULL)
162 PVR_DPF((PVR_DBG_ERROR,"PVRMMapRegisterArea: Couldn't alloc another mapping record from cache"));
166 psOffsetStruct->ui32MMapOffset = ui32Offset;
168 psOffsetStruct->psLinuxMemArea = psLinuxMemArea;
170 psOffsetStruct->ui32Mapped = 0;
172 psOffsetStruct->ui32RealByteSize = ui32RealByteSize;
175 psOffsetStruct->ui32TID = GetCurrentThreadID();
177 psOffsetStruct->ui32PID = OSGetCurrentProcessIDKM();
179 psOffsetStruct->bOnMMapList = IMG_FALSE;
181 psOffsetStruct->ui32RefCount = 0;
183 psOffsetStruct->ui32UserVAddr = 0;
185 #if defined(DEBUG_LINUX_MMAP_AREAS)
187 psOffsetStruct->pszName = pszName;
190 list_add_tail(&psOffsetStruct->sAreaItem, &psLinuxMemArea->sMMapOffsetStructList);
192 return psOffsetStruct;
197 DestroyOffsetStruct(PKV_OFFSET_STRUCT psOffsetStruct)
199 list_del(&psOffsetStruct->sAreaItem);
201 if (psOffsetStruct->bOnMMapList)
203 list_del(&psOffsetStruct->sMMapItem);
206 PVR_DPF((PVR_DBG_MESSAGE, "%s: Table entry: "
207 "psLinuxMemArea=0x%08lX, CpuPAddr=0x%08lX", __FUNCTION__,
208 psOffsetStruct->psLinuxMemArea,
209 LinuxMemAreaToCpuPAddr(psOffsetStruct->psLinuxMemArea, 0)));
211 KMemCacheFreeWrapper(g_psMemmapCache, psOffsetStruct);
215 static inline IMG_VOID
216 DetermineUsersSizeAndByteOffset(LinuxMemArea *psLinuxMemArea,
217 IMG_UINT32 *pui32RealByteSize,
218 IMG_UINT32 *pui32ByteOffset)
220 IMG_UINT32 ui32PageAlignmentOffset;
221 IMG_CPU_PHYADDR CpuPAddr;
223 CpuPAddr = LinuxMemAreaToCpuPAddr(psLinuxMemArea, 0);
224 ui32PageAlignmentOffset = ADDR_TO_PAGE_OFFSET(CpuPAddr.uiAddr);
226 *pui32ByteOffset = ui32PageAlignmentOffset;
228 *pui32RealByteSize = PAGE_ALIGN(psLinuxMemArea->ui32ByteSize + ui32PageAlignmentOffset);
233 PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
235 IMG_UINT32 *pui32MMapOffset,
236 IMG_UINT32 *pui32ByteOffset,
237 IMG_UINT32 *pui32RealByteSize,
238 IMG_UINT32 *pui32UserVAddr)
240 LinuxMemArea *psLinuxMemArea;
241 PKV_OFFSET_STRUCT psOffsetStruct;
242 IMG_HANDLE hOSMemHandle;
245 mutex_lock(&g_sMMapMutex);
247 PVR_ASSERT(PVRSRVGetMaxHandle(psPerProc->psHandleBase) <= MAX_MMAP_HANDLE);
249 eError = PVRSRVLookupOSMemHandle(psPerProc->psHandleBase, &hOSMemHandle, hMHandle);
250 if (eError != PVRSRV_OK)
252 PVR_DPF((PVR_DBG_ERROR, "%s: Lookup of handle 0x%lx failed", __FUNCTION__, hMHandle));
257 psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
259 DetermineUsersSizeAndByteOffset(psLinuxMemArea,
264 list_for_each_entry(psOffsetStruct, &psLinuxMemArea->sMMapOffsetStructList, sAreaItem)
266 if (psPerProc->ui32PID == psOffsetStruct->ui32PID)
269 PVR_ASSERT(*pui32RealByteSize == psOffsetStruct->ui32RealByteSize);
271 *pui32MMapOffset = psOffsetStruct->ui32MMapOffset;
272 *pui32UserVAddr = psOffsetStruct->ui32UserVAddr;
273 psOffsetStruct->ui32RefCount++;
283 if (LinuxMemAreaUsesPhysicalMap(psLinuxMemArea))
285 *pui32MMapOffset = LinuxMemAreaToCpuPFN(psLinuxMemArea, 0);
286 PVR_ASSERT(PFNIsPhysical(*pui32MMapOffset));
290 *pui32MMapOffset = HandleToMMapOffset(hMHandle);
291 PVR_ASSERT(PFNIsSpecial(*pui32MMapOffset));
294 psOffsetStruct = CreateOffsetStruct(psLinuxMemArea, *pui32MMapOffset, *pui32RealByteSize);
295 if (psOffsetStruct == IMG_NULL)
297 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
302 list_add_tail(&psOffsetStruct->sMMapItem, &g_sMMapOffsetStructList);
304 psOffsetStruct->bOnMMapList = IMG_TRUE;
306 psOffsetStruct->ui32RefCount++;
311 mutex_unlock(&g_sMMapMutex);
318 PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
321 IMG_UINT32 *pui32RealByteSize,
322 IMG_UINT32 *pui32UserVAddr)
324 LinuxMemArea *psLinuxMemArea;
325 PKV_OFFSET_STRUCT psOffsetStruct;
326 IMG_HANDLE hOSMemHandle;
328 IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM();
330 mutex_lock(&g_sMMapMutex);
332 PVR_ASSERT(PVRSRVGetMaxHandle(psPerProc->psHandleBase) <= MAX_MMAP_HANDLE);
334 eError = PVRSRVLookupOSMemHandle(psPerProc->psHandleBase, &hOSMemHandle, hMHandle);
335 if (eError != PVRSRV_OK)
337 PVR_DPF((PVR_DBG_ERROR, "%s: Lookup of handle 0x%lx failed", __FUNCTION__, hMHandle));
342 psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
345 list_for_each_entry(psOffsetStruct, &psLinuxMemArea->sMMapOffsetStructList, sAreaItem)
347 if (psOffsetStruct->ui32PID == ui32PID)
349 if (psOffsetStruct->ui32RefCount == 0)
351 PVR_DPF((PVR_DBG_ERROR, "%s: Attempt to release mmap data with zero reference count for offset struct 0x%p, memory area 0x%p", __FUNCTION__, psOffsetStruct, psLinuxMemArea));
352 eError = PVRSRV_ERROR_GENERIC;
356 psOffsetStruct->ui32RefCount--;
358 *pbMUnmap = (IMG_BOOL)((psOffsetStruct->ui32RefCount == 0) && (psOffsetStruct->ui32UserVAddr != 0));
360 *pui32UserVAddr = (*pbMUnmap) ? psOffsetStruct->ui32UserVAddr : 0;
361 *pui32RealByteSize = (*pbMUnmap) ? psOffsetStruct->ui32RealByteSize : 0;
369 PVR_DPF((PVR_DBG_ERROR, "%s: Mapping data not found for handle 0x%lx (memory area 0x%p)", __FUNCTION__, hMHandle, psLinuxMemArea));
371 eError = PVRSRV_ERROR_GENERIC;
374 mutex_unlock(&g_sMMapMutex);
379 static inline PKV_OFFSET_STRUCT
380 FindOffsetStructByOffset(IMG_UINT32 ui32Offset, IMG_UINT32 ui32RealByteSize)
382 PKV_OFFSET_STRUCT psOffsetStruct;
383 IMG_UINT32 ui32TID = GetCurrentThreadID();
384 IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM();
386 list_for_each_entry(psOffsetStruct, &g_sMMapOffsetStructList, sMMapItem)
388 if (ui32Offset == psOffsetStruct->ui32MMapOffset && ui32RealByteSize == psOffsetStruct->ui32RealByteSize && psOffsetStruct->ui32PID == ui32PID)
391 if (!PFNIsPhysical(ui32Offset) || psOffsetStruct->ui32TID == ui32TID)
393 return psOffsetStruct;
403 DoMapToUser(LinuxMemArea *psLinuxMemArea,
404 struct vm_area_struct* ps_vma,
405 IMG_UINT32 ui32ByteOffset)
407 IMG_UINT32 ui32ByteSize;
409 if (psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC)
411 return DoMapToUser(LinuxMemAreaRoot(psLinuxMemArea),
413 psLinuxMemArea->uData.sSubAlloc.ui32ByteOffset + ui32ByteOffset);
417 ui32ByteSize = ps_vma->vm_end - ps_vma->vm_start;
418 PVR_ASSERT(ADDR_TO_PAGE_OFFSET(ui32ByteSize) == 0);
420 #if defined (__sparc__)
422 #error "SPARC not supported"
425 if (PFNIsPhysical(ps_vma->vm_pgoff))
429 PVR_ASSERT(LinuxMemAreaPhysIsContig(psLinuxMemArea));
430 PVR_ASSERT(LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32ByteOffset) == ps_vma->vm_pgoff);
433 result = IO_REMAP_PFN_RANGE(ps_vma, ps_vma->vm_start, ps_vma->vm_pgoff, ui32ByteSize, ps_vma->vm_page_prot);
440 PVR_DPF((PVR_DBG_MESSAGE, "%s: Failed to map contiguous physical address range (%d), trying non-contiguous path", __FUNCTION__, result));
446 IMG_UINT32 ui32ByteEnd = ui32ByteOffset + ui32ByteSize;
450 for(ui32PA = ui32ByteOffset; ui32PA < ui32ByteEnd; ui32PA += PAGE_SIZE)
452 IMG_UINT32 pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32PA);
456 PVR_DPF((PVR_DBG_ERROR,"%s: Error - PFN invalid: 0x%lx", __FUNCTION__, pfn));
462 ulVMAPos = ps_vma->vm_start;
463 for(ui32PA = ui32ByteOffset; ui32PA < ui32ByteEnd; ui32PA += PAGE_SIZE)
469 pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32PA);
470 PVR_ASSERT(pfn_valid(pfn));
472 psPage = pfn_to_page(pfn);
474 result = VM_INSERT_PAGE(ps_vma, ulVMAPos, psPage);
477 PVR_DPF((PVR_DBG_ERROR,"%s: Error - VM_INSERT_PAGE failed (%d)", __FUNCTION__, result));
480 ulVMAPos += PAGE_SIZE;
489 MMapVOpenNoLock(struct vm_area_struct* ps_vma)
491 PKV_OFFSET_STRUCT psOffsetStruct = (PKV_OFFSET_STRUCT)ps_vma->vm_private_data;
492 PVR_ASSERT(psOffsetStruct != IMG_NULL)
493 psOffsetStruct->ui32Mapped++;
494 PVR_ASSERT(!psOffsetStruct->bOnMMapList);
496 if (psOffsetStruct->ui32Mapped > 1)
498 PVR_DPF((PVR_DBG_WARNING, "%s: Offset structure 0x%p is being shared across processes (psOffsetStruct->ui32Mapped: %lu)", __FUNCTION__, psOffsetStruct, psOffsetStruct->ui32Mapped));
499 PVR_ASSERT((ps_vma->vm_flags & VM_DONTCOPY) == 0);
502 #if defined(DEBUG_LINUX_MMAP_AREAS)
504 PVR_DPF((PVR_DBG_MESSAGE,
505 "%s: psLinuxMemArea 0x%p, KVAddress 0x%p MMapOffset %ld, ui32Mapped %d",
507 psOffsetStruct->psLinuxMemArea,
508 LinuxMemAreaToCpuVAddr(psOffsetStruct->psLinuxMemArea),
509 psOffsetStruct->ui32MMapOffset,
510 psOffsetStruct->ui32Mapped));
513 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
520 MMapVOpen(struct vm_area_struct* ps_vma)
522 mutex_lock(&g_sMMapMutex);
524 MMapVOpenNoLock(ps_vma);
526 mutex_unlock(&g_sMMapMutex);
531 MMapVCloseNoLock(struct vm_area_struct* ps_vma)
533 PKV_OFFSET_STRUCT psOffsetStruct = (PKV_OFFSET_STRUCT)ps_vma->vm_private_data;
534 PVR_ASSERT(psOffsetStruct != IMG_NULL)
536 #if defined(DEBUG_LINUX_MMAP_AREAS)
537 PVR_DPF((PVR_DBG_MESSAGE,
538 "%s: psLinuxMemArea 0x%p, CpuVAddr 0x%p ui32MMapOffset %ld, ui32Mapped %d",
540 psOffsetStruct->psLinuxMemArea,
541 LinuxMemAreaToCpuVAddr(psOffsetStruct->psLinuxMemArea),
542 psOffsetStruct->ui32MMapOffset,
543 psOffsetStruct->ui32Mapped));
546 PVR_ASSERT(!psOffsetStruct->bOnMMapList);
547 psOffsetStruct->ui32Mapped--;
548 if (psOffsetStruct->ui32Mapped == 0)
550 if (psOffsetStruct->ui32RefCount != 0)
552 PVR_DPF((PVR_DBG_MESSAGE, "%s: psOffsetStruct 0x%p has non-zero reference count (ui32RefCount = %lu). User mode address of start of mapping: 0x%lx", __FUNCTION__, psOffsetStruct, psOffsetStruct->ui32RefCount, psOffsetStruct->ui32UserVAddr));
555 DestroyOffsetStruct(psOffsetStruct);
558 ps_vma->vm_private_data = NULL;
560 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
566 MMapVClose(struct vm_area_struct* ps_vma)
568 mutex_lock(&g_sMMapMutex);
570 MMapVCloseNoLock(ps_vma);
572 mutex_unlock(&g_sMMapMutex);
576 static struct vm_operations_struct MMapIOOps =
584 PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma)
586 IMG_UINT32 ui32ByteSize;
587 PKV_OFFSET_STRUCT psOffsetStruct;
590 PVR_UNREFERENCED_PARAMETER(pFile);
592 mutex_lock(&g_sMMapMutex);
594 ui32ByteSize = ps_vma->vm_end - ps_vma->vm_start;
597 PVR_DPF((PVR_DBG_MESSAGE, "%s: Received mmap(2) request with ui32MMapOffset 0x%08lx,"
598 " and ui32ByteSize %ld(0x%08lx)",
601 ui32ByteSize, ui32ByteSize));
603 psOffsetStruct = FindOffsetStructByOffset(ps_vma->vm_pgoff, ui32ByteSize);
604 if (psOffsetStruct == IMG_NULL)
606 #if defined(SUPPORT_DRI_DRM)
607 mutex_unlock(&g_sMMapMutex);
610 return drm_mmap(pFile, ps_vma);
612 PVR_UNREFERENCED_PARAMETER(pFile);
614 #if 0 /* FIXME: crash when call to print debug messages */
615 PVR_DPF((PVR_DBG_ERROR,
616 "%s: Attempted to mmap unregistered area at vm_pgoff %ld",
617 __FUNCTION__, ps_vma->vm_pgoff));
621 goto unlock_and_return;
623 list_del(&psOffsetStruct->sMMapItem);
624 psOffsetStruct->bOnMMapList = IMG_FALSE;
627 if (((ps_vma->vm_flags & VM_WRITE) != 0) &&
628 ((ps_vma->vm_flags & VM_SHARED) == 0))
630 #if 0 /* FIXME: crash when call to print debug messages */
631 PVR_DPF((PVR_DBG_ERROR, "%s: Cannot mmap non-shareable writable areas", __FUNCTION__));
634 goto unlock_and_return;
638 #if 0 /* FIXME: crash when call to print debug messages */
639 PVR_DPF((PVR_DBG_MESSAGE, "%s: Mapped psLinuxMemArea 0x%p\n",
640 __FUNCTION__, psOffsetStruct->psLinuxMemArea));
642 ps_vma->vm_flags |= VM_RESERVED;
643 ps_vma->vm_flags |= VM_IO;
646 ps_vma->vm_flags |= VM_DONTEXPAND;
649 ps_vma->vm_flags |= VM_DONTCOPY;
651 ps_vma->vm_private_data = (void *)psOffsetStruct;
653 switch(psOffsetStruct->psLinuxMemArea->ui32AreaFlags & PVRSRV_HAP_CACHETYPE_MASK)
655 case PVRSRV_HAP_CACHED:
658 case PVRSRV_HAP_WRITECOMBINE:
659 ps_vma->vm_page_prot = PGPROT_WC(ps_vma->vm_page_prot);
661 case PVRSRV_HAP_UNCACHED:
662 ps_vma->vm_page_prot = PGPROT_UC(ps_vma->vm_page_prot);
665 PVR_DPF((PVR_DBG_ERROR, "%s: unknown cache type", __FUNCTION__));
667 goto unlock_and_return;
671 ps_vma->vm_ops = &MMapIOOps;
673 if(!DoMapToUser(psOffsetStruct->psLinuxMemArea, ps_vma, 0))
676 goto unlock_and_return;
679 PVR_ASSERT(psOffsetStruct->ui32UserVAddr == 0)
681 psOffsetStruct->ui32UserVAddr = ps_vma->vm_start;
684 MMapVOpenNoLock(ps_vma);
686 #if 0 /* FIXME: crash when call to print debug messages */
687 PVR_DPF((PVR_DBG_MESSAGE, "%s: Mapped area at offset 0x%08lx\n",
688 __FUNCTION__, ps_vma->vm_pgoff));
692 if (iRetVal != 0 && psOffsetStruct != IMG_NULL)
694 DestroyOffsetStruct(psOffsetStruct);
697 mutex_unlock(&g_sMMapMutex);
703 #if defined(DEBUG_LINUX_MMAP_AREAS)
705 #ifdef PVR_PROC_USE_SEQ_FILE
707 static void ProcSeqStartstopMMapRegistations(struct seq_file *sfile,IMG_BOOL start)
711 mutex_lock(&g_sMMapMutex);
715 mutex_unlock(&g_sMMapMutex);
720 static void* ProcSeqOff2ElementMMapRegistrations(struct seq_file *sfile, loff_t off)
722 LinuxMemArea *psLinuxMemArea;
725 return PVR_PROC_SEQ_START_TOKEN;
728 list_for_each_entry(psLinuxMemArea, &g_sMMapAreaList, sMMapItem)
730 PKV_OFFSET_STRUCT psOffsetStruct;
732 list_for_each_entry(psOffsetStruct, &psLinuxMemArea->sMMapOffsetStructList, sAreaItem)
737 PVR_ASSERT(psOffsetStruct->psLinuxMemArea == psLinuxMemArea);
738 return (void*)psOffsetStruct;
745 static void* ProcSeqNextMMapRegistrations(struct seq_file *sfile,void* el,loff_t off)
747 return ProcSeqOff2ElementMMapRegistrations(sfile,off);
751 static void ProcSeqShowMMapRegistrations(struct seq_file *sfile,void* el)
753 KV_OFFSET_STRUCT *psOffsetStruct = (KV_OFFSET_STRUCT*)el;
754 LinuxMemArea *psLinuxMemArea;
755 IMG_UINT32 ui32RealByteSize;
756 IMG_UINT32 ui32ByteOffset;
758 if(el == PVR_PROC_SEQ_START_TOKEN)
761 #if !defined(DEBUG_LINUX_XML_PROC_FILES)
762 "Allocations registered for mmap: %lu\n"
763 "In total these areas correspond to %lu bytes\n"
774 "\t<count>%lu</count>\n"
775 "\t<bytes>%lu</bytes>\n"
778 g_ui32RegisteredAreas,
784 psLinuxMemArea = psOffsetStruct->psLinuxMemArea;
786 DetermineUsersSizeAndByteOffset(psLinuxMemArea,
791 #if !defined(DEBUG_LINUX_XML_PROC_FILES)
792 "%-8p %08lx %-8p %08lx %08lx %-8ld %-24s %-5lu %-8s %08lx(%s)\n",
795 "\t<pointer>%-8p</pointer>\n"
796 "\t<user_virtual>%-8lx</user_virtual>\n"
797 "\t<kernel_virtual>%-8p</kernel_virtual>\n"
798 "\t<cpu_physical>%08lx</cpu_physical>\n"
799 "\t<mmap_offset>%08lx</mmap_offset>\n"
800 "\t<bytes>%-8ld</bytes>\n"
801 "\t<linux_mem_area_type>%-24s</linux_mem_area_type>\n"
802 "\t<pid>%-5lu</pid>\n"
803 "\t<name>%-8s</name>\n"
804 "\t<flags>%08lx</flags>\n"
805 "\t<flags_string>%s</flags_string>\n"
809 psOffsetStruct->ui32UserVAddr + ui32ByteOffset,
810 LinuxMemAreaToCpuVAddr(psLinuxMemArea),
811 LinuxMemAreaToCpuPAddr(psLinuxMemArea,0).uiAddr,
812 psOffsetStruct->ui32MMapOffset,
813 psLinuxMemArea->ui32ByteSize,
814 LinuxMemAreaTypeToString(psLinuxMemArea->eAreaType),
815 psOffsetStruct->ui32PID,
816 psOffsetStruct->pszName,
817 psLinuxMemArea->ui32AreaFlags,
818 HAPFlagsToString(psLinuxMemArea->ui32AreaFlags));
824 PrintMMapRegistrations(IMG_CHAR *buffer, size_t size, off_t off)
826 LinuxMemArea *psLinuxMemArea;
829 mutex_lock(&g_sMMapMutex);
833 Ret = printAppend(buffer, size, 0,
834 #if !defined(DEBUG_LINUX_XML_PROC_FILES)
835 "Allocations registered for mmap: %lu\n"
836 "In total these areas correspond to %lu bytes\n"
847 "\t<count>%lu</count>\n"
848 "\t<bytes>%lu</bytes>\n"
851 g_ui32RegisteredAreas,
855 goto unlock_and_return;
861 goto unlock_and_return;
864 PVR_ASSERT(off != 0);
865 list_for_each_entry(psLinuxMemArea, &g_sMMapAreaList, sMMapItem)
867 PKV_OFFSET_STRUCT psOffsetStruct;
869 list_for_each_entry(psOffsetStruct, &psLinuxMemArea->sMMapOffsetStructList, sAreaItem)
874 IMG_UINT32 ui32RealByteSize;
875 IMG_UINT32 ui32ByteOffset;
877 PVR_ASSERT(psOffsetStruct->psLinuxMemArea == psLinuxMemArea);
879 DetermineUsersSizeAndByteOffset(psLinuxMemArea,
883 Ret = printAppend (buffer, size, 0,
884 #if !defined(DEBUG_LINUX_XML_PROC_FILES)
885 "%-8p %08lx %-8p %08lx %08lx %-8ld %-24s %-5lu %-8s %08lx(%s)\n",
888 "\t<pointer>%-8p</pointer>\n"
889 "\t<user_virtual>%-8lx</user_virtual>\n"
890 "\t<kernel_virtual>%-8p</kernel_virtual>\n"
891 "\t<cpu_physical>%08lx</cpu_physical>\n"
892 "\t<mmap_offset>%08lx</mmap_offset>\n"
893 "\t<bytes>%-8ld</bytes>\n"
894 "\t<linux_mem_area_type>%-24s</linux_mem_area_type>\n"
895 "\t<pid>%-5lu</pid>\n"
896 "\t<name>%-8s</name>\n"
897 "\t<flags>%08lx</flags>\n"
898 "\t<flags_string>%s</flags_string>\n"
902 psOffsetStruct->ui32UserVAddr + ui32ByteOffset,
903 LinuxMemAreaToCpuVAddr(psLinuxMemArea),
904 LinuxMemAreaToCpuPAddr(psLinuxMemArea,0).uiAddr,
905 psOffsetStruct->ui32MMapOffset,
906 psLinuxMemArea->ui32ByteSize,
907 LinuxMemAreaTypeToString(psLinuxMemArea->eAreaType),
908 psOffsetStruct->ui32PID,
909 psOffsetStruct->pszName,
910 psLinuxMemArea->ui32AreaFlags,
911 HAPFlagsToString(psLinuxMemArea->ui32AreaFlags));
912 goto unlock_and_return;
919 mutex_unlock(&g_sMMapMutex);
927 PVRMMapRegisterArea(LinuxMemArea *psLinuxMemArea)
930 #if defined(DEBUG) || defined(DEBUG_LINUX_MMAP_AREAS)
931 const IMG_CHAR *pszName = LinuxMemAreaTypeToString(LinuxMemAreaRootType(psLinuxMemArea));
934 mutex_lock(&g_sMMapMutex);
936 #if defined(DEBUG) || defined(DEBUG_LINUX_MMAP_AREAS)
937 PVR_DPF((PVR_DBG_MESSAGE,
938 "%s(%s, psLinuxMemArea 0x%p, ui32AllocFlags 0x%8lx)",
939 __FUNCTION__, pszName, psLinuxMemArea, psLinuxMemArea->ui32AreaFlags));
942 PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC || LinuxMemAreaRoot(psLinuxMemArea)->eAreaType != LINUX_MEM_AREA_SUB_ALLOC);
945 if(psLinuxMemArea->bMMapRegistered)
947 PVR_DPF((PVR_DBG_ERROR, "%s: psLinuxMemArea 0x%p is already registered",
948 __FUNCTION__, psLinuxMemArea));
949 eError = PVRSRV_ERROR_INVALID_PARAMS;
953 list_add_tail(&psLinuxMemArea->sMMapItem, &g_sMMapAreaList);
955 psLinuxMemArea->bMMapRegistered = IMG_TRUE;
957 #if defined(DEBUG_LINUX_MMAP_AREAS)
958 g_ui32RegisteredAreas++;
960 if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC)
962 g_ui32TotalByteSize += psLinuxMemArea->ui32ByteSize;
969 mutex_unlock(&g_sMMapMutex);
976 PVRMMapRemoveRegisteredArea(LinuxMemArea *psLinuxMemArea)
979 PKV_OFFSET_STRUCT psOffsetStruct, psTmpOffsetStruct;
981 mutex_lock(&g_sMMapMutex);
983 PVR_ASSERT(psLinuxMemArea->bMMapRegistered);
985 list_for_each_entry_safe(psOffsetStruct, psTmpOffsetStruct, &psLinuxMemArea->sMMapOffsetStructList, sAreaItem)
987 if (psOffsetStruct->ui32Mapped != 0)
989 PVR_DPF((PVR_DBG_ERROR, "%s: psOffsetStruct 0x%p for memory area 0x0x%p is still mapped; psOffsetStruct->ui32Mapped %lu", __FUNCTION__, psOffsetStruct, psLinuxMemArea, psOffsetStruct->ui32Mapped));
990 eError = PVRSRV_ERROR_GENERIC;
996 PVR_DPF((PVR_DBG_WARNING, "%s: psOffsetStruct 0x%p was never mapped", __FUNCTION__, psOffsetStruct));
999 PVR_ASSERT((psOffsetStruct->ui32Mapped == 0) && psOffsetStruct->bOnMMapList);
1001 DestroyOffsetStruct(psOffsetStruct);
1004 list_del(&psLinuxMemArea->sMMapItem);
1006 psLinuxMemArea->bMMapRegistered = IMG_FALSE;
1008 #if defined(DEBUG_LINUX_MMAP_AREAS)
1009 g_ui32RegisteredAreas--;
1010 if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC)
1012 g_ui32TotalByteSize -= psLinuxMemArea->ui32ByteSize;
1019 mutex_unlock(&g_sMMapMutex);
1025 LinuxMMapPerProcessConnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc)
1027 PVR_UNREFERENCED_PARAMETER(psEnvPerProc);
1033 LinuxMMapPerProcessDisconnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc)
1035 PKV_OFFSET_STRUCT psOffsetStruct, psTmpOffsetStruct;
1036 IMG_BOOL bWarn = IMG_FALSE;
1037 IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM();
1039 PVR_UNREFERENCED_PARAMETER(psEnvPerProc);
1041 mutex_lock(&g_sMMapMutex);
1043 list_for_each_entry_safe(psOffsetStruct, psTmpOffsetStruct, &g_sMMapOffsetStructList, sMMapItem)
1045 if (psOffsetStruct->ui32PID == ui32PID)
1049 PVR_DPF((PVR_DBG_WARNING, "%s: process has unmapped offset structures. Removing them", __FUNCTION__));
1052 PVR_ASSERT(psOffsetStruct->ui32Mapped == 0);
1053 PVR_ASSERT(psOffsetStruct->bOnMMapList);
1055 DestroyOffsetStruct(psOffsetStruct);
1059 mutex_unlock(&g_sMMapMutex);
1063 PVRSRV_ERROR LinuxMMapPerProcessHandleOptions(PVRSRV_HANDLE_BASE *psHandleBase)
1065 PVRSRV_ERROR eError;
1067 eError = PVRSRVSetMaxHandle(psHandleBase, MAX_MMAP_HANDLE);
1068 if (eError != PVRSRV_OK)
1070 PVR_DPF((PVR_DBG_ERROR,"%s: failed to set handle limit (%d)", __FUNCTION__, eError));
1079 PVRMMapInit(IMG_VOID)
1081 mutex_init(&g_sMMapMutex);
1083 g_psMemmapCache = KMemCacheCreateWrapper("img-mmap", sizeof(KV_OFFSET_STRUCT), 0, 0);
1084 if (!g_psMemmapCache)
1086 PVR_DPF((PVR_DBG_ERROR,"%s: failed to allocate kmem_cache", __FUNCTION__));
1090 #if defined(DEBUG_LINUX_MMAP_AREAS)
1091 #ifdef PVR_PROC_USE_SEQ_FILE
1092 g_ProcMMap = CreateProcReadEntrySeq("mmap", NULL,
1093 ProcSeqNextMMapRegistrations,
1094 ProcSeqShowMMapRegistrations,
1095 ProcSeqOff2ElementMMapRegistrations,
1096 ProcSeqStartstopMMapRegistations
1099 CreateProcReadEntry("mmap", PrintMMapRegistrations);
1111 PVRMMapCleanup(IMG_VOID)
1113 PVRSRV_ERROR eError;
1115 if (!list_empty(&g_sMMapAreaList))
1117 LinuxMemArea *psLinuxMemArea, *psTmpMemArea;
1119 PVR_DPF((PVR_DBG_ERROR, "%s: Memory areas are still registered with MMap", __FUNCTION__));
1121 PVR_TRACE(("%s: Unregistering memory areas", __FUNCTION__));
1122 list_for_each_entry_safe(psLinuxMemArea, psTmpMemArea, &g_sMMapAreaList, sMMapItem)
1124 eError = PVRMMapRemoveRegisteredArea(psLinuxMemArea);
1125 if (eError != PVRSRV_OK)
1127 PVR_DPF((PVR_DBG_ERROR, "%s: PVRMMapRemoveRegisteredArea failed (%d)", __FUNCTION__, eError));
1129 PVR_ASSERT(eError == PVRSRV_OK);
1131 LinuxMemAreaDeepFree(psLinuxMemArea);
1134 PVR_ASSERT(list_empty((&g_sMMapAreaList)));
1136 #if defined(DEBUG_LINUX_MMAP_AREAS)
1137 #ifdef PVR_PROC_USE_SEQ_FILE
1138 RemoveProcEntrySeq(g_ProcMMap);
1140 RemoveProcEntry("mmap");
1146 KMemCacheDestroyWrapper(g_psMemmapCache);
1147 g_psMemmapCache = NULL;