Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 135cba0d authored by Thomas Hellstrom's avatar Thomas Hellstrom Committed by Dave Airlie
Browse files

vmwgfx: Implement a proper GMR eviction mechanism



Use Ben's new range manager hooks to implement a manager for
GMRs that manages ids rather than ranges.
This means we can use the standard TTM code for binding, unbinding and
eviction.

Signed-off-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 8f895da5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -4,6 +4,6 @@ ccflags-y := -Iinclude/drm
vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
	    vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \
	    vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
	    vmwgfx_overlay.o vmwgfx_fence.o
	    vmwgfx_overlay.o vmwgfx_fence.o vmwgfx_gmrid_manager.o

obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
+62 −19
Original line number Diff line number Diff line
@@ -39,6 +39,9 @@ static uint32_t vram_ne_placement_flags = TTM_PL_FLAG_VRAM |
static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM |
	TTM_PL_FLAG_CACHED;

static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR |
	TTM_PL_FLAG_CACHED;

struct ttm_placement vmw_vram_placement = {
	.fpfn = 0,
	.lpfn = 0,
@@ -48,6 +51,20 @@ struct ttm_placement vmw_vram_placement = {
	.busy_placement = &vram_placement_flags
};

static uint32_t vram_gmr_placement_flags[] = {
	TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED,
	VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
};

struct ttm_placement vmw_vram_gmr_placement = {
	.fpfn = 0,
	.lpfn = 0,
	.num_placement = 2,
	.placement = vram_gmr_placement_flags,
	.num_busy_placement = 1,
	.busy_placement = &gmr_placement_flags
};

struct ttm_placement vmw_vram_sys_placement = {
	.fpfn = 0,
	.lpfn = 0,
@@ -77,27 +94,52 @@ struct ttm_placement vmw_sys_placement = {

struct vmw_ttm_backend {
	struct ttm_backend backend;
	struct page **pages;
	unsigned long num_pages;
	struct vmw_private *dev_priv;
	int gmr_id;
};

static int vmw_ttm_populate(struct ttm_backend *backend,
			    unsigned long num_pages, struct page **pages,
			    struct page *dummy_read_page)
{
	struct vmw_ttm_backend *vmw_be =
	    container_of(backend, struct vmw_ttm_backend, backend);

	vmw_be->pages = pages;
	vmw_be->num_pages = num_pages;

	return 0;
}

static int vmw_ttm_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem)
{
	return 0;
	struct vmw_ttm_backend *vmw_be =
	    container_of(backend, struct vmw_ttm_backend, backend);

	vmw_be->gmr_id = bo_mem->start;

	return vmw_gmr_bind(vmw_be->dev_priv, vmw_be->pages,
			    vmw_be->num_pages, vmw_be->gmr_id);
}

static int vmw_ttm_unbind(struct ttm_backend *backend)
{
	struct vmw_ttm_backend *vmw_be =
	    container_of(backend, struct vmw_ttm_backend, backend);

	vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
	return 0;
}

static void vmw_ttm_clear(struct ttm_backend *backend)
{
	struct vmw_ttm_backend *vmw_be =
		container_of(backend, struct vmw_ttm_backend, backend);

	vmw_be->pages = NULL;
	vmw_be->num_pages = 0;
}

static void vmw_ttm_destroy(struct ttm_backend *backend)
@@ -125,6 +167,7 @@ struct ttm_backend *vmw_ttm_backend_init(struct ttm_bo_device *bdev)
		return NULL;

	vmw_be->backend.func = &vmw_ttm_func;
	vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev);

	return &vmw_be->backend;
}
@@ -142,7 +185,7 @@ int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
		/* System memory */

		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
		man->available_caching = TTM_PL_MASK_CACHING;
		man->available_caching = TTM_PL_FLAG_CACHED;
		man->default_caching = TTM_PL_FLAG_CACHED;
		break;
	case TTM_PL_VRAM:
@@ -150,8 +193,20 @@ int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
		man->func = &ttm_bo_manager_func;
		man->gpu_offset = 0;
		man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE;
		man->available_caching = TTM_PL_MASK_CACHING;
		man->default_caching = TTM_PL_FLAG_WC;
		man->available_caching = TTM_PL_FLAG_CACHED;
		man->default_caching = TTM_PL_FLAG_CACHED;
		break;
	case VMW_PL_GMR:
		/*
		 * "Guest Memory Regions" is an aperture like feature with
		 *  one slot per bo. There is an upper limit of the number of
		 *  slots as well as the bo size.
		 */
		man->func = &vmw_gmrid_manager_func;
		man->gpu_offset = 0;
		man->flags = TTM_MEMTYPE_FLAG_CMA | TTM_MEMTYPE_FLAG_MAPPABLE;
		man->available_caching = TTM_PL_FLAG_CACHED;
		man->default_caching = TTM_PL_FLAG_CACHED;
		break;
	default:
		DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
