aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/drm_vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/drm/drm_vm.c')
-rw-r--r--drivers/char/drm/drm_vm.c69
1 files changed, 35 insertions, 34 deletions
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index ffd0800ed601..b9cfc077f6bc 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 == VM_OFFSET(vma))
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;
@@ -150,14 +147,14 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
150 if (address > vma->vm_end) 147 if (address > vma->vm_end)
151 return NOPAGE_SIGBUS; /* Disallow mremap */ 148 return NOPAGE_SIGBUS; /* Disallow mremap */
152 if (!map) 149 if (!map)
153 return NOPAGE_OOM; /* Nothing allocated */ 150 return NOPAGE_SIGBUS; /* Nothing allocated */
154 151
155 offset = address - vma->vm_start; 152 offset = address - vma->vm_start;
156 i = (unsigned long)map->handle + offset; 153 i = (unsigned long)map->handle + offset;
157 page = (map->type == _DRM_CONSISTENT) ? 154 page = (map->type == _DRM_CONSISTENT) ?
158 virt_to_page((void *)i) : vmalloc_to_page((void *)i); 155 virt_to_page((void *)i) : vmalloc_to_page((void *)i);
159 if (!page) 156 if (!page)
160 return NOPAGE_OOM; 157 return NOPAGE_SIGBUS;
161 get_page(page); 158 get_page(page);
162 159
163 DRM_DEBUG("shm_nopage 0x%lx\n", address); 160 DRM_DEBUG("shm_nopage 0x%lx\n", address);
@@ -275,7 +272,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,
275 if (address > vma->vm_end) 272 if (address > vma->vm_end)
276 return NOPAGE_SIGBUS; /* Disallow mremap */ 273 return NOPAGE_SIGBUS; /* Disallow mremap */
277 if (!dma->pagelist) 274 if (!dma->pagelist)
278 return NOPAGE_OOM; /* Nothing allocated */ 275 return NOPAGE_SIGBUS; /* Nothing allocated */
279 276
280 offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */ 277 offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */
281 page_nr = offset >> PAGE_SHIFT; 278 page_nr = offset >> PAGE_SHIFT;
@@ -313,7 +310,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
313 if (address > vma->vm_end) 310 if (address > vma->vm_end)
314 return NOPAGE_SIGBUS; /* Disallow mremap */ 311 return NOPAGE_SIGBUS; /* Disallow mremap */
315 if (!entry->pagelist) 312 if (!entry->pagelist)
316 return NOPAGE_OOM; /* Nothing allocated */ 313 return NOPAGE_SIGBUS; /* Nothing allocated */
317 314
318 offset = address - vma->vm_start; 315 offset = address - vma->vm_start;
319 map_offset = map->offset - (unsigned long)dev->sg->virtual; 316 map_offset = map->offset - (unsigned long)dev->sg->virtual;
@@ -467,7 +464,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
467 dev = priv->head->dev; 464 dev = priv->head->dev;
468 dma = dev->dma; 465 dma = dev->dma;
469 DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", 466 DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
470 vma->vm_start, vma->vm_end, VM_OFFSET(vma)); 467 vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
471 468
472 /* Length must match exact page count */ 469 /* Length must match exact page count */
473 if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { 470 if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
@@ -476,6 +473,22 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
476 } 473 }
477 unlock_kernel(); 474 unlock_kernel();
478 475
476 if (!capable(CAP_SYS_ADMIN) &&
477 (dma->flags & _DRM_DMA_USE_PCI_RO)) {
478 vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
479#if defined(__i386__) || defined(__x86_64__)
480 pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
481#else
482 /* Ye gads this is ugly. With more thought
483 we could move this up higher and use
484 `protection_map' instead. */
485 vma->vm_page_prot =
486 __pgprot(pte_val
487 (pte_wrprotect
488 (__pte(pgprot_val(vma->vm_page_prot)))));
489#endif
490 }
491
479 vma->vm_ops = &drm_vm_dma_ops; 492 vma->vm_ops = &drm_vm_dma_ops;
480 493
481 vma->vm_flags |= VM_RESERVED; /* Don't swap */ 494 vma->vm_flags |= VM_RESERVED; /* Don't swap */
@@ -521,12 +534,11 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
521 drm_file_t *priv = filp->private_data; 534 drm_file_t *priv = filp->private_data;
522 drm_device_t *dev = priv->head->dev; 535 drm_device_t *dev = priv->head->dev;
523 drm_map_t *map = NULL; 536 drm_map_t *map = NULL;
524 drm_map_list_t *r_list;
525 unsigned long offset = 0; 537 unsigned long offset = 0;
526 struct list_head *list; 538 drm_hash_item_t *hash;
527 539
528 DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", 540 DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
529 vma->vm_start, vma->vm_end, VM_OFFSET(vma)); 541 vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
530 542
531 if (!priv->authenticated) 543 if (!priv->authenticated)
532 return -EACCES; 544 return -EACCES;
@@ -535,7 +547,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
535 * the AGP mapped at physical address 0 547 * the AGP mapped at physical address 0
536 * --BenH. 548 * --BenH.
537 */ 549 */
538 if (!VM_OFFSET(vma) 550 if (!(vma->vm_pgoff << PAGE_SHIFT)
539#if __OS_HAS_AGP 551#if __OS_HAS_AGP
540 && (!dev->agp 552 && (!dev->agp
541 || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) 553 || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
@@ -543,23 +555,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
543 ) 555 )
544 return drm_mmap_dma(filp, vma); 556 return drm_mmap_dma(filp, vma);
545 557
546 /* A sequential search of a linked list is 558 if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
547 fine here because: 1) there will only be 559 DRM_ERROR("Could not find map\n");
548 about 5-10 entries in the list and, 2) a 560 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 == VM_OFFSET(vma))
560 break;
561 } 561 }
562 562
563 map = drm_hash_entry(hash, drm_map_list_t, hash)->map;
563 if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) 564 if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
564 return -EPERM; 565 return -EPERM;
565 566
@@ -620,7 +621,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
620 offset = dev->driver->get_reg_ofs(dev); 621 offset = dev->driver->get_reg_ofs(dev);
621#ifdef __sparc__ 622#ifdef __sparc__
622 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 623 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
623 if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start, 624 if (io_remap_pfn_range(vma, vma->vm_start,
624 (map->offset + offset) >> PAGE_SHIFT, 625 (map->offset + offset) >> PAGE_SHIFT,
625 vma->vm_end - vma->vm_start, 626 vma->vm_end - vma->vm_start,
626 vma->vm_page_prot)) 627 vma->vm_page_prot))