//------------------------------------------------------------------------------ // ISC License (ISC) // // Copyright (c) 2004-2010, The Linux Foundation // All rights reserved. // Software was previously licensed under ISC license by Qualcomm Atheros, Inc. // // // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // // // // Author(s): ="Atheros" //------------------------------------------------------------------------------ // #include "ar6000_drv.h" #define malloc(size) kmalloc((size), GFP_ATOMIC) #define free(ptr) kfree((ptr)) typedef struct MemInfo { void *ptr; const char *caller; int lineno; size_t size; } MemInfo; typedef unsigned long hash_key; typedef struct HashItem { hash_key Key; struct HashItem * Next; } HashItem; typedef struct a_hash { HashItem **Buckets; size_t len; int (*cmpKeyFunc)(const hash_key a, const hash_key b); unsigned long (*hashFunc)(const hash_key key); HashItem* (*mkNodeFunc)(hash_key key); } a_hash; static a_hash* gMem; static int cmpMemInfo(const hash_key a, const hash_key b) { return((const MemInfo*)a)->ptr - ((const MemInfo*)b)->ptr; } static unsigned long hashMemInfo(const hash_key key) { return(unsigned long)((const MemInfo*)key)->ptr; } static HashItem* mkMemInfoItem(hash_key key) { HashItem* item; item = malloc(sizeof(HashItem)+ sizeof(MemInfo)); item->Key = (hash_key)(item+1); memcpy((void*)item->Key, (void*)key, sizeof(MemInfo)); return item; } static void rmItem(HashItem* item, void* data) { /* private function, don't use !! */ free(item); } HashItem* a_hash_add(a_hash *hash, const hash_key Key) { int hashIndex = hash->hashFunc(Key) % hash->len; HashItem* item = hash->mkNodeFunc(Key); item->Next = hash->Buckets[hashIndex]; hash->Buckets[hashIndex] = item; return item; } void a_hash_iterate(a_hash* hash, void (*func)(HashItem*, void*), void* data) { size_t i; HashItem *p, *next; for (i=0; ilen; ++i) { p = hash->Buckets[i]; while (p) { next = p->Next; func(p, data); p = next; } } } void a_hash_clear(a_hash* hash) { a_hash_iterate(hash, rmItem, NULL); memset(hash->Buckets, 0, hash->len * sizeof(HashItem*)); } void a_hash_destroy(a_hash* hash) { a_hash_clear(hash); free(hash); } static HashItem** __a_hash_find(a_hash* hash, const hash_key Key) { int hashIndex = hash->hashFunc(Key) % hash->len; HashItem** result = &hash->Buckets[hashIndex]; while (*result) { if (hash->cmpKeyFunc((*result)->Key, Key)==0) return result; else result = &(*result)->Next; } return result; } HashItem* a_hash_find(a_hash* hash, const hash_key Key) { return *__a_hash_find(hash, Key); } HashItem* a_hash_findNext(a_hash* hash, HashItem* item) { hash_key Key = (item) ? item->Key : 0; if (item) item = item->Next; while (item) { if (hash->cmpKeyFunc(item->Key, Key) == 0) return item; else item = item->Next; } return item; } void a_hash_erase(a_hash* hash, const hash_key Key) { HashItem* p; HashItem** prev = __a_hash_find(hash, Key); p = *prev; if (p) { *prev = p->Next; rmItem(p, NULL); } } void __a_meminfo_add(void *ptr, size_t msize, const char *func, int lineno) { MemInfo info; info.ptr = ptr; info.lineno = lineno; info.caller = func; info.size = msize; if (!gMem) { int len = 512; size_t size = sizeof(HashItem*) * len; gMem = (a_hash*)malloc(sizeof(a_hash)+size); memset(gMem, 0, sizeof(a_hash)+size); gMem->Buckets = (HashItem**)(gMem+1); gMem->len = len; gMem->mkNodeFunc = mkMemInfoItem; gMem->cmpKeyFunc = cmpMemInfo; gMem->hashFunc = hashMemInfo; } a_hash_add(gMem, (hash_key)&info); } void a_meminfo_del(void *ptr) { MemInfo info; info.ptr = ptr; if (gMem) { HashItem* p; HashItem** prev = __a_hash_find(gMem, (unsigned long)&info); p = *prev; if (p) { *prev = p->Next; rmItem(p, NULL); } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Warning! memory ptr %p not found!", __func__, ptr)); } } } void* a_mem_alloc(size_t msize, int type, const char *func, int lineno) { void *ptr = kmalloc(msize, type); __a_meminfo_add(ptr, msize, func, lineno); return ptr; } void a_mem_free(void *ptr) { a_meminfo_del(ptr); kfree(ptr); } static void printMemInfo(HashItem *item, void*arg) { MemInfo *info = (MemInfo*)item->Key; int *total = (int*)arg; *total += info->size; A_PRINTF("%s line %d size %d ptr %p\n", info->caller, info->lineno, info->size, info->ptr); } void a_meminfo_report(int clear) { int total = 0; A_PRINTF("AR6K Memory Report\n"); if (gMem) { a_hash_iterate(gMem, printMemInfo, &total); if (clear) { a_hash_destroy(gMem); } } A_PRINTF("Total %d bytes\n", total); } A_BOOL a_meminfo_find(void *ptr) { MemInfo info; info.ptr = ptr; if (gMem) { HashItem* p; HashItem** prev = __a_hash_find(gMem, (unsigned long)&info); p = *prev; if (p) { return TRUE; } else { return FALSE; } } }