Hi, All.

I'd like to bring in the hashed map lookup from the drm-ttm-branch to CVS. It changes the drmmap() map lookup from a linked list search to a hash lookup.

This means that the user_token that identifies the map in user space becomes an arbitrary hash key in the range 0x10000000 to 0x90000000 with page-size increments.

Some 2D and 3D drivers (at least the SiS 3D driver) may still assume that the user_token is equivalent to the physical address of the area to be mapped. Something that will fail in a 64-bit environment, and that will fail catastrophically with the hashed lookup. The current DRM contains a workaround that maps 64-bit addresses to a certain 32-bit region to make those drivers work in 32bit mode, but sooner or later that workaround should go away, and the drivers be properly updated.

While this makes little performance impact now, when we add the TTM stuff, the number of maps may be very large so a hashed lookup is needed.

If anybody is very eager to keep the workaround, please speak up. For those drivers needing a fix, the DRM major needs to be bumped.

/Thomas


? hashed_maps.diff
Index: linux-core/drmP.h
===================================================================
RCS file: /cvs/dri/drm/linux-core/drmP.h,v
retrieving revision 1.177
diff -u -r1.177 drmP.h
--- linux-core/drmP.h	6 Jun 2006 17:46:17 -0000	1.177
+++ linux-core/drmP.h	5 Jul 2006 17:46:06 -0000
@@ -153,6 +153,7 @@
 #define DRM_MEM_HASHTAB   23
 
 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
+#define DRM_MAP_HASH_OFFSET 0x10000000
 
 /[EMAIL PROTECTED]/
 
@@ -502,6 +503,7 @@
  */
 typedef struct drm_map_list {
 	struct list_head head;		/**< list head */
+        drm_hash_item_t hash;
 	drm_map_t *map;			/**< mapping */
 	unsigned int user_token;
 } drm_map_list_t;
@@ -679,6 +681,7 @@
 	/[EMAIL PROTECTED] */
 	drm_map_list_t *maplist;	/**< Linked list of regions */
 	int map_count;			/**< Number of mappable regions */
+        drm_open_hash_t map_hash;       /**< User token hash table for maps */
 
 	/** \name Context handle management */
 	/[EMAIL PROTECTED] */
Index: linux-core/drm_bufs.c
===================================================================
RCS file: /cvs/dri/drm/linux-core/drm_bufs.c,v
retrieving revision 1.79
diff -u -r1.79 drm_bufs.c
--- linux-core/drm_bufs.c	5 Jul 2006 14:39:22 -0000	1.79
+++ linux-core/drm_bufs.c	5 Jul 2006 17:46:06 -0000
@@ -65,44 +65,6 @@
 	return NULL;
 }
 
-/*
- * Used to allocate 32-bit handles for mappings.
- */
-#define START_RANGE 0x10000000
-#define END_RANGE 0x40000000
-
-#ifdef _LP64
-static __inline__ unsigned int HandleID(unsigned long lhandle,
-					drm_device_t *dev) 
-{
-	static unsigned int map32_handle = START_RANGE;
-	unsigned int hash;
-
-	if (lhandle & 0xffffffff00000000) {
-		hash = map32_handle;
-		map32_handle += PAGE_SIZE;
-		if (map32_handle > END_RANGE)
-			map32_handle = START_RANGE;
-	} else
-		hash = lhandle;
-
-	while (1) {
-		drm_map_list_t *_entry;
-		list_for_each_entry(_entry, &dev->maplist->head, head) {
-			if (_entry->user_token == hash)
-				break;
-		}
-		if (&_entry->head == &dev->maplist->head)
-			return hash;
-
-		hash += PAGE_SIZE;
-		map32_handle += PAGE_SIZE;
-	}
-}
-#else
-# define HandleID(x,dev) (unsigned int)(x)
-#endif
-
 /**
  * Ioctl to specify a range of memory that is available for mapping by a non-root process.
  *
@@ -300,9 +262,18 @@
 	list_add(&list->head, &dev->maplist->head);
 	/* Assign a 32-bit handle */
 	/* We do it here so that dev->struct_sem protects the increment */
