diff options
author | Thomas Hellstrom <thomas@tungstengraphics.com> | 2006-08-07 08:36:47 -0400 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2006-09-21 15:32:31 -0400 |
commit | 8d153f7107ff2c5d6e32053ae377c961187ab6b9 (patch) | |
tree | c90cdf1bf8e04237e840b37033fc0f57b74ab292 | |
parent | 8669cbc5e651bf4effa20e8c244a5a7d67da6fe9 (diff) |
drm: update user token hashing and map handles
Keep hashed user tokens, with the following changes:
32-bit physical device addresses are mapped directly to user-tokens. No
duplicate maps are allowed, and the addresses are assumed to be outside
of the range 0x10000000 through 0x30000000. The user-token is identical
to the 32-bit physical start-address of the map.
64-bit physical device addressed are mapped to user-tokens in the range
0x10000000 to 0x30000000 with page-size increments. The user_token should
not be interpreted as an address.
Other map types, like upcoming TTM maps are mapped to user-tokens in the
range
0x10000000 to 0x30000000 with page-size increments. The user_token should
not be interpreted as an address.
Implement hashed map lookups.
Signed-off-by: Dave Airlie <airlied@linux.ie>
-rw-r--r-- | drivers/char/drm/drmP.h | 3 | ||||
-rw-r--r-- | drivers/char/drm/drm_bufs.c | 68 | ||||
-rw-r--r-- | drivers/char/drm/drm_hashtab.h | 2 | ||||
-rw-r--r-- | drivers/char/drm/drm_stub.c | 4 | ||||
-rw-r--r-- | drivers/char/drm/drm_vm.c | 37 |
5 files changed, 51 insertions, 63 deletions
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index fedaf013f848..84e9c18fdbef 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h | |||
@@ -140,6 +140,7 @@ | |||
140 | #define DRM_MEM_HASHTAB 23 | 140 | #define DRM_MEM_HASHTAB 23 |
141 | 141 | ||
142 | #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) | 142 | #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) |
143 | #define DRM_MAP_HASH_OFFSET 0x10000000 | ||
143 | 144 | ||
144 | /*@}*/ | 145 | /*@}*/ |
145 | 146 | ||
@@ -485,6 +486,7 @@ typedef struct drm_sigdata { | |||
485 | */ | 486 | */ |
486 | typedef struct drm_map_list { | 487 | typedef struct drm_map_list { |
487 | struct list_head head; /**< list head */ | 488 | struct list_head head; /**< list head */ |
489 | drm_hash_item_t hash; | ||
488 | drm_map_t *map; /**< mapping */ | 490 | drm_map_t *map; /**< mapping */ |
489 | unsigned int user_token; | 491 | unsigned int user_token; |
490 | } drm_map_list_t; | 492 | } drm_map_list_t; |
@@ -662,6 +664,7 @@ typedef struct drm_device { | |||
662 | /*@{ */ | 664 | /*@{ */ |
663 | drm_map_list_t *maplist; /**< Linked list of regions */ | 665 | drm_map_list_t *maplist; /**< Linked list of regions */ |
664 | int map_count; /**< Number of mappable regions */ | 666 | int map_count; /**< Number of mappable regions */ |
667 | drm_open_hash_t map_hash; /**< User token hash table for maps */ | ||
665 | 668 | ||
666 | /** \name Context handle management */ | 669 | /** \name Context handle management */ |
667 | /*@{ */ | 670 | /*@{ */ |
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 7775fb5dfb9b..4440257f33e4 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c | |||
@@ -65,43 +65,27 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, | |||
65 | return NULL; | 65 | return NULL; |
66 | } | 66 | } |
67 | 67 | ||
68 | /* | 68 | int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash, |
69 | * Used to allocate 32-bit handles for mappings. | 69 | unsigned long user_token, int hashed_handle) |
70 | */ | ||
71 | #define START_RANGE 0x10000000 | ||
72 | #define END_RANGE 0x40000000 | ||
73 | |||
74 | #ifdef _LP64 | ||
75 | static __inline__ unsigned int HandleID(unsigned long lhandle, | ||
76 | drm_device_t *dev) | ||
77 | { | 70 | { |
78 | static unsigned int map32_handle = START_RANGE; | 71 | int use_hashed_handle; |
79 | unsigned int hash; | 72 | #if (BITS_PER_LONG == 64) |
80 | 73 | use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle); | |
81 | if (lhandle & 0xffffffff00000000) { | 74 | #elif (BITS_PER_LONG == 32) |
82 | hash = map32_handle; | 75 | use_hashed_handle = hashed_handle; |
83 | map32_handle += PAGE_SIZE; | 76 | #else |
84 | if (map32_handle > END_RANGE) | 77 | #error Unsupported long size. Neither 64 nor 32 bits. |
85 | map32_handle = START_RANGE; | 78 | #endif |
86 | } else | ||
87 | hash = lhandle; | ||
88 | |||
89 | while (1) { | ||
90 | drm_map_list_t *_entry; | ||
91 | list_for_each_entry(_entry, &dev->maplist->head, head) { | ||
92 | if (_entry->user_token == hash) | ||
93 | break; | ||
94 | } | ||
95 | if (&_entry->head == &dev->maplist->head) | ||
96 | return hash; | ||
97 | 79 | ||
98 | hash += PAGE_SIZE; | 80 | if (use_hashed_handle) { |
99 | map32_handle += PAGE_SIZE; | 81 | return drm_ht_just_insert_please(&dev->map_hash, hash, |
82 | user_token, 32 - PAGE_SHIFT - 3, | ||
83 | PAGE_SHIFT, DRM_MAP_HASH_OFFSET); | ||
84 | } else { | ||
85 | hash->key = user_token; | ||
86 | return drm_ht_insert_item(&dev->map_hash, hash); | ||
100 | } | 87 | } |
101 | } | 88 | } |
102 | #else | ||
103 | # define HandleID(x,dev) (unsigned int)(x) | ||
104 | #endif | ||
105 | 89 | ||
106 | /** | 90 | /** |
107 | * Ioctl to specify a range of memory that is available for mapping by a non-root process. | 91 | * Ioctl to specify a range of memory that is available for mapping by a non-root process. |
@@ -123,6 +107,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, | |||
123 | drm_map_t *map; | 107 | drm_map_t *map; |
124 | drm_map_list_t *list; | 108 | drm_map_list_t *list; |
125 | drm_dma_handle_t *dmah; | 109 | drm_dma_handle_t *dmah; |
110 | unsigned long user_token; | ||
111 | int ret; | ||
126 | 112 | ||
127 | map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); | 113 | map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); |
128 | if (!map) | 114 | if (!map) |
@@ -257,11 +243,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, | |||
257 | 243 | ||
258 | mutex_lock(&dev->struct_mutex); | 244 | mutex_lock(&dev->struct_mutex); |
259 | list_add(&list->head, &dev->maplist->head); | 245 | list_add(&list->head, &dev->maplist->head); |
246 | |||
260 | /* Assign a 32-bit handle */ | 247 | /* Assign a 32-bit handle */ |
261 | /* We do it here so that dev->struct_mutex protects the increment */ | 248 | /* We do it here so that dev->struct_mutex protects the increment */ |
262 | list->user_token = HandleID(map->type == _DRM_SHM | 249 | user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle : |
263 | ? (unsigned long)map->handle | 250 | map->offset; |
264 | : map->offset, dev); | 251 | ret = drm_map_handle(dev, &list->hash, user_token, FALSE); |
252 | if (ret) { | ||
253 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | ||
254 | drm_free(list, sizeof(*list), DRM_MEM_MAPS); | ||
255 | mutex_unlock(&dev->struct_mutex); | ||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | list->user_token = list->hash.key; | ||
265 | mutex_unlock(&dev->struct_mutex); | 260 | mutex_unlock(&dev->struct_mutex); |
266 | 261 | ||
267 | *maplist = list; | 262 | *maplist = list; |
@@ -346,6 +341,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) | |||
346 | 341 | ||
347 | if (r_list->map == map) { | 342 | if (r_list->map == map) { |
348 | list_del(list); | 343 | list_del(list); |
344 | drm_ht_remove_key(&dev->map_hash, r_list->user_token); | ||
349 | drm_free(list, sizeof(*list), DRM_MEM_MAPS); | 345 | drm_free(list, sizeof(*list), DRM_MEM_MAPS); |
350 | break; | 346 | break; |
351 | } | 347 | } |
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h index 9e19ef1814ba..40afec05bff8 100644 --- a/drivers/char/drm/drm_hashtab.h +++ b/drivers/char/drm/drm_hashtab.h | |||
@@ -35,7 +35,7 @@ | |||
35 | #ifndef DRM_HASHTAB_H | 35 | #ifndef DRM_HASHTAB_H |
36 | #define DRM_HASHTAB_H | 36 | #define DRM_HASHTAB_H |
37 | 37 | ||
38 | #define drm_hash_entry(_ptr, _type, _member) list_entry(_ptr, _type, _member) | 38 | #define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) |
39 | 39 | ||
40 | typedef struct drm_hash_item{ | 40 | typedef struct drm_hash_item{ |
41 | struct hlist_node head; | 41 | struct hlist_node head; |
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index b1ead37c51d6..a9bb18ac3a2b 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c | |||
@@ -75,6 +75,10 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, | |||
75 | if (dev->maplist == NULL) | 75 | if (dev->maplist == NULL) |
76 | return -ENOMEM; | 76 | return -ENOMEM; |
77 | INIT_LIST_HEAD(&dev->maplist->head); | 77 | INIT_LIST_HEAD(&dev->maplist->head); |
78 | if (drm_ht_create(&dev->map_hash, 12)) { | ||
79 | drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); | ||
80 | return -ENOMEM; | ||
81 | } | ||
78 | 82 | ||
79 | /* the DRM has 6 basic counters */ | 83 | /* the DRM has 6 basic counters */ |
80 | dev->counters = 6; | 84 | dev->counters = 6; |
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index afb4f0a44b81..b40ae438f531 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c | |||
@@ -59,7 +59,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, | |||
59 | drm_device_t *dev = priv->head->dev; | 59 | drm_device_t *dev = priv->head->dev; |
60 | drm_map_t *map = NULL; | 60 | drm_map_t *map = NULL; |
61 | drm_map_list_t *r_list; | 61 | drm_map_list_t *r_list; |
62 | struct list_head *list; | 62 | drm_hash_item_t *hash; |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * Find the right map | 65 | * Find the right map |
@@ -70,14 +70,11 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, | |||
70 | if (!dev->agp || !dev->agp->cant_use_aperture) | 70 | if (!dev->agp || !dev->agp->cant_use_aperture) |
71 | goto vm_nopage_error; | 71 | goto vm_nopage_error; |
72 | 72 | ||
73 | list_for_each(list, &dev->maplist->head) { | 73 | if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) |
74 | r_list = list_entry(list, drm_map_list_t, head); | 74 | goto vm_nopage_error; |
75 | map = r_list->map; | 75 | |
76 | if (!map) | 76 | r_list = drm_hash_entry(hash, drm_map_list_t, hash); |
77 | continue; | 77 | map = r_list->map; |
78 | if (r_list->user_token == (vma->vm_pgoff << PAGE_SHIFT)) | ||
79 | break; | ||
80 | } | ||
81 | 78 | ||
82 | if (map && map->type == _DRM_AGP) { | 79 | if (map && map->type == _DRM_AGP) { |
83 | unsigned long offset = address - vma->vm_start; | 80 | unsigned long offset = address - vma->vm_start; |
@@ -521,9 +518,8 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
521 | drm_file_t *priv = filp->private_data; | 518 | drm_file_t *priv = filp->private_data; |
522 | drm_device_t *dev = priv->head->dev; | 519 | drm_device_t *dev = priv->head->dev; |
523 | drm_map_t *map = NULL; | 520 | drm_map_t *map = NULL; |
524 | drm_map_list_t *r_list; | ||
525 | unsigned long offset = 0; | 521 | unsigned long offset = 0; |
526 | struct list_head *list; | 522 | drm_hash_item_t *hash; |
527 | 523 | ||
528 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", | 524 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", |
529 | vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); | 525 | vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); |
@@ -543,23 +539,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
543 | ) | 539 | ) |
544 | return drm_mmap_dma(filp, vma); | 540 | return drm_mmap_dma(filp, vma); |
545 | 541 | ||
546 | /* A sequential search of a linked list is | 542 | if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) { |
547 | fine here because: 1) there will only be | 543 | DRM_ERROR("Could not find map\n"); |
548 | about 5-10 entries in the list and, 2) a | 544 | return -EINVAL; |
549 | DRI client only has to do this mapping | ||
550 | once, so it doesn't have to be optimized | ||
551 | for performance, even if the list was a | ||
552 | bit longer. */ | ||
553 | list_for_each(list, &dev->maplist->head) { | ||
554 | |||
555 | r_list = list_entry(list, drm_map_list_t, head); | ||
556 | map = r_list->map; | ||
557 | if (!map) | ||
558 | continue; | ||
559 | if (r_list->user_token == vma->vm_pgoff << PAGE_SHIFT) | ||
560 | break; | ||
561 | } | 545 | } |
562 | 546 | ||
547 | map = drm_hash_entry(hash, drm_map_list_t, hash)->map; | ||
563 | if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) | 548 | if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) |
564 | return -EPERM; | 549 | return -EPERM; |
565 | 550 | ||