@@ -175,18 +230,6 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp)
	return 0;
}

static void vmw_move_notify(struct ttm_buffer_object *bo,
		     struct ttm_mem_reg *new_mem)
{
	if (new_mem->mem_type != TTM_PL_SYSTEM)
		vmw_dmabuf_gmr_unbind(bo);
}

static void vmw_swap_notify(struct ttm_buffer_object *bo)
{
	vmw_dmabuf_gmr_unbind(bo);
}

static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
{
	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
@@ -201,7 +244,7 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg
		return -EINVAL;
	switch (mem->mem_type) {
	case TTM_PL_SYSTEM:
		/* System memory */
	case VMW_PL_GMR:
		return 0;
	case TTM_PL_VRAM:
		mem->bus.offset = mem->start << PAGE_SHIFT;
@@ -277,8 +320,8 @@ struct ttm_bo_driver vmw_bo_driver = {
	.sync_obj_flush = vmw_sync_obj_flush,
	.sync_obj_unref = vmw_sync_obj_unref,
	.sync_obj_ref = vmw_sync_obj_ref,
	.move_notify = vmw_move_notify,
	.swap_notify = vmw_swap_notify,
	.move_notify = NULL,
	.swap_notify = NULL,
	.fault_reserve_notify = &vmw_ttm_fault_reserve_notify,
	.io_mem_reserve = &vmw_ttm_io_mem_reserve,
	.io_mem_free = &vmw_ttm_io_mem_free,
+12 −4
Original line number Diff line number Diff line
@@ -260,13 +260,11 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
	idr_init(&dev_priv->context_idr);
	idr_init(&dev_priv->surface_idr);
	idr_init(&dev_priv->stream_idr);
	ida_init(&dev_priv->gmr_ida);
	mutex_init(&dev_priv->init_mutex);
	init_waitqueue_head(&dev_priv->fence_queue);
	init_waitqueue_head(&dev_priv->fifo_queue);
	atomic_set(&dev_priv->fence_queue_waiters, 0);
	atomic_set(&dev_priv->fifo_queue_waiters, 0);
	INIT_LIST_HEAD(&dev_priv->gmr_lru);

	dev_priv->io_start = pci_resource_start(dev->pdev, 0);
	dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
@@ -341,6 +339,14 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
		goto out_err2;
	}

	dev_priv->has_gmr = true;
	if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
			   dev_priv->max_gmr_ids) != 0) {
		DRM_INFO("No GMR memory available. "
			 "Graphics memory resources are very limited.\n");
		dev_priv->has_gmr = false;
	}

	dev_priv->mmio_mtrr = drm_mtrr_add(dev_priv->mmio_start,
					   dev_priv->mmio_size, DRM_MTRR_WC);

