diff options
Diffstat (limited to 'drivers/gpu/drm/ttm')
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_agp_backend.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_bo.c | 81 | ||||
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_bo_util.c | 70 | ||||
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_bo_vm.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_tt.c | 29 |
5 files changed, 149 insertions, 42 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c index e8f6d2229d8..4648ed2f014 100644 --- a/drivers/gpu/drm/ttm/ttm_agp_backend.c +++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c @@ -63,8 +63,7 @@ static int ttm_agp_populate(struct ttm_backend *backend, if (!page) page = dummy_read_page; - mem->memory[mem->page_count++] = - phys_to_gart(page_to_phys(page)); + mem->pages[mem->page_count++] = page; } agp_be->mem = mem; return 0; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 1587aeca7be..c2b0d710d10 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -43,7 +43,6 @@ #define TTM_BO_HASH_ORDER 13 static int ttm_bo_setup_vm(struct ttm_buffer_object *bo); -static void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo); static int ttm_bo_swapout(struct ttm_mem_shrink *shrink); static inline uint32_t ttm_bo_type_flags(unsigned type) @@ -224,6 +223,9 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc) TTM_ASSERT_LOCKED(&bo->mutex); bo->ttm = NULL; + if (bdev->need_dma32) + page_flags |= TTM_PAGE_FLAG_DMA32; + switch (bo->type) { case ttm_bo_type_device: if (zero_alloc) @@ -282,7 +284,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement); if (ret) - return ret; + goto out_err; if (mem->mem_type != TTM_PL_SYSTEM) { ret = ttm_tt_bind(bo->ttm, mem); @@ -304,6 +306,9 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, } + if (bdev->driver->move_notify) + bdev->driver->move_notify(bo, mem); + if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) && !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) ret = ttm_bo_move_ttm(bo, evict, no_wait, mem); @@ -527,9 +532,12 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, unsigned mem_type, ret = ttm_bo_wait(bo, false, interruptible, no_wait); spin_unlock(&bo->lock); - if (ret && ret != -ERESTART) { - printk(KERN_ERR TTM_PFX "Failed to expire sync object before " - "buffer eviction.\n"); + if (unlikely(ret != 0)) { + if (ret != -ERESTART) { + printk(KERN_ERR TTM_PFX + "Failed to expire sync object before " + "buffer eviction.\n"); + } goto out; } @@ -652,31 +660,52 @@ retry_pre_get: return 0; } +static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man, + uint32_t cur_placement, + uint32_t proposed_placement) +{ + uint32_t caching = proposed_placement & TTM_PL_MASK_CACHING; + uint32_t result = proposed_placement & ~TTM_PL_MASK_CACHING; + + /** + * Keep current caching if possible. + */ + + if ((cur_placement & caching) != 0) + result |= (cur_placement & caching); + else if ((man->default_caching & caching) != 0) + result |= man->default_caching; + else if ((TTM_PL_FLAG_CACHED & caching) != 0) + result |= TTM_PL_FLAG_CACHED; + else if ((TTM_PL_FLAG_WC & caching) != 0) + result |= TTM_PL_FLAG_WC; + else if ((TTM_PL_FLAG_UNCACHED & caching) != 0) + result |= TTM_PL_FLAG_UNCACHED; + + return result; +} + + static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man, bool disallow_fixed, uint32_t mem_type, - uint32_t mask, uint32_t *res_mask) + uint32_t proposed_placement, + uint32_t *masked_placement) { uint32_t cur_flags = ttm_bo_type_flags(mem_type); if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && disallow_fixed) return false; - if ((cur_flags & mask & TTM_PL_MASK_MEM) == 0) + if ((cur_flags & proposed_placement & TTM_PL_MASK_MEM) == 0) return false; - if ((mask & man->available_caching) == 0) + if ((proposed_placement & man->available_caching) == 0) return false; - if (mask & man->default_caching) - cur_flags |= man->default_caching; - else if (mask & TTM_PL_FLAG_CACHED) - cur_flags |= TTM_PL_FLAG_CACHED; - else if (mask & TTM_PL_FLAG_WC) - cur_flags |= TTM_PL_FLAG_WC; - else - cur_flags |= TTM_PL_FLAG_UNCACHED; - *res_mask = cur_flags; + cur_flags |= (proposed_placement & man->available_caching); + + *masked_placement = cur_flags; return true; } @@ -720,6 +749,9 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, if (!type_ok) continue; + cur_flags = ttm_bo_select_caching(man, bo->mem.placement, + cur_flags); + if (mem_type == TTM_PL_SYSTEM) break; @@ -776,6 +808,9 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, proposed_placement, &cur_flags)) continue; + cur_flags = ttm_bo_select_caching(man, bo->mem.placement, + cur_flags); + ret = ttm_bo_mem_force_space(bdev, mem, mem_type, interruptible, no_wait); @@ -1147,13 +1182,14 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev, int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type) { - struct ttm_mem_type_manager *man = &bdev->man[mem_type]; + struct ttm_mem_type_manager *man; int ret = -EINVAL; if (mem_type >= TTM_NUM_MEM_TYPES) { printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", mem_type); return ret; } + man = &bdev->man[mem_type]; if (!man->has_type) { printk(KERN_ERR TTM_PFX "Trying to take down uninitialized " @@ -1302,7 +1338,8 @@ EXPORT_SYMBOL(ttm_bo_device_release); int ttm_bo_device_init(struct ttm_bo_device *bdev, struct ttm_mem_global *mem_glob, - struct ttm_bo_driver *driver, uint64_t file_page_offset) + struct ttm_bo_driver *driver, uint64_t file_page_offset, + bool need_dma32) { int ret = -EINVAL; @@ -1339,6 +1376,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev, INIT_LIST_HEAD(&bdev->ddestroy); INIT_LIST_HEAD(&bdev->swap_lru); bdev->dev_mapping = NULL; + bdev->need_dma32 = need_dma32; ttm_mem_init_shrink(&bdev->shrink, ttm_bo_swapout); ret = ttm_mem_register_shrink(mem_glob, &bdev->shrink); if (unlikely(ret != 0)) { @@ -1416,6 +1454,7 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) unmap_mapping_range(bdev->dev_mapping, offset, holelen, 1); } +EXPORT_SYMBOL(ttm_bo_unmap_virtual); static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo) { @@ -1537,6 +1576,10 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, driver->sync_obj_unref(&sync_obj); driver->sync_obj_unref(&tmp_obj); spin_lock(&bo->lock); + } else { + spin_unlock(&bo->lock); + driver->sync_obj_unref(&sync_obj); + spin_lock(&bo->lock); } } return 0; diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 517c8455963..ad4ada07c6c 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -34,7 +34,6 @@ #include <linux/highmem.h> #include <linux/wait.h> #include <linux/vmalloc.h> -#include <linux/version.h> #include <linux/module.h> void ttm_bo_free_old_node(struct ttm_buffer_object *bo) @@ -137,7 +136,8 @@ static int ttm_copy_io_page(void *dst, void *src, unsigned long page) } static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src, - unsigned long page) + unsigned long page, + pgprot_t prot) { struct page *d = ttm_tt_get_page(ttm, page); void *dst; @@ -146,17 +146,35 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src, return -ENOMEM; src = (void *)((unsigned long)src + (page << PAGE_SHIFT)); - dst = kmap(d); + +#ifdef CONFIG_X86 + dst = kmap_atomic_prot(d, KM_USER0, prot); +#else + if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) + dst = vmap(&d, 1, 0, prot); + else + dst = kmap(d); +#endif if (!dst) return -ENOMEM; memcpy_fromio(dst, src, PAGE_SIZE); - kunmap(d); + +#ifdef CONFIG_X86 + kunmap_atomic(dst, KM_USER0); +#else + if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) + vunmap(dst); + else + kunmap(d); +#endif + return 0; } static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst, - unsigned long page) + unsigned long page, + pgprot_t prot) { struct page *s = ttm_tt_get_page(ttm, page); void *src; @@ -165,12 +183,28 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst, return -ENOMEM; dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); - src = kmap(s); +#ifdef CONFIG_X86 + src = kmap_atomic_prot(s, KM_USER0, prot); +#else + if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) + src = vmap(&s, 1, 0, prot); + else + src = kmap(s); +#endif if (!src) return -ENOMEM; memcpy_toio(dst, src, PAGE_SIZE); - kunmap(s); + +#ifdef CONFIG_X86 + kunmap_atomic(src, KM_USER0); +#else + if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) + vunmap(src); + else + kunmap(s); +#endif + return 0; } @@ -215,11 +249,17 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, for (i = 0; i < new_mem->num_pages; ++i) { page = i * dir + add; - if (old_iomap == NULL) - ret = ttm_copy_ttm_io_page(ttm, new_iomap, page); - else if (new_iomap == NULL) - ret = ttm_copy_io_ttm_page(ttm, old_iomap, page); - else + if (old_iomap == NULL) { + pgprot_t prot = ttm_io_prot(old_mem->placement, + PAGE_KERNEL); + ret = ttm_copy_ttm_io_page(ttm, new_iomap, page, + prot); + } else if (new_iomap == NULL) { + pgprot_t prot = ttm_io_prot(new_mem->placement, + PAGE_KERNEL); + ret = ttm_copy_io_ttm_page(ttm, old_iomap, page, + prot); + } else ret = ttm_copy_io_page(new_iomap, old_iomap, page); if (ret) goto out1; @@ -510,8 +550,8 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, if (evict) { ret = ttm_bo_wait(bo, false, false, false); spin_unlock(&bo->lock); - driver->sync_obj_unref(&bo->sync_obj); - + if (tmp_obj) + driver->sync_obj_unref(&tmp_obj); if (ret) return ret; @@ -533,6 +573,8 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); spin_unlock(&bo->lock); + if (tmp_obj) + driver->sync_obj_unref(&tmp_obj); ret = ttm_buffer_object_transfer(bo, &ghost_obj); if (ret) diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 27b146c54fb..33de7637c0c 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -32,7 +32,6 @@ #include <ttm/ttm_bo_driver.h> #include <ttm/ttm_placement.h> #include <linux/mm.h> -#include <linux/version.h> #include <linux/rbtree.h> #include <linux/module.h> #include <linux/uaccess.h> @@ -102,6 +101,9 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_NOPAGE; } + if (bdev->driver->fault_reserve_notify) + bdev->driver->fault_reserve_notify(bo); + /* * Wait for buffer data in transit, due to a pipelined * move. @@ -328,7 +330,7 @@ ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp, goto out_unref; kmap_offset = dev_offset - bo->vm_node->start; - if (unlikely(kmap_offset) >= bo->num_pages) { + if (unlikely(kmap_offset >= bo->num_pages)) { ret = -EFBIG; goto out_unref; } @@ -402,7 +404,7 @@ ssize_t ttm_bo_fbdev_io(struct ttm_buffer_object *bo, const char __user *wbuf, bool dummy; kmap_offset = (*f_pos >> PAGE_SHIFT); - if (unlikely(kmap_offset) >= bo->num_pages) + if (unlikely(kmap_offset >= bo->num_pages)) return -EFBIG; page_offset = *f_pos & ~PAGE_MASK; diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index c27ab3a877a..b8b6c4a5f98 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -28,7 +28,6 @@ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> */ -#include <linux/version.h> #include <linux/vmalloc.h> #include <linux/sched.h> #include <linux/highmem.h> @@ -68,7 +67,7 @@ static void ttm_tt_cache_flush_clflush(struct page *pages[], ttm_tt_clflush_page(*pages++); mb(); } -#else +#elif !defined(__powerpc__) static void ttm_tt_ipi_handler(void *null) { ; @@ -83,6 +82,21 @@ void ttm_tt_cache_flush(struct page *pages[], unsigned long num_pages) ttm_tt_cache_flush_clflush(pages, num_pages); return; } +#elif defined(__powerpc__) + unsigned long i; + + for (i = 0; i < num_pages; ++i) { + struct page *page = pages[i]; + void *page_virtual; + + if (unlikely(page == NULL)) + continue; + + page_virtual = kmap_atomic(page, KM_USER0); + flush_dcache_range((unsigned long) page_virtual, + (unsigned long) page_virtual + PAGE_SIZE); + kunmap_atomic(page_virtual, KM_USER0); + } #else if (on_each_cpu(ttm_tt_ipi_handler, NULL, 1) != 0) printk(KERN_ERR TTM_PFX @@ -123,10 +137,17 @@ static void ttm_tt_free_page_directory(struct ttm_tt *ttm) static struct page *ttm_tt_alloc_page(unsigned page_flags) { + gfp_t gfp_flags = GFP_USER; + if (page_flags & TTM_PAGE_FLAG_ZERO_ALLOC) - return alloc_page(GFP_HIGHUSER | __GFP_ZERO); + gfp_flags |= __GFP_ZERO; + + if (page_flags & TTM_PAGE_FLAG_DMA32) + gfp_flags |= __GFP_DMA32; + else + gfp_flags |= __GFP_HIGHMEM; - return alloc_page(GFP_HIGHUSER); + return alloc_page(gfp_flags); } static void ttm_tt_free_user_pages(struct ttm_tt *ttm) |