diff options
-rw-r--r-- | linux-core/drm_bo_move.c | 71 | ||||
-rw-r--r-- | linux-core/drm_objects.h | 2 |
2 files changed, 73 insertions, 0 deletions
diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index e81967fd..207a5e07 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -272,6 +272,77 @@ out: } EXPORT_SYMBOL(drm_bo_move_memcpy); +static int drm_memset_io_page(void *dst, unsigned long page) +{ + dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); + memset_io(dst, 0, PAGE_SIZE); + return 0; +} + +static int drm_memset_ttm_page(struct drm_ttm *ttm, unsigned long page) +{ + struct page *d = drm_ttm_get_page(ttm, page); + void *dst; + + dst = kmap(d); + if (!dst) + return -ENOMEM; + + memset_io(dst, 0, PAGE_SIZE); + kunmap(d); + return 0; +} + +int drm_bo_move_zero(struct drm_buffer_object *bo, + int evict, int no_wait, struct drm_bo_mem_reg *new_mem) +{ + struct drm_device *dev = bo->dev; + struct drm_mem_type_manager *man = &dev->bm.man[new_mem->mem_type]; + struct drm_ttm *ttm = bo->ttm; + void *new_iomap; + int ret; + struct drm_bo_mem_reg *old_mem = &bo->mem; + uint64_t save_flags = old_mem->flags; + uint64_t save_proposed_flags = old_mem->proposed_flags; + unsigned long i; + unsigned long page; + + ret = drm_mem_reg_ioremap(dev, new_mem, &new_iomap); + if (ret) + goto out; + + if (new_iomap == NULL && ttm == NULL) + goto out2; + + for (i = 0; i < new_mem->num_pages; ++i) { + if (new_iomap == NULL) + ret = drm_memset_ttm_page(ttm, i); + else + ret = drm_memset_io_page(new_iomap, i); + if (ret) + goto out1; + } + mb(); +out2: + drm_bo_free_old_node(bo); + + *old_mem = *new_mem; + new_mem->mm_node = NULL; + old_mem->proposed_flags = save_proposed_flags; + DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE); + + if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (ttm != NULL)) { + drm_ttm_unbind(ttm); + drm_ttm_destroy(ttm); + bo->ttm = NULL; + } +out1: + drm_mem_reg_iounmap(dev, new_mem, new_iomap); +out: + return ret; +} +EXPORT_SYMBOL(drm_bo_move_zero); + /* * Transfer a buffer object's memory and LRU status to a newly * created object. User-space references remains with the old diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 2493a804..e13475a2 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -808,6 +808,8 @@ extern int drm_bo_move_ttm(struct drm_buffer_object *bo, extern int drm_bo_move_memcpy(struct drm_buffer_object *bo, int evict, int no_wait, struct drm_bo_mem_reg *new_mem); +extern int drm_bo_move_zero(struct drm_buffer_object *bo, + int evict, int no_wait, struct drm_bo_mem_reg *new_mem); extern int drm_bo_move_accel_cleanup(struct drm_buffer_object *bo, int evict, int no_wait, uint32_t fence_class, uint32_t fence_type, |