diff options
Diffstat (limited to 'drivers/char/drm/drm_bufs.c')
-rw-r--r-- | drivers/char/drm/drm_bufs.c | 81 |
1 files changed, 59 insertions, 22 deletions
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index fcc8d244f46f..d1e0b106c261 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c | |||
@@ -64,13 +64,41 @@ static drm_local_map_t *drm_find_matching_map(drm_device_t *dev, | |||
64 | return NULL; | 64 | return NULL; |
65 | } | 65 | } |
66 | 66 | ||
67 | #ifdef CONFIG_COMPAT | ||
68 | /* | 67 | /* |
69 | * Used to allocate 32-bit handles for _DRM_SHM regions | 68 | * Used to allocate 32-bit handles for mappings. |
70 | * The 0x10000000 value is chosen to be out of the way of | ||
71 | * FB/register and GART physical addresses. | ||
72 | */ | 69 | */ |
73 | static unsigned int map32_handle = 0x10000000; | 70 | #define START_RANGE 0x10000000 |
71 | #define END_RANGE 0x40000000 | ||
72 | |||
73 | #ifdef _LP64 | ||
74 | static __inline__ unsigned int HandleID(unsigned long lhandle, drm_device_t *dev) | ||
75 | { | ||
76 | static unsigned int map32_handle = START_RANGE; | ||
77 | unsigned int hash; | ||
78 | |||
79 | if (lhandle & 0xffffffff00000000) { | ||
80 | hash = map32_handle; | ||
81 | map32_handle += PAGE_SIZE; | ||
82 | if (map32_handle > END_RANGE) | ||
83 | map32_handle = START_RANGE; | ||
84 | } else | ||
85 | hash = lhandle; | ||
86 | |||
87 | while (1) { | ||
88 | drm_map_list_t *_entry; | ||
89 | list_for_each_entry(_entry, &dev->maplist->head,head) { | ||
90 | if (_entry->user_token == hash) | ||
91 | break; | ||
92 | } | ||
93 | if (&_entry->head == &dev->maplist->head) | ||
94 | return hash; | ||
95 | |||
96 | hash += PAGE_SIZE; | ||
97 | map32_handle += PAGE_SIZE; | ||
98 | } | ||
99 | } | ||
100 | #else | ||
101 | # define HandleID(x,dev) (unsigned int)(x) | ||
74 | #endif | 102 | #endif |
75 | 103 | ||
76 | /** | 104 | /** |
@@ -198,7 +226,7 @@ int drm_addmap(drm_device_t * dev, unsigned int offset, | |||
198 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | 226 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); |
199 | return -EINVAL; | 227 | return -EINVAL; |
200 | } | 228 | } |
201 | map->offset += dev->sg->handle; | 229 | map->offset += (unsigned long)dev->sg->virtual; |
202 | break; | 230 | break; |
203 | case _DRM_CONSISTENT: | 231 | case _DRM_CONSISTENT: |
204 | /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G, | 232 | /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G, |
@@ -229,12 +257,11 @@ int drm_addmap(drm_device_t * dev, unsigned int offset, | |||
229 | 257 | ||
230 | down(&dev->struct_sem); | 258 | down(&dev->struct_sem); |
231 | list_add(&list->head, &dev->maplist->head); | 259 | list_add(&list->head, &dev->maplist->head); |
232 | #ifdef CONFIG_COMPAT | 260 | /* Assign a 32-bit handle */ |
233 | /* Assign a 32-bit handle for _DRM_SHM mappings */ | ||
234 | /* We do it here so that dev->struct_sem protects the increment */ | 261 | /* We do it here so that dev->struct_sem protects the increment */ |
235 | if (map->type == _DRM_SHM) | 262 | list->user_token = HandleID(map->type==_DRM_SHM |
236 | map->offset = map32_handle += PAGE_SIZE; | 263 | ? (unsigned long)map->handle |
237 | #endif | 264 | : map->offset, dev); |
238 | up(&dev->struct_sem); | 265 | up(&dev->struct_sem); |
239 | 266 | ||
240 | *map_ptr = map; | 267 | *map_ptr = map; |
@@ -251,6 +278,7 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp, | |||
251 | drm_map_t *map_ptr; | 278 | drm_map_t *map_ptr; |
252 | drm_map_t __user *argp = (void __user *)arg; | 279 | drm_map_t __user *argp = (void __user *)arg; |
253 | int err; | 280 | int err; |
281 | unsigned long handle = 0; | ||
254 | 282 | ||
255 | if (!(filp->f_mode & 3)) | 283 | if (!(filp->f_mode & 3)) |
256 | return -EACCES; /* Require read/write */ | 284 | return -EACCES; /* Require read/write */ |
@@ -259,22 +287,29 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp, | |||
259 | return -EFAULT; | 287 | return -EFAULT; |
260 | } | 288 | } |
261 | 289 | ||
262 | err = drm_addmap( dev, map.offset, map.size, map.type, map.flags, | 290 | err = drm_addmap(dev, map.offset, map.size, map.type, map.flags, |
263 | &map_ptr ); | 291 | &map_ptr); |
264 | 292 | ||
265 | if (err) { | 293 | if (err) { |
266 | return err; | 294 | return err; |
267 | } | 295 | } |
268 | 296 | ||
269 | if (copy_to_user(argp, map_ptr, sizeof(*map_ptr))) | 297 | { |
270 | return -EFAULT; | 298 | drm_map_list_t *_entry; |
271 | if (map_ptr->type != _DRM_SHM) { | 299 | list_for_each_entry(_entry, &dev->maplist->head, head) { |
272 | if (copy_to_user(&argp->handle, &map_ptr->offset, | 300 | if (_entry->map == map_ptr) |
273 | sizeof(map_ptr->offset))) | 301 | handle = _entry->user_token; |
302 | } | ||
303 | if (!handle) | ||
274 | return -EFAULT; | 304 | return -EFAULT; |
275 | } | 305 | } |
306 | |||
307 | if (copy_to_user(argp, map_ptr, sizeof(*map_ptr))) | ||
308 | return -EFAULT; | ||
309 | if (put_user(handle, &argp->handle)) | ||
310 | return -EFAULT; | ||
276 | return 0; | 311 | return 0; |
277 | } | 312 | } |
278 | 313 | ||
279 | 314 | ||
280 | /** | 315 | /** |
@@ -388,7 +423,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp, | |||
388 | drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head); | 423 | drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head); |
389 | 424 | ||
390 | if (r_list->map && | 425 | if (r_list->map && |
391 | r_list->map->handle == request.handle && | 426 | r_list->user_token == (unsigned long) request.handle && |
392 | r_list->map->flags & _DRM_REMOVABLE) { | 427 | r_list->map->flags & _DRM_REMOVABLE) { |
393 | map = r_list->map; | 428 | map = r_list->map; |
394 | break; | 429 | break; |
@@ -939,7 +974,8 @@ static int drm_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request) | |||
939 | 974 | ||
940 | buf->offset = (dma->byte_count + offset); | 975 | buf->offset = (dma->byte_count + offset); |
941 | buf->bus_address = agp_offset + offset; | 976 | buf->bus_address = agp_offset + offset; |
942 | buf->address = (void *)(agp_offset + offset + dev->sg->handle); | 977 | buf->address = (void *)(agp_offset + offset |
978 | + (unsigned long)dev->sg->virtual); | ||
943 | buf->next = NULL; | 979 | buf->next = NULL; |
944 | buf->waiting = 0; | 980 | buf->waiting = 0; |
945 | buf->pending = 0; | 981 | buf->pending = 0; |
@@ -1456,6 +1492,7 @@ int drm_mapbufs( struct inode *inode, struct file *filp, | |||
1456 | || (drm_core_check_feature(dev, DRIVER_FB_DMA) | 1492 | || (drm_core_check_feature(dev, DRIVER_FB_DMA) |
1457 | && (dma->flags & _DRM_DMA_USE_FB))) { | 1493 | && (dma->flags & _DRM_DMA_USE_FB))) { |
1458 | drm_map_t *map = dev->agp_buffer_map; | 1494 | drm_map_t *map = dev->agp_buffer_map; |
1495 | unsigned long token = dev->agp_buffer_token; | ||
1459 | 1496 | ||
1460 | if ( !map ) { | 1497 | if ( !map ) { |
1461 | retcode = -EINVAL; | 1498 | retcode = -EINVAL; |
@@ -1470,7 +1507,7 @@ int drm_mapbufs( struct inode *inode, struct file *filp, | |||
1470 | virtual = do_mmap( filp, 0, map->size, | 1507 | virtual = do_mmap( filp, 0, map->size, |
1471 | PROT_READ | PROT_WRITE, | 1508 | PROT_READ | PROT_WRITE, |
1472 | MAP_SHARED, | 1509 | MAP_SHARED, |
1473 | (unsigned long)map->offset ); | 1510 | token ); |
1474 | #if LINUX_VERSION_CODE <= 0x020402 | 1511 | #if LINUX_VERSION_CODE <= 0x020402 |
1475 | up( ¤t->mm->mmap_sem ); | 1512 | up( ¤t->mm->mmap_sem ); |
1476 | #else | 1513 | #else |