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

Commit d991ef03 authored by Jakob Bornecrantz's avatar Jakob Bornecrantz Committed by Dave Airlie
Browse files

vmwgfx: Add dmabuf helper functions for pinning

parent 626ab771
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -5,6 +5,6 @@ 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_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_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
	    vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \
	    vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \
	    vmwgfx_fence.o
	    vmwgfx_fence.o vmwgfx_dmabuf.o


obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
+33 −0
Original line number Original line Diff line number Diff line
@@ -42,6 +42,10 @@ static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM |
static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR |
static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR |
	TTM_PL_FLAG_CACHED;
	TTM_PL_FLAG_CACHED;


static uint32_t gmr_ne_placement_flags = VMW_PL_FLAG_GMR |
	TTM_PL_FLAG_CACHED |
	TTM_PL_FLAG_NO_EVICT;

struct ttm_placement vmw_vram_placement = {
struct ttm_placement vmw_vram_placement = {
	.fpfn = 0,
	.fpfn = 0,
	.lpfn = 0,
	.lpfn = 0,
@@ -65,6 +69,20 @@ struct ttm_placement vmw_vram_gmr_placement = {
	.busy_placement = &gmr_placement_flags
	.busy_placement = &gmr_placement_flags
};
};


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

struct ttm_placement vmw_vram_gmr_ne_placement = {
	.fpfn = 0,
	.lpfn = 0,
	.num_placement = 2,
	.placement = vram_gmr_ne_placement_flags,
	.num_busy_placement = 1,
	.busy_placement = &gmr_ne_placement_flags
};

struct ttm_placement vmw_vram_sys_placement = {
struct ttm_placement vmw_vram_sys_placement = {
	.fpfn = 0,
	.fpfn = 0,
	.lpfn = 0,
	.lpfn = 0,
@@ -92,6 +110,21 @@ struct ttm_placement vmw_sys_placement = {
	.busy_placement = &sys_placement_flags
	.busy_placement = &sys_placement_flags
};
};


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

struct ttm_placement vmw_evictable_placement = {
	.fpfn = 0,
	.lpfn = 0,
	.num_placement = 3,
	.placement = evictable_placement_flags,
	.num_busy_placement = 1,
	.busy_placement = &sys_placement_flags
};

struct vmw_ttm_backend {
struct vmw_ttm_backend {
	struct ttm_backend backend;
	struct ttm_backend backend;
	struct page **pages;
	struct page **pages;
+292 −0
Original line number Original line Diff line number Diff line
/**************************************************************************
 *
 * Copyright © 2011 VMware, Inc., Palo Alto, CA., 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.
 *
 **************************************************************************/

#include "ttm/ttm_placement.h"

#include "drmP.h"
#include "vmwgfx_drv.h"


/**
 * Validate a buffer to placement.
 *
 * May only be called by the current master as this function takes the
 * its lock in write mode.
 *
 * Returns
 *  -ERESTARTSYS if interrupted by a signal.
 */
int vmw_dmabuf_to_placement(struct vmw_private *dev_priv,
			    struct vmw_dma_buffer *buf,
			    struct ttm_placement *placement,
			    bool interruptible)
{
	struct vmw_master *vmaster = dev_priv->active_master;
	struct ttm_buffer_object *bo = &buf->base;
	int ret;

	ret = ttm_write_lock(&vmaster->lock, interruptible);
	if (unlikely(ret != 0))
		return ret;

	ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
	if (unlikely(ret != 0))
		goto err;

	ret = ttm_bo_validate(bo, placement, interruptible, false, false);

	ttm_bo_unreserve(bo);

err:
	ttm_write_unlock(&vmaster->lock);
	return ret;
}

/**
 * Move a buffer to vram or gmr.
 *
 * May only be called by the current master as this function takes the
 * its lock in write mode.
 *
 * @dev_priv:  Driver private.
 * @buf:  DMA buffer to move.
 * @pin:  Pin buffer if true.
 * @interruptible:  Use interruptible wait.
 *
 * Returns
 * -ERESTARTSYS if interrupted by a signal.
 */
int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv,
			      struct vmw_dma_buffer *buf,
			      bool pin, bool interruptible)
{
	struct vmw_master *vmaster = dev_priv->active_master;
	struct ttm_buffer_object *bo = &buf->base;
	struct ttm_placement *placement;
	int ret;

	ret = ttm_write_lock(&vmaster->lock, interruptible);
	if (unlikely(ret != 0))
		return ret;

	ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
	if (unlikely(ret != 0))
		goto err;

	/**
	 * 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 (pin)
		placement = &vmw_vram_gmr_ne_placement;
	else
		placement = &vmw_vram_gmr_placement;

	ret = ttm_bo_validate(bo, placement, interruptible, false, false);
	if (likely(ret == 0) || ret == -ERESTARTSYS)
		goto err_unreserve;


	/**
	 * If that failed, try VRAM again, this time evicting
	 * previous contents.
	 */

	if (pin)
		placement = &vmw_vram_ne_placement;
	else
		placement = &vmw_vram_placement;

	ret = ttm_bo_validate(bo, placement, interruptible, false, false);

err_unreserve:
	ttm_bo_unreserve(bo);
err:
	ttm_write_unlock(&vmaster->lock);
	return ret;
}

/**
 * Move a buffer to vram.
 *
 * May only be called by the current master as this function takes the
 * its lock in write mode.
 *
 * @dev_priv:  Driver private.
 * @buf:  DMA buffer to move.
 * @pin:  Pin buffer in vram if true.
 * @interruptible:  Use interruptible wait.
 *
 * Returns
 * -ERESTARTSYS if interrupted by a signal.
 */
int vmw_dmabuf_to_vram(struct vmw_private *dev_priv,
		       struct vmw_dma_buffer *buf,
		       bool pin, bool interruptible)
{
	struct ttm_placement *placement;

	if (pin)
		placement = &vmw_vram_ne_placement;
	else
		placement = &vmw_vram_placement;

	return vmw_dmabuf_to_placement(dev_priv, buf,
				       placement,
				       interruptible);
}

/**
 * Move a buffer to start of vram.
 *
 * May only be called by the current master as this function takes the
 * its lock in write mode.
 *
 * @dev_priv:  Driver private.
 * @buf:  DMA buffer to move.
 * @pin:  Pin buffer in vram if true.
 * @interruptible:  Use interruptible wait.
 *
 * Returns
 * -ERESTARTSYS if interrupted by a signal.
 */
int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv,
				struct vmw_dma_buffer *buf,
				bool pin, bool interruptible)
{
	struct vmw_master *vmaster = dev_priv->active_master;
	struct ttm_buffer_object *bo = &buf->base;
	struct ttm_placement placement;
	int ret = 0;

	if (pin)
		placement = vmw_vram_ne_placement;
	else
		placement = vmw_vram_placement;
	placement.lpfn = bo->num_pages;

	ret = ttm_write_lock(&vmaster->lock, interruptible);
	if (unlikely(ret != 0))
		return ret;

	ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
	if (unlikely(ret != 0))
		goto err_unlock;

	/* Is this buffer already in vram but not at the start of it? */
	if (bo->mem.mem_type == TTM_PL_VRAM &&
	    bo->mem.start < bo->num_pages &&
	    bo->mem.start > 0)
		(void) ttm_bo_validate(bo, &vmw_sys_placement, false,
				       false, false);

	ret = ttm_bo_validate(bo, &placement, interruptible, false, false);

	/* For some reason we didn't up at the start of vram */
	WARN_ON(ret == 0 && bo->offset != 0);

	ttm_bo_unreserve(bo);
err_unlock:
	ttm_write_unlock(&vmaster->lock);

	return ret;
}

/**
 * Unpin the buffer given buffer, does not move the buffer.
 *
 * May only be called by the current master as this function takes the
 * its lock in write mode.
 *
 * @dev_priv:  Driver private.
 * @buf:  DMA buffer to unpin.
 * @interruptible:  Use interruptible wait.
 *
 * Returns
 * -ERESTARTSYS if interrupted by a signal.
 */
int vmw_dmabuf_unpin(struct vmw_private *dev_priv,
		     struct vmw_dma_buffer *buf,
		     bool interruptible)
{
	/*
	 * We could in theory early out if the buffer is
	 * unpinned but we need to lock and reserve the buffer
	 * anyways so we don't gain much by that.
	 */
	return vmw_dmabuf_to_placement(dev_priv, buf,
				       &vmw_evictable_placement,
				       interruptible);
}

/**
 * Move a buffer to system memory, does not pin the buffer.
 *
 * May only be called by the current master as this function takes the
 * its lock in write mode.
 *
 * @dev_priv:  Driver private.
 * @buf:  DMA buffer to move.
 * @interruptible:  Use interruptible wait.
 *
 * Returns
 * -ERESTARTSYS if interrupted by a signal.
 */
int vmw_dmabuf_to_system(struct vmw_private *dev_priv,
			 struct vmw_dma_buffer *buf,
			 bool interruptible)
{
	return vmw_dmabuf_to_placement(dev_priv, buf,
				       &vmw_sys_placement,
				       interruptible);
}

void vmw_dmabuf_get_id_offset(struct vmw_dma_buffer *buf,
			      uint32_t *gmrId, uint32_t *offset)
{
	if (buf->base.mem.mem_type == TTM_PL_VRAM) {
		*gmrId = SVGA_GMR_FRAMEBUFFER;
		*offset = buf->base.offset;
	} else {
		*gmrId = buf->base.mem.start;
		*offset = 0;
	}
}

void vmw_dmabuf_get_guest_ptr(struct vmw_dma_buffer *buf, SVGAGuestPtr *ptr)
{
	if (buf->base.mem.mem_type == TTM_PL_VRAM) {
		ptr->gmrId = SVGA_GMR_FRAMEBUFFER;
		ptr->offset = buf->base.offset;
	} else {
		ptr->gmrId = buf->base.mem.start;
		ptr->offset = 0;
	}
}
+28 −4
Original line number Original line Diff line number Diff line
@@ -385,10 +385,6 @@ extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
extern void vmw_dmabuf_validate_clear(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,
extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
				  uint32_t id, struct vmw_dma_buffer **out);
				  uint32_t id, struct vmw_dma_buffer **out);
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 int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
				  struct drm_file *file_priv);
				  struct drm_file *file_priv);
extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
@@ -398,6 +394,32 @@ extern int vmw_user_stream_lookup(struct vmw_private *dev_priv,
				  uint32_t *inout_id,
				  uint32_t *inout_id,
				  struct vmw_resource **out);
				  struct vmw_resource **out);


/**
 * DMA buffer helper routines - vmwgfx_dmabuf.c
 */
extern int vmw_dmabuf_to_placement(struct vmw_private *vmw_priv,
				   struct vmw_dma_buffer *bo,
				   struct ttm_placement *placement,
				   bool interruptible);
extern int vmw_dmabuf_to_vram(struct vmw_private *dev_priv,
			      struct vmw_dma_buffer *buf,
			      bool pin, bool interruptible);
extern int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv,
				     struct vmw_dma_buffer *buf,
				     bool pin, bool interruptible);
extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
				       struct vmw_dma_buffer *bo,
				       bool pin, bool interruptible);
extern int vmw_dmabuf_unpin(struct vmw_private *vmw_priv,
			    struct vmw_dma_buffer *bo,
			    bool interruptible);
extern int vmw_dmabuf_to_system(struct vmw_private *vmw_priv,
				struct vmw_dma_buffer *bo,
				bool interruptible);
extern void vmw_dmabuf_get_id_offset(struct vmw_dma_buffer *buf,
				     uint32_t *gmrId, uint32_t *offset);
