1 /*************************************************************************/ /*!
3 @Title Devicemem history functions
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description Devicemem history functions
6 @License Dual MIT/GPLv2
8 The contents of this file are subject to the MIT license as set out below.
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files (the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions:
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
20 Alternatively, the contents of this file may be used under the terms of
21 the GNU General Public License Version 2 ("GPL") in which case the provisions
22 of GPL are applicable instead of those above.
24 If you wish to allow use of your version of this file only under the terms of
25 GPL, and not to allow others to use your version of this file under the terms
26 of the MIT license, indicate your decision by deleting the provisions above
27 and replace them with the notice and other provisions required by GPL as set
28 out in the file called "GPL-COPYING" included in this distribution. If you do
29 not delete the provisions above, a recipient may use your version of this file
30 under the terms of either the MIT license or GPL.
32 This License is also included in this distribution in the file called
35 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
36 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
37 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
38 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
39 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
40 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
41 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 */ /**************************************************************************/
48 #include "pvrsrv_device.h"
49 #include "pvr_debug.h"
50 #include "devicemem_server.h"
52 #include "devicemem_history_server.h"
54 #include "di_server.h"
56 #define ALLOCATION_LIST_NUM_ENTRIES 10000
58 /* data type to hold an allocation index.
59 * we make it 16 bits wide if possible
61 #if ALLOCATION_LIST_NUM_ENTRIES <= 0xFFFF
62 typedef uint16_t ALLOC_INDEX_T;
64 typedef uint32_t ALLOC_INDEX_T;
67 /* a record describing a single allocation known to DeviceMemHistory.
68 * this is an element in a doubly linked list of allocations
70 typedef struct _RECORD_ALLOCATION_
72 /* time when this RECORD_ALLOCATION was created/initialised */
73 IMG_UINT64 ui64CreationTime;
74 /* serial number of the PMR relating to this allocation */
75 IMG_UINT64 ui64Serial;
76 /* base DevVAddr of this allocation */
77 IMG_DEV_VIRTADDR sDevVAddr;
78 /* size in bytes of this allocation */
79 IMG_DEVMEM_SIZE_T uiSize;
80 /* Log2 page size of this allocation's GPU pages */
81 IMG_UINT32 ui32Log2PageSize;
82 /* Process ID (PID) this allocation belongs to */
84 /* index of previous allocation in the list */
85 ALLOC_INDEX_T ui32Prev;
86 /* index of next allocation in the list */
87 ALLOC_INDEX_T ui32Next;
88 /* annotation/name of this allocation */
89 IMG_CHAR szName[DEVMEM_ANNOTATION_MAX_LEN];
92 /* each command in the circular buffer is prefixed with an 8-bit value
93 * denoting the command type
95 typedef enum _COMMAND_TYPE_
98 COMMAND_TYPE_TIMESTAMP,
100 COMMAND_TYPE_UNMAP_ALL,
101 COMMAND_TYPE_MAP_RANGE,
102 COMMAND_TYPE_UNMAP_RANGE,
107 /* Timestamp command:
108 * This command is inserted into the circular buffer to provide an updated
110 * The nanosecond-accuracy timestamp is packed into a 56-bit integer, in order
111 * for the whole command to fit into 8 bytes.
113 typedef struct _COMMAND_TIMESTAMP_
115 IMG_UINT8 aui8TimeNs[7];
119 * This command denotes the allocation at the given index was wholly mapped
122 typedef struct _COMMAND_MAP_ALL_
124 ALLOC_INDEX_T uiAllocIndex;
127 /* UNMAP_ALL command:
128 * This command denotes the allocation at the given index was wholly unmapped
130 * Note: COMMAND_MAP_ALL and COMMAND_UNMAP_ALL commands have the same layout.
132 typedef COMMAND_MAP_ALL COMMAND_UNMAP_ALL;
134 /* packing attributes for the MAP_RANGE command */
135 #define MAP_RANGE_MAX_START ((1 << 18) - 1)
136 #define MAP_RANGE_MAX_RANGE ((1 << 12) - 1)
138 /* MAP_RANGE command:
139 * Denotes a range of pages within the given allocation being mapped.
140 * The range is expressed as [Page Index] + [Page Count]
141 * This information is packed into a 40-bit integer, in order to make
142 * the command size 8 bytes.
145 typedef struct _COMMAND_MAP_RANGE_
147 IMG_UINT8 aui8Data[5];
148 ALLOC_INDEX_T uiAllocIndex;
151 /* UNMAP_RANGE command:
152 * Denotes a range of pages within the given allocation being mapped.
153 * The range is expressed as [Page Index] + [Page Count]
154 * This information is packed into a 40-bit integer, in order to make
155 * the command size 8 bytes.
156 * Note: COMMAND_MAP_RANGE and COMMAND_UNMAP_RANGE commands have the same layout.
158 typedef COMMAND_MAP_RANGE COMMAND_UNMAP_RANGE;
160 /* wrapper structure for a command */
161 typedef struct _COMMAND_WRAPPER_
165 COMMAND_TIMESTAMP sTimeStamp;
166 COMMAND_MAP_ALL sMapAll;
167 COMMAND_UNMAP_ALL sUnmapAll;
168 COMMAND_MAP_RANGE sMapRange;
169 COMMAND_UNMAP_RANGE sUnmapRange;
173 /* target size for the circular buffer of commands */
174 #define CIRCULAR_BUFFER_SIZE_KB 2048
175 /* turn the circular buffer target size into a number of commands */
176 #define CIRCULAR_BUFFER_NUM_COMMANDS ((CIRCULAR_BUFFER_SIZE_KB * 1024) / sizeof(COMMAND_WRAPPER))
178 /* index value denoting the end of a list */
179 #define END_OF_LIST 0xFFFFFFFF
180 #define ALLOC_INDEX_TO_PTR(idx) (&(gsDevicememHistoryData.sRecords.pasAllocations[idx]))
181 #define CHECK_ALLOC_INDEX(idx) (idx < ALLOCATION_LIST_NUM_ENTRIES)
183 /* wrapper structure for the allocation records and the commands circular buffer */
184 typedef struct _RECORDS_
186 RECORD_ALLOCATION *pasAllocations;
187 IMG_UINT32 ui32AllocationsListHead;
191 COMMAND_WRAPPER *pasCircularBuffer;
194 typedef struct _DEVICEMEM_HISTORY_DATA_
201 } DEVICEMEM_HISTORY_DATA;
203 static DEVICEMEM_HISTORY_DATA gsDevicememHistoryData;
205 /* gsDevicememHistoryData is static, hLock is NULL unless
206 * EnablePageFaultDebug is set and DevicememHistoryInitKM()
209 static void DevicememHistoryLock(void)
211 if (gsDevicememHistoryData.hLock)
213 OSLockAcquire(gsDevicememHistoryData.hLock);
217 static void DevicememHistoryUnlock(void)
219 if (gsDevicememHistoryData.hLock)
221 OSLockRelease(gsDevicememHistoryData.hLock);
225 /* given a time stamp, calculate the age in nanoseconds */
226 static IMG_UINT64 _CalculateAge(IMG_UINT64 ui64Now,
230 if (ui64Now >= ui64Then)
233 return ui64Now - ui64Then;
237 /* clock has wrapped */
238 return (ui64Max - ui64Then) + ui64Now + 1;
243 * Acquire the next slot in the circular buffer and
244 * move the circular buffer head along by one
245 * Returns a pointer to the acquired slot.
247 static COMMAND_WRAPPER *AcquireCBSlot(void)
249 COMMAND_WRAPPER *psSlot;
251 psSlot = &gsDevicememHistoryData.sRecords.pasCircularBuffer[gsDevicememHistoryData.sRecords.ui32Head];
253 gsDevicememHistoryData.sRecords.ui32Head =
254 (gsDevicememHistoryData.sRecords.ui32Head + 1)
255 % CIRCULAR_BUFFER_NUM_COMMANDS;
261 * Packs the given timestamp value into the COMMAND_TIMESTAMP structure.
262 * This takes a 64-bit nanosecond timestamp and packs it in to a 56-bit
263 * integer in the COMMAND_TIMESTAMP command.
265 static void TimeStampPack(COMMAND_TIMESTAMP *psTimeStamp, IMG_UINT64 ui64Now)
269 for (i = 0; i < ARRAY_SIZE(psTimeStamp->aui8TimeNs); i++)
271 psTimeStamp->aui8TimeNs[i] = ui64Now & 0xFF;
276 /* packing a 64-bit nanosecond into a 7-byte integer loses the
277 * top 8 bits of data. This must be taken into account when
278 * comparing a full timestamp against an unpacked timestamp
280 #define TIME_STAMP_MASK ((1LLU << 56) - 1)
281 #define DO_TIME_STAMP_MASK(ns64) (ns64 & TIME_STAMP_MASK)
284 * Unpack the timestamp value from the given COMMAND_TIMESTAMP command
286 static IMG_UINT64 TimeStampUnpack(COMMAND_TIMESTAMP *psTimeStamp)
288 IMG_UINT64 ui64TimeNs = 0;
291 for (i = ARRAY_SIZE(psTimeStamp->aui8TimeNs); i > 0; i--)
294 ui64TimeNs |= (IMG_UINT64) psTimeStamp->aui8TimeNs[i - 1];
302 static void EmitPDumpAllocation(PVRSRV_DEVICE_NODE *psDeviceNode,
303 IMG_UINT32 ui32AllocationIndex,
304 RECORD_ALLOCATION *psAlloc)
306 PDUMPCOMMENT(psDeviceNode,
307 "[SrvPFD] Allocation: %u"
308 " Addr: " IMG_DEV_VIRTADDR_FMTSPEC
309 " Size: " IMG_DEVMEM_SIZE_FMTSPEC
315 psAlloc->sDevVAddr.uiAddr,
317 1U << psAlloc->ui32Log2PageSize,
319 OSGetCurrentClientProcessNameKM(),
323 static void EmitPDumpMapUnmapAll(PVRSRV_DEVICE_NODE *psDeviceNode,
325 IMG_UINT32 ui32AllocationIndex)
327 const IMG_CHAR *pszOpName;
331 case COMMAND_TYPE_MAP_ALL:
332 pszOpName = "MAP_ALL";
334 case COMMAND_TYPE_UNMAP_ALL:
335 pszOpName = "UNMAP_ALL";
338 PVR_DPF((PVR_DBG_ERROR, "EmitPDumpMapUnmapAll: Invalid type: %u",
344 PDUMPCOMMENT(psDeviceNode,
345 "[SrvPFD] Op: %s Allocation: %u",
347 ui32AllocationIndex);
350 static void EmitPDumpMapUnmapRange(PVRSRV_DEVICE_NODE *psDeviceNode,
352 IMG_UINT32 ui32AllocationIndex,
353 IMG_UINT32 ui32StartPage,
354 IMG_UINT32 ui32Count)
356 const IMG_CHAR *pszOpName;
360 case COMMAND_TYPE_MAP_RANGE:
361 pszOpName = "MAP_RANGE";
363 case COMMAND_TYPE_UNMAP_RANGE:
364 pszOpName = "UNMAP_RANGE";
367 PVR_DPF((PVR_DBG_ERROR, "EmitPDumpMapUnmapRange: Invalid type: %u",
372 PDUMPCOMMENT(psDeviceNode,
373 "[SrvPFD] Op: %s Allocation: %u Start Page: %u Count: %u",
382 /* InsertTimeStampCommand:
383 * Insert a timestamp command into the circular buffer.
385 static void InsertTimeStampCommand(IMG_UINT64 ui64Now)
387 COMMAND_WRAPPER *psCommand;
389 psCommand = AcquireCBSlot();
391 psCommand->ui8Type = COMMAND_TYPE_TIMESTAMP;
393 TimeStampPack(&psCommand->u.sTimeStamp, ui64Now);
396 /* InsertMapAllCommand:
397 * Insert a "MAP_ALL" command for the given allocation into the circular buffer
399 static void InsertMapAllCommand(PVRSRV_DEVICE_NODE *psDeviceNode,
400 IMG_UINT32 ui32AllocIndex)
402 COMMAND_WRAPPER *psCommand;
404 psCommand = AcquireCBSlot();
406 psCommand->ui8Type = COMMAND_TYPE_MAP_ALL;
407 psCommand->u.sMapAll.uiAllocIndex = ui32AllocIndex;
410 EmitPDumpMapUnmapAll(psDeviceNode, COMMAND_TYPE_MAP_ALL, ui32AllocIndex);
412 PVR_UNREFERENCED_PARAMETER(psDeviceNode);
416 /* InsertUnmapAllCommand:
417 * Insert a "UNMAP_ALL" command for the given allocation into the circular buffer
419 static void InsertUnmapAllCommand(PVRSRV_DEVICE_NODE *psDeviceNode,
420 IMG_UINT32 ui32AllocIndex)
422 COMMAND_WRAPPER *psCommand;
424 psCommand = AcquireCBSlot();
426 psCommand->ui8Type = COMMAND_TYPE_UNMAP_ALL;
427 psCommand->u.sUnmapAll.uiAllocIndex = ui32AllocIndex;
430 EmitPDumpMapUnmapAll(psDeviceNode, COMMAND_TYPE_UNMAP_ALL, ui32AllocIndex);
432 PVR_UNREFERENCED_PARAMETER(psDeviceNode);
437 * Pack the given StartPage and Count values into the 40-bit representation
438 * in the MAP_RANGE command.
440 static void MapRangePack(COMMAND_MAP_RANGE *psMapRange,
441 IMG_UINT32 ui32StartPage,
442 IMG_UINT32 ui32Count)
447 /* we must encode the data into 40 bits:
448 * 18 bits for the start page index
449 * 12 bits for the range
451 PVR_ASSERT(ui32StartPage <= MAP_RANGE_MAX_START);
452 PVR_ASSERT(ui32Count <= MAP_RANGE_MAX_RANGE);
454 ui64Data = (((IMG_UINT64) ui32StartPage) << 12) | ui32Count;
456 for (i = 0; i < ARRAY_SIZE(psMapRange->aui8Data); i++)
458 psMapRange->aui8Data[i] = ui64Data & 0xFF;
464 * Unpack the StartPage and Count values from the 40-bit representation
465 * in the MAP_RANGE command.
467 static void MapRangeUnpack(COMMAND_MAP_RANGE *psMapRange,
468 IMG_UINT32 *pui32StartPage,
469 IMG_UINT32 *pui32Count)
471 IMG_UINT64 ui64Data = 0;
474 for (i = ARRAY_SIZE(psMapRange->aui8Data); i > 0; i--)
477 ui64Data |= (IMG_UINT64) psMapRange->aui8Data[i - 1];
480 *pui32StartPage = (ui64Data >> 12);
481 *pui32Count = ui64Data & ((1 << 12) - 1);
484 /* InsertMapRangeCommand:
485 * Insert a MAP_RANGE command into the circular buffer with the given
486 * StartPage and Count values.
488 static void InsertMapRangeCommand(PVRSRV_DEVICE_NODE *psDeviceNode,
489 IMG_UINT32 ui32AllocIndex,
490 IMG_UINT32 ui32StartPage,
491 IMG_UINT32 ui32Count)
493 COMMAND_WRAPPER *psCommand;
495 psCommand = AcquireCBSlot();
497 psCommand->ui8Type = COMMAND_TYPE_MAP_RANGE;
498 psCommand->u.sMapRange.uiAllocIndex = ui32AllocIndex;
500 MapRangePack(&psCommand->u.sMapRange, ui32StartPage, ui32Count);
503 EmitPDumpMapUnmapRange(psDeviceNode,
504 COMMAND_TYPE_MAP_RANGE,
509 PVR_UNREFERENCED_PARAMETER(psDeviceNode);
513 /* InsertUnmapRangeCommand:
514 * Insert a UNMAP_RANGE command into the circular buffer with the given
515 * StartPage and Count values.
517 static void InsertUnmapRangeCommand(PVRSRV_DEVICE_NODE *psDeviceNode,
518 IMG_UINT32 ui32AllocIndex,
519 IMG_UINT32 ui32StartPage,
520 IMG_UINT32 ui32Count)
522 COMMAND_WRAPPER *psCommand;
524 psCommand = AcquireCBSlot();
526 psCommand->ui8Type = COMMAND_TYPE_UNMAP_RANGE;
527 psCommand->u.sMapRange.uiAllocIndex = ui32AllocIndex;
529 MapRangePack(&psCommand->u.sMapRange, ui32StartPage, ui32Count);
532 EmitPDumpMapUnmapRange(psDeviceNode,
533 COMMAND_TYPE_UNMAP_RANGE,
538 PVR_UNREFERENCED_PARAMETER(psDeviceNode);
542 /* InsertAllocationToList:
543 * Helper function for the allocation list.
544 * Inserts the given allocation at the head of the list, whose current head is
545 * pointed to by pui32ListHead
547 static void InsertAllocationToList(IMG_UINT32 *pui32ListHead, IMG_UINT32 ui32Alloc)
549 RECORD_ALLOCATION *psAlloc;
551 psAlloc = ALLOC_INDEX_TO_PTR(ui32Alloc);
553 if (*pui32ListHead == END_OF_LIST)
555 /* list is currently empty, so just replace it */
556 *pui32ListHead = ui32Alloc;
557 psAlloc->ui32Next = psAlloc->ui32Prev = *pui32ListHead;
561 RECORD_ALLOCATION *psHeadAlloc;
562 RECORD_ALLOCATION *psTailAlloc;
564 psHeadAlloc = ALLOC_INDEX_TO_PTR(*pui32ListHead);
565 psTailAlloc = ALLOC_INDEX_TO_PTR(psHeadAlloc->ui32Prev);
567 /* make the new alloc point forwards to the previous head */
568 psAlloc->ui32Next = *pui32ListHead;
569 /* make the new alloc point backwards to the previous tail */
570 psAlloc->ui32Prev = psHeadAlloc->ui32Prev;
572 /* the head is now our new alloc */
573 *pui32ListHead = ui32Alloc;
575 /* the old head now points back to the new head */
576 psHeadAlloc->ui32Prev = *pui32ListHead;
578 /* the tail now points forward to the new head */
579 psTailAlloc->ui32Next = ui32Alloc;
583 static void InsertAllocationToBusyList(IMG_UINT32 ui32Alloc)
585 InsertAllocationToList(&gsDevicememHistoryData.sRecords.ui32AllocationsListHead, ui32Alloc);
588 /* RemoveAllocationFromList:
589 * Helper function for the allocation list.
590 * Removes the given allocation from the list, whose head is
591 * pointed to by pui32ListHead
593 static void RemoveAllocationFromList(IMG_UINT32 *pui32ListHead, IMG_UINT32 ui32Alloc)
595 RECORD_ALLOCATION *psAlloc;
597 psAlloc = ALLOC_INDEX_TO_PTR(ui32Alloc);
599 /* if this is the only element in the list then just make the list empty */
600 if ((*pui32ListHead == ui32Alloc) && (psAlloc->ui32Next == ui32Alloc))
602 *pui32ListHead = END_OF_LIST;
606 RECORD_ALLOCATION *psPrev, *psNext;
608 psPrev = ALLOC_INDEX_TO_PTR(psAlloc->ui32Prev);
609 psNext = ALLOC_INDEX_TO_PTR(psAlloc->ui32Next);
611 /* remove the allocation from the list */
612 psPrev->ui32Next = psAlloc->ui32Next;
613 psNext->ui32Prev = psAlloc->ui32Prev;
615 /* if this allocation is the head then update the head */
616 if (*pui32ListHead == ui32Alloc)
618 *pui32ListHead = psAlloc->ui32Prev;
623 static void RemoveAllocationFromBusyList(IMG_UINT32 ui32Alloc)
625 RemoveAllocationFromList(&gsDevicememHistoryData.sRecords.ui32AllocationsListHead, ui32Alloc);
628 /* TouchBusyAllocation:
629 * Move the given allocation to the head of the list
631 static void TouchBusyAllocation(IMG_UINT32 ui32Alloc)
633 RemoveAllocationFromBusyList(ui32Alloc);
634 InsertAllocationToBusyList(ui32Alloc);
637 /* GetOldestBusyAllocation:
638 * Returns the index of the oldest allocation in the MRU list
640 static IMG_UINT32 GetOldestBusyAllocation(void)
642 IMG_UINT32 ui32Alloc;
643 RECORD_ALLOCATION *psAlloc;
645 ui32Alloc = gsDevicememHistoryData.sRecords.ui32AllocationsListHead;
647 if (ui32Alloc == END_OF_LIST)
652 psAlloc = ALLOC_INDEX_TO_PTR(ui32Alloc);
654 return psAlloc->ui32Prev;
657 static IMG_UINT32 GetFreeAllocation(void)
659 IMG_UINT32 ui32Alloc;
661 ui32Alloc = GetOldestBusyAllocation();
667 /* InitialiseAllocation:
668 * Initialise the given allocation structure with the given properties
670 static void InitialiseAllocation(RECORD_ALLOCATION *psAlloc,
671 const IMG_CHAR *pszName,
672 IMG_UINT64 ui64Serial,
674 IMG_DEV_VIRTADDR sDevVAddr,
675 IMG_DEVMEM_SIZE_T uiSize,
676 IMG_UINT32 ui32Log2PageSize)
678 OSStringLCopy(psAlloc->szName, pszName, sizeof(psAlloc->szName));
679 psAlloc->ui64Serial = ui64Serial;
680 psAlloc->uiPID = uiPID;
681 psAlloc->sDevVAddr = sDevVAddr;
682 psAlloc->uiSize = uiSize;
683 psAlloc->ui32Log2PageSize = ui32Log2PageSize;
684 psAlloc->ui64CreationTime = OSClockns64();
688 * Creates a new allocation with the given properties then outputs the
689 * index of the allocation
691 static PVRSRV_ERROR CreateAllocation(PVRSRV_DEVICE_NODE *psDeviceNode,
692 const IMG_CHAR *pszName,
693 IMG_UINT64 ui64Serial,
695 IMG_DEV_VIRTADDR sDevVAddr,
696 IMG_DEVMEM_SIZE_T uiSize,
697 IMG_UINT32 ui32Log2PageSize,
699 IMG_UINT32 *puiAllocationIndex)
701 IMG_UINT32 ui32Alloc;
702 RECORD_ALLOCATION *psAlloc;
704 ui32Alloc = GetFreeAllocation();
706 psAlloc = ALLOC_INDEX_TO_PTR(ui32Alloc);
708 InitialiseAllocation(ALLOC_INDEX_TO_PTR(ui32Alloc),
716 /* put the newly initialised allocation at the front of the MRU list */
717 TouchBusyAllocation(ui32Alloc);
719 *puiAllocationIndex = ui32Alloc;
722 EmitPDumpAllocation(psDeviceNode, ui32Alloc, psAlloc);
724 PVR_UNREFERENCED_PARAMETER(psDeviceNode);
731 * Tests if the allocation at the given index matches the supplied properties.
732 * Returns IMG_TRUE if it is a match, otherwise IMG_FALSE.
734 static IMG_BOOL MatchAllocation(IMG_UINT32 ui32AllocationIndex,
735 IMG_UINT64 ui64Serial,
736 IMG_DEV_VIRTADDR sDevVAddr,
737 IMG_DEVMEM_SIZE_T uiSize,
738 const IMG_CHAR *pszName,
739 IMG_UINT32 ui32Log2PageSize,
742 RECORD_ALLOCATION *psAlloc;
744 psAlloc = ALLOC_INDEX_TO_PTR(ui32AllocationIndex);
746 return (psAlloc->ui64Serial == ui64Serial) &&
747 (psAlloc->sDevVAddr.uiAddr == sDevVAddr.uiAddr) &&
748 (psAlloc->uiSize == uiSize) &&
749 (psAlloc->ui32Log2PageSize == ui32Log2PageSize) &&
750 (OSStringNCompare(psAlloc->szName, pszName, DEVMEM_ANNOTATION_MAX_LEN) == 0);
753 /* FindOrCreateAllocation:
754 * Convenience function.
755 * Given a set of allocation properties (serial, DevVAddr, size, name, etc),
756 * this function will look for an existing record of this allocation and
757 * create the allocation if there is no existing record
759 static PVRSRV_ERROR FindOrCreateAllocation(PVRSRV_DEVICE_NODE *psDeviceNode,
760 IMG_UINT32 ui32AllocationIndexHint,
761 IMG_UINT64 ui64Serial,
762 IMG_DEV_VIRTADDR sDevVAddr,
763 IMG_DEVMEM_SIZE_T uiSize,
765 IMG_UINT32 ui32Log2PageSize,
768 IMG_UINT32 *pui32AllocationIndexOut,
771 IMG_UINT32 ui32AllocationIndex;
774 if (ui32AllocationIndexHint != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE)
776 IMG_BOOL bHaveAllocation;
778 /* first, try to match against the index given by the client.
779 * if the caller provided a hint but the allocation record is no longer
780 * there, it must have been purged, so go ahead and create a new allocation
782 bHaveAllocation = MatchAllocation(ui32AllocationIndexHint,
791 *pbCreated = IMG_FALSE;
792 *pui32AllocationIndexOut = ui32AllocationIndexHint;
797 /* if there is no record of the allocation then we
800 eError = CreateAllocation(psDeviceNode,
808 &ui32AllocationIndex);
810 if (eError == PVRSRV_OK)
812 *pui32AllocationIndexOut = ui32AllocationIndex;
813 *pbCreated = IMG_TRUE;
817 PVR_DPF((PVR_DBG_ERROR,
818 "%s: Failed to create record for allocation %s",
826 /* GenerateMapUnmapCommandsForSparsePMR:
827 * Generate the MAP_RANGE or UNMAP_RANGE commands for the sparse PMR, using the PMR's
828 * current mapping table
830 * PMR: The PMR whose mapping table to read.
831 * ui32AllocIndex: The allocation to attribute the MAP_RANGE/UNMAP range commands to.
832 * bMap: Set to TRUE for mapping or IMG_FALSE for unmapping
834 * This function goes through every page in the PMR's mapping table and looks for
835 * virtually contiguous ranges to record as being mapped or unmapped.
837 static void GenerateMapUnmapCommandsForSparsePMR(PMR *psPMR,
838 IMG_UINT32 ui32AllocIndex,
841 PMR_MAPPING_TABLE *psMappingTable;
842 IMG_UINT32 ui32DonePages = 0;
843 IMG_UINT32 ui32NumPages;
845 IMG_BOOL bInARun = IMG_FALSE;
846 IMG_UINT32 ui32CurrentStart = 0;
847 IMG_UINT32 ui32RunCount = 0;
849 psMappingTable = PMR_GetMappingTable(psPMR);
850 ui32NumPages = psMappingTable->ui32NumPhysChunks;
852 if (ui32NumPages == 0)
858 for (i = 0; i < psMappingTable->ui32NumVirtChunks; i++)
860 if (psMappingTable->aui32Translation[i] != TRANSLATION_INVALID)
865 ui32CurrentStart = i;
876 /* test if we need to end this current run and generate the command,
877 * either because the next page is not virtually contiguous
878 * to the current page, we have reached the maximum range,
879 * or this is the last page in the mapping table
881 if ((psMappingTable->aui32Translation[i] == TRANSLATION_INVALID) ||
882 (ui32RunCount == MAP_RANGE_MAX_RANGE) ||
883 (i == (psMappingTable->ui32NumVirtChunks - 1)))
887 InsertMapRangeCommand(PMR_DeviceNode(psPMR),
894 InsertUnmapRangeCommand(PMR_DeviceNode(psPMR),
900 ui32DonePages += ui32RunCount;
902 if (ui32DonePages == ui32NumPages)
914 /* GenerateMapUnmapCommandsForChangeList:
915 * Generate the MAP_RANGE or UNMAP_RANGE commands for the sparse PMR, using the
916 * list of page change (page map or page unmap) indices given.
918 * ui32NumPages: Number of pages which have changed.
919 * pui32PageList: List of indices of the pages which have changed.
920 * ui32AllocIndex: The allocation to attribute the MAP_RANGE/UNMAP range commands to.
921 * bMap: Set to TRUE for mapping or IMG_FALSE for unmapping
923 * This function goes through every page in the list and looks for
924 * virtually contiguous ranges to record as being mapped or unmapped.
926 static void GenerateMapUnmapCommandsForChangeList(PVRSRV_DEVICE_NODE *psDeviceNode,
927 IMG_UINT32 ui32NumPages,
928 IMG_UINT32 *pui32PageList,
929 IMG_UINT32 ui32AllocIndex,
933 IMG_BOOL bInARun = IMG_FALSE;
934 IMG_UINT32 ui32CurrentStart = 0;
935 IMG_UINT32 ui32RunCount = 0;
937 for (i = 0; i < ui32NumPages; i++)
942 ui32CurrentStart = pui32PageList[i];
948 * - the next page in the list is not one greater than the current page
949 * - this is the last page in the list
950 * - we have reached the maximum range size
952 if ((i == (ui32NumPages - 1)) ||
953 ((pui32PageList[i] + 1) != pui32PageList[i + 1]) ||
954 (ui32RunCount == MAP_RANGE_MAX_RANGE))
958 InsertMapRangeCommand(psDeviceNode,
965 InsertUnmapRangeCommand(psDeviceNode,
977 /* DevicememHistoryMapKM:
978 * Entry point for when an allocation is mapped into the MMU GPU
980 * psPMR: The PMR to which the allocation belongs.
981 * ui32Offset: The offset within the PMR at which the allocation begins.
982 * sDevVAddr: The DevVAddr at which the allocation begins.
983 * szName: Annotation/name for the allocation.
984 * ui32Log2PageSize: Page size of the allocation, expressed in log2 form.
985 * ui32AllocationIndex: Allocation index as provided by the client.
986 * We will use this as a short-cut to find the allocation
988 * pui32AllocationIndexOut: An updated allocation index for the client.
989 * This may be a new value if we just created the
992 PVRSRV_ERROR DevicememHistoryMapKM(PMR *psPMR,
993 IMG_UINT32 ui32Offset,
994 IMG_DEV_VIRTADDR sDevVAddr,
995 IMG_DEVMEM_SIZE_T uiSize,
996 const char szName[DEVMEM_ANNOTATION_MAX_LEN],
997 IMG_UINT32 ui32Log2PageSize,
998 IMG_UINT32 ui32AllocationIndex,
999 IMG_UINT32 *pui32AllocationIndexOut)
1001 IMG_BOOL bSparse = PMR_IsSparse(psPMR);
1002 IMG_UINT64 ui64Serial;
1003 IMG_PID uiPID = OSGetCurrentClientProcessIDKM();
1004 PVRSRV_ERROR eError;
1007 if ((ui32AllocationIndex != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE) &&
1008 !CHECK_ALLOC_INDEX(ui32AllocationIndex))
1010 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid allocation index: %u",
1012 ui32AllocationIndex));
1013 return PVRSRV_ERROR_INVALID_PARAMS;
1016 PMRGetUID(psPMR, &ui64Serial);
1018 DevicememHistoryLock();
1020 eError = FindOrCreateAllocation(PMR_DeviceNode(psPMR),
1021 ui32AllocationIndex,
1029 &ui32AllocationIndex,
1032 if ((eError == PVRSRV_OK) && !bCreated)
1034 /* touch the allocation so it goes to the head of our MRU list */
1035 TouchBusyAllocation(ui32AllocationIndex);
1037 else if (eError != PVRSRV_OK)
1039 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to Find or Create allocation %s (%s)",
1042 PVRSRVGETERRORSTRING(eError)));
1048 InsertMapAllCommand(PMR_DeviceNode(psPMR), ui32AllocationIndex);
1052 GenerateMapUnmapCommandsForSparsePMR(psPMR,
1053 ui32AllocationIndex,
1057 InsertTimeStampCommand(OSClockns64());
1059 *pui32AllocationIndexOut = ui32AllocationIndex;
1062 DevicememHistoryUnlock();
1067 static void VRangeInsertMapUnmapCommands(PVRSRV_DEVICE_NODE *psDeviceNode,
1069 IMG_UINT32 ui32AllocationIndex,
1070 IMG_DEV_VIRTADDR sBaseDevVAddr,
1071 IMG_UINT32 ui32StartPage,
1072 IMG_UINT32 ui32NumPages,
1073 const IMG_CHAR *pszName)
1075 while (ui32NumPages > 0)
1077 IMG_UINT32 ui32PagesToAdd;
1079 ui32PagesToAdd = MIN(ui32NumPages, MAP_RANGE_MAX_RANGE);
1081 if (ui32StartPage > MAP_RANGE_MAX_START)
1083 PVR_DPF((PVR_DBG_WARNING, "Cannot record %s range beginning at page "
1084 "%u on allocation %s",
1085 bMap ? "map" : "unmap",
1093 InsertMapRangeCommand(psDeviceNode,
1094 ui32AllocationIndex,
1100 InsertUnmapRangeCommand(psDeviceNode,
1101 ui32AllocationIndex,
1106 ui32StartPage += ui32PagesToAdd;
1107 ui32NumPages -= ui32PagesToAdd;
1111 PVRSRV_ERROR DevicememHistoryMapVRangeKM(CONNECTION_DATA *psConnection,
1112 PVRSRV_DEVICE_NODE *psDeviceNode,
1113 IMG_DEV_VIRTADDR sBaseDevVAddr,
1114 IMG_UINT32 ui32StartPage,
1115 IMG_UINT32 ui32NumPages,
1116 IMG_DEVMEM_SIZE_T uiAllocSize,
1117 const IMG_CHAR szName[DEVMEM_ANNOTATION_MAX_LEN],
1118 IMG_UINT32 ui32Log2PageSize,
1119 IMG_UINT32 ui32AllocationIndex,
1120 IMG_UINT32 *pui32AllocationIndexOut)
1122 IMG_PID uiPID = OSGetCurrentClientProcessIDKM();
1123 PVRSRV_ERROR eError;
1126 PVR_UNREFERENCED_PARAMETER(psConnection);
1128 if ((ui32AllocationIndex != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE) &&
1129 !CHECK_ALLOC_INDEX(ui32AllocationIndex))
1131 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid allocation index: %u",
1133 ui32AllocationIndex));
1134 return PVRSRV_ERROR_INVALID_PARAMS;
1137 DevicememHistoryLock();
1139 eError = FindOrCreateAllocation(psDeviceNode,
1140 ui32AllocationIndex,
1148 &ui32AllocationIndex,
1151 if ((eError == PVRSRV_OK) && !bCreated)
1153 /* touch the allocation so it goes to the head of our MRU list */
1154 TouchBusyAllocation(ui32AllocationIndex);
1156 else if (eError != PVRSRV_OK)
1158 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to Find or Create allocation %s (%s)",
1161 PVRSRVGETERRORSTRING(eError)));
1165 VRangeInsertMapUnmapCommands(psDeviceNode,
1167 ui32AllocationIndex,
1173 *pui32AllocationIndexOut = ui32AllocationIndex;
1176 DevicememHistoryUnlock();
1182 PVRSRV_ERROR DevicememHistoryUnmapVRangeKM(CONNECTION_DATA *psConnection,
1183 PVRSRV_DEVICE_NODE *psDeviceNode,
1184 IMG_DEV_VIRTADDR sBaseDevVAddr,
1185 IMG_UINT32 ui32StartPage,
1186 IMG_UINT32 ui32NumPages,
1187 IMG_DEVMEM_SIZE_T uiAllocSize,
1188 const IMG_CHAR szName[DEVMEM_ANNOTATION_MAX_LEN],
1189 IMG_UINT32 ui32Log2PageSize,
1190 IMG_UINT32 ui32AllocationIndex,
1191 IMG_UINT32 *pui32AllocationIndexOut)
1193 IMG_PID uiPID = OSGetCurrentClientProcessIDKM();
1194 PVRSRV_ERROR eError;
1197 PVR_UNREFERENCED_PARAMETER(psConnection);
1199 if ((ui32AllocationIndex != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE) &&
1200 !CHECK_ALLOC_INDEX(ui32AllocationIndex))
1202 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid allocation index: %u",
1204 ui32AllocationIndex));
1205 return PVRSRV_ERROR_INVALID_PARAMS;
1208 DevicememHistoryLock();
1210 eError = FindOrCreateAllocation(psDeviceNode,
1211 ui32AllocationIndex,
1219 &ui32AllocationIndex,
1222 if ((eError == PVRSRV_OK) && !bCreated)
1224 /* touch the allocation so it goes to the head of our MRU list */
1225 TouchBusyAllocation(ui32AllocationIndex);
1227 else if (eError != PVRSRV_OK)
1229 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to Find or Create allocation %s (%s)",
1232 PVRSRVGETERRORSTRING(eError)));
1236 VRangeInsertMapUnmapCommands(psDeviceNode,
1238 ui32AllocationIndex,
1244 *pui32AllocationIndexOut = ui32AllocationIndex;
1247 DevicememHistoryUnlock();
1254 /* DevicememHistoryUnmapKM:
1255 * Entry point for when an allocation is unmapped from the MMU GPU
1257 * psPMR: The PMR to which the allocation belongs.
1258 * ui32Offset: The offset within the PMR at which the allocation begins.
1259 * sDevVAddr: The DevVAddr at which the allocation begins.
1260 * szName: Annotation/name for the allocation.
1261 * ui32Log2PageSize: Page size of the allocation, expressed in log2 form.
1262 * ui32AllocationIndex: Allocation index as provided by the client.
1263 * We will use this as a short-cut to find the allocation
1265 * pui32AllocationIndexOut: An updated allocation index for the client.
1266 * This may be a new value if we just created the
1267 * allocation record.
1269 PVRSRV_ERROR DevicememHistoryUnmapKM(PMR *psPMR,
1270 IMG_UINT32 ui32Offset,
1271 IMG_DEV_VIRTADDR sDevVAddr,
1272 IMG_DEVMEM_SIZE_T uiSize,
1273 const char szName[DEVMEM_ANNOTATION_MAX_LEN],
1274 IMG_UINT32 ui32Log2PageSize,
1275 IMG_UINT32 ui32AllocationIndex,
1276 IMG_UINT32 *pui32AllocationIndexOut)
1278 IMG_BOOL bSparse = PMR_IsSparse(psPMR);
1279 IMG_UINT64 ui64Serial;
1280 IMG_PID uiPID = OSGetCurrentClientProcessIDKM();
1281 PVRSRV_ERROR eError;
1284 if ((ui32AllocationIndex != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE) &&
1285 !CHECK_ALLOC_INDEX(ui32AllocationIndex))
1287 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid allocation index: %u",
1289 ui32AllocationIndex));
1290 return PVRSRV_ERROR_INVALID_PARAMS;
1293 PMRGetUID(psPMR, &ui64Serial);
1295 DevicememHistoryLock();
1297 eError = FindOrCreateAllocation(PMR_DeviceNode(psPMR),
1298 ui32AllocationIndex,
1306 &ui32AllocationIndex,
1309 if ((eError == PVRSRV_OK) && !bCreated)
1311 /* touch the allocation so it goes to the head of our MRU list */
1312 TouchBusyAllocation(ui32AllocationIndex);
1314 else if (eError != PVRSRV_OK)
1316 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to Find or Create allocation %s (%s)",
1319 PVRSRVGETERRORSTRING(eError)));
1325 InsertUnmapAllCommand(PMR_DeviceNode(psPMR), ui32AllocationIndex);
1329 GenerateMapUnmapCommandsForSparsePMR(psPMR,
1330 ui32AllocationIndex,
1334 InsertTimeStampCommand(OSClockns64());
1336 *pui32AllocationIndexOut = ui32AllocationIndex;
1339 DevicememHistoryUnlock();
1344 /* DevicememHistorySparseChangeKM:
1345 * Entry point for when a sparse allocation is changed, such that some of the
1346 * pages within the sparse allocation are mapped or unmapped.
1348 * psPMR: The PMR to which the allocation belongs.
1349 * ui32Offset: The offset within the PMR at which the allocation begins.
1350 * sDevVAddr: The DevVAddr at which the allocation begins.
1351 * szName: Annotation/name for the allocation.
1352 * ui32Log2PageSize: Page size of the allocation, expressed in log2 form.
1353 * ui32AllocPageCount: Number of pages which have been mapped.
1354 * paui32AllocPageIndices: Indices of pages which have been mapped.
1355 * ui32FreePageCount: Number of pages which have been unmapped.
1356 * paui32FreePageIndices: Indices of pages which have been unmapped.
1357 * ui32AllocationIndex: Allocation index as provided by the client.
1358 * We will use this as a short-cut to find the allocation
1360 * pui32AllocationIndexOut: An updated allocation index for the client.
1361 * This may be a new value if we just created the
1362 * allocation record.
1364 PVRSRV_ERROR DevicememHistorySparseChangeKM(PMR *psPMR,
1365 IMG_UINT32 ui32Offset,
1366 IMG_DEV_VIRTADDR sDevVAddr,
1367 IMG_DEVMEM_SIZE_T uiSize,
1368 const char szName[DEVMEM_ANNOTATION_MAX_LEN],
1369 IMG_UINT32 ui32Log2PageSize,
1370 IMG_UINT32 ui32AllocPageCount,
1371 IMG_UINT32 *paui32AllocPageIndices,
1372 IMG_UINT32 ui32FreePageCount,
1373 IMG_UINT32 *paui32FreePageIndices,
1374 IMG_UINT32 ui32AllocationIndex,
1375 IMG_UINT32 *pui32AllocationIndexOut)
1377 IMG_UINT64 ui64Serial;
1378 IMG_PID uiPID = OSGetCurrentClientProcessIDKM();
1379 PVRSRV_ERROR eError;
1382 if ((ui32AllocationIndex != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE) &&
1383 !CHECK_ALLOC_INDEX(ui32AllocationIndex))
1385 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid allocation index: %u",
1387 ui32AllocationIndex));
1388 return PVRSRV_ERROR_INVALID_PARAMS;
1391 PMRGetUID(psPMR, &ui64Serial);
1393 DevicememHistoryLock();
1395 eError = FindOrCreateAllocation(PMR_DeviceNode(psPMR),
1396 ui32AllocationIndex,
1403 IMG_TRUE /* bSparse */,
1404 &ui32AllocationIndex,
1407 if ((eError == PVRSRV_OK) && !bCreated)
1409 /* touch the allocation so it goes to the head of our MRU list */
1410 TouchBusyAllocation(ui32AllocationIndex);
1412 else if (eError != PVRSRV_OK)
1414 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to Find or Create allocation %s (%s)",
1417 PVRSRVGETERRORSTRING(eError)));
1421 GenerateMapUnmapCommandsForChangeList(PMR_DeviceNode(psPMR),
1423 paui32AllocPageIndices,
1424 ui32AllocationIndex,
1427 GenerateMapUnmapCommandsForChangeList(PMR_DeviceNode(psPMR),
1429 paui32FreePageIndices,
1430 ui32AllocationIndex,
1433 InsertTimeStampCommand(OSClockns64());
1435 *pui32AllocationIndexOut = ui32AllocationIndex;
1438 DevicememHistoryUnlock();
1444 /* CircularBufferIterateStart:
1445 * Initialise local state for iterating over the circular buffer
1447 static void CircularBufferIterateStart(IMG_UINT32 *pui32Head, IMG_UINT32 *pui32Iter)
1449 *pui32Head = gsDevicememHistoryData.sRecords.ui32Head;
1451 if (*pui32Head != 0)
1453 *pui32Iter = *pui32Head - 1;
1457 *pui32Iter = CIRCULAR_BUFFER_NUM_COMMANDS - 1;
1461 /* CircularBufferIteratePrevious:
1462 * Iterate to the previous item in the circular buffer.
1463 * This is called repeatedly to iterate over the whole circular buffer.
1465 static COMMAND_WRAPPER *CircularBufferIteratePrevious(IMG_UINT32 ui32Head,
1466 IMG_UINT32 *pui32Iter,
1467 COMMAND_TYPE *peType,
1470 IMG_UINT8 *pui8Header;
1471 COMMAND_WRAPPER *psOut = NULL;
1473 psOut = gsDevicememHistoryData.sRecords.pasCircularBuffer + *pui32Iter;
1475 pui8Header = (void *) psOut;
1477 /* Check the command looks valid.
1478 * this condition should never happen, but check for it anyway
1479 * and try to handle it
1481 if (*pui8Header >= COMMAND_TYPE_COUNT)
1483 /* invalid header detected. Circular buffer corrupted? */
1484 PVR_DPF((PVR_DBG_ERROR, "CircularBufferIteratePrevious: "
1485 "Invalid header: %u",
1491 *peType = *pui8Header;
1493 if (*pui32Iter != 0)
1499 *pui32Iter = CIRCULAR_BUFFER_NUM_COMMANDS - 1;
1503 /* inform the caller this is the last command if either we have reached
1504 * the head (where we started) or if we have reached an empty command,
1505 * which means we have covered all populated entries
1507 if ((*pui32Iter == ui32Head) || (*peType == COMMAND_TYPE_NONE))
1509 /* this is the final iteration */
1516 /* MapUnmapCommandGetInfo:
1517 * Helper function to get the address and mapping information from a MAP_ALL, UNMAP_ALL,
1518 * MAP_RANGE or UNMAP_RANGE command
1520 static void MapUnmapCommandGetInfo(COMMAND_WRAPPER *psCommand,
1522 IMG_DEV_VIRTADDR *psDevVAddrStart,
1523 IMG_DEV_VIRTADDR *psDevVAddrEnd,
1525 IMG_UINT32 *pui32AllocIndex)
1527 if ((eType == COMMAND_TYPE_MAP_ALL) || ((eType == COMMAND_TYPE_UNMAP_ALL)))
1529 COMMAND_MAP_ALL *psMapAll = &psCommand->u.sMapAll;
1530 RECORD_ALLOCATION *psAlloc;
1532 *pbMap = (eType == COMMAND_TYPE_MAP_ALL);
1533 *pui32AllocIndex = psMapAll->uiAllocIndex;
1535 psAlloc = ALLOC_INDEX_TO_PTR(psMapAll->uiAllocIndex);
1537 *psDevVAddrStart = psAlloc->sDevVAddr;
1538 psDevVAddrEnd->uiAddr = psDevVAddrStart->uiAddr + psAlloc->uiSize - 1;
1540 else if ((eType == COMMAND_TYPE_MAP_RANGE) || ((eType == COMMAND_TYPE_UNMAP_RANGE)))
1542 COMMAND_MAP_RANGE *psMapRange = &psCommand->u.sMapRange;
1543 RECORD_ALLOCATION *psAlloc;
1544 IMG_UINT32 ui32StartPage, ui32Count;
1546 *pbMap = (eType == COMMAND_TYPE_MAP_RANGE);
1547 *pui32AllocIndex = psMapRange->uiAllocIndex;
1549 psAlloc = ALLOC_INDEX_TO_PTR(psMapRange->uiAllocIndex);
1551 MapRangeUnpack(psMapRange, &ui32StartPage, &ui32Count);
1553 psDevVAddrStart->uiAddr = psAlloc->sDevVAddr.uiAddr +
1554 ((1ULL << psAlloc->ui32Log2PageSize) * ui32StartPage);
1556 psDevVAddrEnd->uiAddr = psDevVAddrStart->uiAddr +
1557 ((1ULL << psAlloc->ui32Log2PageSize) * ui32Count) - 1;
1561 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid command type: %u",
1567 /* DevicememHistoryQuery:
1568 * Entry point for rgxdebug to look up addresses relating to a page fault
1570 IMG_BOOL DevicememHistoryQuery(DEVICEMEM_HISTORY_QUERY_IN *psQueryIn,
1571 DEVICEMEM_HISTORY_QUERY_OUT *psQueryOut,
1572 IMG_UINT32 ui32PageSizeBytes,
1573 IMG_BOOL bMatchAnyAllocInPage)
1575 IMG_UINT32 ui32Head, ui32Iter;
1576 COMMAND_TYPE eType = COMMAND_TYPE_NONE;
1577 COMMAND_WRAPPER *psCommand = NULL;
1578 IMG_BOOL bLast = IMG_FALSE;
1579 IMG_UINT64 ui64StartTime = OSClockns64();
1580 IMG_UINT64 ui64TimeNs = 0;
1582 /* initialise the results count for the caller */
1583 psQueryOut->ui32NumResults = 0;
1585 DevicememHistoryLock();
1587 /* if the search is constrained to a particular PID then we
1588 * first search the list of allocations to see if this
1589 * PID is known to us
1591 if (psQueryIn->uiPID != DEVICEMEM_HISTORY_PID_ANY)
1593 IMG_UINT32 ui32Alloc;
1594 ui32Alloc = gsDevicememHistoryData.sRecords.ui32AllocationsListHead;
1596 while (ui32Alloc != END_OF_LIST)
1598 RECORD_ALLOCATION *psAlloc;
1600 psAlloc = ALLOC_INDEX_TO_PTR(ui32Alloc);
1602 if (psAlloc->uiPID == psQueryIn->uiPID)
1607 if (ui32Alloc == gsDevicememHistoryData.sRecords.ui32AllocationsListHead)
1609 /* gone through whole list */
1614 /* PID not found, so we do not have any suitable data for this
1622 CircularBufferIterateStart(&ui32Head, &ui32Iter);
1626 psCommand = CircularBufferIteratePrevious(ui32Head, &ui32Iter, &eType, &bLast);
1628 if (eType == COMMAND_TYPE_TIMESTAMP)
1630 ui64TimeNs = TimeStampUnpack(&psCommand->u.sTimeStamp);
1634 if ((eType == COMMAND_TYPE_MAP_ALL) ||
1635 (eType == COMMAND_TYPE_UNMAP_ALL) ||
1636 (eType == COMMAND_TYPE_MAP_RANGE) ||
1637 (eType == COMMAND_TYPE_UNMAP_RANGE))
1639 RECORD_ALLOCATION *psAlloc;
1640 IMG_DEV_VIRTADDR sAllocStartAddrOrig, sAllocEndAddrOrig;
1641 IMG_DEV_VIRTADDR sAllocStartAddr, sAllocEndAddr;
1643 IMG_UINT32 ui32AllocIndex;
1645 MapUnmapCommandGetInfo(psCommand,
1647 &sAllocStartAddrOrig,
1652 sAllocStartAddr = sAllocStartAddrOrig;
1653 sAllocEndAddr = sAllocEndAddrOrig;
1655 psAlloc = ALLOC_INDEX_TO_PTR(ui32AllocIndex);
1657 /* skip this command if we need to search within
1658 * a particular PID, and this allocation is not from
1661 if ((psQueryIn->uiPID != DEVICEMEM_HISTORY_PID_ANY) &&
1662 (psAlloc->uiPID != psQueryIn->uiPID))
1667 /* if the allocation was created after this event, then this
1668 * event must be for an old/removed allocation, so skip it
1670 if (DO_TIME_STAMP_MASK(psAlloc->ui64CreationTime) > ui64TimeNs)
1675 /* if the caller wants us to match any allocation in the
1676 * same page as the allocation then tweak the real start/end
1677 * addresses of the allocation here
1679 if (bMatchAnyAllocInPage)
1681 sAllocStartAddr.uiAddr = sAllocStartAddr.uiAddr & ~(IMG_UINT64) (ui32PageSizeBytes - 1);
1682 sAllocEndAddr.uiAddr = (sAllocEndAddr.uiAddr + ui32PageSizeBytes - 1) & ~(IMG_UINT64) (ui32PageSizeBytes - 1);
1685 if ((psQueryIn->sDevVAddr.uiAddr >= sAllocStartAddr.uiAddr) &&
1686 (psQueryIn->sDevVAddr.uiAddr < sAllocEndAddr.uiAddr))
1688 DEVICEMEM_HISTORY_QUERY_OUT_RESULT *psResult = &psQueryOut->sResults[psQueryOut->ui32NumResults];
1690 OSStringLCopy(psResult->szString, psAlloc->szName, sizeof(psResult->szString));
1691 psResult->sBaseDevVAddr = psAlloc->sDevVAddr;
1692 psResult->uiSize = psAlloc->uiSize;
1693 psResult->bMap = bMap;
1694 psResult->ui64Age = _CalculateAge(ui64StartTime, ui64TimeNs, TIME_STAMP_MASK);
1695 psResult->ui64When = ui64TimeNs;
1696 /* write the responsible PID in the placeholder */
1697 psResult->sProcessInfo.uiPID = psAlloc->uiPID;
1699 if ((eType == COMMAND_TYPE_MAP_ALL) || (eType == COMMAND_TYPE_UNMAP_ALL))
1701 psResult->bRange = IMG_FALSE;
1702 psResult->bAll = IMG_TRUE;
1706 psResult->bRange = IMG_TRUE;
1707 MapRangeUnpack(&psCommand->u.sMapRange,
1708 &psResult->ui32StartPage,
1709 &psResult->ui32PageCount);
1710 psResult->bAll = (psResult->ui32PageCount * (1U << psAlloc->ui32Log2PageSize))
1712 psResult->sMapStartAddr = sAllocStartAddrOrig;
1713 psResult->sMapEndAddr = sAllocEndAddrOrig;
1716 psQueryOut->ui32NumResults++;
1718 if (psQueryOut->ui32NumResults == DEVICEMEM_HISTORY_QUERY_OUT_MAX_RESULTS)
1727 DevicememHistoryUnlock();
1729 return psQueryOut->ui32NumResults > 0;
1732 static void DeviceMemHistoryFmt(IMG_CHAR szBuffer[PVR_MAX_DEBUG_MESSAGE_LEN],
1734 const IMG_CHAR *pszName,
1735 const IMG_CHAR *pszAction,
1736 IMG_DEV_VIRTADDR sDevVAddrStart,
1737 IMG_DEV_VIRTADDR sDevVAddrEnd,
1738 IMG_UINT64 ui64TimeNs)
1741 OSSNPrintf(szBuffer, PVR_MAX_DEBUG_MESSAGE_LEN,
1742 /* PID NAME MAP/UNMAP MIN-MAX SIZE AbsUS AgeUS*/
1744 IMG_DEV_VIRTADDR_FMTSPEC "-" IMG_DEV_VIRTADDR_FMTSPEC " "
1745 "0x%08" IMG_UINT64_FMTSPECX " "
1746 "%013" IMG_UINT64_FMTSPEC, /* 13 digits is over 2 hours of ns */
1750 sDevVAddrStart.uiAddr,
1751 sDevVAddrEnd.uiAddr,
1752 sDevVAddrEnd.uiAddr - sDevVAddrStart.uiAddr + 1,
1756 static void DeviceMemHistoryFmtHeader(IMG_CHAR szBuffer[PVR_MAX_DEBUG_MESSAGE_LEN])
1758 OSSNPrintf(szBuffer, PVR_MAX_DEBUG_MESSAGE_LEN,
1759 "%-4s %-40s %-6s %10s %10s %8s %13s",
1769 static const char *CommandTypeToString(COMMAND_TYPE eType)
1773 case COMMAND_TYPE_MAP_ALL:
1775 case COMMAND_TYPE_UNMAP_ALL:
1777 case COMMAND_TYPE_MAP_RANGE:
1779 case COMMAND_TYPE_UNMAP_RANGE:
1780 return "UnmapRange";
1781 case COMMAND_TYPE_TIMESTAMP:
1788 static void DevicememHistoryPrintAll(OSDI_IMPL_ENTRY *psEntry)
1790 IMG_CHAR szBuffer[PVR_MAX_DEBUG_MESSAGE_LEN];
1791 IMG_UINT32 ui32Iter;
1792 IMG_UINT32 ui32Head;
1793 IMG_BOOL bLast = IMG_FALSE;
1794 IMG_UINT64 ui64TimeNs = 0;
1795 IMG_UINT64 ui64StartTime = OSClockns64();
1797 DeviceMemHistoryFmtHeader(szBuffer);
1798 DIPrintf(psEntry, "%s\n", szBuffer);
1800 CircularBufferIterateStart(&ui32Head, &ui32Iter);
1804 COMMAND_WRAPPER *psCommand;
1805 COMMAND_TYPE eType = COMMAND_TYPE_NONE;
1807 psCommand = CircularBufferIteratePrevious(ui32Head, &ui32Iter, &eType,
1810 if (eType == COMMAND_TYPE_TIMESTAMP)
1812 ui64TimeNs = TimeStampUnpack(&psCommand->u.sTimeStamp);
1817 if ((eType == COMMAND_TYPE_MAP_ALL) ||
1818 (eType == COMMAND_TYPE_UNMAP_ALL) ||
1819 (eType == COMMAND_TYPE_MAP_RANGE) ||
1820 (eType == COMMAND_TYPE_UNMAP_RANGE))
1822 RECORD_ALLOCATION *psAlloc;
1823 IMG_DEV_VIRTADDR sDevVAddrStart, sDevVAddrEnd;
1825 IMG_UINT32 ui32AllocIndex;
1827 MapUnmapCommandGetInfo(psCommand,
1834 psAlloc = ALLOC_INDEX_TO_PTR(ui32AllocIndex);
1836 if (DO_TIME_STAMP_MASK(psAlloc->ui64CreationTime) > ui64TimeNs)
1838 /* if this event relates to an allocation we
1839 * are no longer tracking then do not print it
1844 DeviceMemHistoryFmt(szBuffer,
1847 CommandTypeToString(eType),
1852 DIPrintf(psEntry, "%s\n", szBuffer);
1856 DIPrintf(psEntry, "\nTimestamp reference: %013" IMG_UINT64_FMTSPEC "\n",
1860 static int DevicememHistoryPrintAllWrapper(OSDI_IMPL_ENTRY *psEntry,
1863 PVR_UNREFERENCED_PARAMETER(pvData);
1865 DevicememHistoryLock();
1866 DevicememHistoryPrintAll(psEntry);
1867 DevicememHistoryUnlock();
1872 static PVRSRV_ERROR CreateRecords(void)
1874 gsDevicememHistoryData.sRecords.pasAllocations =
1875 OSAllocMem(sizeof(RECORD_ALLOCATION) * ALLOCATION_LIST_NUM_ENTRIES);
1877 PVR_RETURN_IF_NOMEM(gsDevicememHistoryData.sRecords.pasAllocations);
1879 /* Allocated and initialise the circular buffer with zeros so every
1880 * command is initialised as a command of type COMMAND_TYPE_NONE. */
1881 gsDevicememHistoryData.sRecords.pasCircularBuffer =
1882 OSAllocZMem(sizeof(COMMAND_WRAPPER) * CIRCULAR_BUFFER_NUM_COMMANDS);
1884 if (gsDevicememHistoryData.sRecords.pasCircularBuffer == NULL)
1886 OSFreeMem(gsDevicememHistoryData.sRecords.pasAllocations);
1887 return PVRSRV_ERROR_OUT_OF_MEMORY;
1893 static void DestroyRecords(void)
1895 OSFreeMem(gsDevicememHistoryData.sRecords.pasCircularBuffer);
1896 OSFreeMem(gsDevicememHistoryData.sRecords.pasAllocations);
1899 static void InitialiseRecords(void)
1903 /* initialise the allocations list */
1905 gsDevicememHistoryData.sRecords.pasAllocations[0].ui32Prev = ALLOCATION_LIST_NUM_ENTRIES - 1;
1906 gsDevicememHistoryData.sRecords.pasAllocations[0].ui32Next = 1;
1908 for (i = 1; i < ALLOCATION_LIST_NUM_ENTRIES; i++)
1910 gsDevicememHistoryData.sRecords.pasAllocations[i].ui32Prev = i - 1;
1911 gsDevicememHistoryData.sRecords.pasAllocations[i].ui32Next = i + 1;
1914 gsDevicememHistoryData.sRecords.pasAllocations[ALLOCATION_LIST_NUM_ENTRIES - 1].ui32Next = 0;
1916 gsDevicememHistoryData.sRecords.ui32AllocationsListHead = 0;
1919 PVRSRV_ERROR DevicememHistoryInitKM(void)
1921 PVRSRV_ERROR eError;
1922 DI_ITERATOR_CB sIterator = {.pfnShow = DevicememHistoryPrintAllWrapper};
1924 eError = OSLockCreate(&gsDevicememHistoryData.hLock);
1925 PVR_LOG_GOTO_IF_ERROR(eError, "OSLockCreate", err_lock);
1927 eError = CreateRecords();
1928 PVR_LOG_GOTO_IF_ERROR(eError, "CreateRecords", err_allocations);
1930 InitialiseRecords();
1932 eError = DICreateEntry("devicemem_history", NULL, &sIterator, NULL,
1933 DI_ENTRY_TYPE_GENERIC,
1934 &gsDevicememHistoryData.psDIEntry);
1935 PVR_LOG_GOTO_IF_ERROR(eError, "DICreateEntry", err_di_creation);
1942 OSLockDestroy(gsDevicememHistoryData.hLock);
1943 gsDevicememHistoryData.hLock = NULL;
1948 void DevicememHistoryDeInitKM(void)
1950 if (gsDevicememHistoryData.psDIEntry != NULL)
1952 DIDestroyEntry(gsDevicememHistoryData.psDIEntry);
1957 if (gsDevicememHistoryData.hLock != NULL)
1959 OSLockDestroy(gsDevicememHistoryData.hLock);
1960 gsDevicememHistoryData.hLock = NULL;