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 */ /**************************************************************************/
47 #include "pvrsrv_device.h"
48 #include "pvr_debug.h"
49 #include "devicemem_server.h"
51 #include "devicemem_history_server.h"
54 #define ALLOCATION_LIST_NUM_ENTRIES 10000
56 /* data type to hold an allocation index.
57 * we make it 16 bits wide if possible
59 #if ALLOCATION_LIST_NUM_ENTRIES <= 0xFFFF
60 typedef uint16_t ALLOC_INDEX_T;
62 typedef uint32_t ALLOC_INDEX_T;
65 /* a record describing a single allocation known to DeviceMemHistory.
66 * this is an element in a doubly linked list of allocations
68 typedef struct _RECORD_ALLOCATION_
70 /* time when this RECORD_ALLOCATION was created/initialised */
71 IMG_UINT64 ui64CreationTime;
72 /* serial number of the PMR relating to this allocation */
73 IMG_UINT64 ui64Serial;
74 /* base DevVAddr of this allocation */
75 IMG_DEV_VIRTADDR sDevVAddr;
76 /* size in bytes of this allocation */
77 IMG_DEVMEM_SIZE_T uiSize;
78 /* Log2 page size of this allocation's GPU pages */
79 IMG_UINT32 ui32Log2PageSize;
80 /* Process ID (PID) this allocation belongs to */
82 /* index of previous allocation in the list */
83 ALLOC_INDEX_T ui32Prev;
84 /* index of next allocation in the list */
85 ALLOC_INDEX_T ui32Next;
86 /* annotation/name of this allocation */
87 IMG_CHAR szName[DEVICEMEM_HISTORY_TEXT_BUFSZ];
90 /* each command in the circular buffer is prefixed with an 8-bit value
91 * denoting the command type
93 typedef enum _COMMAND_TYPE_
96 COMMAND_TYPE_TIMESTAMP,
98 COMMAND_TYPE_UNMAP_ALL,
99 COMMAND_TYPE_MAP_RANGE,
100 COMMAND_TYPE_UNMAP_RANGE,
105 /* Timestamp command:
106 * This command is inserted into the circular buffer to provide an updated
108 * The nanosecond-accuracy timestamp is packed into a 56-bit integer, in order
109 * for the whole command to fit into 8 bytes.
111 typedef struct _COMMAND_TIMESTAMP_
113 IMG_UINT8 aui8TimeNs[7];
117 * This command denotes the allocation at the given index was wholly mapped
120 typedef struct _COMMAND_MAP_ALL_
122 ALLOC_INDEX_T uiAllocIndex;
125 /* UNMAP_ALL command:
126 * This command denotes the allocation at the given index was wholly unmapped
128 * Note: COMMAND_MAP_ALL and COMMAND_UNMAP_ALL commands have the same layout.
130 typedef COMMAND_MAP_ALL COMMAND_UNMAP_ALL;
132 /* packing attributes for the MAP_RANGE command */
133 #define MAP_RANGE_MAX_START ((1 << 18) - 1)
134 #define MAP_RANGE_MAX_RANGE ((1 << 12) - 1)
136 /* MAP_RANGE command:
137 * Denotes a range of pages within the given allocation being mapped.
138 * The range is expressed as [Page Index] + [Page Count]
139 * This information is packed into a 40-bit integer, in order to make
140 * the command size 8 bytes.
143 typedef struct _COMMAND_MAP_RANGE_
145 IMG_UINT8 aui8Data[5];
146 ALLOC_INDEX_T uiAllocIndex;
149 /* UNMAP_RANGE command:
150 * Denotes a range of pages within the given allocation being mapped.
151 * The range is expressed as [Page Index] + [Page Count]
152 * This information is packed into a 40-bit integer, in order to make
153 * the command size 8 bytes.
154 * Note: COMMAND_MAP_RANGE and COMMAND_UNMAP_RANGE commands have the same layout.
156 typedef COMMAND_MAP_RANGE COMMAND_UNMAP_RANGE;
158 /* wrapper structure for a command */
159 typedef struct _COMMAND_WRAPPER_
163 COMMAND_TIMESTAMP sTimeStamp;
164 COMMAND_MAP_ALL sMapAll;
165 COMMAND_UNMAP_ALL sUnmapAll;
166 COMMAND_MAP_RANGE sMapRange;
167 COMMAND_UNMAP_RANGE sUnmapRange;
171 /* target size for the circular buffer of commands */
172 #define CIRCULAR_BUFFER_SIZE_KB 2048
173 /* turn the circular buffer target size into a number of commands */
174 #define CIRCULAR_BUFFER_NUM_COMMANDS ((CIRCULAR_BUFFER_SIZE_KB * 1024) / sizeof(COMMAND_WRAPPER))
176 /* index value denoting the end of a list */
177 #define END_OF_LIST 0xFFFFFFFF
178 #define ALLOC_INDEX_TO_PTR(idx) (&(gsDevicememHistoryData.sRecords.pasAllocations[idx]))
179 #define CHECK_ALLOC_INDEX(idx) (idx < ALLOCATION_LIST_NUM_ENTRIES)
181 /* wrapper structure for the allocation records and the commands circular buffer */
182 typedef struct _RECORDS_
184 RECORD_ALLOCATION *pasAllocations;
185 IMG_UINT32 ui32AllocationsListHead;
189 COMMAND_WRAPPER *pasCircularBuffer;;
192 typedef struct _DEVICEMEM_HISTORY_DATA_
199 } DEVICEMEM_HISTORY_DATA;
201 static DEVICEMEM_HISTORY_DATA gsDevicememHistoryData = { 0 };
203 static void DevicememHistoryLock(void)
205 OSLockAcquire(gsDevicememHistoryData.hLock);
208 static void DevicememHistoryUnlock(void)
210 OSLockRelease(gsDevicememHistoryData.hLock);
213 /* given a time stamp, calculate the age in nanoseconds */
214 static IMG_UINT64 _CalculateAge(IMG_UINT64 ui64Now,
218 if(ui64Now >= ui64Then)
221 return ui64Now - ui64Then;
225 /* clock has wrapped */
226 return (ui64Max - ui64Then) + ui64Now + 1;
231 * Acquire the next slot in the circular buffer and
232 * move the circular buffer head along by one
233 * Returns a pointer to the acquired slot.
235 static COMMAND_WRAPPER *AcquireCBSlot(void)
237 COMMAND_WRAPPER *psSlot;
239 psSlot = &gsDevicememHistoryData.sRecords.pasCircularBuffer[gsDevicememHistoryData.sRecords.ui32Head];
241 gsDevicememHistoryData.sRecords.ui32Head =
242 (gsDevicememHistoryData.sRecords.ui32Head + 1)
243 % CIRCULAR_BUFFER_NUM_COMMANDS;
249 * Packs the given timestamp value into the COMMAND_TIMESTAMP structure.
250 * This takes a 64-bit nanosecond timestamp and packs it in to a 56-bit
251 * integer in the COMMAND_TIMESTAMP command.
253 static void TimeStampPack(COMMAND_TIMESTAMP *psTimeStamp, IMG_UINT64 ui64Now)
257 for(i = 0; i < IMG_ARR_NUM_ELEMS(psTimeStamp->aui8TimeNs); i++)
259 psTimeStamp->aui8TimeNs[i] = ui64Now & 0xFF;
264 /* packing a 64-bit nanosecond into a 7-byte integer loses the
265 * top 8 bits of data. This must be taken into account when
266 * comparing a full timestamp against an unpacked timestamp
268 #define TIME_STAMP_MASK ((1LLU << 56) - 1)
269 #define DO_TIME_STAMP_MASK(ns64) (ns64 & TIME_STAMP_MASK)
272 * Unpack the timestamp value from the given COMMAND_TIMESTAMP command
274 static IMG_UINT64 TimeStampUnpack(COMMAND_TIMESTAMP *psTimeStamp)
276 IMG_UINT64 ui64TimeNs = 0;
279 for(i = IMG_ARR_NUM_ELEMS(psTimeStamp->aui8TimeNs); i > 0; i--)
282 ui64TimeNs |= psTimeStamp->aui8TimeNs[i - 1];
290 static void EmitPDumpAllocation(IMG_UINT32 ui32AllocationIndex,
291 RECORD_ALLOCATION *psAlloc)
293 PDUMPCOMMENT("[SrvPFD] Allocation: %u"
294 " Addr: " IMG_DEV_VIRTADDR_FMTSPEC
295 " Size: " IMG_DEVMEM_SIZE_FMTSPEC
301 psAlloc->sDevVAddr.uiAddr,
303 1U << psAlloc->ui32Log2PageSize,
305 OSGetCurrentClientProcessNameKM(),
309 static void EmitPDumpMapUnmapAll(COMMAND_TYPE eType,
310 IMG_UINT32 ui32AllocationIndex)
312 const IMG_CHAR *pszOpName;
316 case COMMAND_TYPE_MAP_ALL:
317 pszOpName = "MAP_ALL";
319 case COMMAND_TYPE_UNMAP_ALL:
320 pszOpName = "UNMAP_ALL";
323 PVR_DPF((PVR_DBG_ERROR, "EmitPDumpMapUnmapAll: Invalid type: %u",
329 PDUMPCOMMENT("[SrvPFD] Op: %s Allocation: %u",
331 ui32AllocationIndex);
334 static void EmitPDumpMapUnmapRange(COMMAND_TYPE eType,
335 IMG_UINT32 ui32AllocationIndex,
336 IMG_UINT32 ui32StartPage,
337 IMG_UINT32 ui32Count)
339 const IMG_CHAR *pszOpName;
343 case COMMAND_TYPE_MAP_RANGE:
344 pszOpName = "MAP_RANGE";
346 case COMMAND_TYPE_UNMAP_RANGE:
347 pszOpName = "UNMAP_RANGE";
350 PVR_DPF((PVR_DBG_ERROR, "EmitPDumpMapUnmapRange: Invalid type: %u",
355 PDUMPCOMMENT("[SrvPFD] Op: %s Allocation: %u Start Page: %u Count: %u",
364 /* InsertTimeStampCommand:
365 * Insert a timestamp command into the circular buffer.
367 static void InsertTimeStampCommand(IMG_UINT64 ui64Now)
369 COMMAND_WRAPPER *psCommand;
371 psCommand = AcquireCBSlot();
373 psCommand->ui8Type = COMMAND_TYPE_TIMESTAMP;
375 TimeStampPack(&psCommand->u.sTimeStamp, ui64Now);
378 /* InsertMapAllCommand:
379 * Insert a "MAP_ALL" command for the given allocation into the circular buffer
381 static void InsertMapAllCommand(IMG_UINT32 ui32AllocIndex)
383 COMMAND_WRAPPER *psCommand;
385 psCommand = AcquireCBSlot();
387 psCommand->ui8Type = COMMAND_TYPE_MAP_ALL;
388 psCommand->u.sMapAll.uiAllocIndex = ui32AllocIndex;
391 EmitPDumpMapUnmapAll(COMMAND_TYPE_MAP_ALL, ui32AllocIndex);
395 /* InsertUnmapAllCommand:
396 * Insert a "UNMAP_ALL" command for the given allocation into the circular buffer
398 static void InsertUnmapAllCommand(IMG_UINT32 ui32AllocIndex)
400 COMMAND_WRAPPER *psCommand;
402 psCommand = AcquireCBSlot();
404 psCommand->ui8Type = COMMAND_TYPE_UNMAP_ALL;
405 psCommand->u.sUnmapAll.uiAllocIndex = ui32AllocIndex;
408 EmitPDumpMapUnmapAll(COMMAND_TYPE_UNMAP_ALL, ui32AllocIndex);
413 * Pack the given StartPage and Count values into the 40-bit representation
414 * in the MAP_RANGE command.
416 static void MapRangePack(COMMAND_MAP_RANGE *psMapRange,
417 IMG_UINT32 ui32StartPage,
418 IMG_UINT32 ui32Count)
423 /* we must encode the data into 40 bits:
424 * 18 bits for the start page index
425 * 12 bits for the range
428 PVR_ASSERT(ui32StartPage <= MAP_RANGE_MAX_START);
429 PVR_ASSERT(ui32Count <= MAP_RANGE_MAX_RANGE);
431 ui64Data = (((IMG_UINT64) ui32StartPage) << 12) | ui32Count;
433 for(i = 0; i < IMG_ARR_NUM_ELEMS(psMapRange->aui8Data); i++)
435 psMapRange->aui8Data[i] = ui64Data & 0xFF;
441 * Unpack the StartPage and Count values from the 40-bit representation
442 * in the MAP_RANGE command.
444 static void MapRangeUnpack(COMMAND_MAP_RANGE *psMapRange,
445 IMG_UINT32 *pui32StartPage,
446 IMG_UINT32 *pui32Count)
448 IMG_UINT64 ui64Data = 0;
451 for(i = IMG_ARR_NUM_ELEMS(psMapRange->aui8Data); i > 0; i--)
454 ui64Data |= psMapRange->aui8Data[i - 1];
457 *pui32StartPage = (ui64Data >> 12);
458 *pui32Count = ui64Data & ((1 << 12) - 1);
461 /* InsertMapRangeCommand:
462 * Insert a MAP_RANGE command into the circular buffer with the given
463 * StartPage and Count values.
465 static void InsertMapRangeCommand(IMG_UINT32 ui32AllocIndex,
466 IMG_UINT32 ui32StartPage,
467 IMG_UINT32 ui32Count)
469 COMMAND_WRAPPER *psCommand;
471 psCommand = AcquireCBSlot();
473 psCommand->ui8Type = COMMAND_TYPE_MAP_RANGE;
474 psCommand->u.sMapRange.uiAllocIndex = ui32AllocIndex;
476 MapRangePack(&psCommand->u.sMapRange, ui32StartPage, ui32Count);
479 EmitPDumpMapUnmapRange(COMMAND_TYPE_MAP_RANGE,
486 /* InsertUnmapRangeCommand:
487 * Insert a UNMAP_RANGE command into the circular buffer with the given
488 * StartPage and Count values.
490 static void InsertUnmapRangeCommand(IMG_UINT32 ui32AllocIndex,
491 IMG_UINT32 ui32StartPage,
492 IMG_UINT32 ui32Count)
494 COMMAND_WRAPPER *psCommand;
496 psCommand = AcquireCBSlot();
498 psCommand->ui8Type = COMMAND_TYPE_UNMAP_RANGE;
499 psCommand->u.sMapRange.uiAllocIndex = ui32AllocIndex;
501 MapRangePack(&psCommand->u.sMapRange, ui32StartPage, ui32Count);
504 EmitPDumpMapUnmapRange(COMMAND_TYPE_UNMAP_RANGE,
511 /* InsertAllocationToList:
512 * Helper function for the allocation list.
513 * Inserts the given allocation at the head of the list, whose current head is
514 * pointed to by pui32ListHead
516 static void InsertAllocationToList(IMG_UINT32 *pui32ListHead, IMG_UINT32 ui32Alloc)
518 RECORD_ALLOCATION *psAlloc;
520 psAlloc = ALLOC_INDEX_TO_PTR(ui32Alloc);
522 if(*pui32ListHead == END_OF_LIST)
524 /* list is currently empty, so just replace it */
525 *pui32ListHead = ui32Alloc;
526 psAlloc->ui32Next = psAlloc->ui32Prev = *pui32ListHead;
530 RECORD_ALLOCATION *psHeadAlloc;
531 RECORD_ALLOCATION *psTailAlloc;
533 psHeadAlloc = ALLOC_INDEX_TO_PTR(*pui32ListHead);
534 psTailAlloc = ALLOC_INDEX_TO_PTR(psHeadAlloc->ui32Prev);
536 /* make the new alloc point forwards to the previous head */
537 psAlloc->ui32Next = *pui32ListHead;
538 /* make the new alloc point backwards to the previous tail */
539 psAlloc->ui32Prev = psHeadAlloc->ui32Prev;
541 /* the head is now our new alloc */
542 *pui32ListHead = ui32Alloc;
544 /* the old head now points back to the new head */
545 psHeadAlloc->ui32Prev = *pui32ListHead;
547 /* the tail now points forward to the new head */
548 psTailAlloc->ui32Next = ui32Alloc;
552 static void InsertAllocationToBusyList(IMG_UINT32 ui32Alloc)
554 InsertAllocationToList(&gsDevicememHistoryData.sRecords.ui32AllocationsListHead, ui32Alloc);
557 /* RemoveAllocationFromList:
558 * Helper function for the allocation list.
559 * Removes the given allocation from the list, whose head is
560 * pointed to by pui32ListHead
562 static void RemoveAllocationFromList(IMG_UINT32 *pui32ListHead, IMG_UINT32 ui32Alloc)
564 RECORD_ALLOCATION *psAlloc;
566 psAlloc = ALLOC_INDEX_TO_PTR(ui32Alloc);
568 /* if this is the only element in the list then just make the list empty */
569 if((*pui32ListHead == ui32Alloc) && (psAlloc->ui32Next == ui32Alloc))
571 *pui32ListHead = END_OF_LIST;
575 RECORD_ALLOCATION *psPrev, *psNext;
577 psPrev = ALLOC_INDEX_TO_PTR(psAlloc->ui32Prev);
578 psNext = ALLOC_INDEX_TO_PTR(psAlloc->ui32Next);
580 /* remove the allocation from the list */
581 psPrev->ui32Next = psAlloc->ui32Next;
582 psNext->ui32Prev = psAlloc->ui32Prev;
584 /* if this allocation is the head then update the head */
585 if(*pui32ListHead == ui32Alloc)
587 *pui32ListHead = psAlloc->ui32Prev;
592 static void RemoveAllocationFromBusyList(IMG_UINT32 ui32Alloc)
594 RemoveAllocationFromList(&gsDevicememHistoryData.sRecords.ui32AllocationsListHead, ui32Alloc);
597 /* TouchBusyAllocation:
598 * Move the given allocation to the head of the list
600 static void TouchBusyAllocation(IMG_UINT32 ui32Alloc)
602 RemoveAllocationFromBusyList(ui32Alloc);
603 InsertAllocationToBusyList(ui32Alloc);
606 static INLINE IMG_BOOL IsAllocationListEmpty(IMG_UINT32 ui32ListHead)
608 return ui32ListHead == END_OF_LIST;
611 /* GetOldestBusyAllocation:
612 * Returns the index of the oldest allocation in the MRU list
614 static IMG_UINT32 GetOldestBusyAllocation(void)
616 IMG_UINT32 ui32Alloc;
617 RECORD_ALLOCATION *psAlloc;
619 ui32Alloc = gsDevicememHistoryData.sRecords.ui32AllocationsListHead;
621 if(ui32Alloc == END_OF_LIST)
626 psAlloc = ALLOC_INDEX_TO_PTR(ui32Alloc);
628 return psAlloc->ui32Prev;
631 static IMG_UINT32 GetFreeAllocation(void)
633 IMG_UINT32 ui32Alloc;
635 ui32Alloc = GetOldestBusyAllocation();
641 * Searches the list of allocations and returns the index if an allocation
642 * is found which matches the given properties
644 static IMG_UINT32 FindAllocation(const IMG_CHAR *pszName,
645 IMG_UINT64 ui64Serial,
647 IMG_DEV_VIRTADDR sDevVAddr,
648 IMG_DEVMEM_SIZE_T uiSize)
650 IMG_UINT32 ui32Head, ui32Index;
651 RECORD_ALLOCATION *psAlloc;
653 ui32Head = ui32Index = gsDevicememHistoryData.sRecords.ui32AllocationsListHead;
655 if(IsAllocationListEmpty(ui32Index))
662 psAlloc = &gsDevicememHistoryData.sRecords.pasAllocations[ui32Index];
664 if( (psAlloc->ui64Serial == ui64Serial) &&
665 (psAlloc->sDevVAddr.uiAddr == sDevVAddr.uiAddr) &&
666 (psAlloc->uiSize == uiSize) &&
667 (strcmp(psAlloc->szName, pszName) == 0))
672 ui32Index = psAlloc->ui32Next;
673 } while(ui32Index != ui32Head);
677 ui32Index = END_OF_LIST;
680 /* if the allocation was not found then we return END_OF_LIST.
681 * otherwise, we return the index of the allocation
687 /* InitialiseAllocation:
688 * Initialise the given allocation structure with the given properties
690 static void InitialiseAllocation(RECORD_ALLOCATION *psAlloc,
691 const IMG_CHAR *pszName,
692 IMG_UINT64 ui64Serial,
694 IMG_DEV_VIRTADDR sDevVAddr,
695 IMG_DEVMEM_SIZE_T uiSize,
696 IMG_UINT32 ui32Log2PageSize)
698 OSStringNCopy(psAlloc->szName, pszName, sizeof(psAlloc->szName));
699 psAlloc->szName[sizeof(psAlloc->szName) - 1] = '\0';
700 psAlloc->ui64Serial = ui64Serial;
701 psAlloc->uiPID = uiPID;
702 psAlloc->sDevVAddr = sDevVAddr;
703 psAlloc->uiSize = uiSize;
704 psAlloc->ui32Log2PageSize = ui32Log2PageSize;
705 psAlloc->ui64CreationTime = OSClockns64();
709 * Creates a new allocation with the given properties then outputs the
710 * index of the allocation
712 static PVRSRV_ERROR CreateAllocation(const IMG_CHAR *pszName,
713 IMG_UINT64 ui64Serial,
715 IMG_DEV_VIRTADDR sDevVAddr,
716 IMG_DEVMEM_SIZE_T uiSize,
717 IMG_UINT32 ui32Log2PageSize,
719 IMG_UINT32 *puiAllocationIndex)
721 IMG_UINT32 ui32Alloc;
722 RECORD_ALLOCATION *psAlloc;
724 ui32Alloc = GetFreeAllocation();
726 psAlloc = ALLOC_INDEX_TO_PTR(ui32Alloc);
728 InitialiseAllocation(ALLOC_INDEX_TO_PTR(ui32Alloc),
736 /* put the newly initialised allocation at the front of the MRU list */
737 TouchBusyAllocation(ui32Alloc);
739 *puiAllocationIndex = ui32Alloc;
742 EmitPDumpAllocation(ui32Alloc, psAlloc);
749 * Tests if the allocation at the given index matches the supplied properties.
750 * Returns IMG_TRUE if it is a match, otherwise IMG_FALSE.
752 static IMG_BOOL MatchAllocation(IMG_UINT32 ui32AllocationIndex,
753 IMG_UINT64 ui64Serial,
754 IMG_DEV_VIRTADDR sDevVAddr,
755 IMG_DEVMEM_SIZE_T uiSize,
756 const IMG_CHAR *pszName,
757 IMG_UINT32 ui32Log2PageSize,
760 RECORD_ALLOCATION *psAlloc;
762 psAlloc = ALLOC_INDEX_TO_PTR(ui32AllocationIndex);
764 return (psAlloc->ui64Serial == ui64Serial) &&
765 (psAlloc->sDevVAddr.uiAddr == sDevVAddr.uiAddr) &&
766 (psAlloc->uiSize == uiSize) &&
767 (psAlloc->ui32Log2PageSize == ui32Log2PageSize) &&
768 (strcmp(psAlloc->szName, pszName) == 0);
771 /* FindOrCreateAllocation:
772 * Convenience function.
773 * Given a set of allocation properties (serial, DevVAddr, size, name, etc),
774 * this function will look for an existing record of this allocation and
775 * create the allocation if there is no existing record
777 static PVRSRV_ERROR FindOrCreateAllocation(IMG_UINT32 ui32AllocationIndexHint,
778 IMG_UINT64 ui64Serial,
779 IMG_DEV_VIRTADDR sDevVAddr,
780 IMG_DEVMEM_SIZE_T uiSize,
782 IMG_UINT32 ui32Log2PageSize,
785 IMG_UINT32 *pui32AllocationIndexOut,
788 IMG_UINT32 ui32AllocationIndex;
790 if(ui32AllocationIndexHint != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE)
792 IMG_BOOL bHaveAllocation;
794 /* first, try to match against the index given by the client */
795 bHaveAllocation = MatchAllocation(ui32AllocationIndexHint,
804 *pbCreated = IMG_FALSE;
805 *pui32AllocationIndexOut = ui32AllocationIndexHint;
810 /* if matching against the client-supplied index fails then check
811 * if the allocation exists in the list
813 ui32AllocationIndex = FindAllocation(pszName,
819 /* if there is no record of the allocation then we
822 if(ui32AllocationIndex == END_OF_LIST)
825 eError = CreateAllocation(pszName,
832 &ui32AllocationIndex);
834 if(eError == PVRSRV_OK)
836 *pui32AllocationIndexOut = ui32AllocationIndex;
837 *pbCreated = IMG_TRUE;
841 PVR_DPF((PVR_DBG_ERROR,
842 "%s: Failed to create record for allocation %s",
851 /* found existing record */
852 *pui32AllocationIndexOut = ui32AllocationIndex;
853 *pbCreated = IMG_FALSE;
859 /* GenerateMapUnmapCommandsForSparsePMR:
860 * Generate the MAP_RANGE or UNMAP_RANGE commands for the sparse PMR, using the PMR's
861 * current mapping table
863 * PMR: The PMR whose mapping table to read.
864 * ui32AllocIndex: The allocation to attribute the MAP_RANGE/UNMAP range commands to.
865 * bMap: Set to TRUE for mapping or IMG_FALSE for unmapping
867 * This function goes through every page in the PMR's mapping table and looks for
868 * virtually contiguous ranges to record as being mapped or unmapped.
870 static void GenerateMapUnmapCommandsForSparsePMR(PMR *psPMR,
871 IMG_UINT32 ui32AllocIndex,
874 PMR_MAPPING_TABLE *psMappingTable;
875 IMG_UINT32 ui32DonePages = 0;
876 IMG_UINT32 ui32NumPages;
878 IMG_BOOL bInARun = IMG_FALSE;
879 IMG_UINT32 ui32CurrentStart = 0;
880 IMG_UINT32 ui32RunCount = 0;
882 psMappingTable = PMR_GetMappigTable(psPMR);
883 ui32NumPages = psMappingTable->ui32NumPhysChunks;
885 if(ui32NumPages == 0)
891 for(i = 0; i < psMappingTable->ui32NumVirtChunks; i++)
893 if(psMappingTable->aui32Translation[i] != TRANSLATION_INVALID)
898 ui32CurrentStart = i;
909 /* test if we need to end this current run and generate the command,
910 * either because the next page is not virtually contiguous
911 * to the current page, we have reached the maximum range,
912 * or this is the last page in the mapping table
914 if((psMappingTable->aui32Translation[i] == TRANSLATION_INVALID) ||
915 (ui32RunCount == MAP_RANGE_MAX_RANGE) ||
916 (i == (psMappingTable->ui32NumVirtChunks - 1)))
920 InsertMapRangeCommand(ui32AllocIndex,
926 InsertUnmapRangeCommand(ui32AllocIndex,
931 ui32DonePages += ui32RunCount;
933 if(ui32DonePages == ui32NumPages)
945 /* GenerateMapUnmapCommandsForChangeList:
946 * Generate the MAP_RANGE or UNMAP_RANGE commands for the sparse PMR, using the
947 * list of page change (page map or page unmap) indices given.
949 * ui32NumPages: Number of pages which have changed.
950 * pui32PageList: List of indices of the pages which have changed.
951 * ui32AllocIndex: The allocation to attribute the MAP_RANGE/UNMAP range commands to.
952 * bMap: Set to TRUE for mapping or IMG_FALSE for unmapping
954 * This function goes through every page in the list and looks for
955 * virtually contiguous ranges to record as being mapped or unmapped.
957 static void GenerateMapUnmapCommandsForChangeList(IMG_UINT32 ui32NumPages,
958 IMG_UINT32 *pui32PageList,
959 IMG_UINT32 ui32AllocIndex,
963 IMG_BOOL bInARun = IMG_FALSE;
964 IMG_UINT32 ui32CurrentStart = 0;
965 IMG_UINT32 ui32RunCount = 0;
967 for(i = 0; i < ui32NumPages; i++)
972 ui32CurrentStart = pui32PageList[i];
978 * - the next page in the list is not one greater than the current page
979 * - this is the last page in the list
980 * - we have reached the maximum range size
982 if((i == (ui32NumPages - 1)) ||
983 ((pui32PageList[i] + 1) != pui32PageList[i + 1]) ||
984 (ui32RunCount == MAP_RANGE_MAX_RANGE))
988 InsertMapRangeCommand(ui32AllocIndex,
994 InsertUnmapRangeCommand(ui32AllocIndex,
1005 /* DevicememHistoryMapKM:
1006 * Entry point for when an allocation is mapped into the MMU GPU
1008 * psPMR: The PMR to which the allocation belongs.
1009 * ui32Offset: The offset within the PMR at which the allocation begins.
1010 * sDevVAddr: The DevVAddr at which the allocation begins.
1011 * szName: Annotation/name for the allocation.
1012 * ui32Log2PageSize: Page size of the allocation, expressed in log2 form.
1013 * ui32AllocationIndex: Allocation index as provided by the client.
1014 * We will use this as a short-cut to find the allocation
1016 * pui32AllocationIndexOut: An updated allocation index for the client.
1017 * This may be a new value if we just created the
1018 * allocation record.
1020 PVRSRV_ERROR DevicememHistoryMapNewKM(PMR *psPMR,
1021 IMG_UINT32 ui32Offset,
1022 IMG_DEV_VIRTADDR sDevVAddr,
1023 IMG_DEVMEM_SIZE_T uiSize,
1024 const char szName[DEVICEMEM_HISTORY_TEXT_BUFSZ],
1025 IMG_UINT32 ui32Log2PageSize,
1026 IMG_UINT32 ui32AllocationIndex,
1027 IMG_UINT32 *pui32AllocationIndexOut)
1029 IMG_BOOL bSparse = PMR_IsSparse(psPMR);
1030 IMG_UINT64 ui64Serial;
1031 IMG_PID uiPID = OSGetCurrentProcessID();
1032 PVRSRV_ERROR eError;
1035 if((ui32AllocationIndex != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE) &&
1036 !CHECK_ALLOC_INDEX(ui32AllocationIndex))
1038 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid allocation index: %u",
1040 ui32AllocationIndex));
1041 return PVRSRV_ERROR_INVALID_PARAMS;
1044 PMRGetUID(psPMR, &ui64Serial);
1046 DevicememHistoryLock();
1048 eError = FindOrCreateAllocation(ui32AllocationIndex,
1056 &ui32AllocationIndex,
1059 if((eError == PVRSRV_OK) && !bCreated)
1061 /* touch the allocation so it goes to the head of our MRU list */
1062 TouchBusyAllocation(ui32AllocationIndex);
1064 else if(eError != PVRSRV_OK)
1066 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to Find or Create allocation %s (%s)",
1069 PVRSRVGETERRORSTRING(eError)));
1075 InsertMapAllCommand(ui32AllocationIndex);
1079 GenerateMapUnmapCommandsForSparsePMR(psPMR,
1080 ui32AllocationIndex,
1084 InsertTimeStampCommand(OSClockns64());
1086 *pui32AllocationIndexOut = ui32AllocationIndex;
1089 DevicememHistoryUnlock();
1094 static void VRangeInsertMapUnmapCommands(IMG_BOOL bMap,
1095 IMG_UINT32 ui32AllocationIndex,
1096 IMG_DEV_VIRTADDR sBaseDevVAddr,
1097 IMG_UINT32 ui32StartPage,
1098 IMG_UINT32 ui32NumPages,
1099 const IMG_CHAR *pszName)
1101 while(ui32NumPages > 0)
1103 IMG_UINT32 ui32PagesToAdd;
1105 ui32PagesToAdd = MIN(ui32NumPages, MAP_RANGE_MAX_RANGE);
1107 if(ui32StartPage > MAP_RANGE_MAX_START)
1109 PVR_DPF((PVR_DBG_WARNING, "Cannot record %s range beginning at page "
1110 "%u on allocation %s",
1111 bMap ? "map" : "unmap",
1119 InsertMapRangeCommand(ui32AllocationIndex,
1125 InsertUnmapRangeCommand(ui32AllocationIndex,
1130 ui32StartPage += ui32PagesToAdd;
1131 ui32NumPages -= ui32PagesToAdd;
1135 PVRSRV_ERROR DevicememHistoryMapVRangeKM(IMG_DEV_VIRTADDR sBaseDevVAddr,
1136 IMG_UINT32 ui32StartPage,
1137 IMG_UINT32 ui32NumPages,
1138 IMG_DEVMEM_SIZE_T uiAllocSize,
1139 const IMG_CHAR szName[DEVICEMEM_HISTORY_TEXT_BUFSZ],
1140 IMG_UINT32 ui32Log2PageSize,
1141 IMG_UINT32 ui32AllocationIndex,
1142 IMG_UINT32 *pui32AllocationIndexOut)
1144 IMG_PID uiPID = OSGetCurrentProcessID();
1145 PVRSRV_ERROR eError;
1148 if((ui32AllocationIndex != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE) &&
1149 !CHECK_ALLOC_INDEX(ui32AllocationIndex))
1151 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid allocation index: %u",
1153 ui32AllocationIndex));
1154 return PVRSRV_ERROR_INVALID_PARAMS;
1157 DevicememHistoryLock();
1159 eError = FindOrCreateAllocation(ui32AllocationIndex,
1167 &ui32AllocationIndex,
1170 if((eError == PVRSRV_OK) && !bCreated)
1172 /* touch the allocation so it goes to the head of our MRU list */
1173 TouchBusyAllocation(ui32AllocationIndex);
1175 else if(eError != PVRSRV_OK)
1177 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to Find or Create allocation %s (%s)",
1180 PVRSRVGETERRORSTRING(eError)));
1184 VRangeInsertMapUnmapCommands(IMG_TRUE,
1185 ui32AllocationIndex,
1191 *pui32AllocationIndexOut = ui32AllocationIndex;
1194 DevicememHistoryUnlock();
1200 PVRSRV_ERROR DevicememHistoryUnmapVRangeKM(IMG_DEV_VIRTADDR sBaseDevVAddr,
1201 IMG_UINT32 ui32StartPage,
1202 IMG_UINT32 ui32NumPages,
1203 IMG_DEVMEM_SIZE_T uiAllocSize,
1204 const IMG_CHAR szName[DEVICEMEM_HISTORY_TEXT_BUFSZ],
1205 IMG_UINT32 ui32Log2PageSize,
1206 IMG_UINT32 ui32AllocationIndex,
1207 IMG_UINT32 *pui32AllocationIndexOut)
1209 IMG_PID uiPID = OSGetCurrentProcessID();
1210 PVRSRV_ERROR eError;
1213 if((ui32AllocationIndex != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE) &&
1214 !CHECK_ALLOC_INDEX(ui32AllocationIndex))
1216 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid allocation index: %u",
1218 ui32AllocationIndex));
1219 return PVRSRV_ERROR_INVALID_PARAMS;
1222 DevicememHistoryLock();
1224 eError = FindOrCreateAllocation(ui32AllocationIndex,
1232 &ui32AllocationIndex,
1235 if((eError == PVRSRV_OK) && !bCreated)
1237 /* touch the allocation so it goes to the head of our MRU list */
1238 TouchBusyAllocation(ui32AllocationIndex);
1240 else if(eError != PVRSRV_OK)
1242 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to Find or Create allocation %s (%s)",
1245 PVRSRVGETERRORSTRING(eError)));
1249 VRangeInsertMapUnmapCommands(IMG_FALSE,
1250 ui32AllocationIndex,
1256 *pui32AllocationIndexOut = ui32AllocationIndex;
1259 DevicememHistoryUnlock();
1266 /* DevicememHistoryUnmapKM:
1267 * Entry point for when an allocation is unmapped from the MMU GPU
1269 * psPMR: The PMR to which the allocation belongs.
1270 * ui32Offset: The offset within the PMR at which the allocation begins.
1271 * sDevVAddr: The DevVAddr at which the allocation begins.
1272 * szName: Annotation/name for the allocation.
1273 * ui32Log2PageSize: Page size of the allocation, expressed in log2 form.
1274 * ui32AllocationIndex: Allocation index as provided by the client.
1275 * We will use this as a short-cut to find the allocation
1277 * pui32AllocationIndexOut: An updated allocation index for the client.
1278 * This may be a new value if we just created the
1279 * allocation record.
1281 PVRSRV_ERROR DevicememHistoryUnmapNewKM(PMR *psPMR,
1282 IMG_UINT32 ui32Offset,
1283 IMG_DEV_VIRTADDR sDevVAddr,
1284 IMG_DEVMEM_SIZE_T uiSize,
1285 const char szName[DEVICEMEM_HISTORY_TEXT_BUFSZ],
1286 IMG_UINT32 ui32Log2PageSize,
1287 IMG_UINT32 ui32AllocationIndex,
1288 IMG_UINT32 *pui32AllocationIndexOut)
1290 IMG_BOOL bSparse = PMR_IsSparse(psPMR);
1291 IMG_UINT64 ui64Serial;
1292 IMG_PID uiPID = OSGetCurrentProcessID();
1293 PVRSRV_ERROR eError;
1296 if((ui32AllocationIndex != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE) &&
1297 !CHECK_ALLOC_INDEX(ui32AllocationIndex))
1299 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid allocation index: %u",
1301 ui32AllocationIndex));
1302 return PVRSRV_ERROR_INVALID_PARAMS;
1305 PMRGetUID(psPMR, &ui64Serial);
1307 DevicememHistoryLock();
1309 eError = FindOrCreateAllocation(ui32AllocationIndex,
1317 &ui32AllocationIndex,
1320 if((eError == PVRSRV_OK) && !bCreated)
1322 /* touch the allocation so it goes to the head of our MRU list */
1323 TouchBusyAllocation(ui32AllocationIndex);
1325 else if(eError != PVRSRV_OK)
1327 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to Find or Create allocation %s (%s)",
1330 PVRSRVGETERRORSTRING(eError)));
1336 InsertUnmapAllCommand(ui32AllocationIndex);
1340 GenerateMapUnmapCommandsForSparsePMR(psPMR,
1341 ui32AllocationIndex,
1345 InsertTimeStampCommand(OSClockns64());
1347 *pui32AllocationIndexOut = ui32AllocationIndex;
1350 DevicememHistoryUnlock();
1355 /* DevicememHistorySparseChangeKM:
1356 * Entry point for when a sparse allocation is changed, such that some of the
1357 * pages within the sparse allocation are mapped or unmapped.
1359 * psPMR: The PMR to which the allocation belongs.
1360 * ui32Offset: The offset within the PMR at which the allocation begins.
1361 * sDevVAddr: The DevVAddr at which the allocation begins.
1362 * szName: Annotation/name for the allocation.
1363 * ui32Log2PageSize: Page size of the allocation, expressed in log2 form.
1364 * ui32AllocPageCount: Number of pages which have been mapped.
1365 * paui32AllocPageIndices: Indices of pages which have been mapped.
1366 * ui32FreePageCount: Number of pages which have been unmapped.
1367 * paui32FreePageIndices: Indices of pages which have been unmapped.
1368 * ui32AllocationIndex: Allocation index as provided by the client.
1369 * We will use this as a short-cut to find the allocation
1371 * pui32AllocationIndexOut: An updated allocation index for the client.
1372 * This may be a new value if we just created the
1373 * allocation record.
1375 PVRSRV_ERROR DevicememHistorySparseChangeKM(PMR *psPMR,
1376 IMG_UINT32 ui32Offset,
1377 IMG_DEV_VIRTADDR sDevVAddr,
1378 IMG_DEVMEM_SIZE_T uiSize,
1379 const char szName[DEVICEMEM_HISTORY_TEXT_BUFSZ],
1380 IMG_UINT32 ui32Log2PageSize,
1381 IMG_UINT32 ui32AllocPageCount,
1382 IMG_UINT32 *paui32AllocPageIndices,
1383 IMG_UINT32 ui32FreePageCount,
1384 IMG_UINT32 *paui32FreePageIndices,
1385 IMG_UINT32 ui32AllocationIndex,
1386 IMG_UINT32 *pui32AllocationIndexOut)
1388 IMG_UINT64 ui64Serial;
1389 IMG_PID uiPID = OSGetCurrentProcessID();
1390 PVRSRV_ERROR eError;
1393 if((ui32AllocationIndex != DEVICEMEM_HISTORY_ALLOC_INDEX_NONE) &&
1394 !CHECK_ALLOC_INDEX(ui32AllocationIndex))
1396 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid allocation index: %u",
1398 ui32AllocationIndex));
1399 return PVRSRV_ERROR_INVALID_PARAMS;
1402 PMRGetUID(psPMR, &ui64Serial);
1404 DevicememHistoryLock();
1406 eError = FindOrCreateAllocation(ui32AllocationIndex,
1413 IMG_TRUE /* bSparse */,
1414 &ui32AllocationIndex,
1417 if((eError == PVRSRV_OK) && !bCreated)
1419 /* touch the allocation so it goes to the head of our MRU list */
1420 TouchBusyAllocation(ui32AllocationIndex);
1422 else if(eError != PVRSRV_OK)
1424 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to Find or Create allocation %s (%s)",
1427 PVRSRVGETERRORSTRING(eError)));
1431 GenerateMapUnmapCommandsForChangeList(ui32AllocPageCount,
1432 paui32AllocPageIndices,
1433 ui32AllocationIndex,
1436 GenerateMapUnmapCommandsForChangeList(ui32FreePageCount,
1437 paui32FreePageIndices,
1438 ui32AllocationIndex,
1441 InsertTimeStampCommand(OSClockns64());
1443 *pui32AllocationIndexOut = ui32AllocationIndex;
1446 DevicememHistoryUnlock();
1452 /* CircularBufferIterateStart:
1453 * Initialise local state for iterating over the circular buffer
1455 static void CircularBufferIterateStart(IMG_UINT32 *pui32Head, IMG_UINT32 *pui32Iter)
1457 *pui32Head = gsDevicememHistoryData.sRecords.ui32Head;
1461 *pui32Iter = *pui32Head - 1;
1465 *pui32Iter = CIRCULAR_BUFFER_NUM_COMMANDS - 1;
1469 /* CircularBufferIteratePrevious:
1470 * Iterate to the previous item in the circular buffer.
1471 * This is called repeatedly to iterate over the whole circular buffer.
1473 static COMMAND_WRAPPER *CircularBufferIteratePrevious(IMG_UINT32 ui32Head,
1474 IMG_UINT32 *pui32Iter,
1475 COMMAND_TYPE *peType,
1478 IMG_UINT8 *pui8Header;
1479 COMMAND_WRAPPER *psOut = NULL;
1481 psOut = gsDevicememHistoryData.sRecords.pasCircularBuffer + *pui32Iter;
1483 pui8Header = (IMG_UINT8 *) psOut;
1485 /* sanity check the command looks valid.
1486 * this condition should never happen, but check for it anyway
1487 * and try to handle it
1489 if(*pui8Header >= COMMAND_TYPE_COUNT)
1491 /* invalid header detected. Circular buffer corrupted? */
1492 PVR_DPF((PVR_DBG_ERROR, "CircularBufferIteratePrevious: "
1493 "Invalid header: %u",
1499 *peType = *pui8Header;
1507 *pui32Iter = CIRCULAR_BUFFER_NUM_COMMANDS - 1;
1511 /* inform the caller this is the last command if either we have reached
1512 * the head (where we started) or if we have reached an empty command,
1513 * which means we have covered all populated entries
1515 if((*pui32Iter == ui32Head) || (*peType == COMMAND_TYPE_NONE))
1517 /* this is the final iteration */
1524 /* MapUnmapCommandGetInfo:
1525 * Helper function to get the address and mapping information from a MAP_ALL, UNMAP_ALL,
1526 * MAP_RANGE or UNMAP_RANGE command
1528 static void MapUnmapCommandGetInfo(COMMAND_WRAPPER *psCommand,
1530 IMG_DEV_VIRTADDR *psDevVAddrStart,
1531 IMG_DEV_VIRTADDR *psDevVAddrEnd,
1533 IMG_UINT32 *pui32AllocIndex)
1535 if((eType == COMMAND_TYPE_MAP_ALL) || ((eType == COMMAND_TYPE_UNMAP_ALL)))
1537 COMMAND_MAP_ALL *psMapAll = &psCommand->u.sMapAll;
1538 RECORD_ALLOCATION *psAlloc;
1540 *pbMap = (eType == COMMAND_TYPE_MAP_ALL);
1541 *pui32AllocIndex = psMapAll->uiAllocIndex;
1543 psAlloc = ALLOC_INDEX_TO_PTR(psMapAll->uiAllocIndex);
1545 *psDevVAddrStart = psAlloc->sDevVAddr;
1546 psDevVAddrEnd->uiAddr = psDevVAddrStart->uiAddr + psAlloc->uiSize - 1;
1548 else if((eType == COMMAND_TYPE_MAP_RANGE) || ((eType == COMMAND_TYPE_UNMAP_RANGE)))
1550 COMMAND_MAP_RANGE *psMapRange = &psCommand->u.sMapRange;
1551 RECORD_ALLOCATION *psAlloc;
1552 IMG_UINT32 ui32StartPage, ui32Count;
1554 *pbMap = (eType == COMMAND_TYPE_MAP_RANGE);
1555 *pui32AllocIndex = psMapRange->uiAllocIndex;
1557 psAlloc = ALLOC_INDEX_TO_PTR(psMapRange->uiAllocIndex);
1559 MapRangeUnpack(psMapRange, &ui32StartPage, &ui32Count);
1561 psDevVAddrStart->uiAddr = psAlloc->sDevVAddr.uiAddr +
1562 ((1U << psAlloc->ui32Log2PageSize) * ui32StartPage);
1564 psDevVAddrEnd->uiAddr = psDevVAddrStart->uiAddr +
1565 ((1U << psAlloc->ui32Log2PageSize) * ui32Count) - 1;
1569 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid command type: %u",
1575 /* DevicememHistoryQuery:
1576 * Entry point for rgxdebug to look up addresses relating to a page fault
1578 IMG_BOOL DevicememHistoryQuery(DEVICEMEM_HISTORY_QUERY_IN *psQueryIn,
1579 DEVICEMEM_HISTORY_QUERY_OUT *psQueryOut,
1580 IMG_UINT32 ui32PageSizeBytes,
1581 IMG_BOOL bMatchAnyAllocInPage)
1583 IMG_UINT32 ui32Head, ui32Iter;
1584 COMMAND_TYPE eType = COMMAND_TYPE_NONE;
1585 COMMAND_WRAPPER *psCommand = NULL;
1586 IMG_BOOL bLast = IMG_FALSE;
1587 IMG_UINT64 ui64StartTime = OSClockns64();
1588 IMG_UINT64 ui64TimeNs = 0;
1590 /* initialise the results count for the caller */
1591 psQueryOut->ui32NumResults = 0;
1593 DevicememHistoryLock();
1595 /* if the search is constrained to a particular PID then we
1596 * first search the list of allocations to see if this
1597 * PID is known to us
1599 if(psQueryIn->uiPID != DEVICEMEM_HISTORY_PID_ANY)
1601 IMG_UINT32 ui32Alloc;
1602 ui32Alloc = gsDevicememHistoryData.sRecords.ui32AllocationsListHead;
1604 while(ui32Alloc != END_OF_LIST)
1606 RECORD_ALLOCATION *psAlloc;
1608 psAlloc = ALLOC_INDEX_TO_PTR(ui32Alloc);
1610 if(psAlloc->uiPID == psQueryIn->uiPID)
1615 if(ui32Alloc == gsDevicememHistoryData.sRecords.ui32AllocationsListHead)
1617 /* gone through whole list */
1622 /* PID not found, so we do not have any suitable data for this
1630 CircularBufferIterateStart(&ui32Head, &ui32Iter);
1634 psCommand = CircularBufferIteratePrevious(ui32Head, &ui32Iter, &eType, &bLast);
1636 if(eType == COMMAND_TYPE_TIMESTAMP)
1638 ui64TimeNs = TimeStampUnpack(&psCommand->u.sTimeStamp);
1642 if((eType == COMMAND_TYPE_MAP_ALL) ||
1643 (eType == COMMAND_TYPE_UNMAP_ALL) ||
1644 (eType == COMMAND_TYPE_MAP_RANGE) ||
1645 (eType == COMMAND_TYPE_UNMAP_RANGE))
1647 RECORD_ALLOCATION *psAlloc;
1648 IMG_DEV_VIRTADDR sAllocStartAddrOrig, sAllocEndAddrOrig;
1649 IMG_DEV_VIRTADDR sAllocStartAddr, sAllocEndAddr;
1651 IMG_UINT32 ui32AllocIndex;
1653 MapUnmapCommandGetInfo(psCommand,
1655 &sAllocStartAddrOrig,
1660 sAllocStartAddr = sAllocStartAddrOrig;
1661 sAllocEndAddr = sAllocEndAddrOrig;
1663 psAlloc = ALLOC_INDEX_TO_PTR(ui32AllocIndex);
1665 /* skip this command if we need to search within
1666 * a particular PID, and this allocation is not from
1669 if((psQueryIn->uiPID != DEVICEMEM_HISTORY_PID_ANY) &&
1670 (psAlloc->uiPID != psQueryIn->uiPID))
1675 /* if the allocation was created after this event, then this
1676 * event must be for an old/removed allocation, so skip it
1678 if(DO_TIME_STAMP_MASK(psAlloc->ui64CreationTime) > ui64TimeNs)
1683 /* if the caller wants us to match any allocation in the
1684 * same page as the allocation then tweak the real start/end
1685 * addresses of the allocation here
1687 if(bMatchAnyAllocInPage)
1689 sAllocStartAddr.uiAddr = sAllocStartAddr.uiAddr & ~(IMG_UINT64) (ui32PageSizeBytes - 1);
1690 sAllocEndAddr.uiAddr = (sAllocEndAddr.uiAddr + ui32PageSizeBytes - 1) & ~(IMG_UINT64) (ui32PageSizeBytes - 1);
1693 if((psQueryIn->sDevVAddr.uiAddr >= sAllocStartAddr.uiAddr) &&
1694 (psQueryIn->sDevVAddr.uiAddr < sAllocEndAddr.uiAddr))
1696 DEVICEMEM_HISTORY_QUERY_OUT_RESULT *psResult = &psQueryOut->sResults[psQueryOut->ui32NumResults];
1698 OSStringNCopy(psResult->szString, psAlloc->szName, sizeof(psResult->szString));
1699 psResult->szString[DEVICEMEM_HISTORY_TEXT_BUFSZ - 1] = '\0';
1700 psResult->sBaseDevVAddr = psAlloc->sDevVAddr;
1701 psResult->uiSize = psAlloc->uiSize;
1702 psResult->bMap = bMap;
1703 psResult->ui64Age = _CalculateAge(ui64StartTime, ui64TimeNs, TIME_STAMP_MASK);
1704 psResult->ui64When = ui64TimeNs;
1705 /* write the responsible PID in the placeholder */
1706 psResult->sProcessInfo.uiPID = psAlloc->uiPID;
1708 if((eType == COMMAND_TYPE_MAP_ALL) || (eType == COMMAND_TYPE_UNMAP_ALL))
1710 psResult->bRange = IMG_FALSE;
1711 psResult->bAll = IMG_TRUE;
1715 psResult->bRange = IMG_TRUE;
1716 MapRangeUnpack(&psCommand->u.sMapRange,
1717 &psResult->ui32StartPage,
1718 &psResult->ui32PageCount);
1719 psResult->bAll = (psResult->ui32PageCount * (1U << psAlloc->ui32Log2PageSize))
1721 psResult->sMapStartAddr = sAllocStartAddrOrig;
1722 psResult->sMapEndAddr = sAllocEndAddrOrig;
1725 psQueryOut->ui32NumResults++;
1727 if(psQueryOut->ui32NumResults == DEVICEMEM_HISTORY_QUERY_OUT_MAX_RESULTS)
1736 DevicememHistoryUnlock();
1738 return psQueryOut->ui32NumResults > 0;
1741 static void DeviceMemHistoryFmt(IMG_CHAR szBuffer[PVR_MAX_DEBUG_MESSAGE_LEN],
1743 const IMG_CHAR *pszName,
1744 const IMG_CHAR *pszAction,
1745 IMG_DEV_VIRTADDR sDevVAddrStart,
1746 IMG_DEV_VIRTADDR sDevVAddrEnd,
1747 IMG_UINT64 ui64TimeNs)
1750 szBuffer[PVR_MAX_DEBUG_MESSAGE_LEN - 1] = '\0';
1751 OSSNPrintf(szBuffer, PVR_MAX_DEBUG_MESSAGE_LEN,
1752 /* PID NAME MAP/UNMAP MIN-MAX SIZE AbsUS AgeUS*/
1754 IMG_DEV_VIRTADDR_FMTSPEC "-" IMG_DEV_VIRTADDR_FMTSPEC " "
1756 "%013llu", /* 13 digits is over 2 hours of ns */
1760 sDevVAddrStart.uiAddr,
1761 sDevVAddrEnd.uiAddr,
1762 sDevVAddrEnd.uiAddr - sDevVAddrStart.uiAddr,
1766 static void DeviceMemHistoryFmtHeader(IMG_CHAR szBuffer[PVR_MAX_DEBUG_MESSAGE_LEN])
1768 OSSNPrintf(szBuffer, PVR_MAX_DEBUG_MESSAGE_LEN,
1769 "%-4s %-40s %-6s %10s %10s %8s %13s",
1779 static const char *CommandTypeToString(COMMAND_TYPE eType)
1783 case COMMAND_TYPE_MAP_ALL:
1785 case COMMAND_TYPE_UNMAP_ALL:
1787 case COMMAND_TYPE_MAP_RANGE:
1789 case COMMAND_TYPE_UNMAP_RANGE:
1790 return "UnmapRange";
1791 case COMMAND_TYPE_TIMESTAMP:
1798 static void DevicememHistoryPrintAll(void *pvFilePtr, OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf)
1800 IMG_CHAR szBuffer[PVR_MAX_DEBUG_MESSAGE_LEN];
1801 IMG_UINT32 ui32Iter;
1802 IMG_UINT32 ui32Head;
1803 IMG_BOOL bLast = IMG_FALSE;
1804 IMG_UINT64 ui64TimeNs = 0;
1805 IMG_UINT64 ui64StartTime = OSClockns64();
1807 DeviceMemHistoryFmtHeader(szBuffer);
1808 pfnOSStatsPrintf(pvFilePtr, "%s\n", szBuffer);
1810 CircularBufferIterateStart(&ui32Head, &ui32Iter);
1814 COMMAND_WRAPPER *psCommand;
1815 COMMAND_TYPE eType = COMMAND_TYPE_NONE;
1817 psCommand = CircularBufferIteratePrevious(ui32Head, &ui32Iter, &eType, &bLast);
1819 if(eType == COMMAND_TYPE_TIMESTAMP)
1821 ui64TimeNs = TimeStampUnpack(&psCommand->u.sTimeStamp);
1826 if((eType == COMMAND_TYPE_MAP_ALL) ||
1827 (eType == COMMAND_TYPE_UNMAP_ALL) ||
1828 (eType == COMMAND_TYPE_MAP_RANGE) ||
1829 (eType == COMMAND_TYPE_UNMAP_RANGE))
1831 RECORD_ALLOCATION *psAlloc;
1832 IMG_DEV_VIRTADDR sDevVAddrStart, sDevVAddrEnd;
1834 IMG_UINT32 ui32AllocIndex;
1836 MapUnmapCommandGetInfo(psCommand,
1843 psAlloc = ALLOC_INDEX_TO_PTR(ui32AllocIndex);
1845 if(DO_TIME_STAMP_MASK(psAlloc->ui64CreationTime) > ui64TimeNs)
1847 /* if this event relates to an allocation we
1848 * are no longer tracking then do not print it
1853 DeviceMemHistoryFmt(szBuffer,
1856 CommandTypeToString(eType),
1861 pfnOSStatsPrintf(pvFilePtr, "%s\n", szBuffer);
1865 pfnOSStatsPrintf(pvFilePtr, "\nTimestamp reference: %013llu\n", ui64StartTime);
1868 static void DevicememHistoryPrintAllWrapper(void *pvFilePtr, void *pvData, OS_STATS_PRINTF_FUNC* pfnOSStatsPrintf)
1870 PVR_UNREFERENCED_PARAMETER(pvData);
1871 DevicememHistoryLock();
1872 DevicememHistoryPrintAll(pvFilePtr, pfnOSStatsPrintf);
1873 DevicememHistoryUnlock();
1876 static PVRSRV_ERROR CreateRecords(void)
1878 gsDevicememHistoryData.sRecords.pasAllocations =
1879 OSAllocMem(sizeof(RECORD_ALLOCATION) * ALLOCATION_LIST_NUM_ENTRIES);
1881 if(gsDevicememHistoryData.sRecords.pasAllocations == NULL)
1883 return PVRSRV_ERROR_OUT_OF_MEMORY;
1886 gsDevicememHistoryData.sRecords.pasCircularBuffer =
1887 OSAllocMem(sizeof(COMMAND_WRAPPER) * CIRCULAR_BUFFER_NUM_COMMANDS);
1889 if(gsDevicememHistoryData.sRecords.pasCircularBuffer == NULL)
1891 OSFreeMem(gsDevicememHistoryData.sRecords.pasAllocations);
1892 return PVRSRV_ERROR_OUT_OF_MEMORY;
1898 static void DestroyRecords(void)
1900 OSFreeMem(gsDevicememHistoryData.sRecords.pasCircularBuffer);
1901 OSFreeMem(gsDevicememHistoryData.sRecords.pasAllocations);
1904 static void InitialiseRecords(void)
1908 /* initialise the allocations list */
1910 gsDevicememHistoryData.sRecords.pasAllocations[0].ui32Prev = ALLOCATION_LIST_NUM_ENTRIES - 1;
1911 gsDevicememHistoryData.sRecords.pasAllocations[0].ui32Next = 1;
1913 for(i = 1; i < ALLOCATION_LIST_NUM_ENTRIES; i++)
1915 gsDevicememHistoryData.sRecords.pasAllocations[i].ui32Prev = i - 1;
1916 gsDevicememHistoryData.sRecords.pasAllocations[i].ui32Next = i + 1;
1919 gsDevicememHistoryData.sRecords.pasAllocations[ALLOCATION_LIST_NUM_ENTRIES - 1].ui32Next = 0;
1921 gsDevicememHistoryData.sRecords.ui32AllocationsListHead = 0;
1923 /* initialise the circular buffer with zeros so every command
1924 * is initialised as a command of type COMMAND_TYPE_NONE
1926 OSCachedMemSet(gsDevicememHistoryData.sRecords.pasCircularBuffer,
1928 sizeof(gsDevicememHistoryData.sRecords.pasCircularBuffer[0]) * CIRCULAR_BUFFER_NUM_COMMANDS);
1931 PVRSRV_ERROR DevicememHistoryInitKM(void)
1933 PVRSRV_ERROR eError;
1935 eError = OSLockCreate(&gsDevicememHistoryData.hLock, LOCK_TYPE_PASSIVE);
1937 if(eError != PVRSRV_OK)
1939 PVR_DPF((PVR_DBG_ERROR, "DevicememHistoryInitKM: Failed to create lock"));
1943 eError = CreateRecords();
1945 if(eError != PVRSRV_OK)
1947 PVR_DPF((PVR_DBG_ERROR, "DevicememHistoryInitKM: Failed to create records"));
1948 goto err_allocations;
1951 InitialiseRecords();
1953 gsDevicememHistoryData.pvStatsEntry = OSCreateStatisticEntry("devicemem_history",
1955 DevicememHistoryPrintAllWrapper,
1963 OSLockDestroy(gsDevicememHistoryData.hLock);
1968 void DevicememHistoryDeInitKM(void)
1970 if(gsDevicememHistoryData.pvStatsEntry != NULL)
1972 OSRemoveStatisticEntry(gsDevicememHistoryData.pvStatsEntry);
1977 OSLockDestroy(gsDevicememHistoryData.hLock);
1980 PVRSRV_ERROR DevicememHistoryMapKM(IMG_DEV_VIRTADDR sDevVAddr, size_t uiSize, const char szString[DEVICEMEM_HISTORY_TEXT_BUFSZ])
1982 IMG_UINT32 ui32AllocationIndex = DEVICEMEM_HISTORY_ALLOC_INDEX_NONE;
1983 IMG_UINT32 ui32Log2PageSize;
1984 IMG_UINT32 ui32StartPage;
1985 IMG_UINT32 ui32NumPages;
1987 /* assume 4K page size */
1988 ui32Log2PageSize = 12;
1991 ui32NumPages = (uiSize + 4095) / 4096;
1993 return DevicememHistoryMapVRangeKM(sDevVAddr,
1999 ui32AllocationIndex,
2000 &ui32AllocationIndex);
2003 PVRSRV_ERROR DevicememHistoryUnmapKM(IMG_DEV_VIRTADDR sDevVAddr, size_t uiSize, const char szString[DEVICEMEM_HISTORY_TEXT_BUFSZ])
2005 IMG_UINT32 ui32AllocationIndex = DEVICEMEM_HISTORY_ALLOC_INDEX_NONE;
2006 IMG_UINT32 ui32Log2PageSize;
2007 IMG_UINT32 ui32StartPage;
2008 IMG_UINT32 ui32NumPages;
2010 /* assume 4K page size */
2011 ui32Log2PageSize = 12;
2014 ui32NumPages = (uiSize + 4095) / 4096;
2016 return DevicememHistoryUnmapVRangeKM(sDevVAddr,
2022 ui32AllocationIndex,
2023 &ui32AllocationIndex);