Staging: tidspbridge: Use hashtable implementation
Use upstream hashtable implementation instead of generic code Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
3a21f00a50
Коммит
d305558530
|
@ -14,56 +14,45 @@
|
||||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/hashtable.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include <dspbridge/host_os.h>
|
struct gh_node {
|
||||||
#include <dspbridge/gh.h>
|
struct hlist_node hl;
|
||||||
|
u8 data[0];
|
||||||
struct element {
|
|
||||||
struct element *next;
|
|
||||||
u8 data[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define GH_HASH_ORDER 8
|
||||||
|
|
||||||
struct gh_t_hash_tab {
|
struct gh_t_hash_tab {
|
||||||
u16 max_bucket;
|
u32 val_size;
|
||||||
u16 val_size;
|
DECLARE_HASHTABLE(hash_table, GH_HASH_ORDER);
|
||||||
struct element **buckets;
|
u32 (*hash)(const void *key);
|
||||||
u16(*hash) (void *, u16);
|
bool (*match)(const void *key, const void *value);
|
||||||
bool(*match) (void *, void *);
|
void (*delete)(void *key);
|
||||||
void (*delete) (void *);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void noop(void *p);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ======== gh_create ========
|
* ======== gh_create ========
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct gh_t_hash_tab *gh_create(u16 max_bucket, u16 val_size,
|
struct gh_t_hash_tab *gh_create(u32 val_size, u32 (*hash)(const void *),
|
||||||
u16(*hash) (void *, u16), bool(*match) (void *,
|
bool (*match)(const void *, const void *),
|
||||||
void *),
|
void (*delete)(void *))
|
||||||
void (*delete) (void *))
|
|
||||||
{
|
{
|
||||||
struct gh_t_hash_tab *hash_tab;
|
struct gh_t_hash_tab *hash_tab;
|
||||||
u16 i;
|
|
||||||
hash_tab = kzalloc(sizeof(struct gh_t_hash_tab), GFP_KERNEL);
|
hash_tab = kzalloc(sizeof(struct gh_t_hash_tab), GFP_KERNEL);
|
||||||
if (hash_tab == NULL)
|
if (!hash_tab)
|
||||||
return NULL;
|
return ERR_PTR(-ENOMEM);
|
||||||
hash_tab->max_bucket = max_bucket;
|
|
||||||
|
hash_init(hash_tab->hash_table);
|
||||||
|
|
||||||
hash_tab->val_size = val_size;
|
hash_tab->val_size = val_size;
|
||||||
hash_tab->hash = hash;
|
hash_tab->hash = hash;
|
||||||
hash_tab->match = match;
|
hash_tab->match = match;
|
||||||
hash_tab->delete = delete == NULL ? noop : delete;
|
hash_tab->delete = delete;
|
||||||
|
|
||||||
hash_tab->buckets =
|
|
||||||
kzalloc(sizeof(struct element *) * max_bucket, GFP_KERNEL);
|
|
||||||
if (hash_tab->buckets == NULL) {
|
|
||||||
gh_delete(hash_tab);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < max_bucket; i++)
|
|
||||||
hash_tab->buckets[i] = NULL;
|
|
||||||
|
|
||||||
return hash_tab;
|
return hash_tab;
|
||||||
}
|
}
|
||||||
|
@ -73,21 +62,16 @@ struct gh_t_hash_tab *gh_create(u16 max_bucket, u16 val_size,
|
||||||
*/
|
*/
|
||||||
void gh_delete(struct gh_t_hash_tab *hash_tab)
|
void gh_delete(struct gh_t_hash_tab *hash_tab)
|
||||||
{
|
{
|
||||||
struct element *elem, *next;
|
struct gh_node *n;
|
||||||
u16 i;
|
struct hlist_node *tmp;
|
||||||
|
u32 i;
|
||||||
|
|
||||||
if (hash_tab != NULL) {
|
if (hash_tab) {
|
||||||
if (hash_tab->buckets != NULL) {
|
hash_for_each_safe(hash_tab->hash_table, i, tmp, n, hl) {
|
||||||
for (i = 0; i < hash_tab->max_bucket; i++) {
|
hash_del(&n->hl);
|
||||||
for (elem = hash_tab->buckets[i]; elem != NULL;
|
if (hash_tab->delete)
|
||||||
elem = next) {
|
hash_tab->delete(n->data);
|
||||||
next = elem->next;
|
kfree(n);
|
||||||
(*hash_tab->delete) (elem->data);
|
|
||||||
kfree(elem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(hash_tab->buckets);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(hash_tab);
|
kfree(hash_tab);
|
||||||
|
@ -98,56 +82,39 @@ void gh_delete(struct gh_t_hash_tab *hash_tab)
|
||||||
* ======== gh_find ========
|
* ======== gh_find ========
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void *gh_find(struct gh_t_hash_tab *hash_tab, void *key)
|
void *gh_find(struct gh_t_hash_tab *hash_tab, const void *key)
|
||||||
{
|
{
|
||||||
struct element *elem;
|
struct gh_node *n;
|
||||||
|
u32 key_hash = hash_tab->hash(key);
|
||||||
|
|
||||||
elem = hash_tab->buckets[(*hash_tab->hash) (key, hash_tab->max_bucket)];
|
hash_for_each_possible(hash_tab->hash_table, n, hl, key_hash) {
|
||||||
|
if (hash_tab->match(key, n->data))
|
||||||
for (; elem; elem = elem->next) {
|
return n->data;
|
||||||
if ((*hash_tab->match) (key, elem->data))
|
|
||||||
return elem->data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return ERR_PTR(-ENODATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ======== gh_insert ========
|
* ======== gh_insert ========
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void *gh_insert(struct gh_t_hash_tab *hash_tab, void *key, void *value)
|
void *gh_insert(struct gh_t_hash_tab *hash_tab, const void *key,
|
||||||
|
const void *value)
|
||||||
{
|
{
|
||||||
struct element *elem;
|
struct gh_node *n;
|
||||||
u16 i;
|
|
||||||
char *src, *dst;
|
|
||||||
|
|
||||||
elem = kzalloc(sizeof(struct element) - 1 + hash_tab->val_size,
|
n = kmalloc(sizeof(struct gh_node) + hash_tab->val_size,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (elem != NULL) {
|
|
||||||
|
|
||||||
dst = (char *)elem->data;
|
if (!n)
|
||||||
src = (char *)value;
|
return ERR_PTR(-ENOMEM);
|
||||||
for (i = 0; i < hash_tab->val_size; i++)
|
|
||||||
*dst++ = *src++;
|
|
||||||
|
|
||||||
i = (*hash_tab->hash) (key, hash_tab->max_bucket);
|
INIT_HLIST_NODE(&n->hl);
|
||||||
elem->next = hash_tab->buckets[i];
|
hash_add(hash_tab->hash_table, &n->hl, hash_tab->hash(key));
|
||||||
hash_tab->buckets[i] = elem;
|
memcpy(n->data, value, hash_tab->val_size);
|
||||||
|
|
||||||
return elem->data;
|
return n->data;
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ======== noop ========
|
|
||||||
*/
|
|
||||||
/* ARGSUSED */
|
|
||||||
static void noop(void *p)
|
|
||||||
{
|
|
||||||
p = p; /* stifle compiler warning */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
|
#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
|
||||||
|
@ -162,16 +129,13 @@ static void noop(void *p)
|
||||||
void gh_iterate(struct gh_t_hash_tab *hash_tab,
|
void gh_iterate(struct gh_t_hash_tab *hash_tab,
|
||||||
void (*callback)(void *, void *), void *user_data)
|
void (*callback)(void *, void *), void *user_data)
|
||||||
{
|
{
|
||||||
struct element *elem;
|
struct gh_node *n;
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
if (hash_tab && hash_tab->buckets)
|
if (!hash_tab)
|
||||||
for (i = 0; i < hash_tab->max_bucket; i++) {
|
return;
|
||||||
elem = hash_tab->buckets[i];
|
|
||||||
while (elem) {
|
hash_for_each(hash_tab->hash_table, i, n, hl)
|
||||||
callback(&elem->data, user_data);
|
callback(&n->data, user_data);
|
||||||
elem = elem->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,13 +18,13 @@
|
||||||
#define GH_
|
#define GH_
|
||||||
#include <dspbridge/host_os.h>
|
#include <dspbridge/host_os.h>
|
||||||
|
|
||||||
extern struct gh_t_hash_tab *gh_create(u16 max_bucket, u16 val_size,
|
extern struct gh_t_hash_tab *gh_create(u32 val_size,
|
||||||
u16(*hash) (void *, u16),
|
u32 (*hash)(const void *), bool (*match)(const void *,
|
||||||
bool(*match) (void *, void *),
|
const void *), void (*delete) (void *));
|
||||||
void (*delete) (void *));
|
|
||||||
extern void gh_delete(struct gh_t_hash_tab *hash_tab);
|
extern void gh_delete(struct gh_t_hash_tab *hash_tab);
|
||||||
extern void *gh_find(struct gh_t_hash_tab *hash_tab, void *key);
|
extern void *gh_find(struct gh_t_hash_tab *hash_tab, const void *key);
|
||||||
extern void *gh_insert(struct gh_t_hash_tab *hash_tab, void *key, void *value);
|
extern void *gh_insert(struct gh_t_hash_tab *hash_tab, const void *key,
|
||||||
|
const void *value);
|
||||||
#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
|
#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
|
||||||
void gh_iterate(struct gh_t_hash_tab *hash_tab,
|
void gh_iterate(struct gh_t_hash_tab *hash_tab,
|
||||||
void (*callback)(void *, void *), void *user_data);
|
void (*callback)(void *, void *), void *user_data);
|
||||||
|
|
|
@ -33,9 +33,6 @@
|
||||||
#include <dspbridge/dbll.h>
|
#include <dspbridge/dbll.h>
|
||||||
#include <dspbridge/rmm.h>
|
#include <dspbridge/rmm.h>
|
||||||
|
|
||||||
/* Number of buckets for symbol hash table */
|
|
||||||
#define MAXBUCKETS 211
|
|
||||||
|
|
||||||
/* Max buffer length */
|
/* Max buffer length */
|
||||||
#define MAXEXPR 128
|
#define MAXEXPR 128
|
||||||
|
|
||||||
|
@ -183,8 +180,8 @@ static int execute(struct dynamic_loader_initialize *this, ldr_addr start);
|
||||||
static void release(struct dynamic_loader_initialize *this);
|
static void release(struct dynamic_loader_initialize *this);
|
||||||
|
|
||||||
/* symbol table hash functions */
|
/* symbol table hash functions */
|
||||||
static u16 name_hash(void *key, u16 max_bucket);
|
static u32 name_hash(const void *key);
|
||||||
static bool name_match(void *key, void *sp);
|
static bool name_match(const void *key, const void *sp);
|
||||||
static void sym_delete(void *value);
|
static void sym_delete(void *value);
|
||||||
|
|
||||||
/* Symbol Redefinition */
|
/* Symbol Redefinition */
|
||||||
|
@ -277,17 +274,16 @@ bool dbll_get_addr(struct dbll_library_obj *zl_lib, char *name,
|
||||||
struct dbll_sym_val **sym_val)
|
struct dbll_sym_val **sym_val)
|
||||||
{
|
{
|
||||||
struct dbll_symbol *sym;
|
struct dbll_symbol *sym;
|
||||||
bool status = false;
|
|
||||||
|
|
||||||
sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, name);
|
sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, name);
|
||||||
if (sym != NULL) {
|
if (IS_ERR(sym))
|
||||||
*sym_val = &sym->value;
|
return false;
|
||||||
status = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p, status 0x%x\n",
|
*sym_val = &sym->value;
|
||||||
__func__, zl_lib, name, sym_val, status);
|
|
||||||
return status;
|
dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p\n",
|
||||||
|
__func__, zl_lib, name, sym_val);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -312,7 +308,6 @@ bool dbll_get_c_addr(struct dbll_library_obj *zl_lib, char *name,
|
||||||
{
|
{
|
||||||
struct dbll_symbol *sym;
|
struct dbll_symbol *sym;
|
||||||
char cname[MAXEXPR + 1];
|
char cname[MAXEXPR + 1];
|
||||||
bool status = false;
|
|
||||||
|
|
||||||
cname[0] = '_';
|
cname[0] = '_';
|
||||||
|
|
||||||
|
@ -321,13 +316,12 @@ bool dbll_get_c_addr(struct dbll_library_obj *zl_lib, char *name,
|
||||||
|
|
||||||
/* Check for C name, if not found */
|
/* Check for C name, if not found */
|
||||||
sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, cname);
|
sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, cname);
|
||||||
|
if (IS_ERR(sym))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (sym != NULL) {
|
*sym_val = &sym->value;
|
||||||
*sym_val = &sym->value;
|
|
||||||
status = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -416,12 +410,13 @@ int dbll_load(struct dbll_library_obj *lib, dbll_flags flags,
|
||||||
/* Create a hash table for symbols if not already created */
|
/* Create a hash table for symbols if not already created */
|
||||||
if (zl_lib->sym_tab == NULL) {
|
if (zl_lib->sym_tab == NULL) {
|
||||||
got_symbols = false;
|
got_symbols = false;
|
||||||
zl_lib->sym_tab = gh_create(MAXBUCKETS,
|
zl_lib->sym_tab = gh_create(sizeof(struct dbll_symbol),
|
||||||
sizeof(struct dbll_symbol),
|
|
||||||
name_hash,
|
name_hash,
|
||||||
name_match, sym_delete);
|
name_match, sym_delete);
|
||||||
if (zl_lib->sym_tab == NULL)
|
if (IS_ERR(zl_lib->sym_tab)) {
|
||||||
status = -ENOMEM;
|
status = PTR_ERR(zl_lib->sym_tab);
|
||||||
|
zl_lib->sym_tab = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -593,10 +588,11 @@ int dbll_open(struct dbll_tar_obj *target, char *file, dbll_flags flags,
|
||||||
goto func_cont;
|
goto func_cont;
|
||||||
|
|
||||||
zl_lib->sym_tab =
|
zl_lib->sym_tab =
|
||||||
gh_create(MAXBUCKETS, sizeof(struct dbll_symbol), name_hash,
|
gh_create(sizeof(struct dbll_symbol), name_hash, name_match,
|
||||||
name_match, sym_delete);
|
sym_delete);
|
||||||
if (zl_lib->sym_tab == NULL) {
|
if (IS_ERR(zl_lib->sym_tab)) {
|
||||||
status = -ENOMEM;
|
status = PTR_ERR(zl_lib->sym_tab);
|
||||||
|
zl_lib->sym_tab = NULL;
|
||||||
} else {
|
} else {
|
||||||
/* Do a fake load to get symbols - set write func to no_op */
|
/* Do a fake load to get symbols - set write func to no_op */
|
||||||
zl_lib->init.dl_init.writemem = no_op;
|
zl_lib->init.dl_init.writemem = no_op;
|
||||||
|
@ -793,11 +789,10 @@ static int dof_open(struct dbll_library_obj *zl_lib)
|
||||||
/*
|
/*
|
||||||
* ======== name_hash ========
|
* ======== name_hash ========
|
||||||
*/
|
*/
|
||||||
static u16 name_hash(void *key, u16 max_bucket)
|
static u32 name_hash(const void *key)
|
||||||
{
|
{
|
||||||
u16 ret;
|
u32 hash;
|
||||||
u16 hash;
|
const char *name = key;
|
||||||
char *name = (char *)key;
|
|
||||||
|
|
||||||
hash = 0;
|
hash = 0;
|
||||||
|
|
||||||
|
@ -806,19 +801,16 @@ static u16 name_hash(void *key, u16 max_bucket)
|
||||||
hash ^= *name++;
|
hash ^= *name++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = hash % max_bucket;
|
return hash;
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ======== name_match ========
|
* ======== name_match ========
|
||||||
*/
|
*/
|
||||||
static bool name_match(void *key, void *sp)
|
static bool name_match(const void *key, const void *sp)
|
||||||
{
|
{
|
||||||
if ((key != NULL) && (sp != NULL)) {
|
if ((key != NULL) && (sp != NULL)) {
|
||||||
if (strcmp((char *)key, ((struct dbll_symbol *)sp)->name) ==
|
if (strcmp(key, ((struct dbll_symbol *)sp)->name) == 0)
|
||||||
0)
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -937,7 +929,6 @@ static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
|
||||||
*this, const char *name,
|
*this, const char *name,
|
||||||
unsigned moduleid)
|
unsigned moduleid)
|
||||||
{
|
{
|
||||||
struct dynload_symbol *ret_sym;
|
|
||||||
struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
|
struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
|
||||||
struct dbll_library_obj *lib;
|
struct dbll_library_obj *lib;
|
||||||
struct dbll_symbol *sym;
|
struct dbll_symbol *sym;
|
||||||
|
@ -945,8 +936,10 @@ static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
|
||||||
lib = ldr_sym->lib;
|
lib = ldr_sym->lib;
|
||||||
sym = (struct dbll_symbol *)gh_find(lib->sym_tab, (char *)name);
|
sym = (struct dbll_symbol *)gh_find(lib->sym_tab, (char *)name);
|
||||||
|
|
||||||
ret_sym = (struct dynload_symbol *)&sym->value;
|
if (IS_ERR(sym))
|
||||||
return ret_sym;
|
return NULL;
|
||||||
|
|
||||||
|
return (struct dynload_symbol *)&sym->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -991,8 +984,10 @@ static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
|
||||||
sym_ptr =
|
sym_ptr =
|
||||||
(struct dbll_symbol *)gh_insert(lib->sym_tab, (void *)name,
|
(struct dbll_symbol *)gh_insert(lib->sym_tab, (void *)name,
|
||||||
(void *)&symbol);
|
(void *)&symbol);
|
||||||
if (sym_ptr == NULL)
|
if (IS_ERR(sym_ptr)) {
|
||||||
kfree(symbol.name);
|
kfree(symbol.name);
|
||||||
|
sym_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (sym_ptr != NULL)
|
if (sym_ptr != NULL)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче