250 lines
6.0 KiB
C
250 lines
6.0 KiB
C
|
//------------------------------------------------------------------------------
|
||
|
// 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; 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;
|
||
|
}
|
||
|
}
|
||
|
}
|