summaryrefslogtreecommitdiff
path: root/linux-core/drm_vm.c
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2006-10-10 10:37:26 +0200
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2006-10-10 10:37:26 +0200
commitc58574c60505a699e19e1ed59e1b441be2594e53 (patch)
treea8e5e025e843d49d81007ce1c0f986a5f986bf71 /linux-core/drm_vm.c
parentcee659afb56e7ac443402ac791144f391721061e (diff)
Use a nopage-based approach to fault in pfns.
Diffstat (limited to 'linux-core/drm_vm.c')
-rw-r--r--linux-core/drm_vm.c48
1 files changed, 36 insertions, 12 deletions
diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c
index 4755684e..5fbbaadd 100644
--- a/linux-core/drm_vm.c
+++ b/linux-core/drm_vm.c
@@ -237,7 +237,7 @@ static int drm_ttm_remap_bound_pfn(struct vm_area_struct *vma,
}
if (ret) {
- DRM_ERROR("Map returned %c\n", ret);
+ DRM_ERROR("Map returned %c\n", ret);
}
return ret;
}
@@ -254,6 +254,7 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma,
pgprot_t default_prot;
uint32_t page_flags;
drm_buffer_manager_t *bm;
+ drm_device_t *dev;
if (address > vma->vm_end)
return NOPAGE_SIGBUS; /* Disallow mremap */
@@ -262,7 +263,11 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma,
map = (drm_map_t *) entry->map;
ttm = (drm_ttm_t *) map->offset;
- bm = &ttm->dev->bm;
+
+ dev = ttm->dev;
+ mutex_lock(&dev->struct_mutex);
+
+ bm = &dev->bm;
page_offset = (address - vma->vm_start) >> PAGE_SHIFT;
page = ttm->pages[page_offset];
@@ -270,22 +275,43 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma,
if (!page) {
if (bm->cur_pages >= bm->max_pages) {
- DRM_ERROR("Maximum locked page count exceeded\n");
- return NOPAGE_OOM;
+ DRM_ERROR("Maximum locked page count exceeded\n");
+ page = NOPAGE_OOM;
+ goto out;
}
++bm->cur_pages;
page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0);
+ if (page) {
+ SetPageLocked(page);
+ } else {
+ page = NOPAGE_OOM;
+ }
}
- if (!page)
- return NOPAGE_OOM;
- SetPageLocked(page);
- get_page(page);
+ if (page_flags & DRM_TTM_PAGE_UNCACHED) {
- default_prot = vm_get_page_prot(vma->vm_flags);
+ /*
+ * This makes sure we don't race with another
+ * drm_ttm_remap_bound_pfn();
+ */
- BUG_ON(page_flags & DRM_TTM_PAGE_UNCACHED);
+ if (!drm_pte_is_clear(vma, address)) {
+ page = NOPAGE_RETRY;
+ goto out1;
+ }
+
+ drm_ttm_remap_bound_pfn(vma, address, PAGE_SIZE);
+ page = NOPAGE_RETRY;
+ goto out1;
+ }
+ get_page(page);
+
+ out1:
+ default_prot = vm_get_page_prot(vma->vm_flags);
vma->vm_page_prot = default_prot;
+
+ out:
+ mutex_unlock(&dev->struct_mutex);
return page;
}
@@ -645,7 +671,6 @@ static int drm_vm_ttm_open(struct vm_area_struct *vma) {
*entry = *tmp_vma;
map = (drm_map_t *) entry->map;
ttm = (drm_ttm_t *) map->offset;
- ret = drm_ttm_add_mm_to_list(ttm, vma->vm_mm);
if (!ret) {
atomic_inc(&ttm->vma_count);
INIT_LIST_HEAD(&entry->head);
@@ -717,7 +742,6 @@ static void drm_vm_ttm_close(struct vm_area_struct *vma)
ttm = (drm_ttm_t *) map->offset;
dev = ttm->dev;
mutex_lock(&dev->struct_mutex);
- drm_ttm_delete_mm(ttm, vma->vm_mm);
list_del(&ttm_vma->head);
drm_free(ttm_vma, sizeof(*ttm_vma), DRM_MEM_VMAS);
if (atomic_dec_and_test(&ttm->vma_count)) {