diff options
Diffstat (limited to 'drivers/gpu/pvr/osfunc.c')
-rw-r--r-- | drivers/gpu/pvr/osfunc.c | 2906 |
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) | ||
79 | PVRSRV_ERROR OSAllocMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID *ppvCpuVAddr, IMG_HANDLE *phBlockAlloc) | ||
80 | #else | ||
81 | PVRSRV_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) | ||
126 | PVRSRV_ERROR OSFreeMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID pvCpuVAddr, IMG_HANDLE hBlockAlloc) | ||
127 | #else | ||
128 | PVRSRV_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 | |||
155 | PVRSRV_ERROR | ||
156 | OSAllocPages_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 | |||
230 | PVRSRV_ERROR | ||
231 | OSFreePages(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 | |||
269 | PVRSRV_ERROR | ||
270 | OSGetSubMemHandle(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 | |||
303 | failed_register_area: | ||
304 | *phOSMemHandleRet = NULL; | ||
305 | LinuxMemAreaDeepFree(psLinuxMemArea); | ||
306 | return eError; | ||
307 | } | ||
308 | |||
309 | PVRSRV_ERROR | ||
310 | OSReleaseSubMemHandle(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 | |||
332 | IMG_CPU_PHYADDR | ||
333 | OSMemHandleToCpuPAddr(IMG_VOID *hOSMemHandle, IMG_UINT32 ui32ByteOffset) | ||
334 | { | ||
335 | PVR_ASSERT(hOSMemHandle); | ||
336 | |||
337 | return LinuxMemAreaToCpuPAddr(hOSMemHandle, ui32ByteOffset); | ||
338 | } | ||
339 | |||
340 | |||
341 | |||
342 | IMG_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 | |||
360 | IMG_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 | |||
377 | IMG_CHAR *OSStringCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc) | ||
378 | { | ||
379 | return (strcpy(pszDest, pszSrc)); | ||
380 | } | ||
381 | |||
382 | IMG_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 | |||
394 | IMG_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 | |||
417 | PVRSRV_ERROR OSCreateResource(PVRSRV_RESOURCE *psResource) | ||
418 | { | ||
419 | psResource->ui32ID = 0; | ||
420 | psResource->ui32Lock = 0; | ||
421 | |||
422 | return PVRSRV_OK; | ||
423 | } | ||
424 | |||
425 | |||
426 | PVRSRV_ERROR OSDestroyResource (PVRSRV_RESOURCE *psResource) | ||
427 | { | ||
428 | OSBreakResourceLock (psResource, psResource->ui32ID); | ||
429 | |||
430 | return PVRSRV_OK; | ||
431 | } | ||
432 | |||
433 | |||
434 | PVRSRV_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 | |||
469 | PVRSRV_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 | |||
487 | IMG_VOID OSReleaseThreadQuanta(IMG_VOID) | ||
488 | { | ||
489 | schedule(); | ||
490 | } | ||
491 | |||
492 | |||
493 | |||
494 | IMG_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 | |||
505 | IMG_VOID OSWaitus(IMG_UINT32 ui32Timeus) | ||
506 | { | ||
507 | udelay(ui32Timeus); | ||
508 | } | ||
509 | |||
510 | |||
511 | IMG_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 | |||
530 | IMG_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)) | ||
542 | static 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 | |||
570 | out: | ||
571 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) | ||
572 | return bStatus ? IRQ_HANDLED : IRQ_NONE; | ||
573 | #endif | ||
574 | } | ||
575 | |||
576 | |||
577 | |||
578 | static 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 | |||
606 | out: | ||
607 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) | ||
608 | return bStatus ? IRQ_HANDLED : IRQ_NONE; | ||
609 | #endif | ||
610 | } | ||
611 | PVRSRV_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 | |||
647 | PVRSRV_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 | |||
668 | PVRSRV_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 | |||
702 | PVRSRV_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) | ||
723 | static 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 | |||
738 | PVRSRV_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 | |||
772 | PVRSRV_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 | |||
793 | PVRSRV_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) | ||
807 | static 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 | |||
822 | PVRSRV_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 | |||
848 | PVRSRV_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 | |||
869 | PVRSRV_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 | |||
885 | static void MISRWrapper(unsigned long data) | ||
886 | { | ||
887 | SYS_DATA *psSysData; | ||
888 | |||
889 | psSysData = (SYS_DATA *)data; | ||
890 | |||
891 | PVRSRVMISR(psSysData); | ||
892 | } | ||
893 | |||
894 | |||
895 | PVRSRV_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 | |||
916 | PVRSRV_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 | |||
936 | PVRSRV_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 | |||
954 | IMG_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 | ||
964 | PVRSRV_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 | |||
979 | PVRSRV_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 | |||
1008 | IMG_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 | |||
1018 | IMG_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 | |||
1041 | IMG_VOID * | ||
1042 | OSMapPhysToLin(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 | |||
1081 | IMG_BOOL | ||
1082 | OSUnMapPhysToLin(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 | |||
1112 | static PVRSRV_ERROR | ||
1113 | RegisterExternalMem(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 | |||
1175 | PVRSRV_ERROR | ||
1176 | OSRegisterMem(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 | |||
1188 | PVRSRV_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 | |||
1194 | PVRSRV_ERROR | ||
1195 | OSUnRegisterMem (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 | |||
1235 | PVRSRV_ERROR OSUnRegisterDiscontigMem(IMG_VOID *pvCpuVAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32Flags, IMG_HANDLE hOSMemHandle) | ||
1236 | { | ||
1237 | return OSUnRegisterMem(pvCpuVAddr, ui32Bytes, ui32Flags, hOSMemHandle); | ||
1238 | } | ||
1239 | |||
1240 | PVRSRV_ERROR | ||
1241 | OSReservePhys(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 | |||
1311 | PVRSRV_ERROR | ||
1312 | OSUnReservePhys(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 | |||
1355 | PVRSRV_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 | |||
1386 | PVRSRV_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 | |||
1403 | IMG_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 | |||
1412 | IMG_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 | |||
1423 | PVRSRV_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 | |||
1476 | PVRSRV_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 | |||
1490 | PVRSRV_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 | |||
1499 | enum 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 | |||
1508 | static 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 | |||
1557 | IMG_UINT32 OSPCIAddrRangeLen(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index) | ||
1558 | { | ||
1559 | return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_LEN, hPVRPCI, ui32Index); | ||
1560 | } | ||
1561 | |||
1562 | IMG_UINT32 OSPCIAddrRangeStart(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index) | ||
1563 | { | ||
1564 | return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_START, hPVRPCI, ui32Index); | ||
1565 | } | ||
1566 | |||
1567 | IMG_UINT32 OSPCIAddrRangeEnd(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index) | ||
1568 | { | ||
1569 | return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_END, hPVRPCI, ui32Index); | ||
1570 | } | ||
1571 | |||
1572 | PVRSRV_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 | |||
1578 | PVRSRV_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 | |||
1583 | PVRSRV_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 | |||
1622 | PVRSRV_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 | |||
1667 | PVRSRV_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 | |||
1729 | typedef 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) | ||
1743 | static struct workqueue_struct *psTimerWorkQueue; | ||
1744 | #endif | ||
1745 | |||
1746 | static TIMER_CALLBACK_DATA sTimers[OS_MAX_TIMERS]; | ||
1747 | |||
1748 | #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) | ||
1749 | DEFINE_MUTEX(sTimerStructLock); | ||
1750 | #else | ||
1751 | |||
1752 | static spinlock_t sTimerStructLock = SPIN_LOCK_UNLOCKED; | ||
1753 | #endif | ||
1754 | |||
1755 | static 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 | |||
1768 | static 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) | ||
1787 | static 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 | |||
1795 | IMG_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 | |||
1858 | static 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 | |||
1867 | PVRSRV_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 | |||
1881 | PVRSRV_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 | |||
1901 | PVRSRV_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 | |||
1928 | PVRSRV_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 | |||
1964 | PVRSRV_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 | |||
1989 | PVRSRV_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 | |||
2006 | PVRSRV_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 | |||
2029 | PVRSRV_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 | |||
2053 | PVRSRV_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 | |||
2070 | IMG_BOOL OSProcHasPrivSrvInit(IMG_VOID) | ||
2071 | { | ||
2072 | return (capable(CAP_SYS_MODULE) != 0) ? IMG_TRUE : IMG_FALSE; | ||
2073 | } | ||
2074 | |||
2075 | PVRSRV_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 | |||
2088 | PVRSRV_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 | |||
2101 | IMG_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 | |||
2118 | typedef enum _eWrapMemType_ | ||
2119 | { | ||
2120 | WRAP_TYPE_NULL = 0, | ||
2121 | WRAP_TYPE_GET_USER_PAGES, | ||
2122 | WRAP_TYPE_FIND_VMA | ||
2123 | } eWrapMemType; | ||
2124 | |||
2125 | typedef 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 | |||
2141 | static 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 | |||
2190 | PVRSRV_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 | |||
2264 | PVRSRV_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(¤t->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 | |||
2528 | exit: | ||
2529 | PVR_ASSERT(bMMapSemHeld); | ||
2530 | up_read(¤t->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 | |||
2551 | error: | ||
2552 | if (bMMapSemHeld) | ||
2553 | { | ||
2554 | up_read(¤t->mm->mmap_sem); | ||
2555 | } | ||
2556 | OSReleasePhysPageAddr((IMG_HANDLE)psInfo); | ||
2557 | |||
2558 | PVR_ASSERT(eError != PVRSRV_OK); | ||
2559 | |||
2560 | return eError; | ||
2561 | } | ||
2562 | |||
2563 | typedef void (*InnerCacheOp_t)(const void *pvStart, const void *pvEnd); | ||
2564 | typedef void (*OuterCacheOp_t)(unsigned long ulStart, unsigned long ulEnd); | ||
2565 | |||
2566 | #if defined(CONFIG_OUTER_CACHE) | ||
2567 | |||
2568 | typedef unsigned long (*MemAreaToPhys_t)(LinuxMemArea *psLinuxMemArea, | ||
2569 | IMG_VOID *pvRangeAddrStart, | ||
2570 | IMG_UINT32 ui32PageNumOffset, | ||
2571 | IMG_UINT32 ui32PageNum); | ||
2572 | |||
2573 | static 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 | |||
2581 | static 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 | |||
2593 | static 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 | |||
2605 | static | ||
2606 | IMG_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 | |||
2629 | static | ||
2630 | IMG_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 | |||
2755 | err_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 | |||
2767 | static void per_cpu_cache_flush(void *arg) | ||
2768 | { | ||
2769 | PVR_UNREFERENCED_PARAMETER(arg); | ||
2770 | wbinvd(); | ||
2771 | } | ||
2772 | |||
2773 | static 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 | |||
2788 | IMG_VOID OSCleanCPUCacheKM(IMG_VOID) | ||
2789 | { | ||
2790 | |||
2791 | on_each_cpu(per_cpu_cache_flush, NULL, 1); | ||
2792 | } | ||
2793 | |||
2794 | IMG_VOID OSFlushCPUCacheKM(IMG_VOID) | ||
2795 | { | ||
2796 | on_each_cpu(per_cpu_cache_flush, NULL, 1); | ||
2797 | } | ||
2798 | |||
2799 | IMG_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 | |||
2808 | IMG_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 | |||
2817 | IMG_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 | |||
2830 | IMG_VOID OSCleanCPUCacheKM(IMG_VOID) | ||
2831 | { | ||
2832 | |||
2833 | flush_cache_all(); | ||
2834 | } | ||
2835 | |||
2836 | IMG_VOID OSFlushCPUCacheKM(IMG_VOID) | ||
2837 | { | ||
2838 | flush_cache_all(); | ||
2839 | } | ||
2840 | |||
2841 | IMG_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 | |||
2849 | IMG_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 | |||
2857 | IMG_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 | |||
2873 | PVRSRV_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 | |||
2898 | IMG_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 | } | ||