diff options
Diffstat (limited to 'drivers/gpu/pvr/mmap.c')
-rw-r--r-- | drivers/gpu/pvr/mmap.c | 1132 |
1 files changed, 1132 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/mmap.c b/drivers/gpu/pvr/mmap.c new file mode 100644 index 00000000000..66cef26e522 --- /dev/null +++ b/drivers/gpu/pvr/mmap.c | |||
@@ -0,0 +1,1132 @@ | |||
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 <linux/mm.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/vmalloc.h> | ||
35 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) | ||
36 | #include <linux/wrapper.h> | ||
37 | #endif | ||
38 | #include <linux/slab.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <asm/page.h> | ||
41 | #include <asm/shmparam.h> | ||
42 | #include <asm/pgtable.h> | ||
43 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)) | ||
44 | #include <linux/sched.h> | ||
45 | #include <asm/current.h> | ||
46 | #endif | ||
47 | #if defined(SUPPORT_DRI_DRM) | ||
48 | #include <drm/drmP.h> | ||
49 | #endif | ||
50 | |||
51 | #include "img_defs.h" | ||
52 | #include "services.h" | ||
53 | #include "servicesint.h" | ||
54 | #include "pvrmmap.h" | ||
55 | #include "mutils.h" | ||
56 | #include "mmap.h" | ||
57 | #include "mm.h" | ||
58 | #include "pvr_debug.h" | ||
59 | #include "osfunc.h" | ||
60 | #include "proc.h" | ||
61 | #include "mutex.h" | ||
62 | #include "handle.h" | ||
63 | #include "perproc.h" | ||
64 | #include "env_perproc.h" | ||
65 | #include "bridged_support.h" | ||
66 | #if defined(SUPPORT_DRI_DRM) | ||
67 | #include "pvr_drm.h" | ||
68 | #endif | ||
69 | |||
70 | #if !defined(PVR_SECURE_HANDLES) | ||
71 | #error "The mmap code requires PVR_SECURE_HANDLES" | ||
72 | #endif | ||
73 | |||
74 | static PVRSRV_LINUX_MUTEX g_sMMapMutex; | ||
75 | |||
76 | static LinuxKMemCache *g_psMemmapCache = NULL; | ||
77 | static LIST_HEAD(g_sMMapAreaList); | ||
78 | static LIST_HEAD(g_sMMapOffsetStructList); | ||
79 | #if defined(DEBUG_LINUX_MMAP_AREAS) | ||
80 | static IMG_UINT32 g_ui32RegisteredAreas = 0; | ||
81 | static IMG_UINT32 g_ui32TotalByteSize = 0; | ||
82 | #endif | ||
83 | |||
84 | |||
85 | #if defined(DEBUG_LINUX_MMAP_AREAS) | ||
86 | static struct proc_dir_entry *g_ProcMMap; | ||
87 | #endif | ||
88 | |||
89 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
90 | #define MMAP2_PGOFF_RESOLUTION (32-PAGE_SHIFT+12) | ||
91 | #define RESERVED_PGOFF_BITS 1 | ||
92 | #define MAX_MMAP_HANDLE ((1UL<<(MMAP2_PGOFF_RESOLUTION-RESERVED_PGOFF_BITS))-1) | ||
93 | |||
94 | #define FIRST_PHYSICAL_PFN 0 | ||
95 | #define LAST_PHYSICAL_PFN (FIRST_PHYSICAL_PFN + MAX_MMAP_HANDLE) | ||
96 | #define FIRST_SPECIAL_PFN (LAST_PHYSICAL_PFN + 1) | ||
97 | #define LAST_SPECIAL_PFN (FIRST_SPECIAL_PFN + MAX_MMAP_HANDLE) | ||
98 | |||
99 | #else | ||
100 | |||
101 | #if PAGE_SHIFT != 12 | ||
102 | #error This build variant has not yet been made non-4KB page-size aware | ||
103 | #endif | ||
104 | |||
105 | #if defined(PVR_MMAP_OFFSET_BASE) | ||
106 | #define FIRST_SPECIAL_PFN PVR_MMAP_OFFSET_BASE | ||
107 | #else | ||
108 | #define FIRST_SPECIAL_PFN 0x80000000UL | ||
109 | #endif | ||
110 | |||
111 | #if defined(PVR_NUM_MMAP_HANDLES) | ||
112 | #define MAX_MMAP_HANDLE PVR_NUM_MMAP_HANDLES | ||
113 | #else | ||
114 | #define MAX_MMAP_HANDLE 0x7fffffffUL | ||
115 | #endif | ||
116 | |||
117 | #endif | ||
118 | |||
119 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
120 | static inline IMG_BOOL | ||
121 | PFNIsPhysical(IMG_UINT32 pfn) | ||
122 | { | ||
123 | |||
124 | return ( (pfn <= LAST_PHYSICAL_PFN)) ? IMG_TRUE : IMG_FALSE; | ||
125 | } | ||
126 | |||
127 | static inline IMG_BOOL | ||
128 | PFNIsSpecial(IMG_UINT32 pfn) | ||
129 | { | ||
130 | |||
131 | return ((pfn >= FIRST_SPECIAL_PFN) ) ? IMG_TRUE : IMG_FALSE; | ||
132 | } | ||
133 | #endif | ||
134 | |||
135 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
136 | static inline IMG_HANDLE | ||
137 | MMapOffsetToHandle(IMG_UINT32 pfn) | ||
138 | { | ||
139 | if (PFNIsPhysical(pfn)) | ||
140 | { | ||
141 | PVR_ASSERT(PFNIsPhysical(pfn)); | ||
142 | return IMG_NULL; | ||
143 | } | ||
144 | return (IMG_HANDLE)(pfn - FIRST_SPECIAL_PFN); | ||
145 | } | ||
146 | #endif | ||
147 | |||
148 | static inline IMG_UINT32 | ||
149 | HandleToMMapOffset(IMG_HANDLE hHandle) | ||
150 | { | ||
151 | IMG_UINT32 ulHandle = (IMG_UINT32)hHandle; | ||
152 | |||
153 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
154 | if (PFNIsSpecial(ulHandle)) | ||
155 | { | ||
156 | PVR_ASSERT(PFNIsSpecial(ulHandle)); | ||
157 | return 0; | ||
158 | } | ||
159 | #endif | ||
160 | return ulHandle + FIRST_SPECIAL_PFN; | ||
161 | } | ||
162 | |||
163 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
164 | static inline IMG_BOOL | ||
165 | LinuxMemAreaUsesPhysicalMap(LinuxMemArea *psLinuxMemArea) | ||
166 | { | ||
167 | return LinuxMemAreaPhysIsContig(psLinuxMemArea); | ||
168 | } | ||
169 | #endif | ||
170 | |||
171 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
172 | static inline IMG_UINT32 | ||
173 | GetCurrentThreadID(IMG_VOID) | ||
174 | { | ||
175 | |||
176 | return (IMG_UINT32)current->pid; | ||
177 | } | ||
178 | #endif | ||
179 | |||
180 | static PKV_OFFSET_STRUCT | ||
181 | CreateOffsetStruct(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32Offset, IMG_UINT32 ui32RealByteSize) | ||
182 | { | ||
183 | PKV_OFFSET_STRUCT psOffsetStruct; | ||
184 | #if defined(DEBUG) || defined(DEBUG_LINUX_MMAP_AREAS) | ||
185 | const IMG_CHAR *pszName = LinuxMemAreaTypeToString(LinuxMemAreaRootType(psLinuxMemArea)); | ||
186 | #endif | ||
187 | |||
188 | #if defined(DEBUG) || defined(DEBUG_LINUX_MMAP_AREAS) | ||
189 | PVR_DPF((PVR_DBG_MESSAGE, | ||
190 | "%s(%s, psLinuxMemArea: 0x%p, ui32AllocFlags: 0x%8x)", | ||
191 | __FUNCTION__, pszName, psLinuxMemArea, psLinuxMemArea->ui32AreaFlags)); | ||
192 | #endif | ||
193 | |||
194 | PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC || LinuxMemAreaRoot(psLinuxMemArea)->eAreaType != LINUX_MEM_AREA_SUB_ALLOC); | ||
195 | |||
196 | PVR_ASSERT(psLinuxMemArea->bMMapRegistered); | ||
197 | |||
198 | psOffsetStruct = KMemCacheAllocWrapper(g_psMemmapCache, GFP_KERNEL); | ||
199 | if(psOffsetStruct == IMG_NULL) | ||
200 | { | ||
201 | PVR_DPF((PVR_DBG_ERROR,"PVRMMapRegisterArea: Couldn't alloc another mapping record from cache")); | ||
202 | return IMG_NULL; | ||
203 | } | ||
204 | |||
205 | psOffsetStruct->ui32MMapOffset = ui32Offset; | ||
206 | |||
207 | psOffsetStruct->psLinuxMemArea = psLinuxMemArea; | ||
208 | |||
209 | psOffsetStruct->ui32RealByteSize = ui32RealByteSize; | ||
210 | |||
211 | |||
212 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
213 | psOffsetStruct->ui32TID = GetCurrentThreadID(); | ||
214 | #endif | ||
215 | psOffsetStruct->ui32PID = OSGetCurrentProcessIDKM(); | ||
216 | |||
217 | #if defined(DEBUG_LINUX_MMAP_AREAS) | ||
218 | |||
219 | psOffsetStruct->pszName = pszName; | ||
220 | #endif | ||
221 | |||
222 | list_add_tail(&psOffsetStruct->sAreaItem, &psLinuxMemArea->sMMapOffsetStructList); | ||
223 | |||
224 | return psOffsetStruct; | ||
225 | } | ||
226 | |||
227 | |||
228 | static IMG_VOID | ||
229 | DestroyOffsetStruct(PKV_OFFSET_STRUCT psOffsetStruct) | ||
230 | { | ||
231 | #ifdef DEBUG | ||
232 | IMG_CPU_PHYADDR CpuPAddr; | ||
233 | CpuPAddr = LinuxMemAreaToCpuPAddr(psOffsetStruct->psLinuxMemArea, 0); | ||
234 | #endif | ||
235 | |||
236 | list_del(&psOffsetStruct->sAreaItem); | ||
237 | |||
238 | if (psOffsetStruct->bOnMMapList) | ||
239 | { | ||
240 | list_del(&psOffsetStruct->sMMapItem); | ||
241 | } | ||
242 | |||
243 | #ifdef DEBUG | ||
244 | PVR_DPF((PVR_DBG_MESSAGE, "%s: Table entry: " | ||
245 | "psLinuxMemArea=%p, CpuPAddr=0x%08X", __FUNCTION__, | ||
246 | psOffsetStruct->psLinuxMemArea, | ||
247 | CpuPAddr.uiAddr)); | ||
248 | #endif | ||
249 | |||
250 | KMemCacheFreeWrapper(g_psMemmapCache, psOffsetStruct); | ||
251 | } | ||
252 | |||
253 | |||
254 | static inline IMG_VOID | ||
255 | DetermineUsersSizeAndByteOffset(LinuxMemArea *psLinuxMemArea, | ||
256 | IMG_UINT32 *pui32RealByteSize, | ||
257 | IMG_UINT32 *pui32ByteOffset) | ||
258 | { | ||
259 | IMG_UINT32 ui32PageAlignmentOffset; | ||
260 | IMG_CPU_PHYADDR CpuPAddr; | ||
261 | |||
262 | CpuPAddr = LinuxMemAreaToCpuPAddr(psLinuxMemArea, 0); | ||
263 | ui32PageAlignmentOffset = ADDR_TO_PAGE_OFFSET(CpuPAddr.uiAddr); | ||
264 | |||
265 | *pui32ByteOffset = ui32PageAlignmentOffset; | ||
266 | |||
267 | *pui32RealByteSize = PAGE_ALIGN(psLinuxMemArea->ui32ByteSize + ui32PageAlignmentOffset); | ||
268 | } | ||
269 | |||
270 | |||
271 | PVRSRV_ERROR | ||
272 | PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, | ||
273 | IMG_HANDLE hMHandle, | ||
274 | IMG_UINT32 *pui32MMapOffset, | ||
275 | IMG_UINT32 *pui32ByteOffset, | ||
276 | IMG_UINT32 *pui32RealByteSize, | ||
277 | IMG_UINT32 *pui32UserVAddr) | ||
278 | { | ||
279 | LinuxMemArea *psLinuxMemArea; | ||
280 | PKV_OFFSET_STRUCT psOffsetStruct; | ||
281 | IMG_HANDLE hOSMemHandle; | ||
282 | PVRSRV_ERROR eError; | ||
283 | |||
284 | LinuxLockMutex(&g_sMMapMutex); | ||
285 | |||
286 | PVR_ASSERT(PVRSRVGetMaxHandle(psPerProc->psHandleBase) <= MAX_MMAP_HANDLE); | ||
287 | |||
288 | eError = PVRSRVLookupOSMemHandle(psPerProc->psHandleBase, &hOSMemHandle, hMHandle); | ||
289 | if (eError != PVRSRV_OK) | ||
290 | { | ||
291 | PVR_DPF((PVR_DBG_ERROR, "%s: Lookup of handle %p failed", __FUNCTION__, hMHandle)); | ||
292 | |||
293 | goto exit_unlock; | ||
294 | } | ||
295 | |||
296 | psLinuxMemArea = (LinuxMemArea *)hOSMemHandle; | ||
297 | |||
298 | DetermineUsersSizeAndByteOffset(psLinuxMemArea, | ||
299 | pui32RealByteSize, | ||
300 | pui32ByteOffset); | ||
301 | |||
302 | |||
303 | list_for_each_entry(psOffsetStruct, &psLinuxMemArea->sMMapOffsetStructList, sAreaItem) | ||
304 | { | ||
305 | if (psPerProc->ui32PID == psOffsetStruct->ui32PID) | ||
306 | { | ||
307 | |||
308 | PVR_ASSERT(*pui32RealByteSize == psOffsetStruct->ui32RealByteSize); | ||
309 | |||
310 | *pui32MMapOffset = psOffsetStruct->ui32MMapOffset; | ||
311 | *pui32UserVAddr = psOffsetStruct->ui32UserVAddr; | ||
312 | psOffsetStruct->ui32RefCount++; | ||
313 | |||
314 | eError = PVRSRV_OK; | ||
315 | goto exit_unlock; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | |||
320 | *pui32UserVAddr = 0; | ||
321 | |||
322 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
323 | if (LinuxMemAreaUsesPhysicalMap(psLinuxMemArea)) | ||
324 | { | ||
325 | *pui32MMapOffset = LinuxMemAreaToCpuPFN(psLinuxMemArea, 0); | ||
326 | PVR_ASSERT(PFNIsPhysical(*pui32MMapOffset)); | ||
327 | } | ||
328 | else | ||
329 | #endif | ||
330 | { | ||
331 | *pui32MMapOffset = HandleToMMapOffset(hMHandle); | ||
332 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
333 | PVR_ASSERT(PFNIsSpecial(*pui32MMapOffset)); | ||
334 | #endif | ||
335 | } | ||
336 | |||
337 | psOffsetStruct = CreateOffsetStruct(psLinuxMemArea, *pui32MMapOffset, *pui32RealByteSize); | ||
338 | if (psOffsetStruct == IMG_NULL) | ||
339 | { | ||
340 | eError = PVRSRV_ERROR_OUT_OF_MEMORY; | ||
341 | goto exit_unlock; | ||
342 | } | ||
343 | |||
344 | |||
345 | list_add_tail(&psOffsetStruct->sMMapItem, &g_sMMapOffsetStructList); | ||
346 | |||
347 | psOffsetStruct->bOnMMapList = IMG_TRUE; | ||
348 | |||
349 | psOffsetStruct->ui32RefCount++; | ||
350 | |||
351 | eError = PVRSRV_OK; | ||
352 | |||
353 | |||
354 | |||
355 | |||
356 | *pui32MMapOffset = *pui32MMapOffset << (PAGE_SHIFT - 12); | ||
357 | |||
358 | exit_unlock: | ||
359 | LinuxUnLockMutex(&g_sMMapMutex); | ||
360 | |||
361 | return eError; | ||
362 | } | ||
363 | |||
364 | |||
365 | PVRSRV_ERROR | ||
366 | PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, | ||
367 | IMG_HANDLE hMHandle, | ||
368 | IMG_BOOL *pbMUnmap, | ||
369 | IMG_UINT32 *pui32RealByteSize, | ||
370 | IMG_UINT32 *pui32UserVAddr) | ||
371 | { | ||
372 | LinuxMemArea *psLinuxMemArea; | ||
373 | PKV_OFFSET_STRUCT psOffsetStruct; | ||
374 | IMG_HANDLE hOSMemHandle; | ||
375 | PVRSRV_ERROR eError; | ||
376 | IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM(); | ||
377 | |||
378 | LinuxLockMutex(&g_sMMapMutex); | ||
379 | |||
380 | PVR_ASSERT(PVRSRVGetMaxHandle(psPerProc->psHandleBase) <= MAX_MMAP_HANDLE); | ||
381 | |||
382 | eError = PVRSRVLookupOSMemHandle(psPerProc->psHandleBase, &hOSMemHandle, hMHandle); | ||
383 | if (eError != PVRSRV_OK) | ||
384 | { | ||
385 | PVR_DPF((PVR_DBG_ERROR, "%s: Lookup of handle %p failed", __FUNCTION__, hMHandle)); | ||
386 | |||
387 | goto exit_unlock; | ||
388 | } | ||
389 | |||
390 | psLinuxMemArea = (LinuxMemArea *)hOSMemHandle; | ||
391 | |||
392 | |||
393 | list_for_each_entry(psOffsetStruct, &psLinuxMemArea->sMMapOffsetStructList, sAreaItem) | ||
394 | { | ||
395 | if (psOffsetStruct->ui32PID == ui32PID) | ||
396 | { | ||
397 | if (psOffsetStruct->ui32RefCount == 0) | ||
398 | { | ||
399 | PVR_DPF((PVR_DBG_ERROR, "%s: Attempt to release mmap data with zero reference count for offset struct 0x%p, memory area %p", __FUNCTION__, psOffsetStruct, psLinuxMemArea)); | ||
400 | eError = PVRSRV_ERROR_STILL_MAPPED; | ||
401 | goto exit_unlock; | ||
402 | } | ||
403 | |||
404 | psOffsetStruct->ui32RefCount--; | ||
405 | |||
406 | *pbMUnmap = (IMG_BOOL)((psOffsetStruct->ui32RefCount == 0) && (psOffsetStruct->ui32UserVAddr != 0)); | ||
407 | |||
408 | *pui32UserVAddr = (*pbMUnmap) ? psOffsetStruct->ui32UserVAddr : 0; | ||
409 | *pui32RealByteSize = (*pbMUnmap) ? psOffsetStruct->ui32RealByteSize : 0; | ||
410 | |||
411 | eError = PVRSRV_OK; | ||
412 | goto exit_unlock; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | |||
417 | PVR_DPF((PVR_DBG_ERROR, "%s: Mapping data not found for handle %p (memory area %p)", __FUNCTION__, hMHandle, psLinuxMemArea)); | ||
418 | |||
419 | eError = PVRSRV_ERROR_MAPPING_NOT_FOUND; | ||
420 | |||
421 | exit_unlock: | ||
422 | LinuxUnLockMutex(&g_sMMapMutex); | ||
423 | |||
424 | return eError; | ||
425 | } | ||
426 | |||
427 | static inline PKV_OFFSET_STRUCT | ||
428 | FindOffsetStructByOffset(IMG_UINT32 ui32Offset, IMG_UINT32 ui32RealByteSize) | ||
429 | { | ||
430 | PKV_OFFSET_STRUCT psOffsetStruct; | ||
431 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
432 | IMG_UINT32 ui32TID = GetCurrentThreadID(); | ||
433 | #endif | ||
434 | IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM(); | ||
435 | |||
436 | list_for_each_entry(psOffsetStruct, &g_sMMapOffsetStructList, sMMapItem) | ||
437 | { | ||
438 | if (ui32Offset == psOffsetStruct->ui32MMapOffset && ui32RealByteSize == psOffsetStruct->ui32RealByteSize && psOffsetStruct->ui32PID == ui32PID) | ||
439 | { | ||
440 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
441 | |||
442 | if (!PFNIsPhysical(ui32Offset) || psOffsetStruct->ui32TID == ui32TID) | ||
443 | #endif | ||
444 | { | ||
445 | return psOffsetStruct; | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | |||
450 | return IMG_NULL; | ||
451 | } | ||
452 | |||
453 | |||
454 | static IMG_BOOL | ||
455 | DoMapToUser(LinuxMemArea *psLinuxMemArea, | ||
456 | struct vm_area_struct* ps_vma, | ||
457 | IMG_UINT32 ui32ByteOffset) | ||
458 | { | ||
459 | IMG_UINT32 ui32ByteSize; | ||
460 | |||
461 | if (psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC) | ||
462 | { | ||
463 | return DoMapToUser(LinuxMemAreaRoot(psLinuxMemArea), | ||
464 | ps_vma, | ||
465 | psLinuxMemArea->uData.sSubAlloc.ui32ByteOffset + ui32ByteOffset); | ||
466 | } | ||
467 | |||
468 | |||
469 | ui32ByteSize = ps_vma->vm_end - ps_vma->vm_start; | ||
470 | PVR_ASSERT(ADDR_TO_PAGE_OFFSET(ui32ByteSize) == 0); | ||
471 | |||
472 | #if defined (__sparc__) | ||
473 | |||
474 | #error "SPARC not supported" | ||
475 | #endif | ||
476 | |||
477 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
478 | if (PFNIsPhysical(ps_vma->vm_pgoff)) | ||
479 | { | ||
480 | IMG_INT result; | ||
481 | |||
482 | PVR_ASSERT(LinuxMemAreaPhysIsContig(psLinuxMemArea)); | ||
483 | PVR_ASSERT(LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32ByteOffset) == ps_vma->vm_pgoff); | ||
484 | |||
485 | result = IO_REMAP_PFN_RANGE(ps_vma, ps_vma->vm_start, ps_vma->vm_pgoff, ui32ByteSize, ps_vma->vm_page_prot); | ||
486 | |||
487 | if(result == 0) | ||
488 | { | ||
489 | return IMG_TRUE; | ||
490 | } | ||
491 | |||
492 | PVR_DPF((PVR_DBG_MESSAGE, "%s: Failed to map contiguous physical address range (%d), trying non-contiguous path", __FUNCTION__, result)); | ||
493 | } | ||
494 | #endif | ||
495 | |||
496 | { | ||
497 | |||
498 | IMG_UINT32 ulVMAPos; | ||
499 | IMG_UINT32 ui32ByteEnd = ui32ByteOffset + ui32ByteSize; | ||
500 | IMG_UINT32 ui32PA; | ||
501 | #if defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
502 | IMG_BOOL bMixedMap = IMG_FALSE; | ||
503 | #endif | ||
504 | |||
505 | for(ui32PA = ui32ByteOffset; ui32PA < ui32ByteEnd; ui32PA += PAGE_SIZE) | ||
506 | { | ||
507 | IMG_UINT32 pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32PA); | ||
508 | |||
509 | if (!pfn_valid(pfn)) | ||
510 | { | ||
511 | #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
512 | PVR_DPF((PVR_DBG_ERROR,"%s: Error - PFN invalid: 0x%x", __FUNCTION__, pfn)); | ||
513 | return IMG_FALSE; | ||
514 | #else | ||
515 | bMixedMap = IMG_TRUE; | ||
516 | #endif | ||
517 | } | ||
518 | } | ||
519 | |||
520 | #if defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
521 | if (bMixedMap) | ||
522 | { | ||
523 | ps_vma->vm_flags |= VM_MIXEDMAP; | ||
524 | } | ||
525 | #endif | ||
526 | |||
527 | ulVMAPos = ps_vma->vm_start; | ||
528 | for(ui32PA = ui32ByteOffset; ui32PA < ui32ByteEnd; ui32PA += PAGE_SIZE) | ||
529 | { | ||
530 | IMG_UINT32 pfn; | ||
531 | IMG_INT result; | ||
532 | |||
533 | pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32PA); | ||
534 | |||
535 | #if defined(PVR_MAKE_ALL_PFNS_SPECIAL) | ||
536 | if (bMixedMap) | ||
537 | { | ||
538 | result = vm_insert_mixed(ps_vma, ulVMAPos, pfn); | ||
539 | if(result != 0) | ||
540 | { | ||
541 | PVR_DPF((PVR_DBG_ERROR,"%s: Error - vm_insert_mixed failed (%d)", __FUNCTION__, result)); | ||
542 | return IMG_FALSE; | ||
543 | } | ||
544 | } | ||
545 | else | ||
546 | #endif | ||
547 | { | ||
548 | struct page *psPage; | ||
549 | |||
550 | PVR_ASSERT(pfn_valid(pfn)); | ||
551 | |||
552 | psPage = pfn_to_page(pfn); | ||
553 | |||
554 | result = VM_INSERT_PAGE(ps_vma, ulVMAPos, psPage); | ||
555 | if(result != 0) | ||
556 | { | ||
557 | PVR_DPF((PVR_DBG_ERROR,"%s: Error - VM_INSERT_PAGE failed (%d)", __FUNCTION__, result)); | ||
558 | return IMG_FALSE; | ||
559 | } | ||
560 | } | ||
561 | ulVMAPos += PAGE_SIZE; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | return IMG_TRUE; | ||
566 | } | ||
567 | |||
568 | |||
569 | static IMG_VOID | ||
570 | MMapVOpenNoLock(struct vm_area_struct* ps_vma) | ||
571 | { | ||
572 | PKV_OFFSET_STRUCT psOffsetStruct = (PKV_OFFSET_STRUCT)ps_vma->vm_private_data; | ||
573 | PVR_ASSERT(psOffsetStruct != IMG_NULL) | ||
574 | psOffsetStruct->ui32Mapped++; | ||
575 | PVR_ASSERT(!psOffsetStruct->bOnMMapList); | ||
576 | |||
577 | if (psOffsetStruct->ui32Mapped > 1) | ||
578 | { | ||
579 | PVR_DPF((PVR_DBG_WARNING, "%s: Offset structure 0x%p is being shared across processes (psOffsetStruct->ui32Mapped: %u)", __FUNCTION__, psOffsetStruct, psOffsetStruct->ui32Mapped)); | ||
580 | PVR_ASSERT((ps_vma->vm_flags & VM_DONTCOPY) == 0); | ||
581 | } | ||
582 | |||
583 | #if defined(DEBUG_LINUX_MMAP_AREAS) | ||
584 | |||
585 | PVR_DPF((PVR_DBG_MESSAGE, | ||
586 | "%s: psLinuxMemArea 0x%p, KVAddress 0x%p MMapOffset %d, ui32Mapped %d", | ||
587 | __FUNCTION__, | ||
588 | psOffsetStruct->psLinuxMemArea, | ||
589 | LinuxMemAreaToCpuVAddr(psOffsetStruct->psLinuxMemArea), | ||
590 | psOffsetStruct->ui32MMapOffset, | ||
591 | psOffsetStruct->ui32Mapped)); | ||
592 | #endif | ||
593 | |||
594 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) | ||
595 | MOD_INC_USE_COUNT; | ||
596 | #endif | ||
597 | } | ||
598 | |||
599 | |||
600 | static void | ||
601 | MMapVOpen(struct vm_area_struct* ps_vma) | ||
602 | { | ||
603 | LinuxLockMutex(&g_sMMapMutex); | ||
604 | |||
605 | MMapVOpenNoLock(ps_vma); | ||
606 | |||
607 | LinuxUnLockMutex(&g_sMMapMutex); | ||
608 | } | ||
609 | |||
610 | |||
611 | static IMG_VOID | ||
612 | MMapVCloseNoLock(struct vm_area_struct* ps_vma) | ||
613 | { | ||
614 | PKV_OFFSET_STRUCT psOffsetStruct = (PKV_OFFSET_STRUCT)ps_vma->vm_private_data; | ||
615 | PVR_ASSERT(psOffsetStruct != IMG_NULL) | ||
616 | |||
617 | #if defined(DEBUG_LINUX_MMAP_AREAS) | ||
618 | PVR_DPF((PVR_DBG_MESSAGE, | ||
619 | "%s: psLinuxMemArea %p, CpuVAddr %p ui32MMapOffset %d, ui32Mapped %d", | ||
620 | __FUNCTION__, | ||
621 | psOffsetStruct->psLinuxMemArea, | ||
622 | LinuxMemAreaToCpuVAddr(psOffsetStruct->psLinuxMemArea), | ||
623 | psOffsetStruct->ui32MMapOffset, | ||
624 | psOffsetStruct->ui32Mapped)); | ||
625 | #endif | ||
626 | |||
627 | PVR_ASSERT(!psOffsetStruct->bOnMMapList); | ||
628 | psOffsetStruct->ui32Mapped--; | ||
629 | if (psOffsetStruct->ui32Mapped == 0) | ||
630 | { | ||
631 | if (psOffsetStruct->ui32RefCount != 0) | ||
632 | { | ||
633 | PVR_DPF((PVR_DBG_MESSAGE, "%s: psOffsetStruct %p has non-zero reference count (ui32RefCount = %u). User mode address of start of mapping: 0x%x", __FUNCTION__, psOffsetStruct, psOffsetStruct->ui32RefCount, psOffsetStruct->ui32UserVAddr)); | ||
634 | } | ||
635 | |||
636 | DestroyOffsetStruct(psOffsetStruct); | ||
637 | } | ||
638 | |||
639 | ps_vma->vm_private_data = NULL; | ||
640 | |||
641 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) | ||
642 | MOD_DEC_USE_COUNT; | ||
643 | #endif | ||
644 | } | ||
645 | |||
646 | static void | ||
647 | MMapVClose(struct vm_area_struct* ps_vma) | ||
648 | { | ||
649 | LinuxLockMutex(&g_sMMapMutex); | ||
650 | |||
651 | MMapVCloseNoLock(ps_vma); | ||
652 | |||
653 | LinuxUnLockMutex(&g_sMMapMutex); | ||
654 | } | ||
655 | |||
656 | |||
657 | static struct vm_operations_struct MMapIOOps = | ||
658 | { | ||
659 | .open=MMapVOpen, | ||
660 | .close=MMapVClose | ||
661 | }; | ||
662 | |||
663 | |||
664 | int | ||
665 | PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma) | ||
666 | { | ||
667 | IMG_UINT32 ui32ByteSize; | ||
668 | PKV_OFFSET_STRUCT psOffsetStruct; | ||
669 | int iRetVal = 0; | ||
670 | |||
671 | PVR_UNREFERENCED_PARAMETER(pFile); | ||
672 | |||
673 | LinuxLockMutex(&g_sMMapMutex); | ||
674 | |||
675 | ui32ByteSize = ps_vma->vm_end - ps_vma->vm_start; | ||
676 | |||
677 | PVR_DPF((PVR_DBG_MESSAGE, "%s: Received mmap(2) request with ui32MMapOffset 0x%08lx," | ||
678 | " and ui32ByteSize %d(0x%08x)", | ||
679 | __FUNCTION__, | ||
680 | ps_vma->vm_pgoff, | ||
681 | ui32ByteSize, ui32ByteSize)); | ||
682 | |||
683 | psOffsetStruct = FindOffsetStructByOffset(ps_vma->vm_pgoff, ui32ByteSize); | ||
684 | if (psOffsetStruct == IMG_NULL) | ||
685 | { | ||
686 | #if defined(SUPPORT_DRI_DRM) | ||
687 | LinuxUnLockMutex(&g_sMMapMutex); | ||
688 | |||
689 | #if !defined(SUPPORT_DRI_DRM_EXT) | ||
690 | |||
691 | return drm_mmap(pFile, ps_vma); | ||
692 | #else | ||
693 | |||
694 | return -ENOENT; | ||
695 | #endif | ||
696 | #else | ||
697 | PVR_UNREFERENCED_PARAMETER(pFile); | ||
698 | |||
699 | PVR_DPF((PVR_DBG_ERROR, | ||
700 | "%s: Attempted to mmap unregistered area at vm_pgoff 0x%lx", | ||
701 | __FUNCTION__, ps_vma->vm_pgoff)); | ||
702 | iRetVal = -EINVAL; | ||
703 | #endif | ||
704 | goto unlock_and_return; | ||
705 | } | ||
706 | list_del(&psOffsetStruct->sMMapItem); | ||
707 | psOffsetStruct->bOnMMapList = IMG_FALSE; | ||
708 | |||
709 | |||
710 | if (((ps_vma->vm_flags & VM_WRITE) != 0) && | ||
711 | ((ps_vma->vm_flags & VM_SHARED) == 0)) | ||
712 | { | ||
713 | PVR_DPF((PVR_DBG_ERROR, "%s: Cannot mmap non-shareable writable areas", __FUNCTION__)); | ||
714 | iRetVal = -EINVAL; | ||
715 | goto unlock_and_return; | ||
716 | } | ||
717 | |||
718 | PVR_DPF((PVR_DBG_MESSAGE, "%s: Mapped psLinuxMemArea 0x%p\n", | ||
719 | __FUNCTION__, psOffsetStruct->psLinuxMemArea)); | ||
720 | |||
721 | ps_vma->vm_flags |= VM_RESERVED; | ||
722 | ps_vma->vm_flags |= VM_IO; | ||
723 | |||
724 | |||
725 | ps_vma->vm_flags |= VM_DONTEXPAND; | ||
726 | |||
727 | |||
728 | ps_vma->vm_flags |= VM_DONTCOPY; | ||
729 | |||
730 | ps_vma->vm_private_data = (void *)psOffsetStruct; | ||
731 | |||
732 | switch(psOffsetStruct->psLinuxMemArea->ui32AreaFlags & PVRSRV_HAP_CACHETYPE_MASK) | ||
733 | { | ||
734 | case PVRSRV_HAP_CACHED: | ||
735 | |||
736 | break; | ||
737 | case PVRSRV_HAP_WRITECOMBINE: | ||
738 | ps_vma->vm_page_prot = PGPROT_WC(ps_vma->vm_page_prot); | ||
739 | break; | ||
740 | case PVRSRV_HAP_UNCACHED: | ||
741 | ps_vma->vm_page_prot = PGPROT_UC(ps_vma->vm_page_prot); | ||
742 | break; | ||
743 | default: | ||
744 | PVR_DPF((PVR_DBG_ERROR, "%s: unknown cache type", __FUNCTION__)); | ||
745 | iRetVal = -EINVAL; | ||
746 | goto unlock_and_return; | ||
747 | } | ||
748 | |||
749 | |||
750 | ps_vma->vm_ops = &MMapIOOps; | ||
751 | |||
752 | if(!DoMapToUser(psOffsetStruct->psLinuxMemArea, ps_vma, 0)) | ||
753 | { | ||
754 | iRetVal = -EAGAIN; | ||
755 | goto unlock_and_return; | ||
756 | } | ||
757 | |||
758 | PVR_ASSERT(psOffsetStruct->ui32UserVAddr == 0) | ||
759 | |||
760 | psOffsetStruct->ui32UserVAddr = ps_vma->vm_start; | ||
761 | |||
762 | |||
763 | if(psOffsetStruct->psLinuxMemArea->bNeedsCacheInvalidate) | ||
764 | { | ||
765 | IMG_UINT32 ui32RealByteSize, ui32ByteOffset; | ||
766 | IMG_VOID *pvBase; | ||
767 | |||
768 | DetermineUsersSizeAndByteOffset(psOffsetStruct->psLinuxMemArea, | ||
769 | &ui32RealByteSize, | ||
770 | &ui32ByteOffset); | ||
771 | |||
772 | ui32RealByteSize = psOffsetStruct->psLinuxMemArea->ui32ByteSize; | ||
773 | pvBase = (IMG_VOID *)ps_vma->vm_start + ui32ByteOffset; | ||
774 | |||
775 | OSInvalidateCPUCacheRangeKM(psOffsetStruct->psLinuxMemArea, | ||
776 | pvBase, ui32RealByteSize); | ||
777 | psOffsetStruct->psLinuxMemArea->bNeedsCacheInvalidate = IMG_FALSE; | ||
778 | } | ||
779 | |||
780 | |||
781 | MMapVOpenNoLock(ps_vma); | ||
782 | |||
783 | PVR_DPF((PVR_DBG_MESSAGE, "%s: Mapped area at offset 0x%08lx\n", | ||
784 | __FUNCTION__, ps_vma->vm_pgoff)); | ||
785 | |||
786 | unlock_and_return: | ||
787 | if (iRetVal != 0 && psOffsetStruct != IMG_NULL) | ||
788 | { | ||
789 | DestroyOffsetStruct(psOffsetStruct); | ||
790 | } | ||
791 | |||
792 | LinuxUnLockMutex(&g_sMMapMutex); | ||
793 | |||
794 | return iRetVal; | ||
795 | } | ||
796 | |||
797 | |||
798 | #if defined(DEBUG_LINUX_MMAP_AREAS) | ||
799 | |||
800 | static void ProcSeqStartstopMMapRegistations(struct seq_file *sfile,IMG_BOOL start) | ||
801 | { | ||
802 | if(start) | ||
803 | { | ||
804 | LinuxLockMutex(&g_sMMapMutex); | ||
805 | } | ||
806 | else | ||
807 | { | ||
808 | LinuxUnLockMutex(&g_sMMapMutex); | ||
809 | } | ||
810 | } | ||
811 | |||
812 | |||
813 | static void* ProcSeqOff2ElementMMapRegistrations(struct seq_file *sfile, loff_t off) | ||
814 | { | ||
815 | LinuxMemArea *psLinuxMemArea; | ||
816 | if(!off) | ||
817 | { | ||
818 | return PVR_PROC_SEQ_START_TOKEN; | ||
819 | } | ||
820 | |||
821 | list_for_each_entry(psLinuxMemArea, &g_sMMapAreaList, sMMapItem) | ||
822 | { | ||
823 | PKV_OFFSET_STRUCT psOffsetStruct; | ||
824 | |||
825 | list_for_each_entry(psOffsetStruct, &psLinuxMemArea->sMMapOffsetStructList, sAreaItem) | ||
826 | { | ||
827 | off--; | ||
828 | if (off == 0) | ||
829 | { | ||
830 | PVR_ASSERT(psOffsetStruct->psLinuxMemArea == psLinuxMemArea); | ||
831 | return (void*)psOffsetStruct; | ||
832 | } | ||
833 | } | ||
834 | } | ||
835 | return (void*)0; | ||
836 | } | ||
837 | |||
838 | static void* ProcSeqNextMMapRegistrations(struct seq_file *sfile,void* el,loff_t off) | ||
839 | { | ||
840 | return ProcSeqOff2ElementMMapRegistrations(sfile,off); | ||
841 | } | ||
842 | |||
843 | |||
844 | static void ProcSeqShowMMapRegistrations(struct seq_file *sfile, void *el) | ||
845 | { | ||
846 | KV_OFFSET_STRUCT *psOffsetStruct = (KV_OFFSET_STRUCT*)el; | ||
847 | LinuxMemArea *psLinuxMemArea; | ||
848 | IMG_UINT32 ui32RealByteSize; | ||
849 | IMG_UINT32 ui32ByteOffset; | ||
850 | |||
851 | if(el == PVR_PROC_SEQ_START_TOKEN) | ||
852 | { | ||
853 | seq_printf( sfile, | ||
854 | #if !defined(DEBUG_LINUX_XML_PROC_FILES) | ||
855 | "Allocations registered for mmap: %u\n" | ||
856 | "In total these areas correspond to %u bytes\n" | ||
857 | "psLinuxMemArea " | ||
858 | "UserVAddr " | ||
859 | "KernelVAddr " | ||
860 | "CpuPAddr " | ||
861 | "MMapOffset " | ||
862 | "ByteLength " | ||
863 | "LinuxMemType " | ||
864 | "Pid Name Flags\n", | ||
865 | #else | ||
866 | "<mmap_header>\n" | ||
867 | "\t<count>%u</count>\n" | ||
868 | "\t<bytes>%u</bytes>\n" | ||
869 | "</mmap_header>\n", | ||
870 | #endif | ||
871 | g_ui32RegisteredAreas, | ||
872 | g_ui32TotalByteSize | ||
873 | ); | ||
874 | return; | ||
875 | } | ||
876 | |||
877 | psLinuxMemArea = psOffsetStruct->psLinuxMemArea; | ||
878 | |||
879 | DetermineUsersSizeAndByteOffset(psLinuxMemArea, | ||
880 | &ui32RealByteSize, | ||
881 | &ui32ByteOffset); | ||
882 | |||
883 | seq_printf( sfile, | ||
884 | #if !defined(DEBUG_LINUX_XML_PROC_FILES) | ||
885 | "%-8p %08x %-8p %08x %08x %-8d %-24s %-5u %-8s %08x(%s)\n", | ||
886 | #else | ||
887 | "<mmap_record>\n" | ||
888 | "\t<pointer>%-8p</pointer>\n" | ||
889 | "\t<user_virtual>%-8x</user_virtual>\n" | ||
890 | "\t<kernel_virtual>%-8p</kernel_virtual>\n" | ||
891 | "\t<cpu_physical>%08x</cpu_physical>\n" | ||
892 | "\t<mmap_offset>%08x</mmap_offset>\n" | ||
893 | "\t<bytes>%-8d</bytes>\n" | ||
894 | "\t<linux_mem_area_type>%-24s</linux_mem_area_type>\n" | ||
895 | "\t<pid>%-5u</pid>\n" | ||
896 | "\t<name>%-8s</name>\n" | ||
897 | "\t<flags>%08x</flags>\n" | ||
898 | "\t<flags_string>%s</flags_string>\n" | ||
899 | "</mmap_record>\n", | ||
900 | #endif | ||
901 | psLinuxMemArea, | ||
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 | } | ||
913 | |||
914 | #endif | ||
915 | |||
916 | |||
917 | PVRSRV_ERROR | ||
918 | PVRMMapRegisterArea(LinuxMemArea *psLinuxMemArea) | ||
919 | { | ||
920 | PVRSRV_ERROR eError; | ||
921 | #if defined(DEBUG) || defined(DEBUG_LINUX_MMAP_AREAS) | ||
922 | const IMG_CHAR *pszName = LinuxMemAreaTypeToString(LinuxMemAreaRootType(psLinuxMemArea)); | ||
923 | #endif | ||
924 | |||
925 | LinuxLockMutex(&g_sMMapMutex); | ||
926 | |||
927 | #if defined(DEBUG) || defined(DEBUG_LINUX_MMAP_AREAS) | ||
928 | PVR_DPF((PVR_DBG_MESSAGE, | ||
929 | "%s(%s, psLinuxMemArea 0x%p, ui32AllocFlags 0x%8x)", | ||
930 | __FUNCTION__, pszName, psLinuxMemArea, psLinuxMemArea->ui32AreaFlags)); | ||
931 | #endif | ||
932 | |||
933 | PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC || LinuxMemAreaRoot(psLinuxMemArea)->eAreaType != LINUX_MEM_AREA_SUB_ALLOC); | ||
934 | |||
935 | |||
936 | if(psLinuxMemArea->bMMapRegistered) | ||
937 | { | ||
938 | PVR_DPF((PVR_DBG_ERROR, "%s: psLinuxMemArea 0x%p is already registered", | ||
939 | __FUNCTION__, psLinuxMemArea)); | ||
940 | eError = PVRSRV_ERROR_INVALID_PARAMS; | ||
941 | goto exit_unlock; | ||
942 | } | ||
943 | |||
944 | list_add_tail(&psLinuxMemArea->sMMapItem, &g_sMMapAreaList); | ||
945 | |||
946 | psLinuxMemArea->bMMapRegistered = IMG_TRUE; | ||
947 | |||
948 | #if defined(DEBUG_LINUX_MMAP_AREAS) | ||
949 | g_ui32RegisteredAreas++; | ||
950 | |||
951 | if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) | ||
952 | { | ||
953 | g_ui32TotalByteSize += psLinuxMemArea->ui32ByteSize; | ||
954 | } | ||
955 | #endif | ||
956 | |||
957 | eError = PVRSRV_OK; | ||
958 | |||
959 | exit_unlock: | ||
960 | LinuxUnLockMutex(&g_sMMapMutex); | ||
961 | |||
962 | return eError; | ||
963 | } | ||
964 | |||
965 | |||
966 | PVRSRV_ERROR | ||
967 | PVRMMapRemoveRegisteredArea(LinuxMemArea *psLinuxMemArea) | ||
968 | { | ||
969 | PVRSRV_ERROR eError; | ||
970 | PKV_OFFSET_STRUCT psOffsetStruct, psTmpOffsetStruct; | ||
971 | |||
972 | LinuxLockMutex(&g_sMMapMutex); | ||
973 | |||
974 | PVR_ASSERT(psLinuxMemArea->bMMapRegistered); | ||
975 | |||
976 | list_for_each_entry_safe(psOffsetStruct, psTmpOffsetStruct, &psLinuxMemArea->sMMapOffsetStructList, sAreaItem) | ||
977 | { | ||
978 | if (psOffsetStruct->ui32Mapped != 0) | ||
979 | { | ||
980 | PVR_DPF((PVR_DBG_ERROR, "%s: psOffsetStruct 0x%p for memory area 0x0x%p is still mapped; psOffsetStruct->ui32Mapped %u", __FUNCTION__, psOffsetStruct, psLinuxMemArea, psOffsetStruct->ui32Mapped)); | ||
981 | eError = PVRSRV_ERROR_STILL_MAPPED; | ||
982 | goto exit_unlock; | ||
983 | } | ||
984 | else | ||
985 | { | ||
986 | |||
987 | PVR_DPF((PVR_DBG_WARNING, "%s: psOffsetStruct 0x%p was never mapped", __FUNCTION__, psOffsetStruct)); | ||
988 | } | ||
989 | |||
990 | PVR_ASSERT((psOffsetStruct->ui32Mapped == 0) && psOffsetStruct->bOnMMapList); | ||
991 | |||
992 | DestroyOffsetStruct(psOffsetStruct); | ||
993 | } | ||
994 | |||
995 | list_del(&psLinuxMemArea->sMMapItem); | ||
996 | |||
997 | psLinuxMemArea->bMMapRegistered = IMG_FALSE; | ||
998 | |||
999 | #if defined(DEBUG_LINUX_MMAP_AREAS) | ||
1000 | g_ui32RegisteredAreas--; | ||
1001 | if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) | ||
1002 | { | ||
1003 | g_ui32TotalByteSize -= psLinuxMemArea->ui32ByteSize; | ||
1004 | } | ||
1005 | #endif | ||
1006 | |||
1007 | eError = PVRSRV_OK; | ||
1008 | |||
1009 | exit_unlock: | ||
1010 | LinuxUnLockMutex(&g_sMMapMutex); | ||
1011 | return eError; | ||
1012 | } | ||
1013 | |||
1014 | |||
1015 | PVRSRV_ERROR | ||
1016 | LinuxMMapPerProcessConnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc) | ||
1017 | { | ||
1018 | PVR_UNREFERENCED_PARAMETER(psEnvPerProc); | ||
1019 | |||
1020 | return PVRSRV_OK; | ||
1021 | } | ||
1022 | |||
1023 | IMG_VOID | ||
1024 | LinuxMMapPerProcessDisconnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc) | ||
1025 | { | ||
1026 | PKV_OFFSET_STRUCT psOffsetStruct, psTmpOffsetStruct; | ||
1027 | IMG_BOOL bWarn = IMG_FALSE; | ||
1028 | IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM(); | ||
1029 | |||
1030 | PVR_UNREFERENCED_PARAMETER(psEnvPerProc); | ||
1031 | |||
1032 | LinuxLockMutex(&g_sMMapMutex); | ||
1033 | |||
1034 | list_for_each_entry_safe(psOffsetStruct, psTmpOffsetStruct, &g_sMMapOffsetStructList, sMMapItem) | ||
1035 | { | ||
1036 | if (psOffsetStruct->ui32PID == ui32PID) | ||
1037 | { | ||
1038 | if (!bWarn) | ||
1039 | { | ||
1040 | PVR_DPF((PVR_DBG_WARNING, "%s: process has unmapped offset structures. Removing them", __FUNCTION__)); | ||
1041 | bWarn = IMG_TRUE; | ||
1042 | } | ||
1043 | PVR_ASSERT(psOffsetStruct->ui32Mapped == 0); | ||
1044 | PVR_ASSERT(psOffsetStruct->bOnMMapList); | ||
1045 | |||
1046 | DestroyOffsetStruct(psOffsetStruct); | ||
1047 | } | ||
1048 | } | ||
1049 | |||
1050 | LinuxUnLockMutex(&g_sMMapMutex); | ||
1051 | } | ||
1052 | |||
1053 | |||
1054 | PVRSRV_ERROR LinuxMMapPerProcessHandleOptions(PVRSRV_HANDLE_BASE *psHandleBase) | ||
1055 | { | ||
1056 | PVRSRV_ERROR eError; | ||
1057 | |||
1058 | eError = PVRSRVSetMaxHandle(psHandleBase, MAX_MMAP_HANDLE); | ||
1059 | if (eError != PVRSRV_OK) | ||
1060 | { | ||
1061 | PVR_DPF((PVR_DBG_ERROR,"%s: failed to set handle limit (%d)", __FUNCTION__, eError)); | ||
1062 | return eError; | ||
1063 | } | ||
1064 | |||
1065 | return eError; | ||
1066 | } | ||
1067 | |||
1068 | |||
1069 | IMG_VOID | ||
1070 | PVRMMapInit(IMG_VOID) | ||
1071 | { | ||
1072 | LinuxInitMutex(&g_sMMapMutex); | ||
1073 | |||
1074 | g_psMemmapCache = KMemCacheCreateWrapper("img-mmap", sizeof(KV_OFFSET_STRUCT), 0, 0); | ||
1075 | if (!g_psMemmapCache) | ||
1076 | { | ||
1077 | PVR_DPF((PVR_DBG_ERROR,"%s: failed to allocate kmem_cache", __FUNCTION__)); | ||
1078 | goto error; | ||
1079 | } | ||
1080 | |||
1081 | #if defined(DEBUG_LINUX_MMAP_AREAS) | ||
1082 | g_ProcMMap = CreateProcReadEntrySeq("mmap", NULL, | ||
1083 | ProcSeqNextMMapRegistrations, | ||
1084 | ProcSeqShowMMapRegistrations, | ||
1085 | ProcSeqOff2ElementMMapRegistrations, | ||
1086 | ProcSeqStartstopMMapRegistations | ||
1087 | ); | ||
1088 | #endif | ||
1089 | return; | ||
1090 | |||
1091 | error: | ||
1092 | PVRMMapCleanup(); | ||
1093 | return; | ||
1094 | } | ||
1095 | |||
1096 | |||
1097 | IMG_VOID | ||
1098 | PVRMMapCleanup(IMG_VOID) | ||
1099 | { | ||
1100 | PVRSRV_ERROR eError; | ||
1101 | |||
1102 | if (!list_empty(&g_sMMapAreaList)) | ||
1103 | { | ||
1104 | LinuxMemArea *psLinuxMemArea, *psTmpMemArea; | ||
1105 | |||
1106 | PVR_DPF((PVR_DBG_ERROR, "%s: Memory areas are still registered with MMap", __FUNCTION__)); | ||
1107 | |||
1108 | PVR_TRACE(("%s: Unregistering memory areas", __FUNCTION__)); | ||
1109 | list_for_each_entry_safe(psLinuxMemArea, psTmpMemArea, &g_sMMapAreaList, sMMapItem) | ||
1110 | { | ||
1111 | eError = PVRMMapRemoveRegisteredArea(psLinuxMemArea); | ||
1112 | if (eError != PVRSRV_OK) | ||
1113 | { | ||
1114 | PVR_DPF((PVR_DBG_ERROR, "%s: PVRMMapRemoveRegisteredArea failed (%d)", __FUNCTION__, eError)); | ||
1115 | } | ||
1116 | PVR_ASSERT(eError == PVRSRV_OK); | ||
1117 | |||
1118 | LinuxMemAreaDeepFree(psLinuxMemArea); | ||
1119 | } | ||
1120 | } | ||
1121 | PVR_ASSERT(list_empty((&g_sMMapAreaList))); | ||
1122 | |||
1123 | #if defined(DEBUG_LINUX_MMAP_AREAS) | ||
1124 | RemoveProcEntrySeq(g_ProcMMap); | ||
1125 | #endif | ||
1126 | |||
1127 | if(g_psMemmapCache) | ||
1128 | { | ||
1129 | KMemCacheDestroyWrapper(g_psMemmapCache); | ||
1130 | g_psMemmapCache = NULL; | ||
1131 | } | ||
1132 | } | ||