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