/*************************************************************** ** ** Broadcom Corp. Confidential ** Copyright 1998-2000 Broadcom Corp. All Rights Reserved. ** ** THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED ** SOFTWARE LICENSE AGREEMENT BETWEEN THE USER AND BROADCOM. ** YOU HAVE NO RIGHT TO USE OR EXPLOIT THIS MATERIAL EXCEPT ** SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. ** ** File: bcmMemMgr.c ** Description: Broadcom Hardware Device Memory Manager ** Created: 03/14/00 Jeffrey Fisher ** ** REVISION: ** ** $Log: bcmmemmgr.c,v $ ** Revision 1.1.1.1 2003/11/21 18:44:37 root ** Initial DP922 Checkin ** ** ** ****************************************************************/ #include "bcmmemmgr.h" #include "ministd.h" #ifndef BSTD_INLINE #define BSTD_INLINE inline #endif #ifdef BCM_DEBUG /* Warn everyone that by default memory checker is disabled even in debug build */ /* TODO Remove in warning in production environment. */ #warning "RUNTIME MEMORY DEBUG TURNED OFF, makes UI software slow, define MEM_DEBUG to enable." //#define MEM_DEBUG #endif /* heap chunk */ struct bcm_chunk_t { #ifdef MEM_DEBUG unsigned long sig[MEM_SIGLEN];/* a pattern to help catch corruption bugs */ #endif #ifdef BCM_DEBUG char file[MEM_MAX_FILENAME]; int line; #endif unsigned long padding; /* number of bytes to pad the buffer to achieve proper alignment */ unsigned long size; /* number of bytes allocated to the chunk including header and pad */ struct bcm_chunk_t *prev; /* reference to previous free chunk */ struct bcm_chunk_t *next; /* reference to next free chunk */ }; #ifdef MEM_DEBUG #define kGuardBandLength 16 #else #define kGuardBandLength 0 #endif /* Memory manager uses critical sections, TODO implement OS Specific version */ #if 0 #include "ucos.h" static unsigned int critical_flags = 0; static int in_critical = 0; void bcmKNIEnterCriticalSection(void) { if (in_critical > 0) { BDBG_MSG(("NESTED CRITICAL SECTION NOT ALLOWED\n")); return; } OS_ENTER_CRITICAL(critical_flags); in_critical++; } void bcmKNILeaveCriticalSection(void) { if (--in_critical != 0) { BDBG_MSG(("NESTED CRITICAL SECTION NOT ALLOWED\n")); return; } OS_EXIT_CRITICAL(critical_flags); } #else #if (BCHP_CHIP!=7550) && (BCHP_CHIP!=7552) #define bcmKNIEnterCriticalSection() {unsigned critical_flags = bos_enter_critical(); #define bcmKNILeaveCriticalSection() bos_exit_critical(critical_flags);} #else #define bcmKNIEnterCriticalSection() ((void)0) #define bcmKNILeaveCriticalSection() ((void)0) #endif #endif /*----------------------------------------------------------------------------- - PRIVATE FUNCTIONS -----------------------------------------------------------------------------*/ #if 0 static char mem_chkoverlap(bcm_heap_t *p_heap); static void* chunk_to_pointer(bcm_chunk_t *p_chunk ); static bcm_chunk_t* pointer_to_chunk(void *p_ptr ); static bcm_chunk_t * heap_getfree(bcm_heap_t *p_heap,unsigned long numbytes, char alignbits ); static bcm_chunk_t * heap_newchunk(bcm_heap_t *p_heap, unsigned long numbytes, char alignbits ); static char contiguous(bcm_chunk_t * chunk1,bcm_chunk_t * chunk2); static void heap_deletechunk(bcm_heap_t *p_heap,bcm_chunk_t *p_chunk); #endif /** * Until there's a programmatic way to set level for a message in * brcm_dbg.h, BRCM_DBG_XXX will have to do. You can also define HACK_BRCM_DEBUG * to get memory debugging output without having BRCM_DEBUG turned on. */ #ifdef BCM_DEBUG #define kBrcmDbgOutputMsg 0 #define kBrcmDbgOutputWrn 1 #define kBrcmDbgOutputErr 2 static const int debugOutputLevel = kBrcmDbgOutputWrn; #define BRCM_DBG_ERR(ARGS) printf ARGS #define BRCM_DBG_WRN(ARGS) printf ARGS #define BRCM_DBG_MSG(ARGS) printf ARGS #define BRCM_DBG_XXX(LEVEL,ARGS) \ ((LEVEL)==kBrcmDbgOutputErr?BRCM_DBG_ERR(ARGS): \ (LEVEL)==kBrcmDbgOutputWrn?BRCM_DBG_WRN(ARGS): \ BRCM_DBG_MSG(ARGS)) #define chunk_info_err(CHUNK) chunk_info(CHUNK, kBrcmDbgOutputErr) #define chunk_info_wrn(CHUNK) chunk_info(CHUNK, kBrcmDbgOutputWrn) #define chunk_info_msg(CHUNK) chunk_info(CHUNK, kBrcmDbgOutputMsg) #else #define BRCM_DBG_ERR(ARGS) ((void)0) #define BRCM_DBG_WRN(ARGS) ((void)0) #define BRCM_DBG_MSG(ARGS) ((void)0) #define BRCM_DBG_XXX(LEVEL,ARGS) ((void)0) #endif /****************************************************************************** * void* chunk_to_pointer(bcm_chunk_t *p_chunk ) * * INPUTS: p_chunk = chunk reference * OUTPUTS: None. * RETURNS: return the payload pointer * FUNCTION: convert a chunk to a pointer ******************************************************************************/ BSTD_INLINE void* chunk_to_pointer(bcm_chunk_t *p_chunk ) { return(void*)(((unsigned long)p_chunk) + sizeof(bcm_chunk_t)); } /****************************************************************************** * bcm_chunk_t* pointer_to_chunk(void *p_ptr ) * * INPUTS: p_ptr = pointer to chunk payload * OUTPUTS: None. * RETURNS: return the chunk pointer * FUNCTION: convert a pointer to a chunk reference (always in cached space) ******************************************************************************/ BSTD_INLINE bcm_chunk_t* pointer_to_chunk(void *p_ptr ) { return(bcm_chunk_t*)((((unsigned long)p_ptr) - sizeof(bcm_chunk_t))&~0x20000000); } /****************************************************************************** * void chunk_info(bcm_chunk_t *p_chunk, int debugoutputlevel) * * INPUTS: p_chunk = chunk reference * OUTPUTS: None. * RETURNS: none * FUNCTION: Print chunk members to debug output ******************************************************************************/ static void chunk_info(bcm_chunk_t *p_chunk, int debugOutputLevel) { BRCM_DBG_XXX(debugOutputLevel, ("Chunk: 0x%p(ptr = 0x%p)\n",p_chunk,chunk_to_pointer(p_chunk))); if(p_chunk == NULL) return; #ifdef MEM_DEBUG BRCM_DBG_XXX(debugOutputLevel, (" %s:%d\n",p_chunk->file,p_chunk->line)); { int i; for (i = 0; i < MEM_SIGLEN; ++i) { BRCM_DBG_XXX(debugOutputLevel, (" 0x%08lx\n",p_chunk->sig[i])); } } #endif BRCM_DBG_XXX(debugOutputLevel, (" %ld\n",p_chunk->padding)); BRCM_DBG_XXX(debugOutputLevel, (" %ld\n",p_chunk->size)); BRCM_DBG_XXX(debugOutputLevel, (" 0x%p\n",p_chunk->next)); BRCM_DBG_XXX(debugOutputLevel, (" 0x%p\n",p_chunk->prev)); } /****************************************************************************** * void fillguardband(bcm_chunk_t *p_chunk ) * * INPUTS: p_chunk = chunk reference * OUTPUTS: None. * RETURNS: none * FUNCTION: fill in the guard band for the chunk ******************************************************************************/ #ifdef BCM_DEBUG static const unsigned long signature = 0xDEADBEEF; static const unsigned long free_signature = 0xB00BB00B; BSTD_INLINE void fillguardband(bcm_chunk_t *p_chunk) { #ifdef MEM_DEBUG unsigned long *ptr; unsigned long i; ptr = (unsigned long*) (((unsigned long)p_chunk) + p_chunk->size - p_chunk->padding); for (i = 0; i < p_chunk->padding/4; ++i) { ptr[i] = signature; } #endif /* MEM_DEBUG */ } /****************************************************************************** * char checksignature(bcm_chunk_t *p_chunk) * * INPUTS: p_chunk = chunk reference * OUTPUTS: None. * RETURNS: none-zero if signature is ok, zero if there is a problem * FUNCTION: Validate the signature. ******************************************************************************/ static char checksignature(bcm_chunk_t *p_chunk, int isfree) { #ifdef MEM_DEBUG int i; for (i = 0; i < MEM_SIGLEN; ++i) { if (p_chunk->sig[i] != (isfree ? free_signature : signature)) { BRCM_DBG_ERR(("CHUNK SIGNATURE INVALID\n")); chunk_info_err(p_chunk); BRCM_DBG_ERR(("POSSIBLE CULPRIT p_chunk->prev = 0x%p\n",p_chunk->prev)); chunk_info_err(p_chunk->prev); return 0; } } #endif /* MEM_DEBUG */ return 1; } /****************************************************************************** * char validateguardband(bcm_chunk_t *p_chunk) * * INPUTS: p_chunk = chunk reference * OUTPUTS: None. * RETURNS: none-zero if guard band is ok, zero if there is a problem * FUNCTION: Validate the guard band. ******************************************************************************/ static char validateguardband(bcm_chunk_t *p_chunk) { #ifdef MEM_DEBUG unsigned long *ptr; unsigned long i; char result; if (!checksignature(p_chunk,0)) { BRCM_DBG_ERR(("CHUNK SIGNATURE INVALID validateguardband p_chunk->prev = 0x%p\n",p_chunk->prev)); if (p_chunk->prev) { if (validateguardband(p_chunk->prev) == 0) { BRCM_DBG_ERR(("POSSIBLE CULPRIT p_chunk->prev = 0x%p\n",p_chunk->prev)); chunk_info_err(p_chunk->prev); } } return 0; } ptr = (unsigned long*) (((unsigned long)p_chunk) + p_chunk->size - p_chunk->padding); result = 1; for (i = 0; i < p_chunk->padding/4; ++i) { if (ptr[i] != signature) { BRCM_DBG_MSG((" 0x%08lx\n",ptr[i])); /* if ((((i + 1) % 4) == 0) && (i != 0)) BRCM_DBG_MSG(("\n\n"));*/ result = 0; } } /* if (result == 0) BRCM_DBG_MSG(("\n\n")); */ return result; #else /* MEM_DEBUG */ return 1; #endif /* MEM_DEBUG */ } #endif /* BCM_DEBUG */ /****************************************************************************** * bcm_chunk_t * heap_getfree(bcm_heap_t *p_heap,unsigned long isize) * * INPUTS: p_heap = reference to a heap structure * numbytes = size of chunk payload * alignbits = playload must be aligned to start on alignbits boundry * OUTPUTS: None. * RETURNS: reference to the free chunk * FUNCTION: scan the heap looking for a free chunk with enough space ******************************************************************************/ BSTD_INLINE bcm_chunk_t * heap_getfree(bcm_heap_t *p_heap,unsigned long numbytes, char alignbits ) { bcm_chunk_t * chunk = p_heap->last_free; unsigned long offs = (1L << alignbits); unsigned long mask = offs - 1; unsigned long val,nval,pad; while (chunk != 0L) { val = ((unsigned long)chunk) + chunk->size - numbytes - kGuardBandLength; /* pointer is not aligned so calculate a pad */ if (val & mask) { nval = val & ~(mask); pad = val - nval; } else pad = 0; val = ((unsigned long)chunk) + chunk->size - numbytes - kGuardBandLength - pad; if (val & mask) { BRCM_DBG_ERR(("PTR Not aligned properly \n")); } /* if the chunk is large enough return */ val = (numbytes + pad + sizeof(bcm_chunk_t) + kGuardBandLength); if (val < chunk->size) { if ((val + sizeof(bcm_chunk_t)) > chunk->size) /* the free chunk can not be split */ { if (((unsigned long)chunk_to_pointer(chunk)) & mask) { chunk = chunk->prev; continue; /* the chunk would not result in an aligned pointer */ } } chunk->padding = pad + kGuardBandLength; return chunk; } chunk = chunk->prev; } return 0L; } /****************************************************************************** * void append_alloced(bcm_heap_t *p_heap,bcm_chunk_t * p_chunk) * * INPUTS: p_heap = reference to a heap structure * p_chunk = chunk to add to alloced list * OUTPUTS: None. * RETURNS: None * FUNCTION: Append the chunk to the list of allocated chunks ******************************************************************************/ BSTD_INLINE void append_alloced(bcm_heap_t *p_heap,bcm_chunk_t * p_chunk) { p_chunk->next = 0L; p_chunk->prev = 0L; if (p_heap->last == 0L) { p_heap->first = p_chunk; p_heap->last = p_chunk; } else { p_heap->last->next = p_chunk; p_chunk->prev = p_heap->last; p_heap->last = p_chunk; } #ifdef MEM_DEBUG { int i; for (i = 0; i < MEM_SIGLEN; ++i) p_chunk->sig[i] = signature; } #endif #ifdef BCM_DEBUG p_chunk->file[0] = 0; p_chunk->line = 0; #endif } /****************************************************************************** * void delete_alloced(bcm_heap_t *p_heap,bcm_chunk_t * p_chunk) * * INPUTS: p_heap = reference to a heap structure * p_chunk = chunk to delete from alloced list * OUTPUTS: None. * RETURNS: None * FUNCTION: Delete the chunk from the list of allocated chunks ******************************************************************************/ BSTD_INLINE void delete_alloced(bcm_heap_t *p_heap,bcm_chunk_t * p_chunk) { if (p_chunk == p_heap->first) { if (p_chunk->next == 0L) { p_heap->last = 0L; p_heap->first = 0L; } else { p_heap->first = p_chunk->next; p_heap->first->prev = 0L; } } else { if (p_chunk == p_heap->last) { p_chunk->prev->next = 0L; p_heap->last = p_chunk->prev; } else { p_chunk->next->prev = p_chunk->prev; p_chunk->prev->next = p_chunk->next; } } p_chunk->next = 0L; p_chunk->prev = 0L; #ifdef MEM_DEBUG /* write a new pattern where the chunk was to insure the chunk will not be freed again */ { int i; for (i = 0; i < MEM_SIGLEN; ++i) p_chunk->sig[i] = free_signature; } #endif } /****************************************************************************** * bcm_chunk_t * heap_newchunk(bcm_heap_t *p_heap, unsigned long numbytes ) * * INPUTS: p_heap = reference to a heap structure * numbytes = number of bytes in chunk payload * alignbits = playload must be aligned to start on alignbits boundry * OUTPUTS: None. * RETURNS: reference to the new chunks * FUNCTION: allocate a new chunk from the elements in the free list ******************************************************************************/ BSTD_INLINE bcm_chunk_t * heap_newchunk(bcm_heap_t *p_heap, unsigned long numbytes, char alignbits ) { unsigned long unusedBytes,chunkSize; unsigned long free_size; bcm_chunk_t * freeChunk, *newChunk; free_size = 0; while (1) { freeChunk = heap_getfree(p_heap, numbytes, alignbits); if (freeChunk != 0L) /* if a large enough free chunk was found */ { newChunk = 0L; chunkSize = numbytes + freeChunk->padding + sizeof(bcm_chunk_t); unusedBytes = freeChunk->size - chunkSize; if (sizeof(bcm_chunk_t) <= unusedBytes) /* split the free chunk */ { freeChunk->size -= chunkSize; #ifdef MEM_DEBUG { int i; for (i = 0; i < MEM_SIGLEN; ++i) freeChunk->sig[i] = free_signature; } #endif #ifdef BCM_DEBUG freeChunk->file[0] = 0; freeChunk->line = 0; #endif newChunk = (bcm_chunk_t*)(((unsigned long)freeChunk) + freeChunk->size); newChunk->size = chunkSize; newChunk->padding = freeChunk->padding; } else /* use the free chunk without splitting it apart */ { if (freeChunk->prev) /* if this is not the first chunk */ { freeChunk->prev->next = freeChunk->next; } else p_heap->first_free = freeChunk->next; if (freeChunk->next) /* if this is not the last chunk */ { freeChunk->next->prev = freeChunk->prev; } else p_heap->last_free = freeChunk->prev; newChunk = freeChunk; } append_alloced(p_heap,newChunk); return newChunk; } else /* there is not a chunk big enough */ { return(bcm_chunk_t *)0L; } } return(bcm_chunk_t *)0L; } /****************************************************************************** * char contiguous(bcm_chunk_t * chunk1,bcm_chunk_t * chunk2) * * INPUTS: chunk1 = first chunck * chunk2 = second chunk * OUTPUTS: None. * RETURNS: non-zero if the chunks are contiguous * FUNCTION: determine that chunks are contiguous ******************************************************************************/ static char contiguous(bcm_chunk_t * chunk1,bcm_chunk_t * chunk2) { if (chunk1 < chunk2) { chunk1 = (bcm_chunk_t *) (((unsigned long)chunk1) + chunk1->size); } else { chunk2 = (bcm_chunk_t *) (((unsigned long)chunk2) + chunk2->size); } return(char)(chunk1 == chunk2); } /****************************************************************************** * void heap_deletechunk(bcm_heap_t *p_heap,bcm_chunk_t *p_chunk) * * INPUTS: p_heap = reference to a heap structure * p_chunk = chunk to delete * OUTPUTS: None. * RETURNS: none * FUNCTION: Delete the chunk and return the chunk to the free list ******************************************************************************/ BSTD_INLINE void heap_deletechunk(bcm_heap_t *p_heap,bcm_chunk_t *p_chunk) { bcm_chunk_t * freeChunk, *next, *prev; freeChunk = (bcm_chunk_t *) p_chunk; freeChunk->padding = 0; delete_alloced(p_heap, freeChunk); if (p_heap->first_free || p_heap->last_free) { next = p_heap->first_free; while (next && next < freeChunk) next = next->next; prev = next ? next->prev : p_heap->last_free; freeChunk->prev = prev; if (prev) { if (contiguous(prev,freeChunk)) /* if contiguous merge into single chunk */ { prev->size += freeChunk->size; freeChunk = prev; } else prev->next = freeChunk; } else p_heap->first_free = freeChunk; freeChunk->next = next; if (next) { if (contiguous(freeChunk,next)) { freeChunk->size += next->size; freeChunk->next = next->next; if (freeChunk->next) { freeChunk->next->prev = freeChunk; } else p_heap->last_free = freeChunk; } else next->prev = freeChunk; } else p_heap->last_free = freeChunk; } else /* free list is empty */ { freeChunk->next = 0L; freeChunk->prev = 0L; p_heap->first_free = p_heap->last_free = freeChunk; } } /****************************************************************************** * void heap_init(bcm_heap_t *p_heap,unsigned long *p_buf,unsigned long numbytes) * * INPUTS: p_heap = reference to a heap structure to initialize * p_buf = memory address to manage * numbytes = number of bytes starting at p_buf to manage * OUTPUTS: None. * RETURNS: None * FUNCTION: This function allocates and initializes a bcm_heap_t structure. p_buf * should be on a granularity boundry. ******************************************************************************/ void heap_init(bcm_heap_t *p_heap, unsigned long *p_buf, unsigned long numbytes) { p_heap->start_addr = p_buf; p_heap->end_addr = (bcm_chunk_t*)(((unsigned long)p_buf) + numbytes); p_heap->last_free = (bcm_chunk_t*)p_buf; /* allocate chunk in heap buffer */ p_heap->first_free = p_heap->last_free; #ifdef MEM_DEBUG { int i; for (i = 0; i < MEM_SIGLEN; ++i) p_heap->first_free->sig[i] = free_signature; p_heap->first_free->file[0] = 0; p_heap->first_free->line = 0; } #endif p_heap->first_free->padding = 0; p_heap->first_free->size = numbytes; p_heap->first_free->next = 0L; p_heap->first_free->prev = 0L; } /****************************************************************************** * unsigned long mem_available(bcm_heap_t *p_heap) * * INPUTS: p_heap = reference to a heap structure to initialize * OUTPUTS: None. * RETURNS: largest free chunk * FUNCTION: Find the larget free chunk available. ******************************************************************************/ unsigned long mem_available(bcm_heap_t *p_heap) { bcm_chunk_t * chunk = 0L; unsigned long size = 0; bcmKNIEnterCriticalSection(); for (chunk = p_heap->first_free ; chunk ; chunk = chunk->next) { #ifdef MEM_DEBUG if (!checksignature(chunk,1)) { BRCM_DBG_ERR(("CHUNK SIGNATURE INVALID mem_available\n")); return 0; } #endif if (chunk->size > size) { size = chunk->size; } } bcmKNILeaveCriticalSection(); return size - sizeof(bcm_chunk_t); } /****************************************************************************** * void * mem_alloc(bcm_heap_t* p_heap, unsigned long size) * * INPUTS: p_heap = reference to a heap structure to initialize * size = playload size * alignbits = playload must be aligned to start on alignbits boundry * OUTPUTS: None. * RETURNS: largest free chunk * FUNCTION: Find the larget free chunk available. ******************************************************************************/ void * mem_tagalloc(bcm_heap_t* p_heap, unsigned long size, char alignbits, char* file, int line) { bcm_chunk_t *chunk; unsigned long * ptr = 0L; bcmKNIEnterCriticalSection(); chunk = heap_newchunk(p_heap,size,alignbits); if (chunk) { ptr = (unsigned long*)chunk_to_pointer(chunk); #ifdef BCM_DEBUG if (file) { /* if it doesn't fit, chop off the beginning which usually contains unhelpful path information */ int len = strlen(file); if (len > MEM_MAX_FILENAME-1) file = file + len - (MEM_MAX_FILENAME-1); memcpy(chunk->file,file,MEM_MAX_FILENAME-1); chunk->file[MEM_MAX_FILENAME-1] = '\0'; } else chunk->file[0] = 0; chunk->line = line; #endif #ifdef MEM_DEBUG fillguardband(chunk); #endif } bcmKNILeaveCriticalSection(); #ifdef MEM_DEBUG if (chunk && file) { mem_validate(p_heap); } #endif return ptr; } /****************************************************************************** * void mem_tagfree(bcm_heap_t* p_heap, void* p_ref, char *file, int line) * * INPUTS: p_heap = reference to a heap structure to initialize * p_ref = ptr to memory to be freed * file = file of calling code (__FILE__) * line = line of calling code (__LINE__) * OUTPUTS: None. * RETURNS: largest free chunk * FUNCTION: Frees memory allocated by mem_tagalloc() ******************************************************************************/ void mem_tagfree(bcm_heap_t* p_heap, void* p_ref, char *file, int line) { bcm_chunk_t * chunk = 0L; if (p_ref == 0L) return; chunk = pointer_to_chunk(p_ref); #ifdef MEM_DEBUG if (!checksignature(chunk,0)) { BRCM_DBG_ERR(("CHUNK SIGNATURE INVALID mem_free\n")); return; } #endif bcmKNIEnterCriticalSection(); heap_deletechunk(p_heap,chunk); bcmKNILeaveCriticalSection(); #ifdef MEM_DEBUG /* need to validate after a free */ if (!mem_validate(p_heap)) BRCM_DBG_ERR(("mem_tagfree error: %s, line %d\n", file, line)); #endif } /****************************************************************************** * void mem_report(bcm_heap_t *p_heap) * * INPUTS: p_heap = reference to a heap structure to initialize * OUTPUTS: None. * RETURNS: None * FUNCTION: Ouput a debug report describing the heap. ******************************************************************************/ #ifdef BCM_DEBUG void mem_report(bcm_heap_t *p_heap) { bcm_chunk_t * chunk = 0L; unsigned long size = 0; for (chunk = p_heap->first ; chunk ; chunk = chunk->next) { if (!checksignature(chunk,0)) { BRCM_DBG_ERR(("CHUNK SIGNATURE INVALID mem_report alloced\n")); return; } BRCM_DBG_MSG(("\n <<<<< Alloced Chunk\n")); chunk_info_msg(chunk); size += chunk->size; } BRCM_DBG_MSG(("\nTotal Alloced Size = %ld\n",size)); size = 0; for (chunk = p_heap->first_free ; chunk ; chunk = chunk->next) { if (!checksignature(chunk,1)) { BRCM_DBG_ERR(("CHUNK SIGNATURE INVALID mem_report free\n")); return; } BRCM_DBG_MSG(("\n<<<<< Free Chunk\n")); chunk_info_msg(chunk); size += chunk->size; } BRCM_DBG_MSG(("\nTotal Free Size = %ld\n",size)); } void mem_reportbrief(bcm_heap_t *p_heap) { bcm_chunk_t * chunk = 0L; unsigned long size = 0; mem_validate(p_heap); BRCM_DBG_MSG(("Allocated chunks:\n")); for (chunk = p_heap->first ; chunk ; chunk = chunk->next) { if (!checksignature(chunk,0)) { BRCM_DBG_ERR(("CHUNK SIGNATURE INVALID mem_report alloced\n")); return; } BRCM_DBG_MSG((" %s:%d\t\t%#x[%ld]\n",chunk->file,chunk->line,chunk_to_pointer(chunk),chunk->size)); size += chunk->size; } BRCM_DBG_MSG(("Total Alloced Size = %ld\n",size)); size = 0; BRCM_DBG_MSG(("Free chunks:\n")); for (chunk = p_heap->first_free ; chunk ; chunk = chunk->next) { if (!checksignature(chunk,1)) { BRCM_DBG_ERR(("CHUNK SIGNATURE INVALID mem_report free\n")); return; } BRCM_DBG_MSG((" %ld\n",chunk->size)); size += chunk->size; } BRCM_DBG_MSG(("Total Free Size = %ld\n",size)); } /****************************************************************************** * char mem_chkoverlap(bcm_heap_t *p_heap) * * INPUTS: p_heap = reference to a heap structure to initialize * OUTPUTS: None. * RETURNS: returns non-zero if the guard bands are all valid, zero otherwise. * FUNCTION: Verify no allocation chunk overlaps another. ******************************************************************************/ BSTD_INLINE char mem_chkoverlap(bcm_heap_t *p_heap) { bcm_chunk_t * chunk = 0L; bcm_chunk_t * ochunk = 0L; unsigned long cstart,cend,ostart; for (chunk = p_heap->first ; chunk ; chunk = chunk->next) { cstart = (unsigned long)chunk; cend = cstart + chunk->size; for (ochunk = p_heap->first ; ochunk ; ochunk = ochunk->next) { ostart = (unsigned long)ochunk; if ((chunk != ochunk) && (ostart > cstart) && (ostart < cend)) { BRCM_DBG_ERR(("\nChunks Overlap\n")); chunk_info_err(chunk); BRCM_DBG_ERR(("-------------\n")); chunk_info_err(ochunk); return 0; } } } return 1; } /****************************************************************************** * char mem_validate(bcm_heap_t *p_heap) * * INPUTS: p_heap = reference to a heap structure to initialize * OUTPUTS: None. * RETURNS: returns non-zero if the guard bands are all valid, zero otherwise. * FUNCTION: Validate chunk guard bands. ******************************************************************************/ char mem_validate(bcm_heap_t *p_heap) { char rc = 1; bcm_chunk_t * chunk = 0L; bcmKNIEnterCriticalSection(); for (chunk = p_heap->first ; chunk ; chunk = chunk->next) { if (validateguardband(chunk) == 0) { /* Guard band has been overwritten */ BRCM_DBG_ERR(("\nMemory guard band violated.\n")); chunk_info_err(chunk); rc = 0; } } if (rc) for (chunk = p_heap->first_free ; chunk ; chunk = chunk->next) { if (!checksignature(chunk,1)) { BRCM_DBG_ERR(("\nMemory guard band of free chunk violated.\n")); chunk_info_err(chunk); rc = 0; } } if (rc) rc = mem_chkoverlap(p_heap); bcmKNILeaveCriticalSection(); return rc; } /****************************************************************************** * void mem_debug(bcm_heap_t *p_heap,unsigned char* buf, * int width, int height, int bpp ) * * INPUTS: p_heap = reference to a heap structure to initialize * buf = display buffer to map memory into * width = number of pixels in a row * height = number of rows * OUTPUTS: None. * RETURNS: largest free chunk * FUNCTION: Map the memory into a 565 pixelmap (2 bytes per pixel). ******************************************************************************/ void mem_debug(bcm_heap_t *p_heap,unsigned char* buf, int width, int height ) { bcm_chunk_t * chunk = 0L; int i,minoff,maxoff; unsigned long size = ((unsigned long)p_heap->end_addr) - ((unsigned long)p_heap->start_addr); unsigned long offset; int bpp = (int)(size / (width * height)) + 1; /* bytes per pixel */ for (i = 0; i < (width * height); ++i) ((unsigned short*)buf)[i] = 0x001F; for (chunk = p_heap->first ; chunk ; chunk = chunk->next) { offset = ((unsigned long)chunk) - ((unsigned long)(p_heap->start_addr)); minoff = (offset/bpp); maxoff = minoff + chunk->size/bpp; if (minoff > width * height) break; if (maxoff > width * height) maxoff = width * height; /* paint the allocated chunks */ for (i = minoff; i < (int)maxoff; ++i) { ((unsigned short*)buf)[i] = 0xF800; } offset = ((unsigned long)chunk) - ((unsigned long)(p_heap->start_addr)); offset += chunk->padding; minoff = (offset/bpp); maxoff = minoff + chunk->padding/bpp; if (minoff > width * height) break; if (maxoff > width * height) maxoff = width * height; /* paint the padding */ for (i = minoff; i < (int)maxoff; ++i) { ((unsigned short*)buf)[i] = 0x7e0; } } } #if SUPPORT_DST_PLATFORM /*from CB3*/ /* return zero if no error. return err value if heap is not valid or damaged. */ int mem_status(bcm_heap_t *p_heap, struct bcm_heap_status *p_status) { bcm_chunk_t * chunk; unsigned long size, num_chunk; struct bcm_heap_status heap_status; memset(&heap_status, 0, sizeof(heap_status)); #if 0 // this is too slow if number of chunk is large. // checking overlay is bottleneck. // todo: is there any good algorithm to check overlap? if (!mem_validate(p_heap)) return -1; #endif // total heap size heap_status.size_heap = (uint32_t)p_heap->end_addr - (uint32_t)p_heap->start_addr; // scan alloc chunks size = num_chunk = 0; for (chunk = p_heap->first ; chunk ; chunk = chunk->next) { if (!checksignature(chunk,0)) { //BRCM_DBG_ERR(("%s invalid sig alloc\n", __func__)); return -2; } size += chunk->size; num_chunk++; } printf("num chunk: %d\n", num_chunk); heap_status.size_alloc = size; heap_status.num_alloc_chunk = num_chunk; // scan free chunks size = num_chunk = 0; for (chunk = p_heap->first_free ; chunk ; chunk = chunk->next) { if (!checksignature(chunk,1)) { //BRCM_DBG_ERR(("CHUNK SIGNATURE INVALID mem_report free\n")); return -3; } size += chunk->size; num_chunk++; } heap_status.size_free = size; heap_status.num_free_chunk = num_chunk; if (p_status) *p_status = heap_status; return 0; } void mem_reportbrief_ex(bcm_heap_t *p_heap, int threshold) { bcm_chunk_t * chunk = 0L; unsigned long size = 0; unsigned long run_size = 0xffffffff; int max_size_lower_than_run = 0; mem_validate(p_heap); BRCM_DBG_MSG(("Allocated chunks:\n")); while (run_size > 0) { // search maximum size that is smaller than chunk_size. max_size_lower_than_run = 0; for (chunk = p_heap->first ; chunk ; chunk = chunk->next) { if (!checksignature(chunk,0)) return; if (chunk->size < run_size && chunk->size > max_size_lower_than_run) max_size_lower_than_run = chunk->size; } if (max_size_lower_than_run == 0) break; // print all max_size chunk. for (chunk = p_heap->first ; chunk ; chunk = chunk->next) { if (chunk->size == max_size_lower_than_run) { if (chunk->size > threshold) BRCM_DBG_MSG(("[%7ld] %08x %s:%d\n", chunk->size,chunk_to_pointer(chunk),chunk->file,chunk->line)); size += chunk->size; } } run_size = max_size_lower_than_run; } BRCM_DBG_MSG(("Total Alloced Size = %ld\n",size)); size = 0; BRCM_DBG_MSG(("Free chunks:\n")); for (chunk = p_heap->first_free ; chunk ; chunk = chunk->next) { if (!checksignature(chunk,1)) { BRCM_DBG_ERR(("CHUNK SIGNATURE INVALID mem_report free\n")); return; } BRCM_DBG_MSG((" %ld\n",chunk->size)); size += chunk->size; } BRCM_DBG_MSG(("Total Free Size = %ld\n",size)); } #endif #else void mem_reportbrief(bcm_heap_t *p_heap) { return; } #endif /* MEM_DEBUG */