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