blob: cb7cd3084ba4bbddbe3146f4f78b9862ad7899ee [file] [log] [blame]
//------------------------------------------------------------------------------
// Copyright (c) 2004-2010 Atheros Communications Inc.
// All rights reserved.
//
//
//
// 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; i<hash->len; ++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;
}
}
}