[PATCH libdrm 1/2] util: move some files to an ASIC neutral directory.

Samuel Li Samuel.Li at amd.com
Fri Jun 30 19:24:29 UTC 2017


Change-Id: Iac1c4870253e8b8860a61b7cf175e7a25cc95921
Signed-off-by: Samuel Li <Samuel.Li at amd.com>
---
 Makefile.sources         |  10 +-
 amdgpu/Makefile.am       |   3 +-
 amdgpu/Makefile.sources  |   7 +-
 amdgpu/amdgpu_asic_id.c  | 219 ---------------------------
 amdgpu/amdgpu_device.c   |   7 +-
 amdgpu/amdgpu_internal.h |  11 +-
 amdgpu/util_hash.c       | 387 -----------------------------------------------
 amdgpu/util_hash.h       | 107 -------------
 amdgpu/util_hash_table.c | 262 --------------------------------
 amdgpu/util_hash_table.h |  73 ---------
 util/util_asic_id.c      | 217 ++++++++++++++++++++++++++
 util/util_asic_id.h      |  39 +++++
 util/util_hash.c         | 387 +++++++++++++++++++++++++++++++++++++++++++++++
 util/util_hash.h         | 107 +++++++++++++
 util/util_hash_table.c   | 262 ++++++++++++++++++++++++++++++++
 util/util_hash_table.h   |  73 +++++++++
 16 files changed, 1102 insertions(+), 1069 deletions(-)
 delete mode 100644 amdgpu/amdgpu_asic_id.c
 delete mode 100644 amdgpu/util_hash.c
 delete mode 100644 amdgpu/util_hash.h
 delete mode 100644 amdgpu/util_hash_table.c
 delete mode 100644 amdgpu/util_hash_table.h
 create mode 100644 util/util_asic_id.c
 create mode 100644 util/util_asic_id.h
 create mode 100644 util/util_hash.c
 create mode 100644 util/util_hash.h
 create mode 100644 util/util_hash_table.c
 create mode 100644 util/util_hash_table.h

diff --git a/Makefile.sources b/Makefile.sources
index 10aa1d0..f2b0ec6 100644
--- a/Makefile.sources
+++ b/Makefile.sources
@@ -10,12 +10,18 @@ LIBDRM_FILES := \
 	libdrm_macros.h \
 	libdrm_lists.h \
 	util_double_list.h \
-	util_math.h
+	util_math.h \
+	util/util_asic_id.c \
+	util/util_hash.c \
+	util/util_hash_table.c
 
 LIBDRM_H_FILES := \
 	libsync.h \
 	xf86drm.h \
-	xf86drmMode.h
+	xf86drmMode.h \
+	util/util_asic_id.h \
+	util/util_hash.h \
+	util/util_hash_table.h
 
 LIBDRM_INCLUDE_H_FILES := \
 	include/drm/drm.h \
diff --git a/amdgpu/Makefile.am b/amdgpu/Makefile.am
index 66f6f67..c3e83d6 100644
--- a/amdgpu/Makefile.am
+++ b/amdgpu/Makefile.am
@@ -28,7 +28,8 @@ AM_CFLAGS = \
 	$(WARN_CFLAGS) \
 	-I$(top_srcdir) \
 	$(PTHREADSTUBS_CFLAGS) \