-	list->user_token = HandleID(map->type == _DRM_SHM
-				    ? (unsigned long)map->handle
-				    : map->offset, dev);
+
+        if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, 
+				      ((map->type == _DRM_SHM) ? (unsigned long)map->handle : 
+                                       map->offset) >> PAGE_SHIFT,
+				      32 - PAGE_SHIFT - 1)) {
+                drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                drm_free(list, sizeof(*list), DRM_MEM_MAPS);
+                up(&dev->struct_sem);
+                return -ENOMEM;
+	}
+
+	list->user_token = (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET;
 	up(&dev->struct_sem);
 
 	*maplist = list;
@@ -387,6 +358,8 @@
 
 		if (r_list->map == map) {
 			list_del(list);
+                        drm_ht_remove_key(&dev->map_hash, 
+                                          (r_list->user_token - DRM_MAP_HASH_OFFSET) >> PAGE_SHIFT);
 			drm_free(list, sizeof(*list), DRM_MEM_MAPS);
 			break;
 		}
Index: linux-core/drm_hashtab.h
===================================================================
RCS file: /cvs/dri/drm/linux-core/drm_hashtab.h,v
retrieving revision 1.3
diff -u -r1.3 drm_hashtab.h
--- linux-core/drm_hashtab.h	6 Jun 2006 17:52:03 -0000	1.3
+++ linux-core/drm_hashtab.h	5 Jul 2006 17:46:06 -0000
@@ -35,7 +35,7 @@
 #ifndef DRM_HASHTAB_H
 #define DRM_HASHTAB_H
 
-#define drm_hash_entry(_a1, _a2, _a3) list_entry(_a1, _a2, _a3)
+#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
 
 typedef struct drm_hash_item{
         struct hlist_node head;
Index: linux-core/drm_stub.c
===================================================================
RCS file: /cvs/dri/drm/linux-core/drm_stub.c,v
retrieving revision 1.64
diff -u -r1.64 drm_stub.c
--- linux-core/drm_stub.c	18 Feb 2006 04:18:45 -0000	1.64
+++ linux-core/drm_stub.c	5 Jul 2006 17:46:06 -0000
@@ -82,6 +82,10 @@
 	if (dev->maplist == NULL)
 		return -ENOMEM;
 	INIT_LIST_HEAD(&dev->maplist->head);
+        if (drm_ht_create(&dev->map_hash, 12)) {
+                drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+                return -ENOMEM;
+        }
 
 	/* the DRM has 6 counters */
 	dev->counters = 6;
Index: linux-core/drm_vm.c
===================================================================
RCS file: /cvs/dri/drm/linux-core/drm_vm.c,v
retrieving revision 1.57
diff -u -r1.57 drm_vm.c
--- linux-core/drm_vm.c	18 Feb 2006 02:53:36 -0000	1.57
+++ linux-core/drm_vm.c	5 Jul 2006 17:46:06 -0000
@@ -59,7 +59,7 @@
 	drm_device_t *dev = priv->head->dev;
 	drm_map_t *map = NULL;
 	drm_map_list_t *r_list;
-	struct list_head *list;
+        drm_hash_item_t *hash;
 
 	/*
 	 * Find the right map
@@ -70,14 +70,12 @@
 	if (!dev->agp || !dev->agp->cant_use_aperture)
 		goto vm_nopage_error;
 
-	list_for_each(list, &dev->maplist->head) {
-		r_list = list_entry(list, drm_map_list_t, head);
-		map = r_list->map;
-		if (!map)
-			continue;
-		if (r_list->user_token == VM_OFFSET(vma))
-			break;
-	}
+        if (drm_ht_find_item(&dev->map_hash, (VM_OFFSET(vma) - DRM_MAP_HASH_OFFSET) >> PAGE_SHIFT,  
+                             &hash)) 
+                goto vm_nopage_error;
+
+        r_list = drm_hash_entry(hash, drm_map_list_t, hash);
+	map = r_list->map;
 
 	if (map && map->type == _DRM_AGP) {
 		unsigned long offset = address - vma->vm_start;
@@ -556,9 +554,8 @@
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->head->dev;
 	drm_map_t *map = NULL;
-	drm_map_list_t *r_list;
 	unsigned long offset = 0;
-	struct list_head *list;
+        drm_hash_item_t *hash;
 
 	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
 		  vma->vm_start, vma->vm_end, VM_OFFSET(vma));
@@ -578,22 +575,13 @@
 	    )
 		return drm_mmap_dma(filp, vma);
 
-	/* A sequential search of a linked list is
-	   fine here because: 1) there will only be
-	   about 5-10 entries in the list and, 2) a
-	   DRI client only has to do this mapping
-	   once, so it doesn't have to be optimized
-	   for performance, even if the list was a
-	   bit longer. */
-	list_for_each(list, &dev->maplist->head) {
-
-		r_list = list_entry(list, drm_map_list_t, head);
-		map = r_list->map;
-		if (!map)
-			continue;
-		if (r_list->user_token == VM_OFFSET(vma))
-			break;
-	}
+        if (drm_ht_find_item(&dev->map_hash, (VM_OFFSET(vma) - DRM_MAP_HASH_OFFSET) >> PAGE_SHIFT,
+                             &hash)) {
+                DRM_ERROR("Could not find map\n");
+		return -EINVAL;
+        }
+        
+	map = drm_hash_entry(hash,drm_map_list_t, hash)->map;
 
 	if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
 		return -EPERM;
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to