fixes for bc_cat
[sgx.git] / pvr / devicemem.c
1 /**********************************************************************
2  *
3  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful but, except
10  * as otherwise stated in writing, without any warranty; without even the
11  * implied warranty of merchantability or fitness for a particular purpose.
12  * See the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
24  *
25  ******************************************************************************/
26
27 #include <stddef.h>
28
29 #include "services_headers.h"
30 #include "buffer_manager.h"
31 #include "pvr_pdump.h"
32 #include "pvr_bridge_km.h"
33
34 #include <linux/pagemap.h>
35
36 static enum PVRSRV_ERROR AllocDeviceMem(void *hDevCookie, void *hDevMemHeap,
37                                 u32 ui32Flags, u32 ui32Size, u32 ui32Alignment,
38                                 struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo);
39
40 struct RESMAN_MAP_DEVICE_MEM_DATA {
41         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
42         struct PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo;
43 };
44
45 static inline void get_page_details(u32 vaddr, size_t byte_size,
46                 u32 *page_offset_out, int *page_count_out)
47 {
48         size_t host_page_size;
49         u32 page_offset;
50         int page_count;
51
52         host_page_size = PAGE_SIZE;
53         page_offset = vaddr & (host_page_size - 1);
54         page_count = PAGE_ALIGN(byte_size + page_offset) / host_page_size;
55
56         *page_offset_out = page_offset;
57         *page_count_out = page_count;
58 }
59
60 static inline int get_page_count(u32 vaddr, size_t byte_size)
61 {
62         u32 page_offset;
63         int page_count;
64
65         get_page_details(vaddr, byte_size, &page_offset, &page_count);
66
67         return page_count;
68 }
69
70 enum PVRSRV_ERROR PVRSRVGetDeviceMemHeapsKM(void *hDevCookie,
71                                         struct PVRSRV_HEAP_INFO *psHeapInfo)
72 {
73         struct PVRSRV_DEVICE_NODE *psDeviceNode;
74         u32 ui32HeapCount;
75         struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
76         u32 i;
77
78         if (hDevCookie == NULL) {
79                 PVR_DPF(PVR_DBG_ERROR,
80                          "PVRSRVGetDeviceMemHeapsKM: hDevCookie invalid");
81                 PVR_DBG_BREAK;
82                 return PVRSRV_ERROR_INVALID_PARAMS;
83         }
84
85         psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
86
87         ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
88         psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
89
90         PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
91
92         for (i = 0; i < ui32HeapCount; i++) {
93                 psHeapInfo[i].ui32HeapID = psDeviceMemoryHeap[i].ui32HeapID;
94                 psHeapInfo[i].hDevMemHeap = psDeviceMemoryHeap[i].hDevMemHeap;
95                 psHeapInfo[i].sDevVAddrBase =
96                     psDeviceMemoryHeap[i].sDevVAddrBase;
97                 psHeapInfo[i].ui32HeapByteSize =
98                     psDeviceMemoryHeap[i].ui32HeapSize;
99                 psHeapInfo[i].ui32Attribs = psDeviceMemoryHeap[i].ui32Attribs;
100         }
101
102         for (; i < PVRSRV_MAX_CLIENT_HEAPS; i++) {
103                 OSMemSet(psHeapInfo + i, 0, sizeof(*psHeapInfo));
104                 psHeapInfo[i].ui32HeapID = (u32) PVRSRV_UNDEFINED_HEAP_ID;
105         }
106
107         return PVRSRV_OK;
108 }
109
110 enum PVRSRV_ERROR PVRSRVCreateDeviceMemContextKM(void *hDevCookie,
111                              struct PVRSRV_PER_PROCESS_DATA *psPerProc,
112                              void **phDevMemContext,
113                              u32 *pui32ClientHeapCount,
114                              struct PVRSRV_HEAP_INFO *psHeapInfo,
115                              IMG_BOOL *pbCreated, IMG_BOOL *pbShared)
116 {
117         struct PVRSRV_DEVICE_NODE *psDeviceNode;
118         u32 ui32HeapCount, ui32ClientHeapCount = 0;
119         struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
120         void *hDevMemContext;
121         void *hDevMemHeap;
122         struct IMG_DEV_PHYADDR sPDDevPAddr;
123         u32 i;
124
125         if (hDevCookie == NULL) {
126                 PVR_DPF(PVR_DBG_ERROR,
127                          "PVRSRVCreateDeviceMemContextKM: hDevCookie invalid");
128                 PVR_DBG_BREAK;
129                 return PVRSRV_ERROR_INVALID_PARAMS;
130         }
131
132         psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
133
134         ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
135         psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
136
137         PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
138
139         hDevMemContext = BM_CreateContext(psDeviceNode,
140                                           &sPDDevPAddr, psPerProc, pbCreated);
141         if (hDevMemContext == NULL) {
142                 PVR_DPF(PVR_DBG_ERROR,
143                 "PVRSRVCreateDeviceMemContextKM: Failed BM_CreateContext");
144                 return PVRSRV_ERROR_OUT_OF_MEMORY;
145         }
146
147         for (i = 0; i < ui32HeapCount; i++) {
148                 switch (psDeviceMemoryHeap[i].DevMemHeapType) {
149                 case DEVICE_MEMORY_HEAP_SHARED_EXPORTED:
150                         psHeapInfo[ui32ClientHeapCount].ui32HeapID =
151                                     psDeviceMemoryHeap[i].ui32HeapID;
152                         psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
153                                     psDeviceMemoryHeap[i].hDevMemHeap;
154                         psHeapInfo[ui32ClientHeapCount].sDevVAddrBase =
155                                     psDeviceMemoryHeap[i].sDevVAddrBase;
156                         psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize =
157                                     psDeviceMemoryHeap[i].ui32HeapSize;
158                         psHeapInfo[ui32ClientHeapCount].ui32Attribs =
159                                     psDeviceMemoryHeap[i].ui32Attribs;
160                         pbShared[ui32ClientHeapCount] = IMG_TRUE;
161                         ui32ClientHeapCount++;
162                         break;
163                 case DEVICE_MEMORY_HEAP_PERCONTEXT:
164                         hDevMemHeap = BM_CreateHeap(hDevMemContext,
165                                                     &psDeviceMemoryHeap[i]);
166
167                         psHeapInfo[ui32ClientHeapCount].ui32HeapID =
168                                     psDeviceMemoryHeap[i].ui32HeapID;
169                         psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
170                                     hDevMemHeap;
171                         psHeapInfo[ui32ClientHeapCount].sDevVAddrBase =
172                                     psDeviceMemoryHeap[i].sDevVAddrBase;
173                         psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize =
174                                     psDeviceMemoryHeap[i].ui32HeapSize;
175                         psHeapInfo[ui32ClientHeapCount].ui32Attribs =
176                                     psDeviceMemoryHeap[i].ui32Attribs;
177                         pbShared[ui32ClientHeapCount] = IMG_FALSE;
178
179                         ui32ClientHeapCount++;
180                         break;
181                 }
182         }
183
184         *pui32ClientHeapCount = ui32ClientHeapCount;
185         *phDevMemContext = hDevMemContext;
186
187         return PVRSRV_OK;
188 }
189
190 enum PVRSRV_ERROR PVRSRVDestroyDeviceMemContextKM(void *hDevCookie,
191                                              void *hDevMemContext)
192 {
193         PVR_UNREFERENCED_PARAMETER(hDevCookie);
194
195         pvr_put_ctx(hDevMemContext);
196
197         return PVRSRV_OK;
198 }
199
200 enum PVRSRV_ERROR PVRSRVGetDeviceMemHeapInfoKM(void *hDevCookie,
201                                           void *hDevMemContext,
202                                           u32 *pui32ClientHeapCount,
203                                           struct PVRSRV_HEAP_INFO *psHeapInfo,
204                                           IMG_BOOL *pbShared)
205 {
206         struct PVRSRV_DEVICE_NODE *psDeviceNode;
207         u32 ui32HeapCount, ui32ClientHeapCount = 0;
208         struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
209         void *hDevMemHeap;
210         u32 i;
211
212         if (hDevCookie == NULL) {
213                 PVR_DPF(PVR_DBG_ERROR,
214                          "PVRSRVGetDeviceMemHeapInfoKM: hDevCookie invalid");
215                 PVR_DBG_BREAK;
216                 return PVRSRV_ERROR_INVALID_PARAMS;
217         }
218
219         psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
220
221         ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
222         psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
223
224         PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
225
226         for (i = 0; i < ui32HeapCount; i++) {
227                 switch (psDeviceMemoryHeap[i].DevMemHeapType) {
228                 case DEVICE_MEMORY_HEAP_SHARED_EXPORTED:
229                         psHeapInfo[ui32ClientHeapCount].ui32HeapID =
230                                     psDeviceMemoryHeap[i].ui32HeapID;
231                         psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
232                                     psDeviceMemoryHeap[i].hDevMemHeap;
233                         psHeapInfo[ui32ClientHeapCount].sDevVAddrBase =
234                                     psDeviceMemoryHeap[i].sDevVAddrBase;
235                         psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize =
236                                     psDeviceMemoryHeap[i].ui32HeapSize;
237                         psHeapInfo[ui32ClientHeapCount].ui32Attribs =
238                                     psDeviceMemoryHeap[i].ui32Attribs;
239                         pbShared[ui32ClientHeapCount] = IMG_TRUE;
240                         ui32ClientHeapCount++;
241                         break;
242                 case DEVICE_MEMORY_HEAP_PERCONTEXT:
243                         hDevMemHeap = BM_CreateHeap(hDevMemContext,
244                                                     &psDeviceMemoryHeap[i]);
245                         psHeapInfo[ui32ClientHeapCount].ui32HeapID =
246                                     psDeviceMemoryHeap[i].ui32HeapID;
247                         psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
248                                     hDevMemHeap;
249                         psHeapInfo[ui32ClientHeapCount].sDevVAddrBase =
250                                     psDeviceMemoryHeap[i].sDevVAddrBase;
251                         psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize =
252                                     psDeviceMemoryHeap[i].ui32HeapSize;
253                         psHeapInfo[ui32ClientHeapCount].ui32Attribs =
254                                     psDeviceMemoryHeap[i].ui32Attribs;
255                         pbShared[ui32ClientHeapCount] = IMG_FALSE;
256
257                         ui32ClientHeapCount++;
258                         break;
259                 }
260         }
261         *pui32ClientHeapCount = ui32ClientHeapCount;
262
263         return PVRSRV_OK;
264 }
265
266 static enum PVRSRV_ERROR AllocDeviceMem(void *hDevCookie, void *hDevMemHeap,
267                                    u32 ui32Flags, u32 ui32Size,
268                                    u32 ui32Alignment,
269                                    struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
270 {
271         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
272         void *hBuffer;
273
274         struct PVRSRV_MEMBLK *psMemBlock;
275         IMG_BOOL bBMError;
276
277         PVR_UNREFERENCED_PARAMETER(hDevCookie);
278
279         *ppsMemInfo = NULL;
280
281         if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
282                        sizeof(struct PVRSRV_KERNEL_MEM_INFO),
283                        (void **) &psMemInfo, NULL) != PVRSRV_OK) {
284                 PVR_DPF(PVR_DBG_ERROR,
285                          "AllocDeviceMem: Failed to alloc memory for block");
286                 return PVRSRV_ERROR_OUT_OF_MEMORY;
287         }
288
289         OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
290
291         psMemBlock = &(psMemInfo->sMemBlk);
292
293         psMemInfo->ui32Flags = ui32Flags | PVRSRV_MEM_RAM_BACKED_ALLOCATION;
294
295         bBMError = BM_Alloc(hDevMemHeap, NULL, ui32Size,
296                             &psMemInfo->ui32Flags, ui32Alignment, &hBuffer);
297
298         if (!bBMError) {
299                 PVR_DPF(PVR_DBG_ERROR, "AllocDeviceMem: BM_Alloc Failed");
300                 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
301                           sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
302                           NULL);
303                 return PVRSRV_ERROR_OUT_OF_MEMORY;
304         }
305
306         psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
307         psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
308
309         psMemBlock->hBuffer = (void *)hBuffer;
310         psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
311         psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
312         psMemInfo->ui32AllocSize = ui32Size;
313
314         psMemInfo->pvSysBackupBuffer = NULL;
315
316         *ppsMemInfo = psMemInfo;
317
318         return PVRSRV_OK;
319 }
320
321 static enum PVRSRV_ERROR FreeDeviceMem(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
322 {
323         void *hBuffer;
324
325         if (!psMemInfo)
326                 return PVRSRV_ERROR_INVALID_PARAMS;
327
328         hBuffer = psMemInfo->sMemBlk.hBuffer;
329         BM_Free(hBuffer, psMemInfo->ui32Flags);
330
331         if (psMemInfo->pvSysBackupBuffer)
332                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, psMemInfo->ui32AllocSize,
333                           psMemInfo->pvSysBackupBuffer, NULL);
334
335         OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct PVRSRV_KERNEL_MEM_INFO),
336                   psMemInfo, NULL);
337
338         return PVRSRV_OK;
339 }
340
341 enum PVRSRV_ERROR PVRSRVAllocSyncInfoKM(void *hDevCookie, void *hDevMemContext,
342                     struct PVRSRV_KERNEL_SYNC_INFO **ppsKernelSyncInfo)
343 {
344         void *hSyncDevMemHeap;
345         struct DEVICE_MEMORY_INFO *psDevMemoryInfo;
346         struct BM_CONTEXT *pBMContext;
347         enum PVRSRV_ERROR eError;
348         struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo;
349         struct PVRSRV_SYNC_DATA *psSyncData;
350
351         eError = OSAllocMem(PVRSRV_PAGEABLE_SELECT,
352                             sizeof(struct PVRSRV_KERNEL_SYNC_INFO),
353                             (void **) &psKernelSyncInfo, NULL);
354         if (eError != PVRSRV_OK) {
355                 PVR_DPF(PVR_DBG_ERROR,
356                          "PVRSRVAllocSyncInfoKM: Failed to alloc memory");
357                 return PVRSRV_ERROR_OUT_OF_MEMORY;
358         }
359
360         pBMContext = (struct BM_CONTEXT *)hDevMemContext;
361         psDevMemoryInfo = &pBMContext->psDeviceNode->sDevMemoryInfo;
362
363         hSyncDevMemHeap = psDevMemoryInfo->psDeviceMemoryHeap[psDevMemoryInfo->
364                                                 ui32SyncHeapID].hDevMemHeap;
365
366         eError = AllocDeviceMem(hDevCookie, hSyncDevMemHeap,
367                                 PVRSRV_MEM_CACHE_CONSISTENT,
368                                 sizeof(struct PVRSRV_SYNC_DATA), sizeof(u32),
369                                 &psKernelSyncInfo->psSyncDataMemInfoKM);
370
371         if (eError != PVRSRV_OK) {
372                 PVR_DPF(PVR_DBG_ERROR,
373                          "PVRSRVAllocSyncInfoKM: Failed to alloc memory");
374                 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
375                           sizeof(struct PVRSRV_KERNEL_SYNC_INFO),
376                           psKernelSyncInfo, NULL);
377                 return PVRSRV_ERROR_OUT_OF_MEMORY;
378         }
379
380         psKernelSyncInfo->psSyncData =
381             psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM;
382         psSyncData = psKernelSyncInfo->psSyncData;
383
384         psSyncData->ui32WriteOpsPending = 0;
385         psSyncData->ui32WriteOpsComplete = 0;
386         psSyncData->ui32ReadOpsPending = 0;
387         psSyncData->ui32ReadOpsComplete = 0;
388         psSyncData->ui32LastOpDumpVal = 0;
389         psSyncData->ui32LastReadOpDumpVal = 0;
390
391 #if defined(PDUMP)
392         PDUMPMEM(psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM,
393                  psKernelSyncInfo->psSyncDataMemInfoKM, 0,
394                  psKernelSyncInfo->psSyncDataMemInfoKM->ui32AllocSize,
395                  0, MAKEUNIQUETAG(psKernelSyncInfo->psSyncDataMemInfoKM));
396 #endif
397
398         psKernelSyncInfo->sWriteOpsCompleteDevVAddr.uiAddr =
399             psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr +
400             offsetof(struct PVRSRV_SYNC_DATA, ui32WriteOpsComplete);
401         psKernelSyncInfo->sReadOpsCompleteDevVAddr.uiAddr =
402             psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr +
403             offsetof(struct PVRSRV_SYNC_DATA, ui32ReadOpsComplete);
404
405         psKernelSyncInfo->psSyncDataMemInfoKM->psKernelSyncInfo = NULL;
406
407         *ppsKernelSyncInfo = psKernelSyncInfo;
408
409         return PVRSRV_OK;
410 }
411
412 enum PVRSRV_ERROR PVRSRVFreeSyncInfoKM(
413                         struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo)
414 {
415         FreeDeviceMem(psKernelSyncInfo->psSyncDataMemInfoKM);
416         OSFreeMem(PVRSRV_PAGEABLE_SELECT,
417                   sizeof(struct PVRSRV_KERNEL_SYNC_INFO), psKernelSyncInfo,
418                   NULL);
419
420         return PVRSRV_OK;
421 }
422
423 static inline
424 void get_syncinfo(struct PVRSRV_KERNEL_SYNC_INFO *syncinfo)
425 {
426         syncinfo->refcount++;
427 }
428
429 static inline
430 void put_syncinfo(struct PVRSRV_KERNEL_SYNC_INFO *syncinfo)
431 {
432         struct PVRSRV_DEVICE_NODE *dev = syncinfo->dev_cookie;
433
434         syncinfo->refcount--;
435
436         if (!syncinfo->refcount) {
437                 HASH_Remove(dev->sync_table,
438                             syncinfo->phys_addr.uiAddr);
439                 PVRSRVFreeSyncInfoKM(syncinfo);
440         }
441 }
442
443 static inline
444 enum PVRSRV_ERROR alloc_or_reuse_syncinfo(void *dev_cookie,
445                     void *mem_context_handle,
446                     struct PVRSRV_KERNEL_SYNC_INFO **syncinfo,
447                     struct IMG_SYS_PHYADDR *phys_addr)
448 {
449         enum PVRSRV_ERROR error;
450         struct PVRSRV_DEVICE_NODE *dev;
451
452         dev = (struct PVRSRV_DEVICE_NODE *) dev_cookie;
453
454         *syncinfo = (struct PVRSRV_KERNEL_SYNC_INFO *)
455                                         HASH_Retrieve(dev->sync_table,
456                                                       phys_addr->uiAddr);
457
458         if (!*syncinfo) {
459                 /* Dont' have one so create one */
460                 error = PVRSRVAllocSyncInfoKM(dev_cookie, mem_context_handle,
461                                                syncinfo);
462
463                 if (error != PVRSRV_OK)
464                         return error;
465
466                 /* Setup our extra data */
467                 (*syncinfo)->phys_addr.uiAddr = phys_addr->uiAddr;
468                 (*syncinfo)->dev_cookie = dev_cookie;
469                 (*syncinfo)->refcount = 1;
470
471                 if (!HASH_Insert(dev->sync_table, phys_addr->uiAddr,
472                             (u32) *syncinfo)) {
473                         PVR_DPF(PVR_DBG_ERROR, "alloc_or_reuse_syncinfo: "
474                                 "Failed to add syncobject to hash table");
475                         return PVRSRV_ERROR_GENERIC;
476                 }
477         } else
478                 get_syncinfo(*syncinfo);
479
480         return PVRSRV_OK;
481 }
482
483 static enum PVRSRV_ERROR FreeDeviceMemCallBack(void *pvParam, u32 ui32Param)
484 {
485         enum PVRSRV_ERROR eError = PVRSRV_OK;
486         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam;
487
488         PVR_UNREFERENCED_PARAMETER(ui32Param);
489
490         psMemInfo->ui32RefCount--;
491
492         if (psMemInfo->ui32Flags & PVRSRV_MEM_EXPORTED) {
493                 void *hMemInfo = NULL;
494
495                 if (psMemInfo->ui32RefCount != 0) {
496                         PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: "
497                                         "mappings are open in other processes");
498                         return PVRSRV_ERROR_GENERIC;
499                 }
500
501                 eError = PVRSRVFindHandle(KERNEL_HANDLE_BASE,
502                                           &hMemInfo,
503                                           psMemInfo,
504                                           PVRSRV_HANDLE_TYPE_MEM_INFO);
505                 if (eError != PVRSRV_OK) {
506                         PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: "
507                                 "can't find exported meminfo in the "
508                                 "global handle list");
509                         return eError;
510                 }
511
512                 eError = PVRSRVReleaseHandle(KERNEL_HANDLE_BASE,
513                                              hMemInfo,
514                                              PVRSRV_HANDLE_TYPE_MEM_INFO);
515                 if (eError != PVRSRV_OK) {
516                         PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: "
517                         "PVRSRVReleaseHandle failed for exported meminfo");
518                         return eError;
519                 }
520         }
521
522         PVR_ASSERT(psMemInfo->ui32RefCount == 0);
523
524         if (psMemInfo->psKernelSyncInfo)
525                 eError = PVRSRVFreeSyncInfoKM(psMemInfo->psKernelSyncInfo);
526
527         if (eError == PVRSRV_OK)
528                 eError = FreeDeviceMem(psMemInfo);
529
530         return eError;
531 }
532
533 enum PVRSRV_ERROR PVRSRVFreeDeviceMemKM(void *hDevCookie,
534                                    struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
535 {
536         PVR_UNREFERENCED_PARAMETER(hDevCookie);
537
538         if (!psMemInfo)
539                 return PVRSRV_ERROR_INVALID_PARAMS;
540
541         if (psMemInfo->sMemBlk.hResItem != NULL)
542                 ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
543         else
544                 FreeDeviceMemCallBack(psMemInfo, 0);
545
546         return PVRSRV_OK;
547 }
548
549 enum PVRSRV_ERROR PVRSRVAllocDeviceMemKM(void *hDevCookie,
550                                      struct PVRSRV_PER_PROCESS_DATA *psPerProc,
551                                      void *hDevMemHeap, u32 ui32Flags,
552                                      u32 ui32Size, u32 ui32Alignment,
553                                      struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
554 {
555         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
556         enum PVRSRV_ERROR eError;
557         struct BM_HEAP *psBMHeap;
558         void *hDevMemContext;
559
560         if (!hDevMemHeap || (ui32Size == 0))
561                 return PVRSRV_ERROR_INVALID_PARAMS;
562
563         eError = AllocDeviceMem(hDevCookie, hDevMemHeap, ui32Flags, ui32Size,
564                                 ui32Alignment, &psMemInfo);
565
566         if (eError != PVRSRV_OK)
567                 return eError;
568
569         if (ui32Flags & PVRSRV_MEM_NO_SYNCOBJ) {
570                 psMemInfo->psKernelSyncInfo = NULL;
571         } else {
572                 psBMHeap = (struct BM_HEAP *)hDevMemHeap;
573                 hDevMemContext = (void *) psBMHeap->pBMContext;
574                 eError = PVRSRVAllocSyncInfoKM(hDevCookie,
575                                                hDevMemContext,
576                                                &psMemInfo->psKernelSyncInfo);
577                 if (eError != PVRSRV_OK)
578                         goto free_mainalloc;
579         }
580
581         *ppsMemInfo = psMemInfo;
582
583         if (ui32Flags & PVRSRV_MEM_NO_RESMAN) {
584                 psMemInfo->sMemBlk.hResItem = NULL;
585         } else {
586                 psMemInfo->sMemBlk.hResItem =
587                     ResManRegisterRes(psPerProc->hResManContext,
588                                       RESMAN_TYPE_DEVICEMEM_ALLOCATION,
589                                       psMemInfo, 0, FreeDeviceMemCallBack);
590                 if (psMemInfo->sMemBlk.hResItem == NULL) {
591                         eError = PVRSRV_ERROR_OUT_OF_MEMORY;
592                         goto free_mainalloc;
593                 }
594         }
595
596         psMemInfo->ui32RefCount++;
597
598         return PVRSRV_OK;
599
600 free_mainalloc:
601         FreeDeviceMem(psMemInfo);
602
603         return eError;
604 }
605
606 enum PVRSRV_ERROR PVRSRVDissociateDeviceMemKM(void *hDevCookie,
607                                   struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
608 {
609         enum PVRSRV_ERROR eError;
610         struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevCookie;
611
612         PVR_UNREFERENCED_PARAMETER(hDevCookie);
613
614         if (!psMemInfo)
615                 return PVRSRV_ERROR_INVALID_PARAMS;
616
617         eError = ResManDissociateRes(psMemInfo->sMemBlk.hResItem,
618                                     psDeviceNode->hResManContext);
619
620         PVR_ASSERT(eError == PVRSRV_OK);
621
622         return eError;
623 }
624
625 enum PVRSRV_ERROR PVRSRVGetFreeDeviceMemKM(u32 ui32Flags, u32 *pui32Total,
626                                       u32 *pui32Free, u32 *pui32LargestBlock)
627 {
628
629         PVR_UNREFERENCED_PARAMETER(ui32Flags);
630         PVR_UNREFERENCED_PARAMETER(pui32Total);
631         PVR_UNREFERENCED_PARAMETER(pui32Free);
632         PVR_UNREFERENCED_PARAMETER(pui32LargestBlock);
633
634         return PVRSRV_OK;
635 }
636
637 enum PVRSRV_ERROR PVRSRVUnwrapExtMemoryKM(
638                 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
639 {
640         if (!psMemInfo)
641                 return PVRSRV_ERROR_INVALID_PARAMS;
642
643         ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
644
645         return PVRSRV_OK;
646 }
647
648 static enum PVRSRV_ERROR UnwrapExtMemoryCallBack(void *pvParam, u32 ui32Param)
649 {
650         enum PVRSRV_ERROR eError = PVRSRV_OK;
651         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam;
652         void *hOSWrapMem;
653
654         PVR_UNREFERENCED_PARAMETER(ui32Param);
655
656         hOSWrapMem = psMemInfo->sMemBlk.hOSWrapMem;
657
658         if (psMemInfo->psKernelSyncInfo)
659                 put_syncinfo(psMemInfo->psKernelSyncInfo);
660
661         if (psMemInfo->sMemBlk.psIntSysPAddr) {
662                 int page_count;
663
664                 page_count = get_page_count((u32)psMemInfo->pvLinAddrKM,
665                                 psMemInfo->ui32AllocSize);
666
667                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
668                           page_count * sizeof(struct IMG_SYS_PHYADDR),
669                           psMemInfo->sMemBlk.psIntSysPAddr, NULL);
670         }
671
672         if (eError == PVRSRV_OK) {
673                 psMemInfo->ui32RefCount--;
674                 eError = FreeDeviceMem(psMemInfo);
675         }
676
677         if (hOSWrapMem)
678                 OSReleasePhysPageAddr(hOSWrapMem);
679
680         return eError;
681 }
682
683 enum PVRSRV_ERROR PVRSRVWrapExtMemoryKM(void *hDevCookie,
684                             struct PVRSRV_PER_PROCESS_DATA *psPerProc,
685                             void *hDevMemContext, u32 ui32ByteSize,
686                             u32 ui32PageOffset, IMG_BOOL bPhysContig,
687                             struct IMG_SYS_PHYADDR *psExtSysPAddr,
688                             void *pvLinAddr,
689                             struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
690 {
691         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = NULL;
692         struct DEVICE_MEMORY_INFO *psDevMemoryInfo;
693         u32 ui32HostPageSize = HOST_PAGESIZE();
694         void *hDevMemHeap = NULL;
695         struct PVRSRV_DEVICE_NODE *psDeviceNode;
696         void *hBuffer;
697         struct PVRSRV_MEMBLK *psMemBlock;
698         IMG_BOOL bBMError;
699         struct BM_HEAP *psBMHeap;
700         enum PVRSRV_ERROR eError;
701         void *pvPageAlignedCPUVAddr;
702         struct IMG_SYS_PHYADDR *psIntSysPAddr = NULL;
703         void *hOSWrapMem = NULL;
704         struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
705         int page_count = 0;
706         u32 i;
707
708         psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
709         PVR_ASSERT(psDeviceNode != NULL);
710
711         if (!psDeviceNode || (!pvLinAddr && !psExtSysPAddr)) {
712                 PVR_DPF(PVR_DBG_ERROR,
713                          "PVRSRVWrapExtMemoryKM: invalid parameter");
714                 return PVRSRV_ERROR_INVALID_PARAMS;
715         }
716
717         if (pvLinAddr) {
718                 get_page_details((u32)pvLinAddr, ui32ByteSize,
719                                 &ui32PageOffset, &page_count);
720                 pvPageAlignedCPUVAddr = (void *)((u8 *) pvLinAddr -
721                                         ui32PageOffset);
722
723                 if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
724                                page_count * sizeof(struct IMG_SYS_PHYADDR),
725                                (void **)&psIntSysPAddr, NULL) != PVRSRV_OK) {
726                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM: "
727                                         "Failed to alloc memory for block");
728                         return PVRSRV_ERROR_OUT_OF_MEMORY;
729                 }
730
731                 eError = OSAcquirePhysPageAddr(pvPageAlignedCPUVAddr,
732                                        page_count * ui32HostPageSize,
733                                        psIntSysPAddr, &hOSWrapMem);
734                 if (eError != PVRSRV_OK) {
735                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM:"
736                                    " Failed to alloc memory for block");
737                                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
738                                 goto ErrorExitPhase1;
739                 }
740                 psExtSysPAddr = psIntSysPAddr;
741                 bPhysContig = IMG_FALSE;
742         }
743
744         psDevMemoryInfo =
745             &((struct BM_CONTEXT *)hDevMemContext)->psDeviceNode->
746                                                             sDevMemoryInfo;
747         psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap;
748         for (i = 0; i < PVRSRV_MAX_CLIENT_HEAPS; i++) {
749                 if (HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) ==
750                     psDevMemoryInfo->ui32MappingHeapID) {
751                         if (psDeviceMemoryHeap[i].DevMemHeapType ==
752                             DEVICE_MEMORY_HEAP_PERCONTEXT) {
753                                 hDevMemHeap =
754                                     BM_CreateHeap(hDevMemContext,
755                                                   &psDeviceMemoryHeap[i]);
756                         } else {
757                                 hDevMemHeap =
758                                     psDevMemoryInfo->psDeviceMemoryHeap[i].
759                                     hDevMemHeap;
760                         }
761                         break;
762                 }
763         }
764
765         if (hDevMemHeap == NULL) {
766                 PVR_DPF(PVR_DBG_ERROR,
767                          "PVRSRVWrapExtMemoryKM: unable to find mapping heap");
768                 eError = PVRSRV_ERROR_GENERIC;
769                 goto ErrorExitPhase2;
770         }
771
772         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
773                        sizeof(struct PVRSRV_KERNEL_MEM_INFO),
774                        (void **) &psMemInfo, NULL) != PVRSRV_OK) {
775                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM: "
776                                         "Failed to alloc memory for block");
777                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
778                 goto ErrorExitPhase2;
779         }
780
781         OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
782         psMemBlock = &(psMemInfo->sMemBlk);
783
784         bBMError = BM_Wrap(hDevMemHeap,
785                            ui32ByteSize,
786                            ui32PageOffset,
787                            bPhysContig,
788                            psExtSysPAddr,
789                            NULL, &psMemInfo->ui32Flags, &hBuffer);
790         if (!bBMError) {
791                 PVR_DPF(PVR_DBG_ERROR,
792                          "PVRSRVWrapExtMemoryKM: BM_Wrap Failed");
793                 eError = PVRSRV_ERROR_BAD_MAPPING;
794                 goto ErrorExitPhase3;
795         }
796
797         psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
798         psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
799         psMemBlock->hOSWrapMem = hOSWrapMem;
800         psMemBlock->psIntSysPAddr = psIntSysPAddr;
801
802         psMemBlock->hBuffer = (void *) hBuffer;
803
804         psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
805         psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
806         psMemInfo->ui32AllocSize = ui32ByteSize;
807
808         psMemInfo->pvSysBackupBuffer = NULL;
809
810         psBMHeap = (struct BM_HEAP *)hDevMemHeap;
811         hDevMemContext = (void *) psBMHeap->pBMContext;
812         eError = alloc_or_reuse_syncinfo(hDevCookie,
813                                          hDevMemContext,
814                                          &psMemInfo->psKernelSyncInfo,
815                                          psExtSysPAddr);
816         if (eError != PVRSRV_OK)
817                 goto ErrorExitPhase4;
818
819         psMemInfo->ui32RefCount++;
820
821         psMemInfo->sMemBlk.hResItem =
822             ResManRegisterRes(psPerProc->hResManContext,
823                               RESMAN_TYPE_DEVICEMEM_WRAP, psMemInfo, 0,
824                               UnwrapExtMemoryCallBack);
825
826         *ppsMemInfo = psMemInfo;
827
828         return PVRSRV_OK;
829
830 ErrorExitPhase4:
831         FreeDeviceMem(psMemInfo);
832         psMemInfo = NULL;
833
834 ErrorExitPhase3:
835         if (psMemInfo) {
836                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
837                           sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
838                           NULL);
839         }
840
841 ErrorExitPhase2:
842         if (hOSWrapMem)
843                 OSReleasePhysPageAddr(hOSWrapMem);
844
845 ErrorExitPhase1:
846         if (psIntSysPAddr) {
847                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
848                           page_count * sizeof(struct IMG_SYS_PHYADDR),
849                           psIntSysPAddr, NULL);
850         }
851
852         return eError;
853 }
854
855 enum PVRSRV_ERROR PVRSRVUnmapDeviceMemoryKM(
856                 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
857 {
858         if (!psMemInfo)
859                 return PVRSRV_ERROR_INVALID_PARAMS;
860
861         ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
862
863         return PVRSRV_OK;
864 }
865
866 static enum PVRSRV_ERROR UnmapDeviceMemoryCallBack(void *pvParam, u32 ui32Param)
867 {
868         enum PVRSRV_ERROR eError;
869         struct RESMAN_MAP_DEVICE_MEM_DATA *psMapData = pvParam;
870         int page_count;
871
872         PVR_UNREFERENCED_PARAMETER(ui32Param);
873
874         page_count = get_page_count((u32)psMapData->psMemInfo->pvLinAddrKM,
875                                 psMapData->psMemInfo->ui32AllocSize);
876
877         if (psMapData->psMemInfo->sMemBlk.psIntSysPAddr)
878                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
879                           page_count * sizeof(struct IMG_SYS_PHYADDR),
880                           psMapData->psMemInfo->sMemBlk.psIntSysPAddr, NULL);
881
882         eError = FreeDeviceMem(psMapData->psMemInfo);
883         if (eError != PVRSRV_OK) {
884                 PVR_DPF(PVR_DBG_ERROR, "UnmapDeviceMemoryCallBack: "
885                                 "Failed to free DST meminfo");
886                 return eError;
887         }
888
889         psMapData->psSrcMemInfo->ui32RefCount--;
890
891         PVR_ASSERT(psMapData->psSrcMemInfo->ui32RefCount != (u32) (-1));
892 /*
893  * Don't free the source MemInfo as we didn't allocate it
894  * and it's not our job as the process the allocated
895  * should also free it when it's finished
896  */
897         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
898                   sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), psMapData, NULL);
899
900         return eError;
901 }
902
903 static inline int bm_is_continuous(const struct BM_BUF *buf)
904 {
905         return buf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr;
906 }
907
908 enum PVRSRV_ERROR PVRSRVMapDeviceMemoryKM(
909                 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
910                               struct PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo,
911                               void *hDstDevMemHeap,
912                               struct PVRSRV_KERNEL_MEM_INFO **ppsDstMemInfo)
913 {
914         enum PVRSRV_ERROR eError;
915         u32 ui32PageOffset;
916         u32 ui32HostPageSize = HOST_PAGESIZE();
917         int page_count;
918         int i;
919         struct IMG_SYS_PHYADDR *psSysPAddr = NULL;
920         struct IMG_DEV_PHYADDR sDevPAddr;
921         struct BM_BUF *psBuf;
922         struct IMG_DEV_VIRTADDR sDevVAddr;
923         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = NULL;
924         void *hBuffer;
925         struct PVRSRV_MEMBLK *psMemBlock;
926         IMG_BOOL bBMError;
927         struct PVRSRV_DEVICE_NODE *psDeviceNode;
928         void *pvPageAlignedCPUVAddr;
929         struct RESMAN_MAP_DEVICE_MEM_DATA *psMapData = NULL;
930
931         if (!psSrcMemInfo || !hDstDevMemHeap || !ppsDstMemInfo) {
932                 PVR_DPF(PVR_DBG_ERROR,
933                          "PVRSRVMapDeviceMemoryKM: invalid parameters");
934                 return PVRSRV_ERROR_INVALID_PARAMS;
935         }
936
937         *ppsDstMemInfo = NULL;
938
939         get_page_details((u32)psSrcMemInfo->pvLinAddrKM,
940                         psSrcMemInfo->ui32AllocSize,
941                         &ui32PageOffset, &page_count);
942         pvPageAlignedCPUVAddr =
943             (void *) ((u8 *) psSrcMemInfo->pvLinAddrKM -
944                           ui32PageOffset);
945
946         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
947                        page_count * sizeof(struct IMG_SYS_PHYADDR),
948                        (void **) &psSysPAddr, NULL) != PVRSRV_OK) {
949                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
950                                         "Failed to alloc memory for block");
951                 return PVRSRV_ERROR_OUT_OF_MEMORY;
952         }
953
954         psBuf = psSrcMemInfo->sMemBlk.hBuffer;
955
956         psDeviceNode = psBuf->pMapping->pBMHeap->pBMContext->psDeviceNode;
957
958         sDevVAddr.uiAddr = psSrcMemInfo->sDevVAddr.uiAddr - ui32PageOffset;
959         for (i = 0; i < page_count; i++) {
960                 eError =
961                     BM_GetPhysPageAddr(psSrcMemInfo, sDevVAddr, &sDevPAddr);
962                 if (eError != PVRSRV_OK) {
963                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
964                                 "Failed to retrieve page list from device");
965                         goto ErrorExit;
966                 }
967
968                 psSysPAddr[i] =
969                     SysDevPAddrToSysPAddr(psDeviceNode->sDevId.eDeviceType,
970                                           sDevPAddr);
971
972                 sDevVAddr.uiAddr += ui32HostPageSize;
973         }
974
975         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
976                        sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA),
977                        (void **)&psMapData, NULL) != PVRSRV_OK) {
978                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
979                                 "Failed to alloc resman map data");
980                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
981                 goto ErrorExit;
982         }
983
984         if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
985                        sizeof(struct PVRSRV_KERNEL_MEM_INFO),
986                        (void **)&psMemInfo, NULL) != PVRSRV_OK) {
987                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
988                                 "Failed to alloc memory for block");
989                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
990                 goto ErrorExit;
991         }
992
993         OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
994
995         psMemBlock = &(psMemInfo->sMemBlk);
996
997         bBMError = BM_Wrap(hDstDevMemHeap, psSrcMemInfo->ui32AllocSize,
998                            ui32PageOffset, bm_is_continuous(psBuf), psSysPAddr,
999                            pvPageAlignedCPUVAddr, &psMemInfo->ui32Flags,
1000                            &hBuffer);
1001
1002         if (!bBMError) {
1003                 PVR_DPF(PVR_DBG_ERROR,
1004                          "PVRSRVMapDeviceMemoryKM: BM_Wrap Failed");
1005                 eError = PVRSRV_ERROR_BAD_MAPPING;
1006                 goto ErrorExit;
1007         }
1008
1009         psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
1010         psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
1011
1012         psMemBlock->hBuffer = (void *) hBuffer;
1013
1014         psMemBlock->psIntSysPAddr = psSysPAddr;
1015
1016         psMemInfo->pvLinAddrKM = psSrcMemInfo->pvLinAddrKM;
1017
1018         psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
1019         psMemInfo->ui32AllocSize = psSrcMemInfo->ui32AllocSize;
1020         psMemInfo->psKernelSyncInfo = psSrcMemInfo->psKernelSyncInfo;
1021
1022         psMemInfo->pvSysBackupBuffer = NULL;
1023
1024         psSrcMemInfo->ui32RefCount++;
1025
1026         psMapData->psMemInfo = psMemInfo;
1027         psMapData->psSrcMemInfo = psSrcMemInfo;
1028
1029         psMemInfo->sMemBlk.hResItem =
1030             ResManRegisterRes(psPerProc->hResManContext,
1031                               RESMAN_TYPE_DEVICEMEM_MAPPING, psMapData, 0,
1032                               UnmapDeviceMemoryCallBack);
1033
1034         *ppsDstMemInfo = psMemInfo;
1035
1036         return PVRSRV_OK;
1037
1038 ErrorExit:
1039
1040         if (psSysPAddr) {
1041                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
1042                           sizeof(struct IMG_SYS_PHYADDR), psSysPAddr, NULL);
1043         }
1044
1045         if (psMemInfo) {
1046                 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
1047                           sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
1048                           NULL);
1049         }
1050
1051         if (psMapData) {
1052                 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
1053                           sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), psMapData,
1054                           NULL);
1055         }
1056
1057         return eError;
1058 }
1059
1060 enum PVRSRV_ERROR PVRSRVUnmapDeviceClassMemoryKM(
1061                                 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
1062 {
1063         if (!psMemInfo)
1064                 return PVRSRV_ERROR_INVALID_PARAMS;
1065
1066         ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
1067
1068         return PVRSRV_OK;
1069 }
1070
1071 static enum PVRSRV_ERROR UnmapDeviceClassMemoryCallBack(void *pvParam,
1072                                                         u32 ui32Param)
1073 {
1074         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam;
1075
1076         PVR_UNREFERENCED_PARAMETER(ui32Param);
1077
1078         return FreeDeviceMem(psMemInfo);
1079 }
1080
1081 enum PVRSRV_ERROR PVRSRVMapDeviceClassMemoryKM(
1082                                 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
1083                                 void *hDevMemContext, void *hDeviceClassBuffer,
1084                                 struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo,
1085                                 void **phOSMapInfo)
1086 {
1087         enum PVRSRV_ERROR eError;
1088         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
1089         struct PVRSRV_DEVICECLASS_BUFFER *psDeviceClassBuffer;
1090         struct IMG_SYS_PHYADDR *psSysPAddr;
1091         void *pvCPUVAddr, *pvPageAlignedCPUVAddr;
1092         IMG_BOOL bPhysContig;
1093         struct BM_CONTEXT *psBMContext;
1094         struct DEVICE_MEMORY_INFO *psDevMemoryInfo;
1095         struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
1096         void *hDevMemHeap = NULL;
1097         u32 ui32ByteSize;
1098         u32 ui32Offset;
1099         u32 ui32PageSize = HOST_PAGESIZE();
1100         void *hBuffer;
1101         struct PVRSRV_MEMBLK *psMemBlock;
1102         IMG_BOOL bBMError;
1103         u32 i;
1104
1105         if (!hDeviceClassBuffer || !ppsMemInfo || !phOSMapInfo ||
1106             !hDevMemContext) {
1107                 PVR_DPF(PVR_DBG_ERROR,
1108                          "PVRSRVMapDeviceClassMemoryKM: invalid parameters");
1109                 return PVRSRV_ERROR_INVALID_PARAMS;
1110         }
1111
1112         psDeviceClassBuffer = (struct PVRSRV_DEVICECLASS_BUFFER *)
1113                                                         hDeviceClassBuffer;
1114
1115         eError =
1116             psDeviceClassBuffer->pfnGetBufferAddr(psDeviceClassBuffer->
1117                                                   hExtDevice,
1118                                                   psDeviceClassBuffer->
1119                                                   hExtBuffer, &psSysPAddr,
1120                                                   &ui32ByteSize,
1121                                                   (void __iomem **)&pvCPUVAddr,
1122                                                   phOSMapInfo, &bPhysContig);
1123         if (eError != PVRSRV_OK) {
1124                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: "
1125                                         "unable to get buffer address");
1126                 return PVRSRV_ERROR_GENERIC;
1127         }
1128
1129         psBMContext = (struct BM_CONTEXT *)psDeviceClassBuffer->hDevMemContext;
1130         psDevMemoryInfo = &psBMContext->psDeviceNode->sDevMemoryInfo;
1131         psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap;
1132         for (i = 0; i < PVRSRV_MAX_CLIENT_HEAPS; i++) {
1133                 if (HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) ==
1134                     psDevMemoryInfo->ui32MappingHeapID) {
1135                         if (psDeviceMemoryHeap[i].DevMemHeapType ==
1136                             DEVICE_MEMORY_HEAP_PERCONTEXT)
1137                                 hDevMemHeap =
1138                                     BM_CreateHeap(hDevMemContext,
1139                                                   &psDeviceMemoryHeap[i]);
1140                         else
1141                                 hDevMemHeap =
1142                                     psDevMemoryInfo->psDeviceMemoryHeap[i].
1143                                                                     hDevMemHeap;
1144                         break;
1145                 }
1146         }
1147
1148         if (hDevMemHeap == NULL) {
1149                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: "
1150                                         "unable to find mapping heap");
1151                 return PVRSRV_ERROR_GENERIC;
1152         }
1153
1154         ui32Offset = ((u32)pvCPUVAddr) & (ui32PageSize - 1);
1155         pvPageAlignedCPUVAddr = (void *)((u8 *)pvCPUVAddr - ui32Offset);
1156
1157         if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
1158                        sizeof(struct PVRSRV_KERNEL_MEM_INFO),
1159                        (void **)&psMemInfo, NULL) != PVRSRV_OK) {
1160                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: "
1161                                         "Failed to alloc memory for block");
1162                 return PVRSRV_ERROR_OUT_OF_MEMORY;
1163         }
1164
1165         OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
1166
1167         psMemBlock = &(psMemInfo->sMemBlk);
1168
1169         bBMError = BM_Wrap(hDevMemHeap, ui32ByteSize, ui32Offset, bPhysContig,
1170                            psSysPAddr, pvPageAlignedCPUVAddr,
1171                            &psMemInfo->ui32Flags, &hBuffer);
1172
1173         if (!bBMError) {
1174                 PVR_DPF(PVR_DBG_ERROR,
1175                          "PVRSRVMapDeviceClassMemoryKM: BM_Wrap Failed");
1176                 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
1177                           sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
1178                           NULL);
1179                 return PVRSRV_ERROR_BAD_MAPPING;
1180         }
1181
1182         psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
1183         psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
1184
1185         psMemBlock->hBuffer = (void *) hBuffer;
1186
1187         psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
1188
1189         psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
1190         psMemInfo->ui32AllocSize = ui32ByteSize;
1191         psMemInfo->psKernelSyncInfo = psDeviceClassBuffer->psKernelSyncInfo;
1192
1193         psMemInfo->pvSysBackupBuffer = NULL;
1194
1195         psMemInfo->sMemBlk.hResItem =
1196             ResManRegisterRes(psPerProc->hResManContext,
1197                               RESMAN_TYPE_DEVICECLASSMEM_MAPPING, psMemInfo, 0,
1198                               UnmapDeviceClassMemoryCallBack);
1199
1200         *ppsMemInfo = psMemInfo;
1201
1202         return PVRSRV_OK;
1203 }