-	-I$(top_srcdir)/include/drm
+	-I$(top_srcdir)/include/drm \
+	-I$(top_srcdir)/util
 
 libdrmdatadir = @libdrmdatadir@
 ASIC_ID_TABLE_NUM_ENTRIES := $(shell egrep -ci '^[0-9a-f]{4},.*[0-9a-f]+,' \
diff --git a/amdgpu/Makefile.sources b/amdgpu/Makefile.sources
index bc3abaa..23e9e69 100644
--- a/amdgpu/Makefile.sources
+++ b/amdgpu/Makefile.sources
@@ -1,15 +1,10 @@
 LIBDRM_AMDGPU_FILES := \
-	amdgpu_asic_id.c \
 	amdgpu_bo.c \
 	amdgpu_cs.c \
 	amdgpu_device.c \
 	amdgpu_gpu_info.c \
 	amdgpu_internal.h \
-	amdgpu_vamgr.c \
-	util_hash.c \
-	util_hash.h \
-	util_hash_table.c \
-	util_hash_table.h
+	amdgpu_vamgr.c
 
 LIBDRM_AMDGPU_H_FILES := \
 	amdgpu.h
diff --git a/amdgpu/amdgpu_asic_id.c b/amdgpu/amdgpu_asic_id.c
deleted file mode 100644
index 3a88896..0000000
--- a/amdgpu/amdgpu_asic_id.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright © 2017 Advanced Micro Devices, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "xf86drm.h"
-#include "amdgpu_drm.h"
-#include "amdgpu_internal.h"
-
-static int parse_one_line(const char *line, struct amdgpu_asic_id *id)
-{
-	char *buf, *saveptr;
-	char *s_did;
-	char *s_rid;
-	char *s_name;
-	char *endptr;
-	int r = 0;
-
-	buf = strdup(line);
-	if (!buf)
-		return -ENOMEM;
-
-	/* ignore empty line and commented line */
-	if (strlen(line) == 0 || line[0] == '#') {
-		r = -EAGAIN;
-		goto out;
-	}
-
-	/* device id */
-	s_did = strtok_r(buf, ",", &saveptr);
-	if (!s_did) {
-		r = -EINVAL;
-		goto out;
-	}
-
-	id->did = strtol(s_did, &endptr, 16);
-	if (*endptr) {
-		r = -EINVAL;
-		goto out;
-	}
-
-	/* revision id */
-	s_rid = strtok_r(NULL, ",", &saveptr);
-	if (!s_rid) {
-		r = -EINVAL;
-		goto out;
-	}
-
-	id->rid = strtol(s_rid, &endptr, 16);
-	if (*endptr) {
-		r = -EINVAL;
-		goto out;
-	}
-
-	/* marketing name */
-	s_name = strtok_r(NULL, ",", &saveptr);
-	if (!s_name) {
-		r = -EINVAL;
-		goto out;
-	}
-	/* trim leading whitespaces or tabs */
-	while (isblank(*s_name))
-		s_name++;
-	if (strlen(s_name) == 0) {
-		r = -EINVAL;
-		goto out;
-	}
-
-	id->marketing_name = strdup(s_name);
-	if (id->marketing_name == NULL) {
-		r = -EINVAL;
-		goto out;
-	}
-
-out:
-	free(buf);
-
-	return r;
-}
-
-int amdgpu_parse_asic_ids(struct amdgpu_asic_id **p_asic_id_table)
-{
-	struct amdgpu_asic_id *asic_id_table;
-	struct amdgpu_asic_id *id;
-	FILE *fp;
-	char *line = NULL;
-	size_t len = 0;
-	ssize_t n;
-	int line_num = 1;
-	size_t table_size = 0;
-	size_t table_max_size = AMDGPU_ASIC_ID_TABLE_NUM_ENTRIES;
-	int r = 0;
-
-	fp = fopen(AMDGPU_ASIC_ID_TABLE, "r");
-	if (!fp) {
-		fprintf(stderr, "%s: %s\n", AMDGPU_ASIC_ID_TABLE,
-			strerror(errno));
-		return -EINVAL;
-	}
-
-	asic_id_table = calloc(table_max_size + 1,
-			       sizeof(struct amdgpu_asic_id));
-	if (!asic_id_table) {
-		r = -ENOMEM;
-		goto close;
-	}
-
-	/* 1st valid line is file version */
-	while ((n = getline(&line, &len, fp)) != -1) {
-		/* trim trailing newline */
-		if (line[n - 1] == '\n')
-			line[n - 1] = '\0';
-
-		/* ignore empty line and commented line */
-		if (strlen(line) == 0 || line[0] == '#') {
-			line_num++;
-			continue;
-		}
-
-		drmMsg("%s version: %s\n", AMDGPU_ASIC_ID_TABLE, line);
-		break;
-	}
-
-	while ((n = getline(&line, &len, fp)) != -1) {
-		if (table_size > table_max_size) {
-			/* double table size */
-			table_max_size *= 2;
-			id = realloc(asic_id_table, (table_max_size + 1) *
-				     sizeof(struct amdgpu_asic_id));
-			if (!id) {
-				r = -ENOMEM;
-				goto free;
-			}
-                        asic_id_table = id;
-		}
-
-		id = asic_id_table + table_size;
-
-		/* trim trailing newline */
-		if (line[n - 1] == '\n')
-			line[n - 1] = '\0';
-
-		r = parse_one_line(line, id);
-		if (r) {
-			if (r == -EAGAIN) {
-				line_num++;
-				continue;
-			}
-			fprintf(stderr, "Invalid format: %s: line %d: %s\n",
-				AMDGPU_ASIC_ID_TABLE, line_num, line);
-			goto free;
-		}
-
-		line_num++;
-		table_size++;
-	}
-
-	/* end of table */
-	id = asic_id_table + table_size;
-	memset(id, 0, sizeof(struct amdgpu_asic_id));
-
-	if (table_size != table_max_size) {
-		id = realloc(asic_id_table, (table_size + 1) *
-			     sizeof(struct amdgpu_asic_id));
-		if (!id)
-			r = -ENOMEM;
-		else
-			asic_id_table = id;
-        }
-
-free:
-	free(line);
-
-	if (r && asic_id_table) {
-		while (table_size--) {
-			id = asic_id_table + table_size;
-			free(id->marketing_name);
-		}
-		free(asic_id_table);
-		asic_id_table = NULL;
-	}
-close:
-	fclose(fp);
-
-	*p_asic_id_table = asic_id_table;
-
-	return r;
-}
diff --git a/amdgpu/amdgpu_device.c b/amdgpu/amdgpu_device.c
index 9a238d9..2653ada 100644
--- a/amdgpu/amdgpu_device.c
+++ b/amdgpu/amdgpu_device.c
@@ -130,7 +130,7 @@ static int amdgpu_get_auth(int fd, int *auth)
 
 static void amdgpu_device_free_internal(amdgpu_device_handle dev)
 {
-	const struct amdgpu_asic_id *id;
+	const struct util_asic_id *id;
 	amdgpu_vamgr_deinit(&dev->vamgr_32);
 	amdgpu_vamgr_deinit(&dev->vamgr);
 	util_hash_table_destroy(dev->bo_flink_names);
@@ -273,7 +273,8 @@ int amdgpu_device_initialize(int fd,
 	amdgpu_vamgr_init(&dev->vamgr_32, start, max,
 			  dev->dev_info.virtual_address_alignment);
 
-	r = amdgpu_parse_asic_ids(&dev->asic_ids);
+	r = util_parse_asic_ids(&dev->asic_ids, AMDGPU_ASIC_ID_TABLE,
+				  AMDGPU_ASIC_ID_TABLE_NUM_ENTRIES);
 	if (r) {
 		fprintf(stderr, "%s: Cannot parse ASIC IDs, 0x%x.",
 			__func__, r);
@@ -309,7 +310,7 @@ int amdgpu_device_deinitialize(amdgpu_device_handle dev)
 
 const char *amdgpu_get_marketing_name(amdgpu_device_handle dev)
 {
-	const struct amdgpu_asic_id *id;
+	const struct util_asic_id *id;
 
 	if (!dev->asic_ids)
 		return NULL;
diff --git a/amdgpu/amdgpu_internal.h b/amdgpu/amdgpu_internal.h
index e68246b..07ebda9 100644
--- a/amdgpu/amdgpu_internal.h
+++ b/amdgpu/amdgpu_internal.h
@@ -36,6 +36,7 @@
 #include "xf86atomic.h"
 #include "amdgpu.h"
 #include "util_double_list.h"
+#include "util/util_asic_id.h"
 
 #define AMDGPU_CS_MAX_RINGS 8
 /* do not use below macro if b is not power of 2 aligned value */
@@ -69,12 +70,6 @@ struct amdgpu_va {
 	struct amdgpu_bo_va_mgr *vamgr;
 };
 
-struct amdgpu_asic_id {
-	uint32_t did;
-	uint32_t rid;
-	char *marketing_name;
-};
-
 struct amdgpu_device {
 	atomic_t refcount;
 	int fd;
@@ -83,7 +78,7 @@ struct amdgpu_device {
 	unsigned minor_version;
 
 	/** Lookup table of asic device id, revision id and marketing name */
-	struct amdgpu_asic_id *asic_ids;
+	struct util_asic_id *asic_ids;
 	/** List of buffer handles. Protected by bo_table_mutex. */
 	struct util_hash_table *bo_handles;
 	/** List of buffer GEM flink names. Protected by bo_table_mutex. */
@@ -157,8 +152,6 @@ amdgpu_vamgr_find_va(struct amdgpu_bo_va_mgr *mgr, uint64_t size,
 drm_private void
 amdgpu_vamgr_free_va(struct amdgpu_bo_va_mgr *mgr, uint64_t va, uint64_t size);
 
-drm_private int amdgpu_parse_asic_ids(struct amdgpu_asic_id **asic_ids);
-
 drm_private int amdgpu_query_gpu_info_init(amdgpu_device_handle dev);
 
 drm_private uint64_t amdgpu_cs_calculate_timeout(uint64_t timeout);
diff --git a/amdgpu/util_hash.c b/amdgpu/util_hash.c
deleted file mode 100644
index 87cb671..0000000
--- a/amdgpu/util_hash.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
- /*
-  * Authors:
-  *   Zack Rusin <zackr at vmware.com>
-  */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "util_hash.h"
-
-#include <stdlib.h>
-#include <assert.h>
-
-#define MAX(a, b) ((a > b) ? (a) : (b))
-
-static const int MinNumBits = 4;
-
-static const unsigned char prime_deltas[] = {
-	0,  0,  1,  3,  1,  5,  3,  3,  1,  9,  7,  5,  3,  9, 25,  3,
-	1, 21,  3, 21,  7, 15,  9,  5,  3, 29, 15,  0,  0,  0,  0,  0
-};
-
-static int primeForNumBits(int numBits)
-{
-	return (1 << numBits) + prime_deltas[numBits];
-}
-
-/* Returns the smallest integer n such that
-   primeForNumBits(n) >= hint.
-*/
-static int countBits(int hint)
-{
-	int numBits = 0;
-	int bits = hint;
-
-	while (bits > 1) {
-		bits >>= 1;
-		numBits++;
-	}
-
-	if (numBits >= (int)sizeof(prime_deltas)) {
-		numBits = sizeof(prime_deltas) - 1;
-	} else if (primeForNumBits(numBits) < hint) {
-		++numBits;
-	}
-	return numBits;
-}
-
-struct util_node {
-   struct util_node *next;
-   unsigned key;
-   void *value;
-};
-
-struct util_hash_data {
-   struct util_node *fakeNext;
-   struct util_node **buckets;
-   int size;
-   int nodeSize;
-   short userNumBits;
-   short numBits;
-   int numBuckets;
-};
-
-struct util_hash {
-   union {
-      struct util_hash_data *d;
-      struct util_node      *e;
-   } data;
-};
-
-static void *util_data_allocate_node(struct util_hash_data *hash)
-{
-   return malloc(hash->nodeSize);
-}
-
-static void util_free_node(struct util_node *node)
-{
-   free(node);
-}
-
-static struct util_node *
-util_hash_create_node(struct util_hash *hash,
-                      unsigned akey, void *avalue,
-                      struct util_node **anextNode)
-{
-   struct util_node *node = util_data_allocate_node(hash->data.d);
-
-   if (!node)
-      return NULL;
-
-   node->key = akey;
-   node->value = avalue;
-
-   node->next = (struct util_node*)(*anextNode);
-   *anextNode = node;
-   ++hash->data.d->size;
-   return node;
-}
-
-static void util_data_rehash(struct util_hash_data *hash, int hint)
-{
-   if (hint < 0) {
-      hint = countBits(-hint);
-      if (hint < MinNumBits)
-         hint = MinNumBits;
-      hash->userNumBits = (short)hint;
-      while (primeForNumBits(hint) < (hash->size >> 1))
-         ++hint;
-   } else if (hint < MinNumBits) {
-      hint = MinNumBits;
-   }
-
-   if (hash->numBits != hint) {
-      struct util_node *e = (struct util_node *)(hash);
-      struct util_node **oldBuckets = hash->buckets;
-      int oldNumBuckets = hash->numBuckets;
-      int  i = 0;
-
-      hash->numBits = (short)hint;
-      hash->numBuckets = primeForNumBits(hint);
-      hash->buckets = malloc(sizeof(struct util_node*) * hash->numBuckets);
-      for (i = 0; i < hash->numBuckets; ++i)
-         hash->buckets[i] = e;
-
-      for (i = 0; i < oldNumBuckets; ++i) {
-         struct util_node *firstNode = oldBuckets[i];
-         while (firstNode != e) {
-            unsigned h = firstNode->key;
-            struct util_node *lastNode = firstNode;
-            struct util_node *afterLastNode;
-            struct util_node **beforeFirstNode;
-            
-            while (lastNode->next != e && lastNode->next->key == h)
-               lastNode = lastNode->next;
-
-            afterLastNode = lastNode->next;
-            beforeFirstNode = &hash->buckets[h % hash->numBuckets];
-            while (*beforeFirstNode != e)
-               beforeFirstNode = &(*beforeFirstNode)->next;
-            lastNode->next = *beforeFirstNode;
-            *beforeFirstNode = firstNode;
-            firstNode = afterLastNode;
-         }
-      }
-      free(oldBuckets);
-   }
-}
-
-static void util_data_might_grow(struct util_hash_data *hash)
-{
-   if (hash->size >= hash->numBuckets)
-      util_data_rehash(hash, hash->numBits + 1);
-}
-
-static void util_data_has_shrunk(struct util_hash_data *hash)
-{
-   if (hash->size <= (hash->numBuckets >> 3) &&
-       hash->numBits > hash->userNumBits) {
-      int max = MAX(hash->numBits-2, hash->userNumBits);
-      util_data_rehash(hash,  max);
-   }
-}
-
-static struct util_node *util_data_first_node(struct util_hash_data *hash)
-{
-   struct util_node *e = (struct util_node *)(hash);
-   struct util_node **bucket = hash->buckets;
-   int n = hash->numBuckets;
-   while (n--) {
-      if (*bucket != e)
-         return *bucket;
-      ++bucket;
-   }
-   return e;
-}
-
-static struct util_node **util_hash_find_node(struct util_hash *hash, unsigned akey)
-{
-   struct util_node **node;
-
-   if (hash->data.d->numBuckets) {
-      node = (struct util_node **)(&hash->data.d->buckets[akey % hash->data.d->numBuckets]);
-      assert(*node == hash->data.e || (*node)->next);
-      while (*node != hash->data.e && (*node)->key != akey)
-         node = &(*node)->next;
-   } else {
-      node = (struct util_node **)((const struct util_node * const *)(&hash->data.e));
-   }
-   return node;
-}
-
-drm_private struct util_hash_iter
-util_hash_insert(struct util_hash *hash, unsigned key, void *data)
-{
-   util_data_might_grow(hash->data.d);
-
-   {
-      struct util_node **nextNode = util_hash_find_node(hash, key);
-      struct util_node *node = util_hash_create_node(hash, key, data, nextNode);
-      if (!node) {
-         struct util_hash_iter null_iter = {hash, 0};
-         return null_iter;
-      }
-
-      {
-         struct util_hash_iter iter = {hash, node};
-         return iter;
-      }
-   }
-}
-
-drm_private struct util_hash *util_hash_create(void)
-{
-   struct util_hash *hash = malloc(sizeof(struct util_hash));
-   if (!hash)
-      return NULL;
-
-   hash->data.d = malloc(sizeof(struct util_hash_data));
-   if (!hash->data.d) {
-      free(hash);
-      return NULL;
-   }
-
-   hash->data.d->fakeNext = 0;
-   hash->data.d->buckets = 0;
-   hash->data.d->size = 0;
-   hash->data.d->nodeSize = sizeof(struct util_node);
-   hash->data.d->userNumBits = (short)MinNumBits;
-   hash->data.d->numBits = 0;
-   hash->data.d->numBuckets = 0;
-
-   return hash;
-}
-
-drm_private void util_hash_delete(struct util_hash *hash)
-{
-   struct util_node *e_for_x = (struct util_node *)(hash->data.d);
-   struct util_node **bucket = (struct util_node **)(hash->data.d->buckets);
-   int n = hash->data.d->numBuckets;
-   while (n--) {
-      struct util_node *cur = *bucket++;
-      while (cur != e_for_x) {
-         struct util_node *next = cur->next;
-         util_free_node(cur);
-         cur = next;
-      }
-   }
-   free(hash->data.d->buckets);
-   free(hash->data.d);
-   free(hash);
-}
-
-drm_private struct util_hash_iter
-util_hash_find(struct util_hash *hash, unsigned key)
-{
-   struct util_node **nextNode = util_hash_find_node(hash, key);
-   struct util_hash_iter iter = {hash, *nextNode};
-   return iter;
-}
-
-drm_private unsigned util_hash_iter_key(struct util_hash_iter iter)
-{
-   if (!iter.node || iter.hash->data.e == iter.node)
-      return 0;
-   return iter.node->key;
-}
-
-drm_private void *util_hash_iter_data(struct util_hash_iter iter)
-{
-   if (!iter.node || iter.hash->data.e == iter.node)
-      return 0;
-   return iter.node->value;
-}
-
-static struct util_node *util_hash_data_next(struct util_node *node)
-{
-   union {
-      struct util_node *next;
-      struct util_node *e;
-      struct util_hash_data *d;
-   } a;
-   int start;
-   struct util_node **bucket;
-   int n;
-
-   a.next = node->next;
-   if (!a.next) {
-      /* iterating beyond the last element */
-      return 0;
-   }
-   if (a.next->next)
-      return a.next;
-
-   start = (node->key % a.d->numBuckets) + 1;
-   bucket = a.d->buckets + start;
-   n = a.d->numBuckets - start;
-   while (n--) {
-      if (*bucket != a.e)
-         return *bucket;
-      ++bucket;
-   }
-   return a.e;
-}
-
-drm_private struct util_hash_iter
-util_hash_iter_next(struct util_hash_iter iter)
-{
-   struct util_hash_iter next = {iter.hash, util_hash_data_next(iter.node)};
-   return next;
-}
-
-drm_private int util_hash_iter_is_null(struct util_hash_iter iter)
-{
-   if (!iter.node || iter.node == iter.hash->data.e)
-      return 1;
-   return 0;
-}
-
-drm_private void *util_hash_take(struct util_hash *hash, unsigned akey)
-{
-   struct util_node **node = util_hash_find_node(hash, akey);
-   if (*node != hash->data.e) {
-      void *t = (*node)->value;
-      struct util_node *next = (*node)->next;
-      util_free_node(*node);
-      *node = next;
-      --hash->data.d->size;
-      util_data_has_shrunk(hash->data.d);
-      return t;
-   }
-   return 0;
-}
-
-drm_private struct util_hash_iter util_hash_first_node(struct util_hash *hash)
-{
-   struct util_hash_iter iter = {hash, util_data_first_node(hash->data.d)};
-   return iter;
-}
-
-drm_private struct util_hash_iter
-util_hash_erase(struct util_hash *hash, struct util_hash_iter iter)
-{
-   struct util_hash_iter ret = iter;
-   struct util_node *node = iter.node;
-   struct util_node **node_ptr;
-
-   if (node == hash->data.e)
-      return iter;
-
-   ret = util_hash_iter_next(ret);
-   node_ptr = (struct util_node**)(&hash->data.d->buckets[node->key % hash->data.d->numBuckets]);
-   while (*node_ptr != node)
-      node_ptr = &(*node_ptr)->next;
-   *node_ptr = node->next;
-   util_free_node(node);
-   --hash->data.d->size;
-   return ret;
-}
diff --git a/amdgpu/util_hash.h b/amdgpu/util_hash.h
deleted file mode 100644
index 01a4779..0000000
--- a/amdgpu/util_hash.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-/**
- * @file
- * Hash implementation.
- * 
- * This file provides a hash implementation that is capable of dealing
- * with collisions. It stores colliding entries in linked list. All
- * functions operating on the hash return an iterator. The iterator
- * itself points to the collision list. If there wasn't any collision
- * the list will have just one entry, otherwise client code should
- * iterate over the entries to find the exact entry among ones that
- * had the same key (e.g. memcmp could be used on the data to check
- * that)
- * 
- * @author Zack Rusin <zackr at vmware.com>
- */
-
-#ifndef UTIL_HASH_H
-#define UTIL_HASH_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdbool.h>
-
-#include "libdrm_macros.h"
-
-struct util_hash;
-struct util_node;
-
-struct util_hash_iter {
-	struct util_hash *hash;
-	struct util_node *node;
-};
-
-
-drm_private struct util_hash *util_hash_create(void);
-drm_private void util_hash_delete(struct util_hash *hash);
-
-
-/**
- * Adds a data with the given key to the hash. If entry with the given
- * key is already in the hash, this current entry is instered before it
- * in the collision list.
- * Function returns iterator pointing to the inserted item in the hash.
- */
-drm_private struct util_hash_iter
-util_hash_insert(struct util_hash *hash, unsigned key, void *data);
-
-/**
- * Removes the item pointed to by the current iterator from the hash.
- * Note that the data itself is not erased and if it was a malloc'ed pointer
- * it will have to be freed after calling this function by the callee.
- * Function returns iterator pointing to the item after the removed one in
- * the hash.
- */
-drm_private struct util_hash_iter
-util_hash_erase(struct util_hash *hash, struct util_hash_iter iter);
-
-drm_private void *util_hash_take(struct util_hash *hash, unsigned key);
-
-
-drm_private struct util_hash_iter util_hash_first_node(struct util_hash *hash);
-
-/**
- * Return an iterator pointing to the first entry in the collision list.
- */
-drm_private struct util_hash_iter
-util_hash_find(struct util_hash *hash, unsigned key);
-
-
-drm_private int util_hash_iter_is_null(struct util_hash_iter iter);
-drm_private unsigned util_hash_iter_key(struct util_hash_iter iter);
-drm_private void *util_hash_iter_data(struct util_hash_iter iter);
-
-
-drm_private struct util_hash_iter
-util_hash_iter_next(struct util_hash_iter iter);
-
-#endif
diff --git a/amdgpu/util_hash_table.c b/amdgpu/util_hash_table.c
deleted file mode 100644
index fa7f6ea..0000000
--- a/amdgpu/util_hash_table.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2008 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-/**
- * @file
- * General purpose hash table implementation.
- * 
- * Just uses the util_hash for now, but it might be better switch to a linear
- * probing hash table implementation at some point -- as it is said they have 
- * better lookup and cache performance and it appears to be possible to write 
- * a lock-free implementation of such hash tables . 
- * 
- * @author José Fonseca <jfonseca at vmware.com>
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "util_hash_table.h"
-#include "util_hash.h"
-
-#include <stdlib.h>
-#include <assert.h>
-
-struct util_hash_table
-{
-	struct util_hash *head;
-
-	/** Hash function */
-	unsigned (*make_hash)(void *key);
-
-	/** Compare two keys */
-	int (*compare)(void *key1, void *key2);
-};
-
-struct util_hash_table_item
-{
-	void *key;
-	void *value;
-};
-
-
-static struct util_hash_table_item *
-util_hash_table_item(struct util_hash_iter iter)
-{
-	return (struct util_hash_table_item *)util_hash_iter_data(iter);
-}
-
-drm_private struct util_hash_table *
-util_hash_table_create(unsigned (*hash)(void *key),
-		       int (*compare)(void *key1, void *key2))
-{
-	struct util_hash_table *ht;
-
-	ht = malloc(sizeof(struct util_hash_table));
-	if(!ht)
-		return NULL;
-
-	ht->head = util_hash_create();
-	if(!ht->head) {
-		free(ht);
-		return NULL;
-	}
-
-	ht->make_hash = hash;
-	ht->compare = compare;
-
-	return ht;
-}
-
-static struct util_hash_iter
-util_hash_table_find_iter(struct util_hash_table *ht,
-			  void *key, unsigned key_hash)
-{
-	struct util_hash_iter iter;
-	struct util_hash_table_item *item;
-
-	iter = util_hash_find(ht->head, key_hash);
-	while (!util_hash_iter_is_null(iter)) {
-		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
-		if (!ht->compare(item->key, key))
-			break;
-		iter = util_hash_iter_next(iter);
-	}
-
-	return iter;
-}
-
-static struct util_hash_table_item *
-util_hash_table_find_item(struct util_hash_table *ht,
-                          void *key, unsigned key_hash)
-{
-	struct util_hash_iter iter;
-	struct util_hash_table_item *item;
-
-	iter = util_hash_find(ht->head, key_hash);
-	while (!util_hash_iter_is_null(iter)) {
-		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
-		if (!ht->compare(item->key, key))
-			return item;
-		iter = util_hash_iter_next(iter);
-	}
-
-	return NULL;
-}
-
-drm_private void
-util_hash_table_set(struct util_hash_table *ht, void *key, void *value)
-{
-	unsigned key_hash;
-	struct util_hash_table_item *item;
-	struct util_hash_iter iter;
-
-	assert(ht);
-	if (!ht)
-		return;
-
-	key_hash = ht->make_hash(key);
-
-	item = util_hash_table_find_item(ht, key, key_hash);
-	if(item) {
-		/* TODO: key/value destruction? */
-		item->value = value;
-		return;
-	}
-
-	item = malloc(sizeof(struct util_hash_table_item));
-	if(!item)
-		return;
-
-	item->key = key;
-	item->value = value;
-
-	iter = util_hash_insert(ht->head, key_hash, item);
-	if(util_hash_iter_is_null(iter)) {
-		free(item);
-		return;
-	}
-}
-
-drm_private void *util_hash_table_get(struct util_hash_table *ht, void *key)
-{
-	unsigned key_hash;
-	struct util_hash_table_item *item;
-
-	assert(ht);
-	if (!ht)
-		return NULL;
-
-	key_hash = ht->make_hash(key);
-
-	item = util_hash_table_find_item(ht, key, key_hash);
-	if(!item)
-		return NULL;
-
-	return item->value;
-}
-
-drm_private void util_hash_table_remove(struct util_hash_table *ht, void *key)
-{
-	unsigned key_hash;
-	struct util_hash_iter iter;
-	struct util_hash_table_item *item;
-
-	assert(ht);
-	if (!ht)
-		return;
-
-	key_hash = ht->make_hash(key);
-
-	iter = util_hash_table_find_iter(ht, key, key_hash);
-	if(util_hash_iter_is_null(iter))
-		return;
-
-	item = util_hash_table_item(iter);
-	assert(item);
-	free(item);
-
-	util_hash_erase(ht->head, iter);
-}
-
-drm_private void util_hash_table_clear(struct util_hash_table *ht)
-{
-	struct util_hash_iter iter;
-	struct util_hash_table_item *item;
-
-	assert(ht);
-	if (!ht)
-		return;
-
-	iter = util_hash_first_node(ht->head);
-	while (!util_hash_iter_is_null(iter)) {
-		item = (struct util_hash_table_item *)util_hash_take(ht->head, util_hash_iter_key(iter));
-		free(item);
-		iter = util_hash_first_node(ht->head);
-	}
-}
-
-drm_private void util_hash_table_foreach(struct util_hash_table *ht,
-			void (*callback)(void *key, void *value, void *data),
-			void *data)
-{
-	struct util_hash_iter iter;
-	struct util_hash_table_item *item;
-
-	assert(ht);
-	if (!ht)
-		return;
-
-	iter = util_hash_first_node(ht->head);
-	while (!util_hash_iter_is_null(iter)) {
-		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
-		callback(item->key, item->value, data);
-		iter = util_hash_iter_next(iter);
-	}
-}
-
-drm_private void util_hash_table_destroy(struct util_hash_table *ht)
-{
-	struct util_hash_iter iter;
-	struct util_hash_table_item *item;
-
-	assert(ht);
-	if (!ht)
-		return;
-
-	iter = util_hash_first_node(ht->head);
-	while (!util_hash_iter_is_null(iter)) {
-		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
-		free(item);
-		iter = util_hash_iter_next(iter);
-	}
-
-	util_hash_delete(ht->head);
-	free(ht);
-}
diff --git a/amdgpu/util_hash_table.h b/amdgpu/util_hash_table.h
deleted file mode 100644
index e000128..0000000
--- a/amdgpu/util_hash_table.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2008 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-/**
- * General purpose hash table.
- *  
- * @author José Fonseca <jfonseca at vmware.com>
- */
-
-#ifndef U_HASH_TABLE_H_
-#define U_HASH_TABLE_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "libdrm_macros.h"
-
-/**
- * Generic purpose hash table.
- */
-struct util_hash_table;
-
-/**
- * Create an hash table.
- * 
- * @param hash hash function
- * @param compare should return 0 for two equal keys.
- */
-drm_private struct util_hash_table *
-util_hash_table_create(unsigned (*hash)(void *key),
-		       int (*compare)(void *key1, void *key2));
-
-drm_private void
-util_hash_table_set(struct util_hash_table *ht, void *key, void *value);
-
-drm_private void *util_hash_table_get(struct util_hash_table *ht, void *key);
-
-drm_private void util_hash_table_remove(struct util_hash_table *ht, void *key);
-
-drm_private void util_hash_table_clear(struct util_hash_table *ht);
-
-drm_private void util_hash_table_foreach(struct util_hash_table *ht,
-			void (*callback)(void *key, void *value, void *data),
-			void *data);
-
-drm_private void util_hash_table_destroy(struct util_hash_table *ht);
-
-#endif /* U_HASH_TABLE_H_ */
diff --git a/util/util_asic_id.c b/util/util_asic_id.c
new file mode 100644
index 0000000..e0e04e9
--- /dev/null
+++ b/util/util_asic_id.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright © 2017 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "xf86drm.h"
+#include "util_asic_id.h"
+
+static int parse_one_line(const char *line, struct util_asic_id *id)
+{
+	char *buf, *saveptr;
+	char *s_did;
+	char *s_rid;
+	char *s_name;
+	char *endptr;
+	int r = 0;
+
+	buf = strdup(line);
+	if (!buf)
+		return -ENOMEM;
+
+	/* ignore empty line and commented line */
+	if (strlen(line) == 0 || line[0] == '#') {
+		r = -EAGAIN;
+		goto out;
+	}
+
+	/* device id */
+	s_did = strtok_r(buf, ",", &saveptr);
+	if (!s_did) {
+		r = -EINVAL;
+		goto out;
+	}
+
+	id->did = strtol(s_did, &endptr, 16);
+	if (*endptr) {
+		r = -EINVAL;
+		goto out;
+	}
+
+	/* revision id */
+	s_rid = strtok_r(NULL, ",", &saveptr);
+	if (!s_rid) {
+		r = -EINVAL;
+		goto out;
+	}
+
+	id->rid = strtol(s_rid, &endptr, 16);
+	if (*endptr) {
+		r = -EINVAL;
+		goto out;
+	}
+
+	/* marketing name */
+	s_name = strtok_r(NULL, ",", &saveptr);
+	if (!s_name) {
+		r = -EINVAL;
+		goto out;
+	}
+	/* trim leading whitespaces or tabs */
+	while (isblank(*s_name))
+		s_name++;
+	if (strlen(s_name) == 0) {
+		r = -EINVAL;
+		goto out;
+	}
+
+	id->marketing_name = strdup(s_name);
+	if (id->marketing_name == NULL) {
+		r = -EINVAL;
+		goto out;
+	}
+
+out:
+	free(buf);
+
+	return r;
+}
+
+int util_parse_asic_ids(struct util_asic_id **p_asic_id_table, const char *filename, size_t table_max_size)
+{
+	struct util_asic_id *asic_id_table;
+	struct util_asic_id *id;
+	FILE *fp;
+	char *line = NULL;
+	size_t len = 0;
+	ssize_t n;
+	int line_num = 1;
+	size_t table_size = 0;
+	int r = 0;
+
+	fp = fopen(filename, "r");
+	if (!fp) {
+		fprintf(stderr, "%s: %s\n", filename,
+			strerror(errno));
+		return -EINVAL;
+	}
+
+	asic_id_table = calloc(table_max_size + 1,
+			       sizeof(struct util_asic_id));
+	if (!asic_id_table) {
+		r = -ENOMEM;
+		goto close;
+	}
+
+	/* 1st valid line is file version */
+	while ((n = getline(&line, &len, fp)) != -1) {
+		/* trim trailing newline */
+		if (line[n - 1] == '\n')
+			line[n - 1] = '\0';
+
+		/* ignore empty line and commented line */
+		if (strlen(line) == 0 || line[0] == '#') {
+			line_num++;
+			continue;
+		}
+
+		drmMsg("%s version: %s\n", filename, line);
+		break;
+	}
+
+	while ((n = getline(&line, &len, fp)) != -1) {
+		if (table_size > table_max_size) {
+			/* double table size */
+			table_max_size *= 2;
+			id = realloc(asic_id_table, (table_max_size + 1) *
+				     sizeof(struct util_asic_id));
+			if (!id) {
+				r = -ENOMEM;
+				goto free;
+			}
+                        asic_id_table = id;
+		}
+
+		id = asic_id_table + table_size;
+
+		/* trim trailing newline */
+		if (line[n - 1] == '\n')
+			line[n - 1] = '\0';
+
+		r = parse_one_line(line, id);
+		if (r) {
+			if (r == -EAGAIN) {
+				line_num++;
+				continue;
+			}
+			fprintf(stderr, "Invalid format: %s: line %d: %s\n",
+				filename, line_num, line);
+			goto free;
+		}
+
+		line_num++;
+		table_size++;
+	}
+
+	/* end of table */
+	id = asic_id_table + table_size;
+	memset(id, 0, sizeof(struct util_asic_id));
+
+	if (table_size != table_max_size) {
+		id = realloc(asic_id_table, (table_size + 1) *
+			     sizeof(struct util_asic_id));
+		if (!id)
+			r = -ENOMEM;
+		else
+			asic_id_table = id;
+        }
+
+free:
+	free(line);
+
+	if (r && asic_id_table) {
+		while (table_size--) {
+			id = asic_id_table + table_size;
+			free(id->marketing_name);
+		}
+		free(asic_id_table);
+		asic_id_table = NULL;
+	}
+close:
+	fclose(fp);
+
+	*p_asic_id_table = asic_id_table;
+
+	return r;
+}
diff --git a/util/util_asic_id.h b/util/util_asic_id.h
new file mode 100644
index 0000000..949bcda
--- /dev/null
+++ b/util/util_asic_id.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2017 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _UTIL_ASIC_H_
+#define _UTIL_ASIC_H_
+
+#include "libdrm_macros.h"
+
+struct util_asic_id {
+	uint32_t did;
+	uint32_t rid;
+	char *marketing_name;
+};
+
+int util_parse_asic_ids(struct util_asic_id **p_asic_id_table, const char *filename, size_t table_max_size);
+
+
+#endif
diff --git a/util/util_hash.c b/util/util_hash.c
new file mode 100644
index 0000000..9b5c74c
--- /dev/null
+++ b/util/util_hash.c
@@ -0,0 +1,387 @@
+/**************************************************************************
+ *
+ * Copyright 2007 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+ /*
+  * Authors:
+  *   Zack Rusin <zackr at vmware.com>
+  */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "util_hash.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define MAX(a, b) ((a > b) ? (a) : (b))
+
+static const int MinNumBits = 4;
+
+static const unsigned char prime_deltas[] = {
+	0,  0,  1,  3,  1,  5,  3,  3,  1,  9,  7,  5,  3,  9, 25,  3,
+	1, 21,  3, 21,  7, 15,  9,  5,  3, 29, 15,  0,  0,  0,  0,  0
+};
+
+static int primeForNumBits(int numBits)
+{
+	return (1 << numBits) + prime_deltas[numBits];
+}
+
+/* Returns the smallest integer n such that
+   primeForNumBits(n) >= hint.
+*/
+static int countBits(int hint)
+{
+	int numBits = 0;
+	int bits = hint;
+
+	while (bits > 1) {
+		bits >>= 1;
+		numBits++;
+	}
+
+	if (numBits >= (int)sizeof(prime_deltas)) {
+		numBits = sizeof(prime_deltas) - 1;
+	} else if (primeForNumBits(numBits) < hint) {
+		++numBits;
+	}
+	return numBits;
+}
+
+struct util_node {
+   struct util_node *next;
+   unsigned key;
+   void *value;
+};
+
+struct util_hash_data {
+   struct util_node *fakeNext;
+   struct util_node **buckets;
+   int size;
+   int nodeSize;
+   short userNumBits;
+   short numBits;
+   int numBuckets;
+};
+
+struct util_hash {
+   union {
+      struct util_hash_data *d;
+      struct util_node      *e;
+   } data;
+};
+
+static void *util_data_allocate_node(struct util_hash_data *hash)
+{
+   return malloc(hash->nodeSize);
+}
+
+static void util_free_node(struct util_node *node)
+{
+   free(node);
+}
+
+static struct util_node *
+util_hash_create_node(struct util_hash *hash,
+                      unsigned akey, void *avalue,
+                      struct util_node **anextNode)
+{
+   struct util_node *node = util_data_allocate_node(hash->data.d);
+
+   if (!node)
+      return NULL;
+
+   node->key = akey;
+   node->value = avalue;
+
+   node->next = (struct util_node*)(*anextNode);
+   *anextNode = node;
+   ++hash->data.d->size;
+   return node;
+}
+
+static void util_data_rehash(struct util_hash_data *hash, int hint)
+{
+   if (hint < 0) {
+      hint = countBits(-hint);
+      if (hint < MinNumBits)
+         hint = MinNumBits;
+      hash->userNumBits = (short)hint;
+      while (primeForNumBits(hint) < (hash->size >> 1))
+         ++hint;
+   } else if (hint < MinNumBits) {
+      hint = MinNumBits;
+   }
+
+   if (hash->numBits != hint) {
+      struct util_node *e = (struct util_node *)(hash);
+      struct util_node **oldBuckets = hash->buckets;
+      int oldNumBuckets = hash->numBuckets;
+      int  i = 0;
+
+      hash->numBits = (short)hint;
+      hash->numBuckets = primeForNumBits(hint);
+      hash->buckets = malloc(sizeof(struct util_node*) * hash->numBuckets);
+      for (i = 0; i < hash->numBuckets; ++i)
+         hash->buckets[i] = e;
+
+      for (i = 0; i < oldNumBuckets; ++i) {
+         struct util_node *firstNode = oldBuckets[i];
+         while (firstNode != e) {
+            unsigned h = firstNode->key;
+            struct util_node *lastNode = firstNode;
+            struct util_node *afterLastNode;
+            struct util_node **beforeFirstNode;
+
+            while (lastNode->next != e && lastNode->next->key == h)
+               lastNode = lastNode->next;
+
+            afterLastNode = lastNode->next;
+            beforeFirstNode = &hash->buckets[h % hash->numBuckets];
+            while (*beforeFirstNode != e)
+               beforeFirstNode = &(*beforeFirstNode)->next;
+            lastNode->next = *beforeFirstNode;
+            *beforeFirstNode = firstNode;
+            firstNode = afterLastNode;
+         }
+      }
+      free(oldBuckets);
+   }
+}
+
+static void util_data_might_grow(struct util_hash_data *hash)
+{
+   if (hash->size >= hash->numBuckets)
+      util_data_rehash(hash, hash->numBits + 1);
+}
+
+static void util_data_has_shrunk(struct util_hash_data *hash)
+{
+   if (hash->size <= (hash->numBuckets >> 3) &&
+       hash->numBits > hash->userNumBits) {
+      int max = MAX(hash->numBits-2, hash->userNumBits);
+      util_data_rehash(hash,  max);
+   }
+}
+
+static struct util_node *util_data_first_node(struct util_hash_data *hash)
+{
+   struct util_node *e = (struct util_node *)(hash);
+   struct util_node **bucket = hash->buckets;
+   int n = hash->numBuckets;
+   while (n--) {
+      if (*bucket != e)
+         return *bucket;
+      ++bucket;
+   }
+   return e;
+}
+
+static struct util_node **util_hash_find_node(struct util_hash *hash, unsigned akey)
+{
+   struct util_node **node;
+
+   if (hash->data.d->numBuckets) {
+      node = (struct util_node **)(&hash->data.d->buckets[akey % hash->data.d->numBuckets]);
+      assert(*node == hash->data.e || (*node)->next);
+      while (*node != hash->data.e && (*node)->key != akey)
+         node = &(*node)->next;
+   } else {
+      node = (struct util_node **)((const struct util_node * const *)(&hash->data.e));
+   }
+   return node;
+}
+
+drm_private struct util_hash_iter
+util_hash_insert(struct util_hash *hash, unsigned key, void *data)
+{
+   util_data_might_grow(hash->data.d);
+
+   {
+      struct util_node **nextNode = util_hash_find_node(hash, key);
+      struct util_node *node = util_hash_create_node(hash, key, data, nextNode);
+      if (!node) {
+         struct util_hash_iter null_iter = {hash, 0};
+         return null_iter;
+      }
+
+      {
+         struct util_hash_iter iter = {hash, node};
+         return iter;
+      }
+   }
+}
+
+drm_private struct util_hash *util_hash_create(void)
+{
+   struct util_hash *hash = malloc(sizeof(struct util_hash));
+   if (!hash)
+      return NULL;
+
+   hash->data.d = malloc(sizeof(struct util_hash_data));
+   if (!hash->data.d) {
+      free(hash);
+      return NULL;
+   }
+
+   hash->data.d->fakeNext = 0;
+   hash->data.d->buckets = 0;
+   hash->data.d->size = 0;
+   hash->data.d->nodeSize = sizeof(struct util_node);
+   hash->data.d->userNumBits = (short)MinNumBits;
+   hash->data.d->numBits = 0;
+   hash->data.d->numBuckets = 0;
+
+   return hash;
+}
+
+drm_private void util_hash_delete(struct util_hash *hash)
+{
+   struct util_node *e_for_x = (struct util_node *)(hash->data.d);
+   struct util_node **bucket = (struct util_node **)(hash->data.d->buckets);
+   int n = hash->data.d->numBuckets;
+   while (n--) {
+      struct util_node *cur = *bucket++;
+      while (cur != e_for_x) {
+         struct util_node *next = cur->next;
+         util_free_node(cur);
+         cur = next;
+      }
+   }
+   free(hash->data.d->buckets);
+   free(hash->data.d);
+   free(hash);
+}
+
+drm_private struct util_hash_iter
+util_hash_find(struct util_hash *hash, unsigned key)
+{
+   struct util_node **nextNode = util_hash_find_node(hash, key);
+   struct util_hash_iter iter = {hash, *nextNode};
+   return iter;
+}
+
+drm_private unsigned util_hash_iter_key(struct util_hash_iter iter)
+{
+   if (!iter.node || iter.hash->data.e == iter.node)
+      return 0;
+   return iter.node->key;
+}
+
+drm_private void *util_hash_iter_data(struct util_hash_iter iter)
+{
+   if (!iter.node || iter.hash->data.e == iter.node)
+      return 0;
+   return iter.node->value;
+}
+
+static struct util_node *util_hash_data_next(struct util_node *node)
+{
+   union {
+      struct util_node *next;
+      struct util_node *e;
+      struct util_hash_data *d;
+   } a;
+   int start;
+   struct util_node **bucket;
+   int n;
+
+   a.next = node->next;
+   if (!a.next) {
+      /* iterating beyond the last element */
+      return 0;
+   }
+   if (a.next->next)
+      return a.next;
+
+   start = (node->key % a.d->numBuckets) + 1;
+   bucket = a.d->buckets + start;
+   n = a.d->numBuckets - start;
+   while (n--) {
+      if (*bucket != a.e)
+         return *bucket;
+      ++bucket;
+   }
+   return a.e;
+}
+
+drm_private struct util_hash_iter
+util_hash_iter_next(struct util_hash_iter iter)
+{
+   struct util_hash_iter next = {iter.hash, util_hash_data_next(iter.node)};
+   return next;
+}
+
+drm_private int util_hash_iter_is_null(struct util_hash_iter iter)
+{
+   if (!iter.node || iter.node == iter.hash->data.e)
+      return 1;
+   return 0;
+}
+
+drm_private void *util_hash_take(struct util_hash *hash, unsigned akey)
+{
+   struct util_node **node = util_hash_find_node(hash, akey);
+   if (*node != hash->data.e) {
+      void *t = (*node)->value;
+      struct util_node *next = (*node)->next;
+      util_free_node(*node);
+      *node = next;
+      --hash->data.d->size;
+      util_data_has_shrunk(hash->data.d);
+      return t;
+   }
+   return 0;
+}
+
+drm_private struct util_hash_iter util_hash_first_node(struct util_hash *hash)
+{
+   struct util_hash_iter iter = {hash, util_data_first_node(hash->data.d)};
+   return iter;
+}
+
+drm_private struct util_hash_iter
+util_hash_erase(struct util_hash *hash, struct util_hash_iter iter)
+{
+   struct util_hash_iter ret = iter;
+   struct util_node *node = iter.node;
+   struct util_node **node_ptr;
+
+   if (node == hash->data.e)
+      return iter;
+
+   ret = util_hash_iter_next(ret);
+   node_ptr = (struct util_node**)(&hash->data.d->buckets[node->key % hash->data.d->numBuckets]);
+   while (*node_ptr != node)
+      node_ptr = &(*node_ptr)->next;
+   *node_ptr = node->next;
+   util_free_node(node);
+   --hash->data.d->size;
+   return ret;
+}
diff --git a/util/util_hash.h b/util/util_hash.h
new file mode 100644
index 0000000..6c30be4
--- /dev/null
+++ b/util/util_hash.h
@@ -0,0 +1,107 @@
+/**************************************************************************
+ *
+ * Copyright 2007 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * Hash implementation.
+ *
+ * This file provides a hash implementation that is capable of dealing
+ * with collisions. It stores colliding entries in linked list. All
+ * functions operating on the hash return an iterator. The iterator
+ * itself points to the collision list. If there wasn't any collision
+ * the list will have just one entry, otherwise client code should
+ * iterate over the entries to find the exact entry among ones that
+ * had the same key (e.g. memcmp could be used on the data to check
+ * that)
+ *
+ * @author Zack Rusin <zackr at vmware.com>
+ */
+
+#ifndef UTIL_HASH_H
+#define UTIL_HASH_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdbool.h>
+
+#include "libdrm_macros.h"
+
+struct util_hash;
+struct util_node;
+
+struct util_hash_iter {
+	struct util_hash *hash;
+	struct util_node *node;
+};
+
+
+drm_private struct util_hash *util_hash_create(void);
+drm_private void util_hash_delete(struct util_hash *hash);
+
+
+/**
+ * Adds a data with the given key to the hash. If entry with the given
+ * key is already in the hash, this current entry is instered before it
+ * in the collision list.
+ * Function returns iterator pointing to the inserted item in the hash.
+ */
+drm_private struct util_hash_iter
+util_hash_insert(struct util_hash *hash, unsigned key, void *data);
+
+/**
+ * Removes the item pointed to by the current iterator from the hash.
+ * Note that the data itself is not erased and if it was a malloc'ed pointer
+ * it will have to be freed after calling this function by the callee.
+ * Function returns iterator pointing to the item after the removed one in
+ * the hash.
+ */
+drm_private struct util_hash_iter
+util_hash_erase(struct util_hash *hash, struct util_hash_iter iter);
+
+drm_private void *util_hash_take(struct util_hash *hash, unsigned key);
+
+
+drm_private struct util_hash_iter util_hash_first_node(struct util_hash *hash);
+
+/**
+ * Return an iterator pointing to the first entry in the collision list.
+ */
+drm_private struct util_hash_iter
+util_hash_find(struct util_hash *hash, unsigned key);
+
+
+drm_private int util_hash_iter_is_null(struct util_hash_iter iter);
+drm_private unsigned util_hash_iter_key(struct util_hash_iter iter);
+drm_private void *util_hash_iter_data(struct util_hash_iter iter);
+
+
+drm_private struct util_hash_iter
+util_hash_iter_next(struct util_hash_iter iter);
+
+#endif
diff --git a/util/util_hash_table.c b/util/util_hash_table.c
new file mode 100644
index 0000000..87e7f91
--- /dev/null
+++ b/util/util_hash_table.c
@@ -0,0 +1,262 @@
+/**************************************************************************
+ *
+ * Copyright 2008 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * General purpose hash table implementation.
+ *
+ * Just uses the util_hash for now, but it might be better switch to a linear
+ * probing hash table implementation at some point -- as it is said they have
+ * better lookup and cache performance and it appears to be possible to write
+ * a lock-free implementation of such hash tables .
+ *
+ * @author José Fonseca <jfonseca at vmware.com>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "util_hash_table.h"
+#include "util_hash.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+struct util_hash_table
+{
+	struct util_hash *head;
+
+	/** Hash function */
+	unsigned (*make_hash)(void *key);
+
+	/** Compare two keys */
+	int (*compare)(void *key1, void *key2);
+};
+
+struct util_hash_table_item
+{
+	void *key;
+	void *value;
+};
+
+
+static struct util_hash_table_item *
+util_hash_table_item(struct util_hash_iter iter)
+{
+	return (struct util_hash_table_item *)util_hash_iter_data(iter);
+}
+
+struct util_hash_table *
+util_hash_table_create(unsigned (*hash)(void *key),
+		       int (*compare)(void *key1, void *key2))
+{
+	struct util_hash_table *ht;
+
+	ht = malloc(sizeof(struct util_hash_table));
+	if(!ht)
+		return NULL;
+
+	ht->head = util_hash_create();
+	if(!ht->head) {
+		free(ht);
+		return NULL;
+	}
+
+	ht->make_hash = hash;
+	ht->compare = compare;
+
+	return ht;
+}
+
+static struct util_hash_iter
+util_hash_table_find_iter(struct util_hash_table *ht,
+			  void *key, unsigned key_hash)
+{
+	struct util_hash_iter iter;
+	struct util_hash_table_item *item;
+
+	iter = util_hash_find(ht->head, key_hash);
+	while (!util_hash_iter_is_null(iter)) {
+		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
+		if (!ht->compare(item->key, key))
+			break;
+		iter = util_hash_iter_next(iter);
+	}
+
+	return iter;
+}
+
+static struct util_hash_table_item *
+util_hash_table_find_item(struct util_hash_table *ht,
+                          void *key, unsigned key_hash)
+{
+	struct util_hash_iter iter;
+	struct util_hash_table_item *item;
+
+	iter = util_hash_find(ht->head, key_hash);
+	while (!util_hash_iter_is_null(iter)) {
+		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
+		if (!ht->compare(item->key, key))
+			return item;
+		iter = util_hash_iter_next(iter);
+	}
+
+	return NULL;
+}
+
+void
+util_hash_table_set(struct util_hash_table *ht, void *key, void *value)
+{
+	unsigned key_hash;
+	struct util_hash_table_item *item;
+	struct util_hash_iter iter;
+
+	assert(ht);
+	if (!ht)
+		return;
+
+	key_hash = ht->make_hash(key);
+
+	item = util_hash_table_find_item(ht, key, key_hash);
+	if(item) {
+		/* TODO: key/value destruction? */
+		item->value = value;
+		return;
+	}
+
+	item = malloc(sizeof(struct util_hash_table_item));
+	if(!item)
+		return;
+
+	item->key = key;
+	item->value = value;
+
+	iter = util_hash_insert(ht->head, key_hash, item);
+	if(util_hash_iter_is_null(iter)) {
+		free(item);
+		return;
+	}
+}
+
+void *util_hash_table_get(struct util_hash_table *ht, void *key)
+{
+	unsigned key_hash;
+	struct util_hash_table_item *item;
+
+	assert(ht);
+	if (!ht)
+		return NULL;
+
+	key_hash = ht->make_hash(key);
+
+	item = util_hash_table_find_item(ht, key, key_hash);
+	if(!item)
+		return NULL;
+
+	return item->value;
+}
+
+void util_hash_table_remove(struct util_hash_table *ht, void *key)
+{
+	unsigned key_hash;
+	struct util_hash_iter iter;
+	struct util_hash_table_item *item;
+
+	assert(ht);
+	if (!ht)
+		return;
+
+	key_hash = ht->make_hash(key);
+
+	iter = util_hash_table_find_iter(ht, key, key_hash);
+	if(util_hash_iter_is_null(iter))
+		return;
+
+	item = util_hash_table_item(iter);
+	assert(item);
+	free(item);
+
+	util_hash_erase(ht->head, iter);
+}
+
+void util_hash_table_clear(struct util_hash_table *ht)
+{
+	struct util_hash_iter iter;
+	struct util_hash_table_item *item;
+
+	assert(ht);
+	if (!ht)
+		return;
+
+	iter = util_hash_first_node(ht->head);
+	while (!util_hash_iter_is_null(iter)) {
+		item = (struct util_hash_table_item *)util_hash_take(ht->head, util_hash_iter_key(iter));
+		free(item);
+		iter = util_hash_first_node(ht->head);
+	}
+}
+
+void util_hash_table_foreach(struct util_hash_table *ht,
+			void (*callback)(void *key, void *value, void *data),
+			void *data)
+{
+	struct util_hash_iter iter;
+	struct util_hash_table_item *item;
+
+	assert(ht);
+	if (!ht)
+		return;
+
+	iter = util_hash_first_node(ht->head);
+	while (!util_hash_iter_is_null(iter)) {
+		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
+		callback(item->key, item->value, data);
+		iter = util_hash_iter_next(iter);
+	}
+}
+
+void util_hash_table_destroy(struct util_hash_table *ht)
+{
+	struct util_hash_iter iter;
+	struct util_hash_table_item *item;
+
+	assert(ht);
+	if (!ht)
+		return;
+
+	iter = util_hash_first_node(ht->head);
+	while (!util_hash_iter_is_null(iter)) {
+		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
+		free(item);
+		iter = util_hash_iter_next(iter);
+	}
+
+	util_hash_delete(ht->head);
+	free(ht);
+}
diff --git a/util/util_hash_table.h b/util/util_hash_table.h
new file mode 100644
index 0000000..984f2a4
--- /dev/null
+++ b/util/util_hash_table.h
@@ -0,0 +1,73 @@
+/**************************************************************************
+ *
+ * Copyright 2008 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * General purpose hash table.
+ *
+ * @author José Fonseca <jfonseca at vmware.com>
+ */
+
+#ifndef U_HASH_TABLE_H_
+#define U_HASH_TABLE_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "libdrm_macros.h"
+
+/**
+ * Generic purpose hash table.
+ */
+struct util_hash_table;
+
+/**
+ * Create an hash table.
+ *
+ * @param hash hash function
+ * @param compare should return 0 for two equal keys.
+ */
+struct util_hash_table *
+util_hash_table_create(unsigned (*hash)(void *key),
+		       int (*compare)(void *key1, void *key2));
+
+void
+util_hash_table_set(struct util_hash_table *ht, void *key, void *value);
+
+void *util_hash_table_get(struct util_hash_table *ht, void *key);
+
+void util_hash_table_remove(struct util_hash_table *ht, void *key);
+
+void util_hash_table_clear(struct util_hash_table *ht);
+
+void util_hash_table_foreach(struct util_hash_table *ht,
+			void (*callback)(void *key, void *value, void *data),
+			void *data);
+
+void util_hash_table_destroy(struct util_hash_table *ht);
+
+#endif /* U_HASH_TABLE_H_ */
-- 
2.7.4



More information about the dri-devel mailing list