extern void vmw_dmabuf_get_guest_ptr(struct vmw_dma_buffer *buf,
				     SVGAGuestPtr *ptr);


/**
/**
 * Misc Ioctl functionality - vmwgfx_ioctl.c
 * Misc Ioctl functionality - vmwgfx_ioctl.c
@@ -440,7 +462,9 @@ extern struct ttm_placement vmw_vram_placement;
extern struct ttm_placement vmw_vram_ne_placement;
extern struct ttm_placement vmw_vram_ne_placement;
extern struct ttm_placement vmw_vram_sys_placement;
extern struct ttm_placement vmw_vram_sys_placement;
extern struct ttm_placement vmw_vram_gmr_placement;
extern struct ttm_placement vmw_vram_gmr_placement;
extern struct ttm_placement vmw_vram_gmr_ne_placement;
extern struct ttm_placement vmw_sys_placement;
extern struct ttm_placement vmw_sys_placement;
extern struct ttm_placement vmw_evictable_placement;
extern struct ttm_bo_driver vmw_bo_driver;
extern struct ttm_bo_driver vmw_bo_driver;
extern int vmw_dma_quiescent(struct drm_device *dev);
extern int vmw_dma_quiescent(struct drm_device *dev);


+3 −54
Original line number Original line Diff line number Diff line
@@ -592,58 +592,6 @@ int vmw_fb_close(struct vmw_private *vmw_priv)
	return 0;
	return 0;
}
}


int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
			 struct vmw_dma_buffer *vmw_bo)
{
	struct ttm_buffer_object *bo = &vmw_bo->base;
	int ret = 0;

	ret = ttm_bo_reserve(bo, false, false, false, 0);
	if (unlikely(ret != 0))
		return ret;

	ret = ttm_bo_validate(bo, &vmw_sys_placement, false, false, false);
	ttm_bo_unreserve(bo);

	return ret;
}

int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
				struct vmw_dma_buffer *vmw_bo)
{
	struct ttm_buffer_object *bo = &vmw_bo->base;
	struct ttm_placement ne_placement = vmw_vram_ne_placement;
	int ret = 0;

	ne_placement.lpfn = bo->num_pages;

	/* interuptable? */
	ret = ttm_write_lock(&vmw_priv->active_master->lock, false);
	if (unlikely(ret != 0))
		return ret;

	ret = ttm_bo_reserve(bo, false, false, false, 0);
	if (unlikely(ret != 0))
		goto err_unlock;

	if (bo->mem.mem_type == TTM_PL_VRAM &&
	    bo->mem.start < bo->num_pages &&
	    bo->mem.start > 0)
		(void) ttm_bo_validate(bo, &vmw_sys_placement, false,
				       false, false);

	ret = ttm_bo_validate(bo, &ne_placement, false, false, false);

	/* Could probably bug on */
	WARN_ON(bo->offset != 0);

	ttm_bo_unreserve(bo);
