diff options
Diffstat (limited to 'linux-core/nouveau_buffer.c')
-rw-r--r-- | linux-core/nouveau_buffer.c | 239 |
1 files changed, 175 insertions, 64 deletions
diff --git a/linux-core/nouveau_buffer.c b/linux-core/nouveau_buffer.c index e9f09eb3..c40dff6b 100644 --- a/linux-core/nouveau_buffer.c +++ b/linux-core/nouveau_buffer.c @@ -1,5 +1,5 @@ /* - * Copyright 2005 Stephane Marchesin. + * Copyright 2007 Dave Airlied * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -22,27 +22,39 @@ * OTHER DEALINGS IN THE SOFTWARE. */ /* - * Authors: Jeremy Kolb <jkolb@brandeis.edu> + * Authors: Dave Airlied <airlied@linux.ie> + * Ben Skeggs <darktama@iinet.net.au> + * Jeremy Kolb <jkolb@brandeis.edu> */ #include "drmP.h" #include "nouveau_drm.h" #include "nouveau_drv.h" +#include "nouveau_dma.h" -#ifdef NOUVEAU_HAVE_BUFFER - -struct drm_ttm_backend *nouveau_create_ttm_backend_entry(struct drm_device * dev) +static struct drm_ttm_backend * +nouveau_bo_create_ttm_backend_entry(struct drm_device * dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - return drm_agp_init_ttm(dev); + switch (dev_priv->gart_info.type) { + case NOUVEAU_GART_AGP: + return drm_agp_init_ttm(dev); + case NOUVEAU_GART_SGDMA: + return nouveau_sgdma_init_ttm(dev); + default: + DRM_ERROR("Unknown GART type %d\n", dev_priv->gart_info.type); + break; + } + + return NULL; } -int nouveau_fence_types(struct drm_buffer_object *bo, - uint32_t *fclass, - uint32_t *type) +static int +nouveau_bo_fence_type(struct drm_buffer_object *bo, + uint32_t *fclass, uint32_t *type) { - *fclass = 0; + /* When we get called, *fclass is set to the requested fence class */ if (bo->mem.mask & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) *type = 3; @@ -51,95 +63,194 @@ int nouveau_fence_types(struct drm_buffer_object *bo, return 0; } -int nouveau_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags) + +static int +nouveau_bo_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags) { /* We'll do this from user space. */ return 0; } -int nouveau_init_mem_type(struct drm_device *dev, - uint32_t type, - struct drm_mem_type_manager *man) +static int +nouveau_bo_init_mem_type(struct drm_device *dev, uint32_t type, + struct drm_mem_type_manager *man) { struct drm_nouveau_private *dev_priv = dev->dev_private; switch (type) { - case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_LOCAL: + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CACHED; + man->drm_bus_maptype = 0; + break; + case DRM_BO_MEM_VRAM: + man->flags = _DRM_FLAG_MEMTYPE_FIXED | + _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_NEEDS_IOREMAP; + man->io_addr = NULL; + man->drm_bus_maptype = _DRM_FRAME_BUFFER; + man->io_offset = drm_get_resource_start(dev, 1); + man->io_size = drm_get_resource_len(dev, 1); + if (man->io_size > nouveau_mem_fb_amount(dev)) + man->io_size = nouveau_mem_fb_amount(dev); + break; + case DRM_BO_MEM_PRIV0: + /* Unmappable VRAM */ + man->flags = _DRM_FLAG_MEMTYPE_CMA; + man->drm_bus_maptype = 0; + break; + case DRM_BO_MEM_TT: + switch (dev_priv->gart_info.type) { + case NOUVEAU_GART_AGP: man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | - _DRM_FLAG_MEMTYPE_CACHED; - man->drm_bus_maptype = 0; - break; - - case DRM_BO_MEM_VRAM: - man->flags = _DRM_FLAG_MEMTYPE_FIXED | - _DRM_FLAG_MEMTYPE_MAPPABLE | - _DRM_FLAG_NEEDS_IOREMAP; - man->io_addr = NULL; - man->drm_bus_maptype = _DRM_FRAME_BUFFER; - man->io_offset = drm_get_resource_start(dev, 0); - man->io_size = drm_get_resource_len(dev, 0); + _DRM_FLAG_MEMTYPE_CSELECT | + _DRM_FLAG_NEEDS_IOREMAP; + man->drm_bus_maptype = _DRM_AGP; break; - - case DRM_BO_MEM_TT: - if (!(drm_core_has_AGP(dev) && dev->agp)) { - DRM_ERROR("AGP is not enabled for memory type %u\n", - (unsigned)type); - return -EINVAL; - } - - man->io_offset = dev->agp->agp_info.aper_base; - man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024; - man->io_addr = NULL; + case NOUVEAU_GART_SGDMA: man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | - _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; - man->drm_bus_maptype = _DRM_AGP; + _DRM_FLAG_MEMTYPE_CSELECT | + _DRM_FLAG_MEMTYPE_CMA; + man->drm_bus_maptype = _DRM_SCATTER_GATHER; break; - default: - DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + DRM_ERROR("Unknown GART type: %d\n", + dev_priv->gart_info.type); return -EINVAL; + } + + man->io_offset = dev_priv->gart_info.aper_base; + man->io_size = dev_priv->gart_info.aper_size; + man->io_addr = NULL; + break; + default: + DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + return -EINVAL; } return 0; } -uint32_t nouveau_evict_mask(struct drm_buffer_object *bo) +static uint32_t +nouveau_bo_evict_mask(struct drm_buffer_object *bo) { switch (bo->mem.mem_type) { - case DRM_BO_MEM_LOCAL: - case DRM_BO_MEM_TT: - return DRM_BO_FLAG_MEM_LOCAL; - case DRM_BO_MEM_VRAM: - if (bo->mem.num_pages > 128) - return DRM_BO_MEM_TT; - else - return DRM_BO_MEM_LOCAL; - default: - return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return DRM_BO_FLAG_MEM_LOCAL; + default: + return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; } + return 0; +} +/* GPU-assisted copy using NV_MEMORY_TO_MEMORY_FORMAT, can access + * DRM_BO_MEM_{VRAM,PRIV0,TT} directly. + */ +static int +nouveau_bo_move_m2mf(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_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_drm_channel *dchan = &dev_priv->channel; + struct drm_bo_mem_reg *old_mem = &bo->mem; + uint32_t srch, dsth, page_count; + + /* Can happen during init/takedown */ + if (!dchan->chan) + return -EINVAL; + + srch = old_mem->mem_type == DRM_BO_MEM_TT ? NvDmaTT : NvDmaFB; + dsth = new_mem->mem_type == DRM_BO_MEM_TT ? NvDmaTT : NvDmaFB; + if (srch != dchan->m2mf_dma_source || dsth != dchan->m2mf_dma_destin) { + dchan->m2mf_dma_source = srch; + dchan->m2mf_dma_destin = dsth; + + BEGIN_RING(NvSubM2MF, + NV_MEMORY_TO_MEMORY_FORMAT_SET_DMA_SOURCE, 2); + OUT_RING (dchan->m2mf_dma_source); + OUT_RING (dchan->m2mf_dma_destin); + } + + page_count = new_mem->num_pages; + while (page_count) { + int line_count = (page_count > 2047) ? 2047 : page_count; + + BEGIN_RING(NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); + OUT_RING (old_mem->mm_node->start << PAGE_SHIFT); + OUT_RING (new_mem->mm_node->start << PAGE_SHIFT); + OUT_RING (PAGE_SIZE); /* src_pitch */ + OUT_RING (PAGE_SIZE); /* dst_pitch */ + OUT_RING (PAGE_SIZE); /* line_length */ + OUT_RING (line_count); + OUT_RING ((1<<8)|(1<<0)); + OUT_RING (0); + BEGIN_RING(NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1); + OUT_RING (0); + + page_count -= line_count; + } + + return drm_bo_move_accel_cleanup(bo, evict, no_wait, dchan->chan->id, + DRM_FENCE_TYPE_EXE, 0, new_mem); } -int nouveau_move(struct drm_buffer_object *bo, - int evict, - int no_wait, - struct drm_bo_mem_reg *new_mem) +static int +nouveau_bo_move(struct drm_buffer_object *bo, int evict, int no_wait, + struct drm_bo_mem_reg *new_mem) { struct drm_bo_mem_reg *old_mem = &bo->mem; + if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { + if (old_mem->mem_type == DRM_BO_MEM_LOCAL) + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); +#if 0 + if (!nouveau_bo_move_flipd(bo, evict, no_wait, new_mem)) +#endif + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } + else if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); - else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); +#if 0 + if (nouveau_bo_move_flips(bo, evict, no_wait, new_mem)) +#endif + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); } else { - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); +// if (nouveau_bo_move_m2mf(bo, evict, no_wait, new_mem)) + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); } return 0; } -void nouveau_flush_ttm(struct drm_ttm *ttm) +static void +nouveau_bo_flush_ttm(struct drm_ttm *ttm) { - } -#endif +static uint32_t nouveau_mem_prios[] = { + DRM_BO_MEM_PRIV0, + DRM_BO_MEM_VRAM, + DRM_BO_MEM_TT, + DRM_BO_MEM_LOCAL +}; +static uint32_t nouveau_busy_prios[] = { + DRM_BO_MEM_TT, + DRM_BO_MEM_PRIV0, + DRM_BO_MEM_VRAM, + DRM_BO_MEM_LOCAL +}; + +struct drm_bo_driver nouveau_bo_driver = { + .mem_type_prio = nouveau_mem_prios, + .mem_busy_prio = nouveau_busy_prios, + .num_mem_type_prio = sizeof(nouveau_mem_prios)/sizeof(uint32_t), + .num_mem_busy_prio = sizeof(nouveau_busy_prios)/sizeof(uint32_t), + .create_ttm_backend_entry = nouveau_bo_create_ttm_backend_entry, + .fence_type = nouveau_bo_fence_type, + .invalidate_caches = nouveau_bo_invalidate_caches, + .init_mem_type = nouveau_bo_init_mem_type, + .evict_mask = nouveau_bo_evict_mask, + .move = nouveau_bo_move, + .ttm_cache_flush= nouveau_bo_flush_ttm +}; |