aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/pvr/osfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/pvr/osfunc.c')
-rw-r--r--drivers/gpu/pvr/osfunc.c2906
1 files changed, 2906 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/osfunc.c b/drivers/gpu/pvr/osfunc.c
new file mode 100644
index 00000000000..e465228de64
--- /dev/null
+++ b/drivers/gpu/pvr/osfunc.c
@@ -0,0 +1,2906 @@
1/**********************************************************************
2 *
3 * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful but, except
10 * as otherwise stated in writing, without any warranty; without even the
11 * implied warranty of merchantability or fitness for a particular purpose.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
20 *
21 * Contact Information:
22 * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23 * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
24 *
25 ******************************************************************************/
26
27#ifndef AUTOCONF_INCLUDED
28 #include <linux/config.h>
29#endif
30
31#include <linux/version.h>
32#include <asm/io.h>
33#include <asm/page.h>
34#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
35#include <asm/system.h>
36#endif
37#include <asm/cacheflush.h>
38#include <linux/mm.h>
39#include <linux/pagemap.h>
40#include <linux/hugetlb.h>
41#include <linux/slab.h>
42#include <linux/vmalloc.h>
43#include <linux/delay.h>
44#include <linux/pci.h>
45
46#include <linux/string.h>
47#include <linux/sched.h>
48#include <linux/interrupt.h>
49#include <asm/hardirq.h>
50#include <linux/timer.h>
51#include <linux/capability.h>
52#include <asm/uaccess.h>
53#include <linux/spinlock.h>
54#if defined(PVR_LINUX_MISR_USING_WORKQUEUE) || \
55 defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE) || \
56 defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || \
57 defined(PVR_LINUX_USING_WORKQUEUES)
58#include <linux/workqueue.h>
59#endif
60
61#include "img_types.h"
62#include "services_headers.h"
63#include "mm.h"
64#include "pvrmmap.h"
65#include "mmap.h"
66#include "env_data.h"
67#include "proc.h"
68#include "mutex.h"
69#include "event.h"
70#include "linkage.h"
71#include "pvr_uaccess.h"
72
73#define EVENT_OBJECT_TIMEOUT_MS (100)
74
75#define HOST_ALLOC_MEM_USING_KMALLOC ((IMG_HANDLE)0)
76#define HOST_ALLOC_MEM_USING_VMALLOC ((IMG_HANDLE)1)
77
78#if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
79PVRSRV_ERROR OSAllocMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID *ppvCpuVAddr, IMG_HANDLE *phBlockAlloc)
80#else
81PVRSRV_ERROR OSAllocMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID *ppvCpuVAddr, IMG_HANDLE *phBlockAlloc, IMG_CHAR *pszFilename, IMG_UINT32 ui32Line)
82#endif
83{
84 PVR_UNREFERENCED_PARAMETER(ui32Flags);
85
86#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
87 *ppvCpuVAddr = _KMallocWrapper(ui32Size, pszFilename, ui32Line);
88#else
89 *ppvCpuVAddr = KMallocWrapper(ui32Size);
90#endif
91 if(*ppvCpuVAddr)
92 {
93 if (phBlockAlloc)
94 {
95
96 *phBlockAlloc = HOST_ALLOC_MEM_USING_KMALLOC;
97 }
98 }
99 else
100 {
101 if (!phBlockAlloc)
102 {
103 return PVRSRV_ERROR_OUT_OF_MEMORY;
104 }
105
106
107#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
108 *ppvCpuVAddr = _VMallocWrapper(ui32Size, PVRSRV_HAP_CACHED, pszFilename, ui32Line);
109#else
110 *ppvCpuVAddr = VMallocWrapper(ui32Size, PVRSRV_HAP_CACHED);
111#endif
112 if (!*ppvCpuVAddr)
113 {
114 return PVRSRV_ERROR_OUT_OF_MEMORY;
115 }
116
117
118 *phBlockAlloc = HOST_ALLOC_MEM_USING_VMALLOC;
119 }
120
121 return PVRSRV_OK;
122}
123
124
125#if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
126PVRSRV_ERROR OSFreeMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID pvCpuVAddr, IMG_HANDLE hBlockAlloc)
127#else
128PVRSRV_ERROR OSFreeMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID pvCpuVAddr, IMG_HANDLE hBlockAlloc, IMG_CHAR *pszFilename, IMG_UINT32 ui32Line)
129#endif
130{
131 PVR_UNREFERENCED_PARAMETER(ui32Flags);
132 PVR_UNREFERENCED_PARAMETER(ui32Size);
133
134 if (hBlockAlloc == HOST_ALLOC_MEM_USING_VMALLOC)
135 {
136#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
137 _VFreeWrapper(pvCpuVAddr, pszFilename, ui32Line);
138#else
139 VFreeWrapper(pvCpuVAddr);
140#endif
141 }
142 else
143 {
144#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
145 _KFreeWrapper(pvCpuVAddr, pszFilename, ui32Line);
146#else
147 KFreeWrapper(pvCpuVAddr);
148#endif
149 }
150
151 return PVRSRV_OK;
152}
153
154
155PVRSRV_ERROR
156OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags,
157 IMG_UINT32 ui32Size,
158 IMG_UINT32 ui32PageSize,
159 IMG_VOID **ppvCpuVAddr,
160 IMG_HANDLE *phOSMemHandle)
161{
162 LinuxMemArea *psLinuxMemArea;
163
164 PVR_UNREFERENCED_PARAMETER(ui32PageSize);
165
166#if 0
167
168 if(ui32AllocFlags & PVRSRV_HAP_SINGLE_PROCESS)
169 {
170 ui32AllocFlags &= ~PVRSRV_HAP_SINGLE_PROCESS;
171 ui32AllocFlags |= PVRSRV_HAP_MULTI_PROCESS;
172 }
173#endif
174
175 switch(ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK)
176 {
177 case PVRSRV_HAP_KERNEL_ONLY:
178 {
179 psLinuxMemArea = NewVMallocLinuxMemArea(ui32Size, ui32AllocFlags);
180 if(!psLinuxMemArea)
181 {
182 return PVRSRV_ERROR_OUT_OF_MEMORY;
183 }
184 break;
185 }
186 case PVRSRV_HAP_SINGLE_PROCESS:
187 {
188
189
190 psLinuxMemArea = NewAllocPagesLinuxMemArea(ui32Size, ui32AllocFlags);
191 if(!psLinuxMemArea)
192 {
193 return PVRSRV_ERROR_OUT_OF_MEMORY;
194 }
195 PVRMMapRegisterArea(psLinuxMemArea);
196 break;
197 }
198
199 case PVRSRV_HAP_MULTI_PROCESS:
200 {
201
202#if defined(VIVT_CACHE) || defined(__sh__)
203
204 ui32AllocFlags &= ~PVRSRV_HAP_CACHED;
205#endif
206 psLinuxMemArea = NewVMallocLinuxMemArea(ui32Size, ui32AllocFlags);
207 if(!psLinuxMemArea)
208 {
209 return PVRSRV_ERROR_OUT_OF_MEMORY;
210 }
211 PVRMMapRegisterArea(psLinuxMemArea);
212 break;
213 }
214 default:
215 PVR_DPF((PVR_DBG_ERROR, "OSAllocPages: invalid flags 0x%x\n", ui32AllocFlags));
216 *ppvCpuVAddr = NULL;
217 *phOSMemHandle = (IMG_HANDLE)0;
218 return PVRSRV_ERROR_INVALID_PARAMS;
219 }
220
221 *ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea);
222 *phOSMemHandle = psLinuxMemArea;
223
224 LinuxMemAreaRegister(psLinuxMemArea);
225
226 return PVRSRV_OK;
227}
228
229
230PVRSRV_ERROR
231OSFreePages(IMG_UINT32 ui32AllocFlags, IMG_UINT32 ui32Bytes, IMG_VOID *pvCpuVAddr, IMG_HANDLE hOSMemHandle)
232{
233 LinuxMemArea *psLinuxMemArea;
234 PVRSRV_ERROR eError;
235
236 PVR_UNREFERENCED_PARAMETER(ui32Bytes);
237 PVR_UNREFERENCED_PARAMETER(pvCpuVAddr);
238
239 psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
240
241 switch(ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK)
242 {
243 case PVRSRV_HAP_KERNEL_ONLY:
244 break;
245 case PVRSRV_HAP_SINGLE_PROCESS:
246 case PVRSRV_HAP_MULTI_PROCESS:
247 eError = PVRMMapRemoveRegisteredArea(psLinuxMemArea);
248 if (eError != PVRSRV_OK)
249 {
250 PVR_DPF((PVR_DBG_ERROR,
251 "OSFreePages(ui32AllocFlags=0x%08X, ui32Bytes=%d, "
252 "pvCpuVAddr=%p, hOSMemHandle=%p) FAILED!",
253 ui32AllocFlags, ui32Bytes, pvCpuVAddr, hOSMemHandle));
254 return eError;
255 }
256 break;
257 default:
258 PVR_DPF((PVR_DBG_ERROR,"%s: invalid flags 0x%x\n",
259 __FUNCTION__, ui32AllocFlags));
260 return PVRSRV_ERROR_INVALID_PARAMS;
261 }
262
263 LinuxMemAreaDeepFree(psLinuxMemArea);
264
265 return PVRSRV_OK;
266}
267
268
269PVRSRV_ERROR
270OSGetSubMemHandle(IMG_HANDLE hOSMemHandle,
271 IMG_UINT32 ui32ByteOffset,
272 IMG_UINT32 ui32Bytes,
273 IMG_UINT32 ui32Flags,
274 IMG_HANDLE *phOSMemHandleRet)
275{
276 LinuxMemArea *psParentLinuxMemArea, *psLinuxMemArea;
277 PVRSRV_ERROR eError;
278
279 psParentLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
280
281 psLinuxMemArea = NewSubLinuxMemArea(psParentLinuxMemArea, ui32ByteOffset, ui32Bytes);
282 if(!psLinuxMemArea)
283 {
284 *phOSMemHandleRet = NULL;
285 return PVRSRV_ERROR_OUT_OF_MEMORY;
286 }
287 *phOSMemHandleRet = psLinuxMemArea;
288
289
290 if(ui32Flags & PVRSRV_HAP_KERNEL_ONLY)
291 {
292 return PVRSRV_OK;
293 }
294
295 eError = PVRMMapRegisterArea(psLinuxMemArea);
296 if(eError != PVRSRV_OK)
297 {
298 goto failed_register_area;
299 }
300
301 return PVRSRV_OK;
302
303failed_register_area:
304 *phOSMemHandleRet = NULL;
305 LinuxMemAreaDeepFree(psLinuxMemArea);
306 return eError;
307}
308
309PVRSRV_ERROR
310OSReleaseSubMemHandle(IMG_VOID *hOSMemHandle, IMG_UINT32 ui32Flags)
311{
312 LinuxMemArea *psLinuxMemArea;
313 PVRSRV_ERROR eError;
314
315 psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
316 PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC);
317
318 if((ui32Flags & PVRSRV_HAP_KERNEL_ONLY) == 0)
319 {
320 eError = PVRMMapRemoveRegisteredArea(psLinuxMemArea);
321 if(eError != PVRSRV_OK)
322 {
323 return eError;
324 }
325 }
326 LinuxMemAreaDeepFree(psLinuxMemArea);
327
328 return PVRSRV_OK;
329}
330
331
332IMG_CPU_PHYADDR
333OSMemHandleToCpuPAddr(IMG_VOID *hOSMemHandle, IMG_UINT32 ui32ByteOffset)
334{
335 PVR_ASSERT(hOSMemHandle);
336
337 return LinuxMemAreaToCpuPAddr(hOSMemHandle, ui32ByteOffset);
338}
339
340
341
342IMG_VOID OSMemCopy(IMG_VOID *pvDst, IMG_VOID *pvSrc, IMG_UINT32 ui32Size)
343{
344#if defined(USE_UNOPTIMISED_MEMCPY)
345 IMG_UINT8 *Src,*Dst;
346 IMG_INT i;
347
348 Src=(IMG_UINT8 *)pvSrc;
349 Dst=(IMG_UINT8 *)pvDst;
350 for(i=0;i<ui32Size;i++)
351 {
352 Dst[i]=Src[i];
353 }
354#else
355 memcpy(pvDst, pvSrc, ui32Size);
356#endif
357}
358
359
360IMG_VOID OSMemSet(IMG_VOID *pvDest, IMG_UINT8 ui8Value, IMG_UINT32 ui32Size)
361{
362#if defined(USE_UNOPTIMISED_MEMSET)
363 IMG_UINT8 *Buff;
364 IMG_INT i;
365
366 Buff=(IMG_UINT8 *)pvDest;
367 for(i=0;i<ui32Size;i++)
368 {
369 Buff[i]=ui8Value;
370 }
371#else
372 memset(pvDest, (IMG_INT) ui8Value, (size_t) ui32Size);
373#endif
374}
375
376
377IMG_CHAR *OSStringCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc)
378{
379 return (strcpy(pszDest, pszSrc));
380}
381
382IMG_INT32 OSSNPrintf(IMG_CHAR *pStr, IMG_UINT32 ui32Size, const IMG_CHAR *pszFormat, ...)
383{
384 va_list argList;
385 IMG_INT32 iCount;
386
387 va_start(argList, pszFormat);
388 iCount = vsnprintf(pStr, (size_t)ui32Size, pszFormat, argList);
389 va_end(argList);
390
391 return iCount;
392}
393
394IMG_VOID OSBreakResourceLock (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID)
395{
396 volatile IMG_UINT32 *pui32Access = (volatile IMG_UINT32 *)&psResource->ui32Lock;
397
398 if(*pui32Access)
399 {
400 if(psResource->ui32ID == ui32ID)
401 {
402 psResource->ui32ID = 0;
403 *pui32Access = 0;
404 }
405 else
406 {
407 PVR_DPF((PVR_DBG_MESSAGE,"OSBreakResourceLock: Resource is not locked for this process."));
408 }
409 }
410 else
411 {
412 PVR_DPF((PVR_DBG_MESSAGE,"OSBreakResourceLock: Resource is not locked"));
413 }
414}
415
416
417PVRSRV_ERROR OSCreateResource(PVRSRV_RESOURCE *psResource)
418{
419 psResource->ui32ID = 0;
420 psResource->ui32Lock = 0;
421
422 return PVRSRV_OK;
423}
424
425
426PVRSRV_ERROR OSDestroyResource (PVRSRV_RESOURCE *psResource)
427{
428 OSBreakResourceLock (psResource, psResource->ui32ID);
429
430 return PVRSRV_OK;
431}
432
433
434PVRSRV_ERROR OSInitEnvData(IMG_PVOID *ppvEnvSpecificData)
435{
436 ENV_DATA *psEnvData;
437 PVRSRV_ERROR eError;
438
439
440 eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), (IMG_VOID **)&psEnvData, IMG_NULL,
441 "Environment Data");
442 if (eError != PVRSRV_OK)
443 {
444 return eError;
445 }
446
447 eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, PVRSRV_MAX_BRIDGE_IN_SIZE + PVRSRV_MAX_BRIDGE_OUT_SIZE,
448 &psEnvData->pvBridgeData, IMG_NULL,
449 "Bridge Data");
450 if (eError != PVRSRV_OK)
451 {
452 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), psEnvData, IMG_NULL);
453
454 return eError;
455 }
456
457
458
459 psEnvData->bMISRInstalled = IMG_FALSE;
460 psEnvData->bLISRInstalled = IMG_FALSE;
461
462
463 *ppvEnvSpecificData = psEnvData;
464
465 return PVRSRV_OK;
466}
467
468
469PVRSRV_ERROR OSDeInitEnvData(IMG_PVOID pvEnvSpecificData)
470{
471 ENV_DATA *psEnvData = (ENV_DATA*)pvEnvSpecificData;
472
473 PVR_ASSERT(!psEnvData->bMISRInstalled);
474 PVR_ASSERT(!psEnvData->bLISRInstalled);
475
476 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, PVRSRV_MAX_BRIDGE_IN_SIZE + PVRSRV_MAX_BRIDGE_OUT_SIZE, psEnvData->pvBridgeData, IMG_NULL);
477 psEnvData->pvBridgeData = IMG_NULL;
478
479 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), pvEnvSpecificData, IMG_NULL);
480
481
482 return PVRSRV_OK;
483}
484
485
486
487IMG_VOID OSReleaseThreadQuanta(IMG_VOID)
488{
489 schedule();
490}
491
492
493
494IMG_UINT32 OSClockus(IMG_VOID)
495{
496 IMG_UINT32 time, j = jiffies;
497
498 time = j * (1000000 / HZ);
499
500 return time;
501}
502
503
504
505IMG_VOID OSWaitus(IMG_UINT32 ui32Timeus)
506{
507 udelay(ui32Timeus);
508}
509
510
511IMG_UINT32 OSGetCurrentProcessIDKM(IMG_VOID)
512{
513 if (in_interrupt())
514 {
515 return KERNEL_ID;
516 }
517
518#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
519 return (IMG_UINT32)current->pgrp;
520#else
521#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
522 return (IMG_UINT32)task_tgid_nr(current);
523#else
524 return (IMG_UINT32)current->tgid;
525#endif
526#endif
527}
528
529
530IMG_UINT32 OSGetPageSize(IMG_VOID)
531{
532#if defined(__sh__)
533 IMG_UINT32 ui32ReturnValue = PAGE_SIZE;
534
535 return (ui32ReturnValue);
536#else
537 return PAGE_SIZE;
538#endif
539}
540
541#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
542static irqreturn_t DeviceISRWrapper(int irq, void *dev_id
543#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
544 , struct pt_regs *regs
545#endif
546 )
547{
548 PVRSRV_DEVICE_NODE *psDeviceNode;
549 IMG_BOOL bStatus = IMG_FALSE;
550
551 PVR_UNREFERENCED_PARAMETER(irq);
552
553#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
554 PVR_UNREFERENCED_PARAMETER(regs);
555#endif
556 psDeviceNode = (PVRSRV_DEVICE_NODE*)dev_id;
557 if(!psDeviceNode)
558 {
559 PVR_DPF((PVR_DBG_ERROR, "DeviceISRWrapper: invalid params\n"));
560 goto out;
561 }
562
563 bStatus = PVRSRVDeviceLISR(psDeviceNode);
564
565 if (bStatus)
566 {
567 OSScheduleMISR((IMG_VOID *)psDeviceNode->psSysData);
568 }
569
570out:
571#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
572 return bStatus ? IRQ_HANDLED : IRQ_NONE;
573#endif
574}
575
576
577
578static irqreturn_t SystemISRWrapper(int irq, void *dev_id
579#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
580 , struct pt_regs *regs
581#endif
582 )
583{
584 SYS_DATA *psSysData;
585 IMG_BOOL bStatus = IMG_FALSE;
586
587 PVR_UNREFERENCED_PARAMETER(irq);
588
589#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
590 PVR_UNREFERENCED_PARAMETER(regs);
591#endif
592 psSysData = (SYS_DATA *)dev_id;
593 if(!psSysData)
594 {
595 PVR_DPF((PVR_DBG_ERROR, "SystemISRWrapper: invalid params\n"));
596 goto out;
597 }
598
599 bStatus = PVRSRVSystemLISR(psSysData);
600
601 if (bStatus)
602 {
603 OSScheduleMISR((IMG_VOID *)psSysData);
604 }
605
606out:
607#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
608 return bStatus ? IRQ_HANDLED : IRQ_NONE;
609#endif
610}
611PVRSRV_ERROR OSInstallDeviceLISR(IMG_VOID *pvSysData,
612 IMG_UINT32 ui32Irq,
613 IMG_CHAR *pszISRName,
614 IMG_VOID *pvDeviceNode)
615{
616 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
617 ENV_DATA *psEnvData = (ENV_DATA *)psSysData->pvEnvSpecificData;
618
619 if (psEnvData->bLISRInstalled)
620 {
621 PVR_DPF((PVR_DBG_ERROR, "OSInstallDeviceLISR: An ISR has already been installed: IRQ %d cookie %p", psEnvData->ui32IRQ, psEnvData->pvISRCookie));
622 return PVRSRV_ERROR_ISR_ALREADY_INSTALLED;
623 }
624
625 PVR_TRACE(("Installing device LISR %s on IRQ %d with cookie %p", pszISRName, ui32Irq, pvDeviceNode));
626
627 if(request_irq(ui32Irq, DeviceISRWrapper,
628#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
629 SA_SHIRQ
630#else
631 IRQF_SHARED
632#endif
633 , pszISRName, pvDeviceNode))
634 {
635 PVR_DPF((PVR_DBG_ERROR,"OSInstallDeviceLISR: Couldn't install device LISR on IRQ %d", ui32Irq));
636
637 return PVRSRV_ERROR_UNABLE_TO_INSTALL_ISR;
638 }
639
640 psEnvData->ui32IRQ = ui32Irq;
641 psEnvData->pvISRCookie = pvDeviceNode;
642 psEnvData->bLISRInstalled = IMG_TRUE;
643
644 return PVRSRV_OK;
645}
646
647PVRSRV_ERROR OSUninstallDeviceLISR(IMG_VOID *pvSysData)
648{
649 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
650 ENV_DATA *psEnvData = (ENV_DATA *)psSysData->pvEnvSpecificData;
651
652 if (!psEnvData->bLISRInstalled)
653 {
654 PVR_DPF((PVR_DBG_ERROR, "OSUninstallDeviceLISR: No LISR has been installed"));
655 return PVRSRV_ERROR_ISR_NOT_INSTALLED;
656 }
657
658 PVR_TRACE(("Uninstalling device LISR on IRQ %d with cookie %p", psEnvData->ui32IRQ, psEnvData->pvISRCookie));
659
660 free_irq(psEnvData->ui32IRQ, psEnvData->pvISRCookie);
661
662 psEnvData->bLISRInstalled = IMG_FALSE;
663
664 return PVRSRV_OK;
665}
666
667
668PVRSRV_ERROR OSInstallSystemLISR(IMG_VOID *pvSysData, IMG_UINT32 ui32Irq)
669{
670 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
671 ENV_DATA *psEnvData = (ENV_DATA *)psSysData->pvEnvSpecificData;
672
673 if (psEnvData->bLISRInstalled)
674 {
675 PVR_DPF((PVR_DBG_ERROR, "OSInstallSystemLISR: An LISR has already been installed: IRQ %d cookie %p", psEnvData->ui32IRQ, psEnvData->pvISRCookie));
676 return PVRSRV_ERROR_ISR_ALREADY_INSTALLED;
677 }
678
679 PVR_TRACE(("Installing system LISR on IRQ %d with cookie %p", ui32Irq, pvSysData));
680
681 if(request_irq(ui32Irq, SystemISRWrapper,
682#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
683 SA_SHIRQ
684#else
685 IRQF_SHARED
686#endif
687 , PVRSRV_MODNAME, pvSysData))
688 {
689 PVR_DPF((PVR_DBG_ERROR,"OSInstallSystemLISR: Couldn't install system LISR on IRQ %d", ui32Irq));
690
691 return PVRSRV_ERROR_UNABLE_TO_INSTALL_ISR;
692 }
693
694 psEnvData->ui32IRQ = ui32Irq;
695 psEnvData->pvISRCookie = pvSysData;
696 psEnvData->bLISRInstalled = IMG_TRUE;
697
698 return PVRSRV_OK;
699}
700
701
702PVRSRV_ERROR OSUninstallSystemLISR(IMG_VOID *pvSysData)
703{
704 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
705 ENV_DATA *psEnvData = (ENV_DATA *)psSysData->pvEnvSpecificData;
706
707 if (!psEnvData->bLISRInstalled)
708 {
709 PVR_DPF((PVR_DBG_ERROR, "OSUninstallSystemLISR: No LISR has been installed"));
710 return PVRSRV_ERROR_ISR_NOT_INSTALLED;
711 }
712
713 PVR_TRACE(("Uninstalling system LISR on IRQ %d with cookie %p", psEnvData->ui32IRQ, psEnvData->pvISRCookie));
714
715 free_irq(psEnvData->ui32IRQ, psEnvData->pvISRCookie);
716
717 psEnvData->bLISRInstalled = IMG_FALSE;
718
719 return PVRSRV_OK;
720}
721
722#if defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE)
723static void MISRWrapper(
724#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
725 void *data
726#else
727 struct work_struct *data
728#endif
729)
730{
731 ENV_DATA *psEnvData = container_of(data, ENV_DATA, sMISRWork);
732 SYS_DATA *psSysData = (SYS_DATA *)psEnvData->pvMISRData;
733
734 PVRSRVMISR(psSysData);
735}
736
737
738PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData)
739{
740 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
741 ENV_DATA *psEnvData = (ENV_DATA *)psSysData->pvEnvSpecificData;
742
743 if (psEnvData->bMISRInstalled)
744 {
745 PVR_DPF((PVR_DBG_ERROR, "OSInstallMISR: An MISR has already been installed"));
746 return PVRSRV_ERROR_ISR_ALREADY_INSTALLED;
747 }
748
749 PVR_TRACE(("Installing MISR with cookie %p", pvSysData));
750
751 psEnvData->psWorkQueue = create_singlethread_workqueue("pvr_workqueue");
752
753 if (psEnvData->psWorkQueue == IMG_NULL)
754 {
755 PVR_DPF((PVR_DBG_ERROR, "OSInstallMISR: create_singlethreaded_workqueue failed"));
756 return PVRSRV_ERROR_UNABLE_TO_CREATE_THREAD;
757 }
758
759 INIT_WORK(&psEnvData->sMISRWork, MISRWrapper
760#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
761 , (void *)&psEnvData->sMISRWork
762#endif
763 );
764
765 psEnvData->pvMISRData = pvSysData;
766 psEnvData->bMISRInstalled = IMG_TRUE;
767
768 return PVRSRV_OK;
769}
770
771
772PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData)
773{
774 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
775 ENV_DATA *psEnvData = (ENV_DATA *)psSysData->pvEnvSpecificData;
776
777 if (!psEnvData->bMISRInstalled)
778 {
779 PVR_DPF((PVR_DBG_ERROR, "OSUninstallMISR: No MISR has been installed"));
780 return PVRSRV_ERROR_ISR_NOT_INSTALLED;
781 }
782
783 PVR_TRACE(("Uninstalling MISR"));
784
785 destroy_workqueue(psEnvData->psWorkQueue);
786
787 psEnvData->bMISRInstalled = IMG_FALSE;
788
789 return PVRSRV_OK;
790}
791
792
793PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData)
794{
795 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
796 ENV_DATA *psEnvData = (ENV_DATA*)psSysData->pvEnvSpecificData;
797
798 if (psEnvData->bMISRInstalled)
799 {
800 queue_work(psEnvData->psWorkQueue, &psEnvData->sMISRWork);
801 }
802
803 return PVRSRV_OK;
804}
805#else
806#if defined(PVR_LINUX_MISR_USING_WORKQUEUE)
807static void MISRWrapper(
808#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
809 void *data
810#else
811 struct work_struct *data
812#endif
813)
814{
815 ENV_DATA *psEnvData = container_of(data, ENV_DATA, sMISRWork);
816 SYS_DATA *psSysData = (SYS_DATA *)psEnvData->pvMISRData;
817
818 PVRSRVMISR(psSysData);
819}
820
821
822PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData)
823{
824 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
825 ENV_DATA *psEnvData = (ENV_DATA *)psSysData->pvEnvSpecificData;
826
827 if (psEnvData->bMISRInstalled)
828 {
829 PVR_DPF((PVR_DBG_ERROR, "OSInstallMISR: An MISR has already been installed"));
830 return PVRSRV_ERROR_ISR_ALREADY_INSTALLED;
831 }
832
833 PVR_TRACE(("Installing MISR with cookie %p", pvSysData));
834
835 INIT_WORK(&psEnvData->sMISRWork, MISRWrapper
836#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
837 , (void *)&psEnvData->sMISRWork
838#endif
839 );
840
841 psEnvData->pvMISRData = pvSysData;
842 psEnvData->bMISRInstalled = IMG_TRUE;
843
844 return PVRSRV_OK;
845}
846
847
848PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData)
849{
850 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
851 ENV_DATA *psEnvData = (ENV_DATA *)psSysData->pvEnvSpecificData;
852
853 if (!psEnvData->bMISRInstalled)
854 {
855 PVR_DPF((PVR_DBG_ERROR, "OSUninstallMISR: No MISR has been installed"));
856 return PVRSRV_ERROR_ISR_NOT_INSTALLED;
857 }
858
859 PVR_TRACE(("Uninstalling MISR"));
860
861 flush_scheduled_work();
862
863 psEnvData->bMISRInstalled = IMG_FALSE;
864
865 return PVRSRV_OK;
866}
867
868
869PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData)
870{
871 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
872 ENV_DATA *psEnvData = (ENV_DATA*)psSysData->pvEnvSpecificData;
873
874 if (psEnvData->bMISRInstalled)
875 {
876 schedule_work(&psEnvData->sMISRWork);
877 }
878
879 return PVRSRV_OK;
880}
881
882#else
883
884
885static void MISRWrapper(unsigned long data)
886{
887 SYS_DATA *psSysData;
888
889 psSysData = (SYS_DATA *)data;
890
891 PVRSRVMISR(psSysData);
892}
893
894
895PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData)
896{
897 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
898 ENV_DATA *psEnvData = (ENV_DATA *)psSysData->pvEnvSpecificData;
899
900 if (psEnvData->bMISRInstalled)
901 {
902 PVR_DPF((PVR_DBG_ERROR, "OSInstallMISR: An MISR has already been installed"));
903 return PVRSRV_ERROR_ISR_ALREADY_INSTALLED;
904 }
905
906 PVR_TRACE(("Installing MISR with cookie %p", pvSysData));
907
908 tasklet_init(&psEnvData->sMISRTasklet, MISRWrapper, (unsigned long)pvSysData);
909
910 psEnvData->bMISRInstalled = IMG_TRUE;
911
912 return PVRSRV_OK;
913}
914
915
916PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData)
917{
918 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
919 ENV_DATA *psEnvData = (ENV_DATA *)psSysData->pvEnvSpecificData;
920
921 if (!psEnvData->bMISRInstalled)
922 {
923 PVR_DPF((PVR_DBG_ERROR, "OSUninstallMISR: No MISR has been installed"));
924 return PVRSRV_ERROR_ISR_NOT_INSTALLED;
925 }
926
927 PVR_TRACE(("Uninstalling MISR"));
928
929 tasklet_kill(&psEnvData->sMISRTasklet);
930
931 psEnvData->bMISRInstalled = IMG_FALSE;
932
933 return PVRSRV_OK;
934}
935
936PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData)
937{
938 SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
939 ENV_DATA *psEnvData = (ENV_DATA*)psSysData->pvEnvSpecificData;
940
941 if (psEnvData->bMISRInstalled)
942 {
943 tasklet_schedule(&psEnvData->sMISRTasklet);
944 }
945
946 return PVRSRV_OK;
947}
948
949#endif
950#endif
951
952#endif
953
954IMG_VOID OSPanic(IMG_VOID)
955{
956 BUG();
957}
958
959#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
960#define OS_TAS(p) xchg((p), 1)
961#else
962#define OS_TAS(p) tas(p)
963#endif
964PVRSRV_ERROR OSLockResource ( PVRSRV_RESOURCE *psResource,
965 IMG_UINT32 ui32ID)
966
967{
968 PVRSRV_ERROR eError = PVRSRV_OK;
969
970 if(!OS_TAS(&psResource->ui32Lock))
971 psResource->ui32ID = ui32ID;
972 else
973 eError = PVRSRV_ERROR_UNABLE_TO_LOCK_RESOURCE;
974
975 return eError;
976}
977
978
979PVRSRV_ERROR OSUnlockResource (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID)
980{
981 volatile IMG_UINT32 *pui32Access = (volatile IMG_UINT32 *)&psResource->ui32Lock;
982 PVRSRV_ERROR eError = PVRSRV_OK;
983
984 if(*pui32Access)
985 {
986 if(psResource->ui32ID == ui32ID)
987 {
988 psResource->ui32ID = 0;
989 *pui32Access = 0;
990 }
991 else
992 {
993 PVR_DPF((PVR_DBG_ERROR,"OSUnlockResource: Resource %p is not locked with expected value.", psResource));
994 PVR_DPF((PVR_DBG_MESSAGE,"Should be %x is actually %x", ui32ID, psResource->ui32ID));
995 eError = PVRSRV_ERROR_INVALID_LOCK_ID;
996 }
997 }
998 else
999 {
1000 PVR_DPF((PVR_DBG_ERROR,"OSUnlockResource: Resource %p is not locked", psResource));
1001 eError = PVRSRV_ERROR_RESOURCE_NOT_LOCKED;
1002 }
1003
1004 return eError;
1005}
1006
1007
1008IMG_BOOL OSIsResourceLocked (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID)
1009{
1010 volatile IMG_UINT32 *pui32Access = (volatile IMG_UINT32 *)&psResource->ui32Lock;
1011
1012 return (*(volatile IMG_UINT32 *)pui32Access == 1) && (psResource->ui32ID == ui32ID)
1013 ? IMG_TRUE
1014 : IMG_FALSE;
1015}
1016
1017
1018IMG_CPU_PHYADDR OSMapLinToCPUPhys(IMG_HANDLE hOSMemHandle,
1019 IMG_VOID *pvLinAddr)
1020{
1021 IMG_CPU_PHYADDR CpuPAddr;
1022 LinuxMemArea *psLinuxMemArea;
1023 IMG_UINTPTR_T uiByteOffset;
1024 IMG_UINT32 ui32ByteOffset;
1025
1026 PVR_ASSERT(hOSMemHandle != IMG_NULL);
1027
1028
1029
1030 psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
1031
1032 uiByteOffset = (IMG_UINTPTR_T)pvLinAddr - (IMG_UINTPTR_T)LinuxMemAreaToCpuVAddr(psLinuxMemArea);
1033 ui32ByteOffset = (IMG_UINT32)uiByteOffset;
1034
1035 CpuPAddr = LinuxMemAreaToCpuPAddr(hOSMemHandle, ui32ByteOffset);
1036
1037 return CpuPAddr;
1038}
1039
1040
1041IMG_VOID *
1042OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr,
1043 IMG_UINT32 ui32Bytes,
1044 IMG_UINT32 ui32MappingFlags,
1045 IMG_HANDLE *phOSMemHandle)
1046{
1047 if(ui32MappingFlags & PVRSRV_HAP_KERNEL_ONLY)
1048 {
1049
1050 if(phOSMemHandle == IMG_NULL)
1051 {
1052 IMG_VOID *pvIORemapCookie;
1053 pvIORemapCookie = IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags);
1054 if(pvIORemapCookie == IMG_NULL)
1055 {
1056 return IMG_NULL;
1057 }
1058 return pvIORemapCookie;
1059 }
1060 else
1061 {
1062 LinuxMemArea *psLinuxMemArea = NewIORemapLinuxMemArea(BasePAddr, ui32Bytes, ui32MappingFlags);
1063
1064 if(psLinuxMemArea == IMG_NULL)
1065 {
1066 return IMG_NULL;
1067 }
1068
1069 *phOSMemHandle = (IMG_HANDLE)psLinuxMemArea;
1070 return LinuxMemAreaToCpuVAddr(psLinuxMemArea);
1071 }
1072 }
1073
1074 PVR_DPF((PVR_DBG_ERROR,
1075 "OSMapPhysToLin should only be used with PVRSRV_HAP_KERNEL_ONLY "
1076 " (Use OSReservePhys otherwise)"));
1077
1078 return IMG_NULL;
1079}
1080
1081IMG_BOOL
1082OSUnMapPhysToLin(IMG_VOID *pvLinAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32MappingFlags, IMG_HANDLE hOSMemHandle)
1083{
1084 PVR_TRACE(("%s: unmapping %d bytes from %p", __FUNCTION__, ui32Bytes, pvLinAddr));
1085
1086 PVR_UNREFERENCED_PARAMETER(ui32Bytes);
1087
1088 if(ui32MappingFlags & PVRSRV_HAP_KERNEL_ONLY)
1089 {
1090 if (hOSMemHandle == IMG_NULL)
1091 {
1092 IOUnmapWrapper(pvLinAddr);
1093 }
1094 else
1095 {
1096 LinuxMemArea *psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
1097
1098 PVR_ASSERT(LinuxMemAreaToCpuVAddr(psLinuxMemArea) == pvLinAddr);
1099
1100 FreeIORemapLinuxMemArea(psLinuxMemArea);
1101 }
1102
1103 return IMG_TRUE;
1104 }
1105
1106 PVR_DPF((PVR_DBG_ERROR,
1107 "OSUnMapPhysToLin should only be used with PVRSRV_HAP_KERNEL_ONLY "
1108 " (Use OSUnReservePhys otherwise)"));
1109 return IMG_FALSE;
1110}
1111
1112static PVRSRV_ERROR
1113RegisterExternalMem(IMG_SYS_PHYADDR *pBasePAddr,
1114 IMG_VOID *pvCPUVAddr,
1115 IMG_UINT32 ui32Bytes,
1116 IMG_BOOL bPhysContig,
1117 IMG_UINT32 ui32MappingFlags,
1118 IMG_HANDLE *phOSMemHandle)
1119{
1120 LinuxMemArea *psLinuxMemArea;
1121
1122 switch(ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK)
1123 {
1124 case PVRSRV_HAP_KERNEL_ONLY:
1125 {
1126 psLinuxMemArea = NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr, ui32Bytes, bPhysContig, ui32MappingFlags);
1127
1128 if(!psLinuxMemArea)
1129 {
1130 return PVRSRV_ERROR_BAD_MAPPING;
1131 }
1132 break;
1133 }
1134 case PVRSRV_HAP_SINGLE_PROCESS:
1135 {
1136 psLinuxMemArea = NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr, ui32Bytes, bPhysContig, ui32MappingFlags);
1137
1138 if(!psLinuxMemArea)
1139 {
1140 return PVRSRV_ERROR_BAD_MAPPING;
1141 }
1142 PVRMMapRegisterArea(psLinuxMemArea);
1143 break;
1144 }
1145 case PVRSRV_HAP_MULTI_PROCESS:
1146 {
1147
1148#if defined(VIVT_CACHE) || defined(__sh__)
1149
1150 ui32MappingFlags &= ~PVRSRV_HAP_CACHED;
1151#endif
1152 psLinuxMemArea = NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr, ui32Bytes, bPhysContig, ui32MappingFlags);
1153
1154 if(!psLinuxMemArea)
1155 {
1156 return PVRSRV_ERROR_BAD_MAPPING;
1157 }
1158 PVRMMapRegisterArea(psLinuxMemArea);
1159 break;
1160 }
1161 default:
1162 PVR_DPF((PVR_DBG_ERROR,"OSRegisterMem : invalid flags 0x%x\n", ui32MappingFlags));
1163 *phOSMemHandle = (IMG_HANDLE)0;
1164 return PVRSRV_ERROR_INVALID_FLAGS;
1165 }
1166
1167 *phOSMemHandle = (IMG_HANDLE)psLinuxMemArea;
1168
1169 LinuxMemAreaRegister(psLinuxMemArea);
1170
1171 return PVRSRV_OK;
1172}
1173
1174
1175PVRSRV_ERROR
1176OSRegisterMem(IMG_CPU_PHYADDR BasePAddr,
1177 IMG_VOID *pvCPUVAddr,
1178 IMG_UINT32 ui32Bytes,
1179 IMG_UINT32 ui32MappingFlags,
1180 IMG_HANDLE *phOSMemHandle)
1181{
1182 IMG_SYS_PHYADDR SysPAddr = SysCpuPAddrToSysPAddr(BasePAddr);
1183
1184 return RegisterExternalMem(&SysPAddr, pvCPUVAddr, ui32Bytes, IMG_TRUE, ui32MappingFlags, phOSMemHandle);
1185}
1186
1187
1188PVRSRV_ERROR OSRegisterDiscontigMem(IMG_SYS_PHYADDR *pBasePAddr, IMG_VOID *pvCPUVAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32MappingFlags, IMG_HANDLE *phOSMemHandle)
1189{
1190 return RegisterExternalMem(pBasePAddr, pvCPUVAddr, ui32Bytes, IMG_FALSE, ui32MappingFlags, phOSMemHandle);
1191}
1192
1193
1194PVRSRV_ERROR
1195OSUnRegisterMem (IMG_VOID *pvCpuVAddr,
1196 IMG_UINT32 ui32Bytes,
1197 IMG_UINT32 ui32MappingFlags,
1198 IMG_HANDLE hOSMemHandle)
1199{
1200 LinuxMemArea *psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
1201 PVRSRV_ERROR eError;
1202
1203 PVR_UNREFERENCED_PARAMETER(pvCpuVAddr);
1204 PVR_UNREFERENCED_PARAMETER(ui32Bytes);
1205
1206 switch(ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK)
1207 {
1208 case PVRSRV_HAP_KERNEL_ONLY:
1209 break;
1210 case PVRSRV_HAP_SINGLE_PROCESS:
1211 case PVRSRV_HAP_MULTI_PROCESS:
1212 {
1213 eError = PVRMMapRemoveRegisteredArea(psLinuxMemArea);
1214 if (eError != PVRSRV_OK)
1215 {
1216 PVR_DPF((PVR_DBG_ERROR, "%s(%p, %d, 0x%08X, %p) FAILED!",
1217 __FUNCTION__, pvCpuVAddr, ui32Bytes,
1218 ui32MappingFlags, hOSMemHandle));
1219 return eError;
1220 }
1221 break;
1222 }
1223 default:
1224 {
1225 PVR_DPF((PVR_DBG_ERROR, "OSUnRegisterMem : invalid flags 0x%x", ui32MappingFlags));
1226 return PVRSRV_ERROR_INVALID_PARAMS;
1227 }
1228 }
1229
1230 LinuxMemAreaDeepFree(psLinuxMemArea);
1231
1232 return PVRSRV_OK;
1233}
1234
1235PVRSRV_ERROR OSUnRegisterDiscontigMem(IMG_VOID *pvCpuVAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32Flags, IMG_HANDLE hOSMemHandle)
1236{
1237 return OSUnRegisterMem(pvCpuVAddr, ui32Bytes, ui32Flags, hOSMemHandle);
1238}
1239
1240PVRSRV_ERROR
1241OSReservePhys(IMG_CPU_PHYADDR BasePAddr,
1242 IMG_UINT32 ui32Bytes,
1243 IMG_UINT32 ui32MappingFlags,
1244 IMG_VOID **ppvCpuVAddr,
1245 IMG_HANDLE *phOSMemHandle)
1246{
1247 LinuxMemArea *psLinuxMemArea;
1248
1249#if 0
1250
1251 if(ui32MappingFlags & PVRSRV_HAP_SINGLE_PROCESS)
1252 {
1253 ui32MappingFlags &= ~PVRSRV_HAP_SINGLE_PROCESS;
1254 ui32MappingFlags |= PVRSRV_HAP_MULTI_PROCESS;
1255 }
1256#endif
1257
1258 switch(ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK)
1259 {
1260 case PVRSRV_HAP_KERNEL_ONLY:
1261 {
1262
1263 psLinuxMemArea = NewIORemapLinuxMemArea(BasePAddr, ui32Bytes, ui32MappingFlags);
1264 if(!psLinuxMemArea)
1265 {
1266 return PVRSRV_ERROR_BAD_MAPPING;
1267 }
1268 break;
1269 }
1270 case PVRSRV_HAP_SINGLE_PROCESS:
1271 {
1272
1273 psLinuxMemArea = NewIOLinuxMemArea(BasePAddr, ui32Bytes, ui32MappingFlags);
1274 if(!psLinuxMemArea)
1275 {
1276 return PVRSRV_ERROR_BAD_MAPPING;
1277 }
1278 PVRMMapRegisterArea(psLinuxMemArea);
1279 break;
1280 }
1281 case PVRSRV_HAP_MULTI_PROCESS:
1282 {
1283
1284#if defined(VIVT_CACHE) || defined(__sh__)
1285
1286 ui32MappingFlags &= ~PVRSRV_HAP_CACHED;
1287#endif
1288 psLinuxMemArea = NewIORemapLinuxMemArea(BasePAddr, ui32Bytes, ui32MappingFlags);
1289 if(!psLinuxMemArea)
1290 {
1291 return PVRSRV_ERROR_BAD_MAPPING;
1292 }
1293 PVRMMapRegisterArea(psLinuxMemArea);
1294 break;
1295 }
1296 default:
1297 PVR_DPF((PVR_DBG_ERROR,"OSMapPhysToLin : invalid flags 0x%x\n", ui32MappingFlags));
1298 *ppvCpuVAddr = NULL;
1299 *phOSMemHandle = (IMG_HANDLE)0;
1300 return PVRSRV_ERROR_INVALID_FLAGS;
1301 }
1302
1303 *phOSMemHandle = (IMG_HANDLE)psLinuxMemArea;
1304 *ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea);
1305
1306 LinuxMemAreaRegister(psLinuxMemArea);
1307
1308 return PVRSRV_OK;
1309}
1310
1311PVRSRV_ERROR
1312OSUnReservePhys(IMG_VOID *pvCpuVAddr,
1313 IMG_UINT32 ui32Bytes,
1314 IMG_UINT32 ui32MappingFlags,
1315 IMG_HANDLE hOSMemHandle)
1316{
1317 LinuxMemArea *psLinuxMemArea;
1318 PVRSRV_ERROR eError;
1319
1320 PVR_UNREFERENCED_PARAMETER(pvCpuVAddr);
1321 PVR_UNREFERENCED_PARAMETER(ui32Bytes);
1322
1323 psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
1324
1325 switch(ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK)
1326 {
1327 case PVRSRV_HAP_KERNEL_ONLY:
1328 break;
1329 case PVRSRV_HAP_SINGLE_PROCESS:
1330 case PVRSRV_HAP_MULTI_PROCESS:
1331 {
1332 eError = PVRMMapRemoveRegisteredArea(psLinuxMemArea);
1333 if (eError != PVRSRV_OK)
1334 {
1335 PVR_DPF((PVR_DBG_ERROR, "%s(%p, %d, 0x%08X, %p) FAILED!",
1336 __FUNCTION__, pvCpuVAddr, ui32Bytes,
1337 ui32MappingFlags, hOSMemHandle));
1338 return eError;
1339 }
1340 break;
1341 }
1342 default:
1343 {
1344 PVR_DPF((PVR_DBG_ERROR, "OSUnMapPhysToLin : invalid flags 0x%x", ui32MappingFlags));
1345 return PVRSRV_ERROR_INVALID_PARAMS;
1346 }
1347 }
1348
1349 LinuxMemAreaDeepFree(psLinuxMemArea);
1350
1351 return PVRSRV_OK;
1352}
1353
1354
1355PVRSRV_ERROR OSBaseAllocContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR *pvLinAddr, IMG_CPU_PHYADDR *psPhysAddr)
1356{
1357#if !defined(NO_HARDWARE)
1358 PVR_UNREFERENCED_PARAMETER(ui32Size);
1359 PVR_UNREFERENCED_PARAMETER(pvLinAddr);
1360 PVR_UNREFERENCED_PARAMETER(psPhysAddr);
1361 PVR_DPF((PVR_DBG_ERROR, "%s: Not available", __FUNCTION__));
1362
1363 return PVRSRV_ERROR_OUT_OF_MEMORY;
1364#else
1365 IMG_VOID *pvKernLinAddr;
1366
1367#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
1368 pvKernLinAddr = _KMallocWrapper(ui32Size, __FILE__, __LINE__);
1369#else
1370 pvKernLinAddr = KMallocWrapper(ui32Size);
1371#endif
1372 if (!pvKernLinAddr)
1373 {
1374 return PVRSRV_ERROR_OUT_OF_MEMORY;
1375 }
1376
1377 *pvLinAddr = pvKernLinAddr;
1378
1379 psPhysAddr->uiAddr = virt_to_phys(pvKernLinAddr);
1380
1381 return PVRSRV_OK;
1382#endif
1383}
1384
1385
1386PVRSRV_ERROR OSBaseFreeContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR pvLinAddr, IMG_CPU_PHYADDR psPhysAddr)
1387{
1388#if !defined(NO_HARDWARE)
1389 PVR_UNREFERENCED_PARAMETER(ui32Size);
1390 PVR_UNREFERENCED_PARAMETER(pvLinAddr);
1391 PVR_UNREFERENCED_PARAMETER(psPhysAddr.uiAddr);
1392
1393 PVR_DPF((PVR_DBG_WARNING, "%s: Not available", __FUNCTION__));
1394#else
1395 PVR_UNREFERENCED_PARAMETER(ui32Size);
1396 PVR_UNREFERENCED_PARAMETER(psPhysAddr.uiAddr);
1397
1398 KFreeWrapper(pvLinAddr);
1399#endif
1400 return PVRSRV_OK;
1401}
1402
1403IMG_UINT32 OSReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset)
1404{
1405#if !defined(NO_HARDWARE)
1406 return (IMG_UINT32) readl((IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1407#else
1408 return *(IMG_UINT32 *)((IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1409#endif
1410}
1411
1412IMG_VOID OSWriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT32 ui32Value)
1413{
1414#if !defined(NO_HARDWARE)
1415 writel(ui32Value, (IMG_PBYTE)pvLinRegBaseAddr+ui32Offset);
1416#else
1417 *(IMG_UINT32 *)((IMG_PBYTE)pvLinRegBaseAddr+ui32Offset) = ui32Value;
1418#endif
1419}
1420
1421#if defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14))
1422
1423PVRSRV_PCI_DEV_HANDLE OSPCISetDev(IMG_VOID *pvPCICookie, HOST_PCI_INIT_FLAGS eFlags)
1424{
1425 int err;
1426 IMG_UINT32 i;
1427 PVR_PCI_DEV *psPVRPCI;
1428
1429 PVR_TRACE(("OSPCISetDev"));
1430
1431 if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psPVRPCI), (IMG_VOID **)&psPVRPCI, IMG_NULL,
1432 "PCI Device") != PVRSRV_OK)
1433 {
1434 PVR_DPF((PVR_DBG_ERROR, "OSPCISetDev: Couldn't allocate PVR PCI structure"));
1435 return IMG_NULL;
1436 }
1437
1438 psPVRPCI->psPCIDev = (struct pci_dev *)pvPCICookie;
1439 psPVRPCI->ePCIFlags = eFlags;
1440
1441 err = pci_enable_device(psPVRPCI->psPCIDev);
1442 if (err != 0)
1443 {
1444 PVR_DPF((PVR_DBG_ERROR, "OSPCISetDev: Couldn't enable device (%d)", err));
1445 return IMG_NULL;
1446 }
1447
1448 if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER)
1449 {
1450 pci_set_master(psPVRPCI->psPCIDev);
1451 }
1452
1453 if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_MSI)
1454 {
1455#if defined(CONFIG_PCI_MSI)
1456 err = pci_enable_msi(psPVRPCI->psPCIDev);
1457 if (err != 0)
1458 {
1459 PVR_DPF((PVR_DBG_WARNING, "OSPCISetDev: Couldn't enable MSI (%d)", err));
1460 psPVRPCI->ePCIFlags &= ~HOST_PCI_INIT_FLAG_MSI;
1461 }
1462#else
1463 PVR_DPF((PVR_DBG_WARNING, "OSPCISetDev: MSI support not enabled in the kernel"));
1464#endif
1465 }
1466
1467
1468 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
1469 {
1470 psPVRPCI->abPCIResourceInUse[i] = IMG_FALSE;
1471 }
1472
1473 return (PVRSRV_PCI_DEV_HANDLE)psPVRPCI;
1474}
1475
1476PVRSRV_PCI_DEV_HANDLE OSPCIAcquireDev(IMG_UINT16 ui16VendorID, IMG_UINT16 ui16DeviceID, HOST_PCI_INIT_FLAGS eFlags)
1477{
1478 struct pci_dev *psPCIDev;
1479
1480 psPCIDev = pci_get_device(ui16VendorID, ui16DeviceID, NULL);
1481 if (psPCIDev == NULL)
1482 {
1483 PVR_DPF((PVR_DBG_ERROR, "OSPCIAcquireDev: Couldn't acquire device"));
1484 return IMG_NULL;
1485 }
1486
1487 return OSPCISetDev((IMG_VOID *)psPCIDev, eFlags);
1488}
1489
1490PVRSRV_ERROR OSPCIIRQ(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 *pui32IRQ)
1491{
1492 PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI;
1493
1494 *pui32IRQ = psPVRPCI->psPCIDev->irq;
1495
1496 return PVRSRV_OK;
1497}
1498
1499enum HOST_PCI_ADDR_RANGE_FUNC
1500{
1501 HOST_PCI_ADDR_RANGE_FUNC_LEN,
1502 HOST_PCI_ADDR_RANGE_FUNC_START,
1503 HOST_PCI_ADDR_RANGE_FUNC_END,
1504 HOST_PCI_ADDR_RANGE_FUNC_REQUEST,
1505 HOST_PCI_ADDR_RANGE_FUNC_RELEASE
1506};
1507
1508static IMG_UINT32 OSPCIAddrRangeFunc(enum HOST_PCI_ADDR_RANGE_FUNC eFunc,
1509 PVRSRV_PCI_DEV_HANDLE hPVRPCI,
1510 IMG_UINT32 ui32Index)
1511{
1512 PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI;
1513
1514 if (ui32Index >= DEVICE_COUNT_RESOURCE)
1515 {
1516 PVR_DPF((PVR_DBG_ERROR, "OSPCIAddrRangeFunc: Index out of range"));
1517 return 0;
1518
1519 }
1520
1521 switch (eFunc)
1522 {
1523 case HOST_PCI_ADDR_RANGE_FUNC_LEN:
1524 return pci_resource_len(psPVRPCI->psPCIDev, ui32Index);
1525 case HOST_PCI_ADDR_RANGE_FUNC_START:
1526 return pci_resource_start(psPVRPCI->psPCIDev, ui32Index);
1527 case HOST_PCI_ADDR_RANGE_FUNC_END:
1528 return pci_resource_end(psPVRPCI->psPCIDev, ui32Index);
1529 case HOST_PCI_ADDR_RANGE_FUNC_REQUEST:
1530 {
1531 int err;
1532
1533 err = pci_request_region(psPVRPCI->psPCIDev, (IMG_INT)ui32Index, PVRSRV_MODNAME);
1534 if (err != 0)
1535 {
1536 PVR_DPF((PVR_DBG_ERROR, "OSPCIAddrRangeFunc: pci_request_region_failed (%d)", err));
1537 return 0;
1538 }
1539 psPVRPCI->abPCIResourceInUse[ui32Index] = IMG_TRUE;
1540 return 1;
1541 }
1542 case HOST_PCI_ADDR_RANGE_FUNC_RELEASE:
1543 if (psPVRPCI->abPCIResourceInUse[ui32Index])
1544 {
1545 pci_release_region(psPVRPCI->psPCIDev, (IMG_INT)ui32Index);
1546 psPVRPCI->abPCIResourceInUse[ui32Index] = IMG_FALSE;
1547 }
1548 return 1;
1549 default:
1550 PVR_DPF((PVR_DBG_ERROR, "OSPCIAddrRangeFunc: Unknown function"));
1551 break;
1552 }
1553
1554 return 0;
1555}
1556
1557IMG_UINT32 OSPCIAddrRangeLen(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index)
1558{
1559 return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_LEN, hPVRPCI, ui32Index);
1560}
1561
1562IMG_UINT32 OSPCIAddrRangeStart(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index)
1563{
1564 return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_START, hPVRPCI, ui32Index);
1565}
1566
1567IMG_UINT32 OSPCIAddrRangeEnd(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index)
1568{
1569 return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_END, hPVRPCI, ui32Index);
1570}
1571
1572PVRSRV_ERROR OSPCIRequestAddrRange(PVRSRV_PCI_DEV_HANDLE hPVRPCI,
1573 IMG_UINT32 ui32Index)
1574{
1575 return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_REQUEST, hPVRPCI, ui32Index) == 0 ? PVRSRV_ERROR_PCI_CALL_FAILED : PVRSRV_OK;
1576}
1577
1578PVRSRV_ERROR OSPCIReleaseAddrRange(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index)
1579{
1580 return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_RELEASE, hPVRPCI, ui32Index) == 0 ? PVRSRV_ERROR_PCI_CALL_FAILED : PVRSRV_OK;
1581}
1582
1583PVRSRV_ERROR OSPCIReleaseDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
1584{
1585 PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI;
1586 int i;
1587
1588 PVR_TRACE(("OSPCIReleaseDev"));
1589
1590
1591 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
1592 {
1593 if (psPVRPCI->abPCIResourceInUse[i])
1594 {
1595 PVR_TRACE(("OSPCIReleaseDev: Releasing Address range %d", i));
1596 pci_release_region(psPVRPCI->psPCIDev, i);
1597 psPVRPCI->abPCIResourceInUse[i] = IMG_FALSE;
1598 }
1599 }
1600
1601#if defined(CONFIG_PCI_MSI)
1602 if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_MSI)
1603 {
1604 pci_disable_msi(psPVRPCI->psPCIDev);
1605 }
1606#endif
1607
1608#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
1609 if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER)
1610 {
1611 pci_clear_master(psPVRPCI->psPCIDev);
1612 }
1613#endif
1614 pci_disable_device(psPVRPCI->psPCIDev);
1615
1616 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psPVRPCI), (IMG_VOID *)psPVRPCI, IMG_NULL);
1617
1618
1619 return PVRSRV_OK;
1620}
1621
1622PVRSRV_ERROR OSPCISuspendDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
1623{
1624 PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI;
1625 int i;
1626 int err;
1627
1628 PVR_TRACE(("OSPCISuspendDev"));
1629
1630
1631 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
1632 {
1633 if (psPVRPCI->abPCIResourceInUse[i])
1634 {
1635 pci_release_region(psPVRPCI->psPCIDev, i);
1636 }
1637 }
1638
1639 err = pci_save_state(psPVRPCI->psPCIDev);
1640 if (err != 0)
1641 {
1642 PVR_DPF((PVR_DBG_ERROR, "OSPCISuspendDev: pci_save_state_failed (%d)", err));
1643 return PVRSRV_ERROR_PCI_CALL_FAILED;
1644 }
1645
1646 pci_disable_device(psPVRPCI->psPCIDev);
1647
1648 err = pci_set_power_state(psPVRPCI->psPCIDev, pci_choose_state(psPVRPCI->psPCIDev, PMSG_SUSPEND));
1649 switch(err)
1650 {
1651 case 0:
1652 break;
1653 case -EIO:
1654 PVR_DPF((PVR_DBG_WARNING, "OSPCISuspendDev: device doesn't support PCI PM"));
1655 break;
1656 case -EINVAL:
1657 PVR_DPF((PVR_DBG_ERROR, "OSPCISuspendDev: can't enter requested power state"));
1658 break;
1659 default:
1660 PVR_DPF((PVR_DBG_ERROR, "OSPCISuspendDev: pci_set_power_state failed (%d)", err));
1661 break;
1662 }
1663
1664 return PVRSRV_OK;
1665}
1666
1667PVRSRV_ERROR OSPCIResumeDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
1668{
1669 PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI;
1670 int err;
1671 int i;
1672
1673 PVR_TRACE(("OSPCIResumeDev"));
1674
1675 err = pci_set_power_state(psPVRPCI->psPCIDev, pci_choose_state(psPVRPCI->psPCIDev, PMSG_ON));
1676 switch(err)
1677 {
1678 case 0:
1679 break;
1680 case -EIO:
1681 PVR_DPF((PVR_DBG_WARNING, "OSPCIResumeDev: device doesn't support PCI PM"));
1682 break;
1683 case -EINVAL:
1684 PVR_DPF((PVR_DBG_ERROR, "OSPCIResumeDev: can't enter requested power state"));
1685 return PVRSRV_ERROR_UNKNOWN_POWER_STATE;
1686 default:
1687 PVR_DPF((PVR_DBG_ERROR, "OSPCIResumeDev: pci_set_power_state failed (%d)", err));
1688 return PVRSRV_ERROR_UNKNOWN_POWER_STATE;
1689 }
1690
1691 err = pci_restore_state(psPVRPCI->psPCIDev);
1692 if (err != 0)
1693 {
1694 PVR_DPF((PVR_DBG_ERROR, "OSPCIResumeDev: pci_restore_state failed (%d)", err));
1695 return PVRSRV_ERROR_PCI_CALL_FAILED;
1696 }
1697
1698 err = pci_enable_device(psPVRPCI->psPCIDev);
1699 if (err != 0)
1700 {
1701 PVR_DPF((PVR_DBG_ERROR, "OSPCIResumeDev: Couldn't enable device (%d)", err));
1702 return PVRSRV_ERROR_PCI_CALL_FAILED;
1703 }
1704
1705 if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER)
1706 pci_set_master(psPVRPCI->psPCIDev);
1707
1708
1709 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
1710 {
1711 if (psPVRPCI->abPCIResourceInUse[i])
1712 {
1713 err = pci_request_region(psPVRPCI->psPCIDev, i, PVRSRV_MODNAME);
1714 if (err != 0)
1715 {
1716 PVR_DPF((PVR_DBG_ERROR, "OSPCIResumeDev: pci_request_region_failed (region %d, error %d)", i, err));
1717 }
1718 }
1719
1720 }
1721
1722 return PVRSRV_OK;
1723}
1724
1725#endif
1726
1727#define OS_MAX_TIMERS 8
1728
1729typedef struct TIMER_CALLBACK_DATA_TAG
1730{
1731 IMG_BOOL bInUse;
1732 PFN_TIMER_FUNC pfnTimerFunc;
1733 IMG_VOID *pvData;
1734 struct timer_list sTimer;
1735 IMG_UINT32 ui32Delay;
1736 IMG_BOOL bActive;
1737#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1738 struct work_struct sWork;
1739#endif
1740}TIMER_CALLBACK_DATA;
1741
1742#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1743static struct workqueue_struct *psTimerWorkQueue;
1744#endif
1745
1746static TIMER_CALLBACK_DATA sTimers[OS_MAX_TIMERS];
1747
1748#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1749DEFINE_MUTEX(sTimerStructLock);
1750#else
1751
1752static spinlock_t sTimerStructLock = SPIN_LOCK_UNLOCKED;
1753#endif
1754
1755static void OSTimerCallbackBody(TIMER_CALLBACK_DATA *psTimerCBData)
1756{
1757 if (!psTimerCBData->bActive)
1758 return;
1759
1760
1761 psTimerCBData->pfnTimerFunc(psTimerCBData->pvData);
1762
1763
1764 mod_timer(&psTimerCBData->sTimer, psTimerCBData->ui32Delay + jiffies);
1765}
1766
1767
1768static IMG_VOID OSTimerCallbackWrapper(IMG_UINT32 ui32Data)
1769{
1770 TIMER_CALLBACK_DATA *psTimerCBData = (TIMER_CALLBACK_DATA*)ui32Data;
1771
1772#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1773 int res;
1774
1775 res = queue_work(psTimerWorkQueue, &psTimerCBData->sWork);
1776 if (res == 0)
1777 {
1778 PVR_DPF((PVR_DBG_WARNING, "OSTimerCallbackWrapper: work already queued"));
1779 }
1780#else
1781 OSTimerCallbackBody(psTimerCBData);
1782#endif
1783}
1784
1785
1786#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1787static void OSTimerWorkQueueCallBack(struct work_struct *psWork)
1788{
1789 TIMER_CALLBACK_DATA *psTimerCBData = container_of(psWork, TIMER_CALLBACK_DATA, sWork);
1790
1791 OSTimerCallbackBody(psTimerCBData);
1792}
1793#endif
1794
1795IMG_HANDLE OSAddTimer(PFN_TIMER_FUNC pfnTimerFunc, IMG_VOID *pvData, IMG_UINT32 ui32MsTimeout)
1796{
1797 TIMER_CALLBACK_DATA *psTimerCBData;
1798 IMG_UINT32 ui32i;
1799#if !defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1800 unsigned long ulLockFlags;
1801#endif
1802
1803
1804 if(!pfnTimerFunc)
1805 {
1806 PVR_DPF((PVR_DBG_ERROR, "OSAddTimer: passed invalid callback"));
1807 return IMG_NULL;
1808 }
1809
1810
1811#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1812 mutex_lock(&sTimerStructLock);
1813#else
1814 spin_lock_irqsave(&sTimerStructLock, ulLockFlags);
1815#endif
1816 for (ui32i = 0; ui32i < OS_MAX_TIMERS; ui32i++)
1817 {
1818 psTimerCBData = &sTimers[ui32i];
1819 if (!psTimerCBData->bInUse)
1820 {
1821 psTimerCBData->bInUse = IMG_TRUE;
1822 break;
1823 }
1824 }
1825#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1826 mutex_unlock(&sTimerStructLock);
1827#else
1828 spin_unlock_irqrestore(&sTimerStructLock, ulLockFlags);
1829#endif
1830 if (ui32i >= OS_MAX_TIMERS)
1831 {
1832 PVR_DPF((PVR_DBG_ERROR, "OSAddTimer: all timers are in use"));
1833 return IMG_NULL;
1834 }
1835
1836 psTimerCBData->pfnTimerFunc = pfnTimerFunc;
1837 psTimerCBData->pvData = pvData;
1838 psTimerCBData->bActive = IMG_FALSE;
1839
1840
1841
1842
1843 psTimerCBData->ui32Delay = ((HZ * ui32MsTimeout) < 1000)
1844 ? 1
1845 : ((HZ * ui32MsTimeout) / 1000);
1846
1847 init_timer(&psTimerCBData->sTimer);
1848
1849
1850
1851 psTimerCBData->sTimer.function = (IMG_VOID *)OSTimerCallbackWrapper;
1852 psTimerCBData->sTimer.data = (IMG_UINT32)psTimerCBData;
1853
1854 return (IMG_HANDLE)(ui32i + 1);
1855}
1856
1857
1858static inline TIMER_CALLBACK_DATA *GetTimerStructure(IMG_HANDLE hTimer)
1859{
1860 IMG_UINT32 ui32i = ((IMG_UINT32)hTimer) - 1;
1861
1862 PVR_ASSERT(ui32i < OS_MAX_TIMERS);
1863
1864 return &sTimers[ui32i];
1865}
1866
1867PVRSRV_ERROR OSRemoveTimer (IMG_HANDLE hTimer)
1868{
1869 TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
1870
1871 PVR_ASSERT(psTimerCBData->bInUse);
1872 PVR_ASSERT(!psTimerCBData->bActive);
1873
1874
1875 psTimerCBData->bInUse = IMG_FALSE;
1876
1877 return PVRSRV_OK;
1878}
1879
1880
1881PVRSRV_ERROR OSEnableTimer (IMG_HANDLE hTimer)
1882{
1883 TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
1884
1885 PVR_ASSERT(psTimerCBData->bInUse);
1886 PVR_ASSERT(!psTimerCBData->bActive);
1887
1888
1889 psTimerCBData->bActive = IMG_TRUE;
1890
1891
1892 psTimerCBData->sTimer.expires = psTimerCBData->ui32Delay + jiffies;
1893
1894
1895 add_timer(&psTimerCBData->sTimer);
1896
1897 return PVRSRV_OK;
1898}
1899
1900
1901PVRSRV_ERROR OSDisableTimer (IMG_HANDLE hTimer)
1902{
1903 TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
1904
1905 PVR_ASSERT(psTimerCBData->bInUse);
1906 PVR_ASSERT(psTimerCBData->bActive);
1907
1908
1909 psTimerCBData->bActive = IMG_FALSE;
1910 smp_mb();
1911
1912#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1913 flush_workqueue(psTimerWorkQueue);
1914#endif
1915
1916
1917 del_timer_sync(&psTimerCBData->sTimer);
1918
1919#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
1920
1921 flush_workqueue(psTimerWorkQueue);
1922#endif
1923
1924 return PVRSRV_OK;
1925}
1926
1927
1928PVRSRV_ERROR OSEventObjectCreate(const IMG_CHAR *pszName, PVRSRV_EVENTOBJECT *psEventObject)
1929{
1930
1931 PVRSRV_ERROR eError = PVRSRV_OK;
1932
1933 if(psEventObject)
1934 {
1935 if(pszName)
1936 {
1937
1938 strncpy(psEventObject->szName, pszName, EVENTOBJNAME_MAXLENGTH);
1939 }
1940 else
1941 {
1942
1943 static IMG_UINT16 ui16NameIndex = 0;
1944 snprintf(psEventObject->szName, EVENTOBJNAME_MAXLENGTH, "PVRSRV_EVENTOBJECT_%d", ui16NameIndex++);
1945 }
1946
1947 if(LinuxEventObjectListCreate(&psEventObject->hOSEventKM) != PVRSRV_OK)
1948 {
1949 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
1950 }
1951
1952 }
1953 else
1954 {
1955 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectCreate: psEventObject is not a valid pointer"));
1956 eError = PVRSRV_ERROR_UNABLE_TO_CREATE_EVENT;
1957 }
1958
1959 return eError;
1960
1961}
1962
1963
1964PVRSRV_ERROR OSEventObjectDestroy(PVRSRV_EVENTOBJECT *psEventObject)
1965{
1966 PVRSRV_ERROR eError = PVRSRV_OK;
1967
1968 if(psEventObject)
1969 {
1970 if(psEventObject->hOSEventKM)
1971 {
1972 LinuxEventObjectListDestroy(psEventObject->hOSEventKM);
1973 }
1974 else
1975 {
1976 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectDestroy: hOSEventKM is not a valid pointer"));
1977 eError = PVRSRV_ERROR_INVALID_PARAMS;
1978 }
1979 }
1980 else
1981 {
1982 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectDestroy: psEventObject is not a valid pointer"));
1983 eError = PVRSRV_ERROR_INVALID_PARAMS;
1984 }
1985
1986 return eError;
1987}
1988
1989PVRSRV_ERROR OSEventObjectWait(IMG_HANDLE hOSEventKM)
1990{
1991 PVRSRV_ERROR eError;
1992
1993 if(hOSEventKM)
1994 {
1995 eError = LinuxEventObjectWait(hOSEventKM, EVENT_OBJECT_TIMEOUT_MS);
1996 }
1997 else
1998 {
1999 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectWait: hOSEventKM is not a valid handle"));
2000 eError = PVRSRV_ERROR_INVALID_PARAMS;
2001 }
2002
2003 return eError;
2004}
2005
2006PVRSRV_ERROR OSEventObjectOpen(PVRSRV_EVENTOBJECT *psEventObject,
2007 IMG_HANDLE *phOSEvent)
2008{
2009 PVRSRV_ERROR eError = PVRSRV_OK;
2010
2011 if(psEventObject)
2012 {
2013 if(LinuxEventObjectAdd(psEventObject->hOSEventKM, phOSEvent) != PVRSRV_OK)
2014 {
2015 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectAdd: failed"));
2016 eError = PVRSRV_ERROR_INVALID_PARAMS;
2017 }
2018
2019 }
2020 else
2021 {
2022 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectCreate: psEventObject is not a valid pointer"));
2023 eError = PVRSRV_ERROR_INVALID_PARAMS;
2024 }
2025
2026 return eError;
2027}
2028
2029PVRSRV_ERROR OSEventObjectClose(PVRSRV_EVENTOBJECT *psEventObject,
2030 IMG_HANDLE hOSEventKM)
2031{
2032 PVRSRV_ERROR eError = PVRSRV_OK;
2033
2034 if(psEventObject)
2035 {
2036 if(LinuxEventObjectDelete(psEventObject->hOSEventKM, hOSEventKM) != PVRSRV_OK)
2037 {
2038 PVR_DPF((PVR_DBG_ERROR, "LinuxEventObjectDelete: failed"));
2039 eError = PVRSRV_ERROR_INVALID_PARAMS;
2040 }
2041
2042 }
2043 else
2044 {
2045 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectDestroy: psEventObject is not a valid pointer"));
2046 eError = PVRSRV_ERROR_INVALID_PARAMS;
2047 }
2048
2049 return eError;
2050
2051}
2052
2053PVRSRV_ERROR OSEventObjectSignal(IMG_HANDLE hOSEventKM)
2054{
2055 PVRSRV_ERROR eError;
2056
2057 if(hOSEventKM)
2058 {
2059 eError = LinuxEventObjectSignal(hOSEventKM);
2060 }
2061 else
2062 {
2063 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectSignal: hOSEventKM is not a valid handle"));
2064 eError = PVRSRV_ERROR_INVALID_PARAMS;
2065 }
2066
2067 return eError;
2068}
2069
2070IMG_BOOL OSProcHasPrivSrvInit(IMG_VOID)
2071{
2072 return (capable(CAP_SYS_MODULE) != 0) ? IMG_TRUE : IMG_FALSE;
2073}
2074
2075PVRSRV_ERROR OSCopyToUser(IMG_PVOID pvProcess,
2076 IMG_VOID *pvDest,
2077 IMG_VOID *pvSrc,
2078 IMG_UINT32 ui32Bytes)
2079{
2080 PVR_UNREFERENCED_PARAMETER(pvProcess);
2081
2082 if(pvr_copy_to_user(pvDest, pvSrc, ui32Bytes)==0)
2083 return PVRSRV_OK;
2084 else
2085 return PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY;
2086}
2087
2088PVRSRV_ERROR OSCopyFromUser( IMG_PVOID pvProcess,
2089 IMG_VOID *pvDest,
2090 IMG_VOID *pvSrc,
2091 IMG_UINT32 ui32Bytes)
2092{
2093 PVR_UNREFERENCED_PARAMETER(pvProcess);
2094
2095 if(pvr_copy_from_user(pvDest, pvSrc, ui32Bytes)==0)
2096 return PVRSRV_OK;
2097 else
2098 return PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY;
2099}
2100
2101IMG_BOOL OSAccessOK(IMG_VERIFY_TEST eVerification, IMG_VOID *pvUserPtr, IMG_UINT32 ui32Bytes)
2102{
2103 IMG_INT linuxType;
2104
2105 if (eVerification == PVR_VERIFY_READ)
2106 {
2107 linuxType = VERIFY_READ;
2108 }
2109 else
2110 {
2111 PVR_ASSERT(eVerification == PVR_VERIFY_WRITE);
2112 linuxType = VERIFY_WRITE;
2113 }
2114
2115 return access_ok(linuxType, pvUserPtr, ui32Bytes);
2116}
2117
2118typedef enum _eWrapMemType_
2119{
2120 WRAP_TYPE_NULL = 0,
2121 WRAP_TYPE_GET_USER_PAGES,
2122 WRAP_TYPE_FIND_VMA
2123} eWrapMemType;
2124
2125typedef struct _sWrapMemInfo_
2126{
2127 eWrapMemType eType;
2128 IMG_INT iNumPages;
2129 IMG_INT iNumPagesMapped;
2130 struct page **ppsPages;
2131 IMG_SYS_PHYADDR *psPhysAddr;
2132 IMG_INT iPageOffset;
2133#if defined(DEBUG)
2134 IMG_UINT32 ulStartAddr;
2135 IMG_UINT32 ulBeyondEndAddr;
2136 struct vm_area_struct *psVMArea;
2137#endif
2138} sWrapMemInfo;
2139
2140
2141static IMG_BOOL CPUVAddrToPFN(struct vm_area_struct *psVMArea, IMG_UINT32 ulCPUVAddr, IMG_UINT32 *pulPFN, struct page **ppsPage)
2142{
2143#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10))
2144 pgd_t *psPGD;
2145 pud_t *psPUD;
2146 pmd_t *psPMD;
2147 pte_t *psPTE;
2148 struct mm_struct *psMM = psVMArea->vm_mm;
2149 spinlock_t *psPTLock;
2150 IMG_BOOL bRet = IMG_FALSE;
2151
2152 *pulPFN = 0;
2153 *ppsPage = NULL;
2154
2155 psPGD = pgd_offset(psMM, ulCPUVAddr);
2156 if (pgd_none(*psPGD) || pgd_bad(*psPGD))
2157 return bRet;
2158
2159 psPUD = pud_offset(psPGD, ulCPUVAddr);
2160 if (pud_none(*psPUD) || pud_bad(*psPUD))
2161 return bRet;
2162
2163 psPMD = pmd_offset(psPUD, ulCPUVAddr);
2164 if (pmd_none(*psPMD) || pmd_bad(*psPMD))
2165 return bRet;
2166
2167 psPTE = (pte_t *)pte_offset_map_lock(psMM, psPMD, ulCPUVAddr, &psPTLock);
2168
2169 if ((pte_none(*psPTE) == 0) && (pte_present(*psPTE) != 0) && (pte_write(*psPTE) != 0))
2170 {
2171 *pulPFN = pte_pfn(*psPTE);
2172 bRet = IMG_TRUE;
2173
2174 if (pfn_valid(*pulPFN))
2175 {
2176 *ppsPage = pfn_to_page(*pulPFN);
2177
2178 get_page(*ppsPage);
2179 }
2180 }
2181
2182 pte_unmap_unlock(psPTE, psPTLock);
2183
2184 return bRet;
2185#else
2186 return IMG_FALSE;
2187#endif
2188}
2189
2190PVRSRV_ERROR OSReleasePhysPageAddr(IMG_HANDLE hOSWrapMem)
2191{
2192 sWrapMemInfo *psInfo = (sWrapMemInfo *)hOSWrapMem;
2193 IMG_INT i;
2194
2195 if (psInfo == IMG_NULL)
2196 {
2197 PVR_DPF((PVR_DBG_WARNING,
2198 "OSReleasePhysPageAddr: called with null wrap handle"));
2199 return PVRSRV_OK;
2200 }
2201
2202 switch (psInfo->eType)
2203 {
2204 case WRAP_TYPE_NULL:
2205 {
2206 PVR_DPF((PVR_DBG_WARNING,
2207 "OSReleasePhysPageAddr: called with wrap type WRAP_TYPE_NULL"));
2208 break;
2209 }
2210 case WRAP_TYPE_GET_USER_PAGES:
2211 {
2212 for (i = 0; i < psInfo->iNumPagesMapped; i++)
2213 {
2214 struct page *psPage = psInfo->ppsPages[i];
2215
2216 PVR_ASSERT(psPage != NULL);
2217
2218
2219 if (psInfo->iNumPagesMapped == psInfo->iNumPages)
2220 {
2221 if (!PageReserved(psPage))
2222 {
2223 SetPageDirty(psPage);
2224 }
2225 }
2226 page_cache_release(psPage);
2227 }
2228 break;
2229 }
2230 case WRAP_TYPE_FIND_VMA:
2231 {
2232 for (i = 0; i < psInfo->iNumPages; i++)
2233 {
2234 if (psInfo->ppsPages[i] != IMG_NULL)
2235 {
2236 put_page(psInfo->ppsPages[i]);
2237 }
2238 }
2239 break;
2240 }
2241 default:
2242 {
2243 PVR_DPF((PVR_DBG_ERROR,
2244 "OSReleasePhysPageAddr: Unknown wrap type (%d)", psInfo->eType));
2245 return PVRSRV_ERROR_INVALID_WRAP_TYPE;
2246 }
2247 }
2248
2249 if (psInfo->ppsPages != IMG_NULL)
2250 {
2251 kfree(psInfo->ppsPages);
2252 }
2253
2254 if (psInfo->psPhysAddr != IMG_NULL)
2255 {
2256 kfree(psInfo->psPhysAddr);
2257 }
2258
2259 kfree(psInfo);
2260
2261 return PVRSRV_OK;
2262}
2263
2264PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
2265 IMG_UINT32 ui32Bytes,
2266 IMG_SYS_PHYADDR *psSysPAddr,
2267 IMG_HANDLE *phOSWrapMem)
2268{
2269 IMG_UINT32 ulStartAddrOrig = (IMG_UINT32) pvCPUVAddr;
2270 IMG_UINT32 ulAddrRangeOrig = (IMG_UINT32) ui32Bytes;
2271 IMG_UINT32 ulBeyondEndAddrOrig = ulStartAddrOrig + ulAddrRangeOrig;
2272 IMG_UINT32 ulStartAddr;
2273 IMG_UINT32 ulAddrRange;
2274 IMG_UINT32 ulBeyondEndAddr;
2275 IMG_UINT32 ulAddr;
2276 IMG_INT i;
2277 struct vm_area_struct *psVMArea;
2278 sWrapMemInfo *psInfo = NULL;
2279 IMG_BOOL bHavePageStructs = IMG_FALSE;
2280 IMG_BOOL bHaveNoPageStructs = IMG_FALSE;
2281 IMG_BOOL bPFNMismatch = IMG_FALSE;
2282 IMG_BOOL bMMapSemHeld = IMG_FALSE;
2283 PVRSRV_ERROR eError = PVRSRV_ERROR_OUT_OF_MEMORY;
2284
2285
2286 ulStartAddr = ulStartAddrOrig & PAGE_MASK;
2287 ulBeyondEndAddr = PAGE_ALIGN(ulBeyondEndAddrOrig);
2288 ulAddrRange = ulBeyondEndAddr - ulStartAddr;
2289
2290
2291 if (ulBeyondEndAddr <= ulStartAddr)
2292 {
2293 PVR_DPF((PVR_DBG_ERROR,
2294 "OSAcquirePhysPageAddr: Invalid address range (start %x, length %x)",
2295 ulStartAddrOrig, ulAddrRangeOrig));
2296 goto error;
2297 }
2298
2299
2300 psInfo = kmalloc(sizeof(*psInfo), GFP_KERNEL);
2301 if (psInfo == NULL)
2302 {
2303 PVR_DPF((PVR_DBG_ERROR,
2304 "OSAcquirePhysPageAddr: Couldn't allocate information structure"));
2305 goto error;
2306 }
2307 memset(psInfo, 0, sizeof(*psInfo));
2308
2309#if defined(DEBUG)
2310 psInfo->ulStartAddr = ulStartAddrOrig;
2311 psInfo->ulBeyondEndAddr = ulBeyondEndAddrOrig;
2312#endif
2313
2314 psInfo->iNumPages = (IMG_INT)(ulAddrRange >> PAGE_SHIFT);
2315 psInfo->iPageOffset = (IMG_INT)(ulStartAddrOrig & ~PAGE_MASK);
2316
2317
2318 psInfo->psPhysAddr = kmalloc((size_t)psInfo->iNumPages * sizeof(*psInfo->psPhysAddr), GFP_KERNEL);
2319 if (psInfo->psPhysAddr == NULL)
2320 {
2321 PVR_DPF((PVR_DBG_ERROR,
2322 "OSAcquirePhysPageAddr: Couldn't allocate page array"));
2323 goto error;
2324 }
2325 memset(psInfo->psPhysAddr, 0, (size_t)psInfo->iNumPages * sizeof(*psInfo->psPhysAddr));
2326
2327
2328 psInfo->ppsPages = kmalloc((size_t)psInfo->iNumPages * sizeof(*psInfo->ppsPages), GFP_KERNEL);
2329 if (psInfo->ppsPages == NULL)
2330 {
2331 PVR_DPF((PVR_DBG_ERROR,
2332 "OSAcquirePhysPageAddr: Couldn't allocate page array"));
2333 goto error;
2334 }
2335 memset(psInfo->ppsPages, 0, (size_t)psInfo->iNumPages * sizeof(*psInfo->ppsPages));
2336
2337
2338 eError = PVRSRV_ERROR_BAD_MAPPING;
2339
2340
2341 psInfo->eType = WRAP_TYPE_GET_USER_PAGES;
2342
2343
2344 down_read(&current->mm->mmap_sem);
2345 bMMapSemHeld = IMG_TRUE;
2346
2347
2348 psInfo->iNumPagesMapped = get_user_pages(current, current->mm, ulStartAddr, psInfo->iNumPages, 1, 0, psInfo->ppsPages, NULL);
2349
2350 if (psInfo->iNumPagesMapped >= 0)
2351 {
2352
2353 if (psInfo->iNumPagesMapped != psInfo->iNumPages)
2354 {
2355 PVR_TRACE(("OSAcquirePhysPageAddr: Couldn't map all the pages needed (wanted: %d, got %d)", psInfo->iNumPages, psInfo->iNumPagesMapped));
2356
2357 goto error;
2358 }
2359
2360
2361 for (i = 0; i < psInfo->iNumPages; i++)
2362 {
2363 IMG_CPU_PHYADDR CPUPhysAddr;
2364 IMG_UINT32 ulPFN;
2365
2366 ulPFN = page_to_pfn(psInfo->ppsPages[i]);
2367 CPUPhysAddr.uiAddr = ulPFN << PAGE_SHIFT;
2368 if ((CPUPhysAddr.uiAddr >> PAGE_SHIFT) != ulPFN)
2369 {
2370 PVR_DPF((PVR_DBG_ERROR,
2371 "OSAcquirePhysPageAddr: Page frame number out of range (%x)", ulPFN));
2372
2373 goto error;
2374 }
2375 psInfo->psPhysAddr[i] = SysCpuPAddrToSysPAddr(CPUPhysAddr);
2376 psSysPAddr[i] = psInfo->psPhysAddr[i];
2377
2378 }
2379
2380 goto exit;
2381 }
2382
2383 PVR_DPF((PVR_DBG_MESSAGE, "OSAcquirePhysPageAddr: get_user_pages failed (%d), using CPU page table", psInfo->iNumPagesMapped));
2384
2385
2386 psInfo->eType = WRAP_TYPE_NULL;
2387 psInfo->iNumPagesMapped = 0;
2388 memset(psInfo->ppsPages, 0, (size_t)psInfo->iNumPages * sizeof(*psInfo->ppsPages));
2389
2390
2391
2392 psInfo->eType = WRAP_TYPE_FIND_VMA;
2393
2394 psVMArea = find_vma(current->mm, ulStartAddrOrig);
2395 if (psVMArea == NULL)
2396 {
2397 PVR_DPF((PVR_DBG_ERROR,
2398 "OSAcquirePhysPageAddr: Couldn't find memory region containing start address %x", ulStartAddrOrig));
2399
2400 goto error;
2401 }
2402#if defined(DEBUG)
2403 psInfo->psVMArea = psVMArea;
2404#endif
2405
2406
2407 if (ulStartAddrOrig < psVMArea->vm_start)
2408 {
2409 PVR_DPF((PVR_DBG_ERROR,
2410 "OSAcquirePhysPageAddr: Start address %x is outside of the region returned by find_vma", ulStartAddrOrig));
2411 goto error;
2412 }
2413
2414
2415 if (ulBeyondEndAddrOrig > psVMArea->vm_end)
2416 {
2417 PVR_DPF((PVR_DBG_ERROR,
2418 "OSAcquirePhysPageAddr: End address %x is outside of the region returned by find_vma", ulBeyondEndAddrOrig));
2419 goto error;
2420 }
2421
2422
2423 if ((psVMArea->vm_flags & (VM_IO | VM_RESERVED)) != (VM_IO | VM_RESERVED))
2424 {
2425 PVR_DPF((PVR_DBG_ERROR,
2426 "OSAcquirePhysPageAddr: Memory region does not represent memory mapped I/O (VMA flags: 0x%lx)", psVMArea->vm_flags));
2427 goto error;
2428 }
2429
2430
2431 if ((psVMArea->vm_flags & (VM_READ | VM_WRITE)) != (VM_READ | VM_WRITE))
2432 {
2433 PVR_DPF((PVR_DBG_ERROR,
2434 "OSAcquirePhysPageAddr: No read/write access to memory region (VMA flags: 0x%lx)", psVMArea->vm_flags));
2435 goto error;
2436 }
2437
2438 for (ulAddr = ulStartAddrOrig, i = 0; ulAddr < ulBeyondEndAddrOrig; ulAddr += PAGE_SIZE, i++)
2439 {
2440 IMG_CPU_PHYADDR CPUPhysAddr;
2441 IMG_UINT32 ulPFN = 0;
2442
2443 PVR_ASSERT(i < psInfo->iNumPages);
2444
2445 if (!CPUVAddrToPFN(psVMArea, ulAddr, &ulPFN, &psInfo->ppsPages[i]))
2446 {
2447 PVR_DPF((PVR_DBG_ERROR,
2448 "OSAcquirePhysPageAddr: Invalid CPU virtual address"));
2449
2450 goto error;
2451 }
2452 if (psInfo->ppsPages[i] == NULL)
2453 {
2454
2455 bHaveNoPageStructs = IMG_TRUE;
2456
2457#if defined(VM_PFNMAP)
2458 if ((psVMArea->vm_flags & VM_PFNMAP) != 0)
2459 {
2460 IMG_UINT32 ulPFNRaw = ((ulAddr - psVMArea->vm_start) >> PAGE_SHIFT) + psVMArea->vm_pgoff;
2461
2462 if (ulPFNRaw != ulPFN)
2463 {
2464 bPFNMismatch = IMG_TRUE;
2465 }
2466 }
2467#endif
2468 }
2469 else
2470 {
2471 bHavePageStructs = IMG_TRUE;
2472
2473 psInfo->iNumPagesMapped++;
2474
2475 PVR_ASSERT(ulPFN == page_to_pfn(psInfo->ppsPages[i]));
2476 }
2477
2478 CPUPhysAddr.uiAddr = ulPFN << PAGE_SHIFT;
2479 if ((CPUPhysAddr.uiAddr >> PAGE_SHIFT) != ulPFN)
2480 {
2481 PVR_DPF((PVR_DBG_ERROR,
2482 "OSAcquirePhysPageAddr: Page frame number out of range (%x)", ulPFN));
2483
2484 goto error;
2485 }
2486
2487 psInfo->psPhysAddr[i] = SysCpuPAddrToSysPAddr(CPUPhysAddr);
2488 psSysPAddr[i] = psInfo->psPhysAddr[i];
2489 }
2490 PVR_ASSERT(i == psInfo->iNumPages);
2491
2492#if defined(VM_MIXEDMAP)
2493 if ((psVMArea->vm_flags & VM_MIXEDMAP) != 0)
2494 {
2495 goto exit;
2496 }
2497#endif
2498
2499 if (bHavePageStructs && bHaveNoPageStructs)
2500 {
2501 PVR_DPF((PVR_DBG_ERROR,
2502 "OSAcquirePhysPageAddr: Region is VM_MIXEDMAP, but isn't marked as such"));
2503 goto error;
2504 }
2505
2506 if (!bHaveNoPageStructs)
2507 {
2508
2509 goto exit;
2510 }
2511
2512#if defined(VM_PFNMAP)
2513 if ((psVMArea->vm_flags & VM_PFNMAP) == 0)
2514#endif
2515 {
2516 PVR_DPF((PVR_DBG_ERROR,
2517 "OSAcquirePhysPageAddr: Region is VM_PFNMAP, but isn't marked as such"));
2518 goto error;
2519 }
2520
2521 if (bPFNMismatch)
2522 {
2523 PVR_DPF((PVR_DBG_ERROR,
2524 "OSAcquirePhysPageAddr: PFN calculation mismatch for VM_PFNMAP region"));
2525 goto error;
2526 }
2527
2528exit:
2529 PVR_ASSERT(bMMapSemHeld);
2530 up_read(&current->mm->mmap_sem);
2531
2532
2533 *phOSWrapMem = (IMG_HANDLE)psInfo;
2534
2535 if (bHaveNoPageStructs)
2536 {
2537 PVR_DPF((PVR_DBG_WARNING,
2538 "OSAcquirePhysPageAddr: Region contains pages which can't be locked down (no page structures)"));
2539 }
2540
2541 PVR_ASSERT(psInfo->eType != 0);
2542
2543#if 0
2544
2545
2546 OSCleanCPUCacheRangeKM(pvCPUVAddr, (IMG_VOID *)((IMG_CHAR *)pvCPUVAddr + ui32Bytes));
2547#endif
2548
2549 return PVRSRV_OK;
2550
2551error:
2552 if (bMMapSemHeld)
2553 {
2554 up_read(&current->mm->mmap_sem);
2555 }
2556 OSReleasePhysPageAddr((IMG_HANDLE)psInfo);
2557
2558 PVR_ASSERT(eError != PVRSRV_OK);
2559
2560 return eError;
2561}
2562
2563typedef void (*InnerCacheOp_t)(const void *pvStart, const void *pvEnd);
2564typedef void (*OuterCacheOp_t)(unsigned long ulStart, unsigned long ulEnd);
2565
2566#if defined(CONFIG_OUTER_CACHE)
2567
2568typedef unsigned long (*MemAreaToPhys_t)(LinuxMemArea *psLinuxMemArea,
2569 IMG_VOID *pvRangeAddrStart,
2570 IMG_UINT32 ui32PageNumOffset,
2571 IMG_UINT32 ui32PageNum);
2572
2573static unsigned long VMallocAreaToPhys(LinuxMemArea *psLinuxMemArea,
2574 IMG_VOID *pvRangeAddrStart,
2575 IMG_UINT32 ui32PageNumOffset,
2576 IMG_UINT32 ui32PageNum)
2577{
2578 return vmalloc_to_pfn(pvRangeAddrStart + ui32PageNum * PAGE_SIZE) << PAGE_SHIFT;
2579}
2580
2581static unsigned long ExternalKVAreaToPhys(LinuxMemArea *psLinuxMemArea,
2582 IMG_VOID *pvRangeAddrStart,
2583 IMG_UINT32 ui32PageNumOffset,
2584 IMG_UINT32 ui32PageNum)
2585{
2586 IMG_SYS_PHYADDR SysPAddr;
2587 IMG_CPU_PHYADDR CpuPAddr;
2588 SysPAddr = psLinuxMemArea->uData.sExternalKV.uPhysAddr.pSysPhysAddr[ui32PageNumOffset + ui32PageNum];
2589 CpuPAddr = SysSysPAddrToCpuPAddr(SysPAddr);
2590 return CpuPAddr.uiAddr;
2591}
2592
2593static unsigned long AllocPagesAreaToPhys(LinuxMemArea *psLinuxMemArea,
2594 IMG_VOID *pvRangeAddrStart,
2595 IMG_UINT32 ui32PageNumOffset,
2596 IMG_UINT32 ui32PageNum)
2597{
2598 struct page *pPage;
2599 pPage = psLinuxMemArea->uData.sPageList.pvPageList[ui32PageNumOffset + ui32PageNum];
2600 return page_to_pfn(pPage) << PAGE_SHIFT;
2601}
2602
2603#endif
2604
2605static
2606IMG_VOID *FindMMapBaseVAddr(struct list_head *psMMapOffsetStructList,
2607 IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length)
2608{
2609 PKV_OFFSET_STRUCT psOffsetStruct;
2610 IMG_VOID *pvMinVAddr;
2611
2612
2613 list_for_each_entry(psOffsetStruct, psMMapOffsetStructList, sAreaItem)
2614 {
2615 if(OSGetCurrentProcessIDKM() != psOffsetStruct->ui32PID)
2616 continue;
2617
2618 pvMinVAddr = (IMG_VOID *)psOffsetStruct->ui32UserVAddr;
2619
2620
2621 if(pvRangeAddrStart >= pvMinVAddr &&
2622 ui32Length <= psOffsetStruct->ui32RealByteSize)
2623 return pvMinVAddr;
2624 }
2625
2626 return IMG_NULL;
2627}
2628
2629static
2630IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle,
2631 IMG_VOID *pvRangeAddrStart,
2632 IMG_UINT32 ui32Length,
2633 InnerCacheOp_t pfnInnerCacheOp,
2634 OuterCacheOp_t pfnOuterCacheOp)
2635{
2636 LinuxMemArea *psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
2637 IMG_UINT32 ui32AreaLength, ui32AreaOffset = 0;
2638 struct list_head *psMMapOffsetStructList;
2639 IMG_VOID *pvMinVAddr;
2640
2641#if defined(CONFIG_OUTER_CACHE)
2642 MemAreaToPhys_t pfnMemAreaToPhys;
2643 IMG_UINT32 ui32PageNumOffset = 0;
2644#endif
2645
2646 PVR_ASSERT(psLinuxMemArea != IMG_NULL);
2647
2648 ui32AreaLength = psLinuxMemArea->ui32ByteSize;
2649 psMMapOffsetStructList = &psLinuxMemArea->sMMapOffsetStructList;
2650
2651 PVR_ASSERT(ui32Length <= ui32AreaLength);
2652
2653 if(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC)
2654 {
2655 ui32AreaOffset = psLinuxMemArea->uData.sSubAlloc.ui32ByteOffset;
2656 psLinuxMemArea = psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea;
2657 }
2658
2659
2660 PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC);
2661
2662 switch(psLinuxMemArea->eAreaType)
2663 {
2664 case LINUX_MEM_AREA_VMALLOC:
2665 {
2666 pvMinVAddr = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress + ui32AreaOffset;
2667
2668
2669 if(pvRangeAddrStart < pvMinVAddr &&
2670 ui32AreaOffset + ui32Length > ui32AreaLength)
2671 goto err_blocked;
2672
2673#if defined(CONFIG_OUTER_CACHE)
2674 pfnMemAreaToPhys = VMallocAreaToPhys;
2675#endif
2676 break;
2677 }
2678
2679 case LINUX_MEM_AREA_EXTERNAL_KV:
2680 {
2681
2682 PVR_ASSERT(psLinuxMemArea->uData.sExternalKV.bPhysContig != IMG_TRUE);
2683
2684
2685 PVR_ASSERT(psLinuxMemArea->uData.sExternalKV.pvExternalKV == IMG_NULL);
2686
2687
2688
2689 pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList,
2690 pvRangeAddrStart, ui32Length);
2691 if(!pvMinVAddr)
2692 goto err_blocked;
2693
2694#if defined(CONFIG_OUTER_CACHE)
2695 ui32PageNumOffset = (ui32AreaOffset + (pvRangeAddrStart - pvMinVAddr)) >> PAGE_SHIFT;
2696 pfnMemAreaToPhys = ExternalKVAreaToPhys;
2697#endif
2698 break;
2699 }
2700
2701 case LINUX_MEM_AREA_ALLOC_PAGES:
2702 {
2703 pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList,
2704 pvRangeAddrStart, ui32Length);
2705 if(!pvMinVAddr)
2706 goto err_blocked;
2707
2708#if defined(CONFIG_OUTER_CACHE)
2709 ui32PageNumOffset = (ui32AreaOffset + (pvRangeAddrStart - pvMinVAddr)) >> PAGE_SHIFT;
2710 pfnMemAreaToPhys = AllocPagesAreaToPhys;
2711#endif
2712 break;
2713 }
2714
2715 default:
2716 PVR_DBG_BREAK;
2717 }
2718
2719
2720 pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
2721
2722#if defined(CONFIG_OUTER_CACHE)
2723
2724 {
2725 unsigned long ulStart, ulEnd, ulLength, ulStartOffset, ulEndOffset;
2726 IMG_UINT32 i, ui32NumPages;
2727
2728
2729 ulLength = (unsigned long)ui32Length;
2730 ulStartOffset = ((unsigned long)pvRangeAddrStart) & (PAGE_SIZE - 1);
2731 ulEndOffset = ((unsigned long)pvRangeAddrStart + ulLength) & (PAGE_SIZE - 1);
2732
2733
2734 ui32NumPages = (ulStartOffset + ulLength + PAGE_SIZE - 1) >> PAGE_SHIFT;
2735
2736 for(i = 0; i < ui32NumPages; i++)
2737 {
2738 ulStart = pfnMemAreaToPhys(psLinuxMemArea, pvRangeAddrStart,
2739 ui32PageNumOffset, i);
2740 ulEnd = ulStart + PAGE_SIZE;
2741
2742 if(i == ui32NumPages - 1 && ulEndOffset != 0)
2743 ulEnd = ulStart + ulEndOffset;
2744
2745 if(i == 0)
2746 ulStart += ulStartOffset;
2747
2748 pfnOuterCacheOp(ulStart, ulEnd);
2749 }
2750 }
2751#endif
2752
2753 return IMG_TRUE;
2754
2755err_blocked:
2756 PVR_DPF((PVR_DBG_WARNING, "%s: Blocked cache op on virtual range "
2757 "%p-%p (type %d)", __func__,
2758 pvRangeAddrStart, pvRangeAddrStart + ui32Length,
2759 psLinuxMemArea->eAreaType));
2760 return IMG_FALSE;
2761}
2762
2763#if defined(__i386__)
2764
2765#define ROUND_UP(x,a) (((x) + (a) - 1) & ~((a) - 1))
2766
2767static void per_cpu_cache_flush(void *arg)
2768{
2769 PVR_UNREFERENCED_PARAMETER(arg);
2770 wbinvd();
2771}
2772
2773static void x86_flush_cache_range(const void *pvStart, const void *pvEnd)
2774{
2775 IMG_BYTE *pbStart = (IMG_BYTE *)pvStart;
2776 IMG_BYTE *pbEnd = (IMG_BYTE *)pvEnd;
2777 IMG_BYTE *pbBase;
2778
2779 pbEnd = (IMG_BYTE *)ROUND_UP((IMG_UINTPTR_T)pbEnd,
2780 boot_cpu_data.x86_clflush_size);
2781
2782 mb();
2783 for(pbBase = pbStart; pbBase < pbEnd; pbBase += boot_cpu_data.x86_clflush_size)
2784 clflush(pbBase);
2785 mb();
2786}
2787
2788IMG_VOID OSCleanCPUCacheKM(IMG_VOID)
2789{
2790
2791 on_each_cpu(per_cpu_cache_flush, NULL, 1);
2792}
2793
2794IMG_VOID OSFlushCPUCacheKM(IMG_VOID)
2795{
2796 on_each_cpu(per_cpu_cache_flush, NULL, 1);
2797}
2798
2799IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
2800 IMG_VOID *pvRangeAddrStart,
2801 IMG_UINT32 ui32Length)
2802{
2803
2804 return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
2805 x86_flush_cache_range, IMG_NULL);
2806}
2807
2808IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
2809 IMG_VOID *pvRangeAddrStart,
2810 IMG_UINT32 ui32Length)
2811{
2812
2813 return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
2814 x86_flush_cache_range, IMG_NULL);
2815}
2816
2817IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
2818 IMG_VOID *pvRangeAddrStart,
2819 IMG_UINT32 ui32Length)
2820{
2821
2822 return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
2823 x86_flush_cache_range, IMG_NULL);
2824}
2825
2826#else
2827
2828#if defined(__arm__)
2829
2830IMG_VOID OSCleanCPUCacheKM(IMG_VOID)
2831{
2832
2833 flush_cache_all();
2834}
2835
2836IMG_VOID OSFlushCPUCacheKM(IMG_VOID)
2837{
2838 flush_cache_all();
2839}
2840
2841IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
2842 IMG_VOID *pvRangeAddrStart,
2843 IMG_UINT32 ui32Length)
2844{
2845 return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
2846 dmac_flush_range, outer_flush_range);
2847}
2848
2849IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
2850 IMG_VOID *pvRangeAddrStart,
2851 IMG_UINT32 ui32Length)
2852{
2853 return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
2854 dmac_clean_range, outer_clean_range);
2855}
2856
2857IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
2858 IMG_VOID *pvRangeAddrStart,
2859 IMG_UINT32 ui32Length)
2860{
2861 return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
2862 dmac_inv_range, outer_inv_range);
2863}
2864
2865#else
2866
2867#error "Implement CPU cache flush/clean/invalidate primitives for this CPU!"
2868
2869#endif
2870
2871#endif
2872
2873PVRSRV_ERROR PVROSFuncInit(IMG_VOID)
2874{
2875#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
2876 {
2877 IMG_UINT32 ui32i;
2878
2879 psTimerWorkQueue = create_workqueue("pvr_timer");
2880 if (psTimerWorkQueue == NULL)
2881 {
2882 PVR_DPF((PVR_DBG_ERROR, "%s: couldn't create timer workqueue", __FUNCTION__));
2883 return PVRSRV_ERROR_UNABLE_TO_CREATE_THREAD;
2884
2885 }
2886
2887 for (ui32i = 0; ui32i < OS_MAX_TIMERS; ui32i++)
2888 {
2889 TIMER_CALLBACK_DATA *psTimerCBData = &sTimers[ui32i];
2890
2891 INIT_WORK(&psTimerCBData->sWork, OSTimerWorkQueueCallBack);
2892 }
2893 }
2894#endif
2895 return PVRSRV_OK;
2896}
2897
2898IMG_VOID PVROSFuncDeInit(IMG_VOID)
2899{
2900#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
2901 if (psTimerWorkQueue != NULL)
2902 {
2903 destroy_workqueue(psTimerWorkQueue);
2904 }
2905#endif
2906}