drm/vmwgfx: Hook up MOBs to TTM as a separate memory type

To bind a buffer object as a MOB, just validate it as a MOB
memory type. We are reusing the GMRID manager, although we create a new
instance of it to manage MOB ids and tomake sure we don't exceed
the maximum amount of MOB pages.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
This commit is contained in:
Thomas Hellstrom 2012-11-21 11:06:22 +01:00
parent 3530bdc35e
commit 6da768aa66
5 changed files with 136 additions and 13 deletions

View File

@ -51,6 +51,9 @@ static uint32_t gmr_ne_placement_flags = VMW_PL_FLAG_GMR |
TTM_PL_FLAG_CACHED | TTM_PL_FLAG_CACHED |
TTM_PL_FLAG_NO_EVICT; TTM_PL_FLAG_NO_EVICT;
static uint32_t mob_placement_flags = VMW_PL_FLAG_MOB |
TTM_PL_FLAG_CACHED;
struct ttm_placement vmw_vram_placement = { struct ttm_placement vmw_vram_placement = {
.fpfn = 0, .fpfn = 0,
.lpfn = 0, .lpfn = 0,
@ -132,13 +135,14 @@ struct ttm_placement vmw_sys_ne_placement = {
static uint32_t evictable_placement_flags[] = { static uint32_t evictable_placement_flags[] = {
TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED, TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED,
TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED,
VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED,
VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED
}; };
struct ttm_placement vmw_evictable_placement = { struct ttm_placement vmw_evictable_placement = {
.fpfn = 0, .fpfn = 0,
.lpfn = 0, .lpfn = 0,
.num_placement = 3, .num_placement = 4,
.placement = evictable_placement_flags, .placement = evictable_placement_flags,
.num_busy_placement = 1, .num_busy_placement = 1,
.busy_placement = &sys_placement_flags .busy_placement = &sys_placement_flags
@ -153,10 +157,21 @@ struct ttm_placement vmw_srf_placement = {
.busy_placement = gmr_vram_placement_flags .busy_placement = gmr_vram_placement_flags
}; };
struct ttm_placement vmw_mob_placement = {
.fpfn = 0,
.lpfn = 0,
.num_placement = 1,
.num_busy_placement = 1,
.placement = &mob_placement_flags,
.busy_placement = &mob_placement_flags
};
struct vmw_ttm_tt { struct vmw_ttm_tt {
struct ttm_dma_tt dma_ttm; struct ttm_dma_tt dma_ttm;
struct vmw_private *dev_priv; struct vmw_private *dev_priv;
int gmr_id; int gmr_id;
struct vmw_mob *mob;
int mem_type;
struct sg_table sgt; struct sg_table sgt;
struct vmw_sg_table vsgt; struct vmw_sg_table vsgt;
uint64_t sg_alloc_size; uint64_t sg_alloc_size;
@ -448,9 +463,27 @@ static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
return ret; return ret;
vmw_be->gmr_id = bo_mem->start; vmw_be->gmr_id = bo_mem->start;
vmw_be->mem_type = bo_mem->mem_type;
return vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt, switch (bo_mem->mem_type) {
ttm->num_pages, vmw_be->gmr_id); case VMW_PL_GMR:
return vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt,
ttm->num_pages, vmw_be->gmr_id);
case VMW_PL_MOB:
if (unlikely(vmw_be->mob == NULL)) {
vmw_be->mob =
vmw_mob_create(ttm->num_pages);
if (unlikely(vmw_be->mob == NULL))
return -ENOMEM;
}
return vmw_mob_bind(vmw_be->dev_priv, vmw_be->mob,
ttm->pages, ttm->num_pages,
vmw_be->gmr_id);
default:
BUG();
}
return 0;
} }
static int vmw_ttm_unbind(struct ttm_tt *ttm) static int vmw_ttm_unbind(struct ttm_tt *ttm)
@ -458,7 +491,16 @@ static int vmw_ttm_unbind(struct ttm_tt *ttm)
struct vmw_ttm_tt *vmw_be = struct vmw_ttm_tt *vmw_be =
container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm); container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id); switch (vmw_be->mem_type) {
case VMW_PL_GMR:
vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
break;
case VMW_PL_MOB:
vmw_mob_unbind(vmw_be->dev_priv, vmw_be->mob);
break;
default:
BUG();
}
if (vmw_be->dev_priv->map_mode == vmw_dma_map_bind) if (vmw_be->dev_priv->map_mode == vmw_dma_map_bind)
vmw_ttm_unmap_dma(vmw_be); vmw_ttm_unmap_dma(vmw_be);
@ -466,6 +508,7 @@ static int vmw_ttm_unbind(struct ttm_tt *ttm)
return 0; return 0;
} }
static void vmw_ttm_destroy(struct ttm_tt *ttm) static void vmw_ttm_destroy(struct ttm_tt *ttm)
{ {
struct vmw_ttm_tt *vmw_be = struct vmw_ttm_tt *vmw_be =
@ -476,6 +519,10 @@ static void vmw_ttm_destroy(struct ttm_tt *ttm)
ttm_dma_tt_fini(&vmw_be->dma_ttm); ttm_dma_tt_fini(&vmw_be->dma_ttm);
else else
ttm_tt_fini(ttm); ttm_tt_fini(ttm);
if (vmw_be->mob)
vmw_mob_destroy(vmw_be->mob);
kfree(vmw_be); kfree(vmw_be);
} }
@ -513,6 +560,12 @@ static void vmw_ttm_unpopulate(struct ttm_tt *ttm)
struct vmw_private *dev_priv = vmw_tt->dev_priv; struct vmw_private *dev_priv = vmw_tt->dev_priv;
struct ttm_mem_global *glob = vmw_mem_glob(dev_priv); struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
if (vmw_tt->mob) {
vmw_mob_destroy(vmw_tt->mob);
vmw_tt->mob = NULL;
}
vmw_ttm_unmap_dma(vmw_tt); vmw_ttm_unmap_dma(vmw_tt);
if (dev_priv->map_mode == vmw_dma_alloc_coherent) { if (dev_priv->map_mode == vmw_dma_alloc_coherent) {
size_t size = size_t size =
@ -543,6 +596,7 @@ static struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev,
vmw_be->dma_ttm.ttm.func = &vmw_ttm_func; vmw_be->dma_ttm.ttm.func = &vmw_ttm_func;
vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev); vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev);
vmw_be->mob = NULL;
if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent) if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent)
ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bdev, size, page_flags, ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bdev, size, page_flags,
@ -584,6 +638,7 @@ static int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
man->default_caching = TTM_PL_FLAG_CACHED; man->default_caching = TTM_PL_FLAG_CACHED;
break; break;
case VMW_PL_GMR: case VMW_PL_GMR:
case VMW_PL_MOB:
/* /*
* "Guest Memory Regions" is an aperture like feature with * "Guest Memory Regions" is an aperture like feature with
* one slot per bo. There is an upper limit of the number of * one slot per bo. There is an upper limit of the number of
@ -631,6 +686,7 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg
switch (mem->mem_type) { switch (mem->mem_type) {
case TTM_PL_SYSTEM: case TTM_PL_SYSTEM:
case VMW_PL_GMR: case VMW_PL_GMR:
case VMW_PL_MOB:
return 0; return 0;
case TTM_PL_VRAM: case TTM_PL_VRAM:
mem->bus.offset = mem->start << PAGE_SHIFT; mem->bus.offset = mem->start << PAGE_SHIFT;
@ -690,6 +746,38 @@ static int vmw_sync_obj_wait(void *sync_obj, bool lazy, bool interruptible)
VMW_FENCE_WAIT_TIMEOUT); VMW_FENCE_WAIT_TIMEOUT);
} }
/**
* vmw_move_notify - TTM move_notify_callback
*
* @bo: The TTM buffer object about to move.
* @mem: The truct ttm_mem_reg indicating to what memory
* region the move is taking place.
*
* Calls move_notify for all subsystems needing it.
* (currently only resources).
*/
static void vmw_move_notify(struct ttm_buffer_object *bo,
struct ttm_mem_reg *mem)
{
vmw_resource_move_notify(bo, mem);
}
/**
* vmw_swap_notify - TTM move_notify_callback
*
* @bo: The TTM buffer object about to be swapped out.
*/
static void vmw_swap_notify(struct ttm_buffer_object *bo)
{
struct ttm_bo_device *bdev = bo->bdev;
spin_lock(&bdev->fence_lock);
ttm_bo_wait(bo, false, false, false);
spin_unlock(&bdev->fence_lock);
}
struct ttm_bo_driver vmw_bo_driver = { struct ttm_bo_driver vmw_bo_driver = {
.ttm_tt_create = &vmw_ttm_tt_create, .ttm_tt_create = &vmw_ttm_tt_create,
.ttm_tt_populate = &vmw_ttm_populate, .ttm_tt_populate = &vmw_ttm_populate,
@ -704,8 +792,8 @@ struct ttm_bo_driver vmw_bo_driver = {
.sync_obj_flush = vmw_sync_obj_flush, .sync_obj_flush = vmw_sync_obj_flush,
.sync_obj_unref = vmw_sync_obj_unref, .sync_obj_unref = vmw_sync_obj_unref,
.sync_obj_ref = vmw_sync_obj_ref, .sync_obj_ref = vmw_sync_obj_ref,
.move_notify = NULL, .move_notify = vmw_move_notify,
.swap_notify = NULL, .swap_notify = vmw_swap_notify,
.fault_reserve_notify = &vmw_ttm_fault_reserve_notify, .fault_reserve_notify = &vmw_ttm_fault_reserve_notify,
.io_mem_reserve = &vmw_ttm_io_mem_reserve, .io_mem_reserve = &vmw_ttm_io_mem_reserve,
.io_mem_free = &vmw_ttm_io_mem_free, .io_mem_free = &vmw_ttm_io_mem_free,

View File

@ -304,9 +304,11 @@ void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin)
lockdep_assert_held(&bo->resv->lock.base); lockdep_assert_held(&bo->resv->lock.base);
BUG_ON(old_mem_type != TTM_PL_VRAM && BUG_ON(old_mem_type != TTM_PL_VRAM &&
old_mem_type != VMW_PL_GMR); old_mem_type != VMW_PL_GMR &&
old_mem_type != VMW_PL_MOB);
pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED; pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB
| TTM_PL_FLAG_CACHED;
if (pin) if (pin)
pl_flags |= TTM_PL_FLAG_NO_EVICT; pl_flags |= TTM_PL_FLAG_NO_EVICT;

View File

@ -643,6 +643,14 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
*/ */
dev_priv->memory_size = 512*1024*1024; dev_priv->memory_size = 512*1024*1024;
} }
dev_priv->max_mob_pages = 0;
if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
uint64_t mem_size =
vmw_read(dev_priv,
SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB);
dev_priv->max_mob_pages = mem_size * 1024 / PAGE_SIZE;
}
ret = vmw_dma_masks(dev_priv); ret = vmw_dma_masks(dev_priv);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
@ -698,14 +706,21 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->has_gmr = true; dev_priv->has_gmr = true;
if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) ||
refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR, refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
dev_priv->max_gmr_ids) != 0) { VMW_PL_GMR) != 0) {
DRM_INFO("No GMR memory available. " DRM_INFO("No GMR memory available. "
"Graphics memory resources are very limited.\n"); "Graphics memory resources are very limited.\n");
dev_priv->has_gmr = false; dev_priv->has_gmr = false;
} }
if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
dev_priv->has_mob = true; dev_priv->has_mob = true;
if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB,
VMW_PL_MOB) != 0) {
DRM_INFO("No MOB memory available. "
"3D will be disabled.\n");
dev_priv->has_mob = false;
}
}
dev_priv->mmio_mtrr = arch_phys_wc_add(dev_priv->mmio_start, dev_priv->mmio_mtrr = arch_phys_wc_add(dev_priv->mmio_start,
dev_priv->mmio_size); dev_priv->mmio_size);
@ -809,6 +824,8 @@ out_err4:
iounmap(dev_priv->mmio_virt); iounmap(dev_priv->mmio_virt);
out_err3: out_err3:
arch_phys_wc_del(dev_priv->mmio_mtrr); arch_phys_wc_del(dev_priv->mmio_mtrr);
if (dev_priv->has_mob)
(void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
if (dev_priv->has_gmr) if (dev_priv->has_gmr)
(void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
(void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
@ -853,6 +870,8 @@ static int vmw_driver_unload(struct drm_device *dev)
ttm_object_device_release(&dev_priv->tdev); ttm_object_device_release(&dev_priv->tdev);
iounmap(dev_priv->mmio_virt); iounmap(dev_priv->mmio_virt);
arch_phys_wc_del(dev_priv->mmio_mtrr); arch_phys_wc_del(dev_priv->mmio_mtrr);
if (dev_priv->has_mob)
(void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
if (dev_priv->has_gmr) if (dev_priv->has_gmr)
(void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
(void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);

View File

@ -63,6 +63,8 @@
#define VMW_PL_GMR TTM_PL_PRIV0 #define VMW_PL_GMR TTM_PL_PRIV0
#define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0 #define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0
#define VMW_PL_MOB TTM_PL_PRIV1
#define VMW_PL_FLAG_MOB TTM_PL_FLAG_PRIV1
#define VMW_RES_CONTEXT ttm_driver_type0 #define VMW_RES_CONTEXT ttm_driver_type0
#define VMW_RES_SURFACE ttm_driver_type1 #define VMW_RES_SURFACE ttm_driver_type1
@ -303,6 +305,7 @@ struct vmw_private {
uint32_t capabilities; uint32_t capabilities;
uint32_t max_gmr_ids; uint32_t max_gmr_ids;
uint32_t max_gmr_pages; uint32_t max_gmr_pages;
uint32_t max_mob_pages;
uint32_t memory_size; uint32_t memory_size;
bool has_gmr; bool has_gmr;
bool has_mob; bool has_mob;

View File

@ -125,10 +125,21 @@ static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
return -ENOMEM; return -ENOMEM;
spin_lock_init(&gman->lock); spin_lock_init(&gman->lock);
gman->max_gmr_pages = dev_priv->max_gmr_pages;
gman->used_gmr_pages = 0; gman->used_gmr_pages = 0;
ida_init(&gman->gmr_ida); ida_init(&gman->gmr_ida);
gman->max_gmr_ids = p_size;
switch (p_size) {
case VMW_PL_GMR:
gman->max_gmr_ids = dev_priv->max_gmr_ids;
gman->max_gmr_pages = dev_priv->max_gmr_pages;
break;
case VMW_PL_MOB:
gman->max_gmr_ids = VMWGFX_NUM_MOB;
gman->max_gmr_pages = dev_priv->max_mob_pages;
break;
default:
BUG();
}
man->priv = (void *) gman; man->priv = (void *) gman;
return 0; return 0;
} }