summaryrefslogtreecommitdiff
path: root/linux-core/drm_bo_move.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core/drm_bo_move.c')
-rw-r--r--linux-core/drm_bo_move.c614
1 files changed, 0 insertions, 614 deletions
diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c
deleted file mode 100644
index d794e985..00000000
--- a/linux-core/drm_bo_move.c
+++ /dev/null
@@ -1,614 +0,0 @@
-/**************************************************************************
- *
- * Copyright (c) 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-/*
- * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
- */
-
-#include "drmP.h"
-
-/**
- * Free the old memory node unless it's a pinned region and we
- * have not been requested to free also pinned regions.
- */
-
-static void drm_bo_free_old_node(struct drm_buffer_object *bo)
-{
- struct drm_bo_mem_reg *old_mem = &bo->mem;
-
- if (old_mem->mm_node && (old_mem->mm_node != bo->pinned_node)) {
- mutex_lock(&bo->dev->struct_mutex);
- drm_mm_put_block(old_mem->mm_node);
- mutex_unlock(&bo->dev->struct_mutex);
- }
- old_mem->mm_node = NULL;
-}
-
-int drm_bo_move_ttm(struct drm_buffer_object *bo,
- int evict, int no_wait, struct drm_bo_mem_reg *new_mem)
-{
- struct drm_ttm *ttm = bo->ttm;
- 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;
- int ret;
-
- if (old_mem->mem_type != DRM_BO_MEM_LOCAL) {
- if (evict)
- drm_ttm_evict(ttm);
- else
- drm_ttm_unbind(ttm);
-
- drm_bo_free_old_node(bo);
- DRM_FLAG_MASKED(old_mem->flags,
- DRM_BO_FLAG_CACHED | DRM_BO_FLAG_MAPPABLE |
- DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEMTYPE);
- old_mem->mem_type = DRM_BO_MEM_LOCAL;
- save_flags = old_mem->flags;
- }
- if (new_mem->mem_type != DRM_BO_MEM_LOCAL) {
- ret = drm_ttm_bind(ttm, new_mem);
- if (ret)
- return ret;
- }
-
- *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);
- return 0;
-}
-EXPORT_SYMBOL(drm_bo_move_ttm);
-
-/**
- * \c Return a kernel virtual address to the buffer object PCI memory.
- *
- * \param bo The buffer object.
- * \return Failure indication.
- *
- * Returns -EINVAL if the buffer object is currently not mappable.
- * Returns -ENOMEM if the ioremap operation failed.
- * Otherwise returns zero.
- *
- * After a successfull call, bo->iomap contains the virtual address, or NULL
- * if the buffer object content is not accessible through PCI space.
- * Call bo->mutex locked.
- */
-
-int drm_mem_reg_ioremap(struct drm_device *dev, struct drm_bo_mem_reg *mem,
- void **virtual)
-{
- struct drm_buffer_manager *bm = &dev->bm;
- struct drm_mem_type_manager *man = &bm->man[mem->mem_type];
- unsigned long bus_offset;
- unsigned long bus_size;
- unsigned long bus_base;
- int ret;
- void *addr;
-
- *virtual = NULL;
- ret = drm_bo_pci_offset(dev, mem, &bus_base, &bus_offset, &bus_size);
- if (ret || bus_size == 0)
- return ret;
-
- if (!(man->flags & _DRM_FLAG_NEEDS_IOREMAP))
- addr = (void *)(((u8 *) man->io_addr) + bus_offset);
- else {
- addr = ioremap_nocache(bus_base + bus_offset, bus_size);
- if (!addr)
- return -ENOMEM;
- }
- *virtual = addr;
- return 0;
-}
-EXPORT_SYMBOL(drm_mem_reg_ioremap);
-
-/**
- * \c Unmap mapping obtained using drm_bo_ioremap
- *
- * \param bo The buffer object.
- *
- * Call bo->mutex locked.
- */
-
-void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg *mem,
- void *virtual)
-{
- struct drm_buffer_manager *bm;
- struct drm_mem_type_manager *man;
-
- bm = &dev->bm;
- man = &bm->man[mem->mem_type];
-
- if (virtual && (man->flags & _DRM_FLAG_NEEDS_IOREMAP))
- iounmap(virtual);
-}
-
-static int drm_copy_io_page(void *dst, void *src, unsigned long page)
-{
- uint32_t *dstP =
- (uint32_t *) ((unsigned long)dst + (page << PAGE_SHIFT));
- uint32_t *srcP =
- (uint32_t *) ((unsigned long)src + (page << PAGE_SHIFT));
-
- int i;
- for (i = 0; i < PAGE_SIZE / sizeof(uint32_t); ++i)
- iowrite32(ioread32(srcP++), dstP++);
- return 0;
-}
-
-static int drm_copy_io_ttm_page(struct drm_ttm *ttm, void *src,
- unsigned long page)
-{
- struct page *d = drm_ttm_get_page(ttm, page);
- void *dst;
-
- if (!d)
- return -ENOMEM;
-
- src = (void *)((unsigned long)src + (page << PAGE_SHIFT));
- dst = kmap(d);
- if (!dst)
- return -ENOMEM;
-
- memcpy_fromio(dst, src, PAGE_SIZE);
- kunmap(d);
- return 0;
-}
-
-static int drm_copy_ttm_io_page(struct drm_ttm *ttm, void *dst, unsigned long page)
-{
- struct page *s = drm_ttm_get_page(ttm, page);
- void *src;
-
- if (!s)
- return -ENOMEM;
-
- dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT));
- src = kmap(s);
- if (!src)
- return -ENOMEM;
-
- memcpy_toio(dst, src, PAGE_SIZE);
- kunmap(s);
- return 0;
-}
-
-int drm_bo_move_memcpy(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;
- struct drm_bo_mem_reg *old_mem = &bo->mem;
- struct drm_bo_mem_reg old_copy = *old_mem;
- void *old_iomap;
- void *new_iomap;
- int ret;
- uint64_t save_flags = old_mem->flags;
- uint64_t save_proposed_flags = old_mem->proposed_flags;
- unsigned long i;
- unsigned long page;
- unsigned long add = 0;
- int dir;
-
- ret = drm_mem_reg_ioremap(dev, old_mem, &old_iomap);
- if (ret)
- return ret;
- ret = drm_mem_reg_ioremap(dev, new_mem, &new_iomap);
- if (ret)
- goto out;
-
- if (old_iomap == NULL && new_iomap == NULL)
- goto out2;
- if (old_iomap == NULL && ttm == NULL)
- goto out2;
-
- add = 0;
- dir = 1;
-
- if ((old_mem->mem_type == new_mem->mem_type) &&
- (new_mem->mm_node->start <
- old_mem->mm_node->start + old_mem->mm_node->size)) {
- dir = -1;
- add = new_mem->num_pages - 1;
- }
-
- for (i = 0; i < new_mem->num_pages; ++i) {
- page = i * dir + add;
- if (old_iomap == NULL)
- ret = drm_copy_ttm_io_page(ttm, new_iomap, page);
- else if (new_iomap == NULL)
- ret = drm_copy_io_ttm_page(ttm, old_iomap, page);
- else
- ret = drm_copy_io_page(new_iomap, old_iomap, page);
- 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:
- drm_mem_reg_iounmap(dev, &old_copy, old_iomap);
- return ret;
-}
-EXPORT_SYMBOL(drm_bo_move_memcpy);
-
-/*
- * Transfer a buffer object's memory and LRU status to a newly
- * created object. User-space references remains with the old
- * object. Call bo->mutex locked.
- */
-
-int drm_buffer_object_transfer(struct drm_buffer_object *bo,
- struct drm_buffer_object **new_obj)
-{
- struct drm_buffer_object *fbo;
- struct drm_device *dev = bo->dev;
- struct drm_buffer_manager *bm = &dev->bm;
-
- fbo = drm_ctl_calloc(1, sizeof(*fbo), DRM_MEM_BUFOBJ);
- if (!fbo)
- return -ENOMEM;
-
- *fbo = *bo;
- mutex_init(&fbo->mutex);
- mutex_lock(&fbo->mutex);
- mutex_lock(&dev->struct_mutex);
-
- DRM_INIT_WAITQUEUE(&bo->event_queue);
- INIT_LIST_HEAD(&fbo->ddestroy);
- INIT_LIST_HEAD(&fbo->lru);
- INIT_LIST_HEAD(&fbo->pinned_lru);
-
- fbo->fence = drm_fence_reference_locked(bo->fence);
- fbo->pinned_node = NULL;
- fbo->mem.mm_node->private = (void *)fbo;
- atomic_set(&fbo->usage, 1);
- atomic_inc(&bm->count);
- mutex_unlock(&dev->struct_mutex);
- mutex_unlock(&fbo->mutex);
-
- *new_obj = fbo;
- return 0;
-}
-
-/*
- * Since move is underway, we need to block signals in this function.
- * We cannot restart until it has finished.
- */
-
-int drm_bo_move_accel_cleanup(struct drm_buffer_object *bo,
- int evict, int no_wait, uint32_t fence_class,
- uint32_t fence_type, uint32_t fence_flags,
- 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_bo_mem_reg *old_mem = &bo->mem;
- int ret;
- uint64_t save_flags = old_mem->flags;
- uint64_t save_proposed_flags = old_mem->proposed_flags;
- struct drm_buffer_object *old_obj;
-
- if (bo->fence)
- drm_fence_usage_deref_unlocked(&bo->fence);
- ret = drm_fence_object_create(dev, fence_class, fence_type,
- fence_flags | DRM_FENCE_FLAG_EMIT,
- &bo->fence);
- bo->fence_type = fence_type;
- if (ret)
- return ret;
-
- if (evict || ((bo->mem.mm_node == bo->pinned_node) &&
- bo->mem.mm_node != NULL))
- {
- if (bo->fence) {
- (void) drm_fence_object_wait(bo->fence, 0, 1,
- bo->fence_type);
- drm_fence_usage_deref_unlocked(&bo->fence);
- }
- drm_bo_free_old_node(bo);
-
- if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (bo->ttm != NULL)) {
- drm_ttm_unbind(bo->ttm);
- drm_ttm_destroy(bo->ttm);
- bo->ttm = NULL;
- }
- } else {
-
- /* This should help pipeline ordinary buffer moves.
- *
- * Hang old buffer memory on a new buffer object,
- * and leave it to be released when the GPU
- * operation has completed.
- */
-
- ret = drm_buffer_object_transfer(bo, &old_obj);
-
- if (ret)
- return ret;
-
- if (!(man->flags & _DRM_FLAG_MEMTYPE_FIXED))
- old_obj->ttm = NULL;
- else
- bo->ttm = NULL;
-
- mutex_lock(&dev->struct_mutex);
- list_del_init(&old_obj->lru);
- DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED);
- drm_bo_add_to_lru(old_obj);
-
- drm_bo_usage_deref_locked(&old_obj);
- mutex_unlock(&dev->struct_mutex);
-
- }
-
- *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);
- return 0;
-}
-EXPORT_SYMBOL(drm_bo_move_accel_cleanup);
-
-int drm_bo_same_page(unsigned long offset,
- unsigned long offset2)
-{
- return (offset & PAGE_MASK) == (offset2 & PAGE_MASK);
-}
-EXPORT_SYMBOL(drm_bo_same_page);
-
-unsigned long drm_bo_offset_end(unsigned long offset,
- unsigned long end)
-{
- offset = (offset + PAGE_SIZE) & PAGE_MASK;
- return (end < offset) ? end : offset;
-}
-EXPORT_SYMBOL(drm_bo_offset_end);
-
-static pgprot_t drm_kernel_io_prot(uint32_t map_type)
-{
- pgprot_t tmp = PAGE_KERNEL;
-
-#if defined(__i386__) || defined(__x86_64__)
-#ifdef USE_PAT_WC
-#warning using pat
- if (drm_use_pat() && map_type == _DRM_TTM) {
- pgprot_val(tmp) |= _PAGE_PAT;
- return tmp;
- }
-#endif
- if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) {
- pgprot_val(tmp) |= _PAGE_PCD;
- pgprot_val(tmp) &= ~_PAGE_PWT;
- }
-#elif defined(__powerpc__)
- pgprot_val(tmp) |= _PAGE_NO_CACHE;
- if (map_type == _DRM_REGISTERS)
- pgprot_val(tmp) |= _PAGE_GUARDED;
-#endif
-#if defined(__ia64__)
- if (map_type == _DRM_TTM)
- tmp = pgprot_writecombine(tmp);
- else
- tmp = pgprot_noncached(tmp);
-#endif
- return tmp;
-}
-
-static int drm_bo_ioremap(struct drm_buffer_object *bo, unsigned long bus_base,
- unsigned long bus_offset, unsigned long bus_size,
- struct drm_bo_kmap_obj *map)
-{
- struct drm_device *dev = bo->dev;
- struct drm_bo_mem_reg *mem = &bo->mem;
- struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type];
-
- if (!(man->flags & _DRM_FLAG_NEEDS_IOREMAP)) {
- map->bo_kmap_type = bo_map_premapped;
- map->virtual = (void *)(((u8 *) man->io_addr) + bus_offset);
- } else {
- map->bo_kmap_type = bo_map_iomap;
- map->virtual = ioremap_nocache(bus_base + bus_offset, bus_size);
- }
- return (!map->virtual) ? -ENOMEM : 0;
-}
-
-static int drm_bo_kmap_ttm(struct drm_buffer_object *bo,
- unsigned long start_page, unsigned long num_pages,
- struct drm_bo_kmap_obj *map)
-{
- struct drm_device *dev = bo->dev;
- struct drm_bo_mem_reg *mem = &bo->mem;
- struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type];
- pgprot_t prot;
- struct drm_ttm *ttm = bo->ttm;
- struct page *d;
- int i;
-
- BUG_ON(!ttm);
-
- if (num_pages == 1 && (mem->flags & DRM_BO_FLAG_CACHED)) {
-
- /*
- * We're mapping a single page, and the desired
- * page protection is consistent with the bo.
- */
-
- map->bo_kmap_type = bo_map_kmap;
- map->page = drm_ttm_get_page(ttm, start_page);
- map->virtual = kmap(map->page);
- } else {
- /*
- * Populate the part we're mapping;
- */
-
- for (i = start_page; i < start_page + num_pages; ++i) {
- d = drm_ttm_get_page(ttm, i);
- if (!d)
- return -ENOMEM;
- }
-
- /*
- * We need to use vmap to get the desired page protection
- * or to make the buffer object look contigous.
- */
-
- prot = (mem->flags & DRM_BO_FLAG_CACHED) ?
- PAGE_KERNEL :
- drm_kernel_io_prot(man->drm_bus_maptype);
- map->bo_kmap_type = bo_map_vmap;
- map->virtual = vmap(ttm->pages + start_page,
- num_pages, 0, prot);
- }
- return (!map->virtual) ? -ENOMEM : 0;
-}
-
-/*
- * This function is to be used for kernel mapping of buffer objects.
- * It chooses the appropriate mapping method depending on the memory type
- * and caching policy the buffer currently has.
- * Mapping multiple pages or buffers that live in io memory is a bit slow and
- * consumes vmalloc space. Be restrictive with such mappings.
- * Mapping single pages usually returns the logical kernel address,
- * (which is fast)
- * BUG may use slower temporary mappings for high memory pages or
- * uncached / write-combined pages.
- *
- * The function fills in a drm_bo_kmap_obj which can be used to return the
- * kernel virtual address of the buffer.
- *
- * Code servicing a non-priviliged user request is only allowed to map one
- * page at a time. We might need to implement a better scheme to stop such
- * processes from consuming all vmalloc space.
- */
-
-int drm_bo_kmap(struct drm_buffer_object *bo, unsigned long start_page,
- unsigned long num_pages, struct drm_bo_kmap_obj *map)
-{
- int ret;
- unsigned long bus_base;
- unsigned long bus_offset;
- unsigned long bus_size;
-
- map->virtual = NULL;
-
- if (num_pages > bo->num_pages)
- return -EINVAL;
- if (start_page > bo->num_pages)
- return -EINVAL;
-#if 0
- if (num_pages > 1 && !DRM_SUSER(DRM_CURPROC))
- return -EPERM;
-#endif
- ret = drm_bo_pci_offset(bo->dev, &bo->mem, &bus_base,
- &bus_offset, &bus_size);
-
- if (ret)
- return ret;
-
- if (bus_size == 0) {
- return drm_bo_kmap_ttm(bo, start_page, num_pages, map);
- } else {
- bus_offset += start_page << PAGE_SHIFT;
- bus_size = num_pages << PAGE_SHIFT;
- return drm_bo_ioremap(bo, bus_base, bus_offset, bus_size, map);
- }
-}
-EXPORT_SYMBOL(drm_bo_kmap);
-
-void drm_bo_kunmap(struct drm_bo_kmap_obj *map)
-{
- if (!map->virtual)
- return;
-
- switch (map->bo_kmap_type) {
- case bo_map_iomap:
- iounmap(map->virtual);
- break;
- case bo_map_vmap:
- vunmap(map->virtual);
- break;
- case bo_map_kmap:
- kunmap(map->page);
- break;
- case bo_map_premapped:
- break;
- default:
- BUG();
- }
- map->virtual = NULL;
- map->page = NULL;
-}
-EXPORT_SYMBOL(drm_bo_kunmap);
-
-int drm_bo_pfn_prot(struct drm_buffer_object *bo,
- unsigned long dst_offset,
- unsigned long *pfn,
- pgprot_t *prot)
-{
- struct drm_bo_mem_reg *mem = &bo->mem;
- struct drm_device *dev = bo->dev;
- unsigned long bus_offset;
- unsigned long bus_size;
- unsigned long bus_base;
- struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type];
- int ret;
-
- ret = drm_bo_pci_offset(dev, mem, &bus_base, &bus_offset,
- &bus_size);
- if (ret)
- return -EINVAL;
-
- if (bus_size != 0)
- *pfn = (bus_base + bus_offset + dst_offset) >> PAGE_SHIFT;
- else if (!bo->ttm)
- return -EINVAL;
- else
- *pfn = page_to_pfn(drm_ttm_get_page(bo->ttm, dst_offset >> PAGE_SHIFT));
-
- *prot = (mem->flags & DRM_BO_FLAG_CACHED) ?
- PAGE_KERNEL : drm_kernel_io_prot(man->drm_bus_maptype);
-
- return 0;
-}
-EXPORT_SYMBOL(drm_bo_pfn_prot);
-