err_unlock:
	ttm_write_unlock(&vmw_priv->active_master->lock);

	return ret;
}

int vmw_fb_off(struct vmw_private *vmw_priv)
int vmw_fb_off(struct vmw_private *vmw_priv)
{
{
	struct fb_info *info;
	struct fb_info *info;
@@ -665,7 +613,8 @@ int vmw_fb_off(struct vmw_private *vmw_priv)
	par->bo_ptr = NULL;
	par->bo_ptr = NULL;
	ttm_bo_kunmap(&par->map);
	ttm_bo_kunmap(&par->map);


	vmw_dmabuf_from_vram(vmw_priv, par->vmw_bo);
	/* move this to system instead of just unpinning it */
	vmw_dmabuf_to_system(vmw_priv, par->vmw_bo, false);


	return 0;
	return 0;
}
}
@@ -691,7 +640,7 @@ int vmw_fb_on(struct vmw_private *vmw_priv)
	/* Make sure that all overlays are stoped when we take over */
	/* Make sure that all overlays are stoped when we take over */
	vmw_overlay_stop_all(vmw_priv);
	vmw_overlay_stop_all(vmw_priv);


	ret = vmw_dmabuf_to_start_of_vram(vmw_priv, par->vmw_bo);
	ret = vmw_dmabuf_to_start_of_vram(vmw_priv, par->vmw_bo, true, false);
	if (unlikely(ret != 0)) {
	if (unlikely(ret != 0)) {
		DRM_ERROR("could not move buffer to start of VRAM\n");
		DRM_ERROR("could not move buffer to start of VRAM\n");
		goto err_no_buffer;
		goto err_no_buffer;
Loading