@@ -440,13 +446,14 @@ out_err4:
out_err3:
	drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
		     dev_priv->mmio_size, DRM_MTRR_WC);
	if (dev_priv->has_gmr)
		(void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
	(void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
out_err2:
	(void)ttm_bo_device_release(&dev_priv->bdev);
out_err1:
	vmw_ttm_global_release(dev_priv);
out_err0:
	ida_destroy(&dev_priv->gmr_ida);
	idr_destroy(&dev_priv->surface_idr);
	idr_destroy(&dev_priv->context_idr);
	idr_destroy(&dev_priv->stream_idr);
@@ -478,10 +485,11 @@ static int vmw_driver_unload(struct drm_device *dev)
	iounmap(dev_priv->mmio_virt);
	drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
		     dev_priv->mmio_size, DRM_MTRR_WC);
	if (dev_priv->has_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_device_release(&dev_priv->bdev);
	vmw_ttm_global_release(dev_priv);
	ida_destroy(&dev_priv->gmr_ida);
	idr_destroy(&dev_priv->surface_idr);
	idr_destroy(&dev_priv->context_idr);
	idr_destroy(&dev_priv->stream_idr);
+14 −15
Original line number Diff line number Diff line
@@ -49,6 +49,9 @@
#define VMWGFX_MAX_GMRS 2048
#define VMWGFX_MAX_DISPLAYS 16

#define VMW_PL_GMR TTM_PL_PRIV0
#define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0

struct vmw_fpriv {
	struct drm_master *locked_master;
	struct ttm_object_file *tfile;
@@ -57,8 +60,6 @@ struct vmw_fpriv {
struct vmw_dma_buffer {
	struct ttm_buffer_object base;
	struct list_head validate_list;
	struct list_head gmr_lru;
	uint32_t gmr_id;
	bool gmr_bound;
	uint32_t cur_validate_node;
	bool on_validate_list;
@@ -184,6 +185,7 @@ struct vmw_private {
	uint32_t capabilities;
	uint32_t max_gmr_descriptors;
	uint32_t max_gmr_ids;
	bool has_gmr;
	struct mutex hw_mutex;

	/*
@@ -265,14 +267,6 @@ struct vmw_private {
	uint32_t val_seq;
	struct mutex cmdbuf_mutex;

	/**
	 * GMR management. Protected by the lru spinlock.
	 */

	struct ida gmr_ida;
	struct list_head gmr_lru;


	/**
	 * Operating mode.
	 */
@@ -334,7 +328,9 @@ void vmw_3d_resource_dec(struct vmw_private *dev_priv);
 */

extern int vmw_gmr_bind(struct vmw_private *dev_priv,
			struct ttm_buffer_object *bo);
			struct page *pages[],
			unsigned long num_pages,
			int gmr_id);
extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);

/**
@@ -383,14 +379,10 @@ extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo);
extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
				  uint32_t id, struct vmw_dma_buffer **out);
extern uint32_t vmw_dmabuf_gmr(struct ttm_buffer_object *bo);
extern void vmw_dmabuf_set_gmr(struct ttm_buffer_object *bo, uint32_t id);
extern int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id);
extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
				       struct vmw_dma_buffer *bo);
extern int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
				struct vmw_dma_buffer *bo);
extern void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo);
extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
				  struct drm_file *file_priv);
extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
@@ -442,6 +434,7 @@ extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma);
extern struct ttm_placement vmw_vram_placement;
extern struct ttm_placement vmw_vram_ne_placement;
extern struct ttm_placement vmw_vram_sys_placement;
extern struct ttm_placement vmw_vram_gmr_placement;
extern struct ttm_placement vmw_sys_placement;
extern struct ttm_bo_driver vmw_bo_driver;
extern int vmw_dma_quiescent(struct drm_device *dev);
@@ -543,6 +536,12 @@ int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id);
int vmw_overlay_num_overlays(struct vmw_private *dev_priv);
int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv);

/**
 * GMR Id manager
 */

extern const struct ttm_mem_type_manager_func vmw_gmrid_manager_func;

/**
 * Inline helper functions
 */
+11 −18
Original line number Diff line number Diff line
@@ -538,8 +538,11 @@ static void vmw_apply_relocations(struct vmw_sw_context *sw_context)
		reloc = &sw_context->relocs[i];
		validate = &sw_context->val_bufs[reloc->index];
		bo = validate->bo;
		if (bo->mem.mem_type == TTM_PL_VRAM) {
			reloc->location->offset += bo->offset;
		reloc->location->gmrId = vmw_dmabuf_gmr(bo);
			reloc->location->gmrId = SVGA_GMR_FRAMEBUFFER;
		} else
			reloc->location->gmrId = bo->mem.start;
	}
	vmw_free_relocations(sw_context);
}
@@ -563,25 +566,14 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
{
	int ret;

	if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
		return 0;

	/**
	 * Put BO in VRAM, only if there is space.
	 */

	ret = ttm_bo_validate(bo, &vmw_vram_sys_placement, true, false, false);
	if (unlikely(ret == -ERESTARTSYS))
		return ret;

	/**
	 * Otherwise, set it up as GMR.
	 * Put BO in VRAM if there is space, otherwise as a GMR.
	 * If there is no space in VRAM and GMR ids are all used up,
	 * start evicting GMRs to make room. If the DMA buffer can't be
	 * used as a GMR, this will return -ENOMEM.
	 */

	if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
		return 0;

	ret = vmw_gmr_bind(dev_priv, bo);
	ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, true, false, false);
	if (likely(ret == 0 || ret == -ERESTARTSYS))
		return ret;

@@ -590,6 +582,7 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
	 * previous contents.
	 */

	DRM_INFO("Falling through to VRAM.\n");
	ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false, false);
	return ret;
}
Loading