diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c')
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 216 | 
1 files changed, 104 insertions, 112 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index f1a52f9e729..87e39f68e9d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -26,15 +26,16 @@   **************************************************************************/ -#include "drmP.h" +#include <drm/drmP.h>  #include "vmwgfx_drv.h" -#include "ttm/ttm_placement.h" +#include <drm/ttm/ttm_placement.h>  #include "svga_overlay.h"  #include "svga_escape.h"  #define VMW_MAX_NUM_STREAMS 1 +#define VMW_OVERLAY_CAP_MASK (SVGA_FIFO_CAP_VIDEO | SVGA_FIFO_CAP_ESCAPE)  struct vmw_stream {  	struct vmw_dma_buffer *buf; @@ -87,48 +88,6 @@ static inline void fill_flush(struct vmw_escape_video_flush *cmd,  }  /** - * Pin or unpin a buffer in vram. - * - * @dev_priv:  Driver private. - * @buf:  DMA buffer to pin or unpin. - * @pin:  Pin buffer in vram if true. - * @interruptible:  Use interruptible wait. - * - * Takes the current masters ttm lock in read. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. - */ -static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, -				  struct vmw_dma_buffer *buf, -				  bool pin, bool interruptible) -{ -	struct ttm_buffer_object *bo = &buf->base; -	struct ttm_placement *overlay_placement = &vmw_vram_placement; -	int ret; - -	ret = ttm_read_lock(&dev_priv->active_master->lock, interruptible); -	if (unlikely(ret != 0)) -		return ret; - -	ret = ttm_bo_reserve(bo, interruptible, false, false, 0); -	if (unlikely(ret != 0)) -		goto err; - -	if (pin) -		overlay_placement = &vmw_vram_ne_placement; - -	ret = ttm_bo_validate(bo, overlay_placement, interruptible, false, false); - -	ttm_bo_unreserve(bo); - -err: -	ttm_read_unlock(&dev_priv->active_master->lock); - -	return ret; -} - -/**   * Send put command to hw.   *   * Returns @@ -139,68 +98,80 @@ static int vmw_overlay_send_put(struct vmw_private *dev_priv,  				struct drm_vmw_control_stream_arg *arg,  				bool interruptible)  { +	struct vmw_escape_video_flush *flush; +	size_t fifo_size; +	bool have_so = dev_priv->sou_priv ? true : false; +	int i, num_items; +	SVGAGuestPtr ptr; +  	struct {  		struct vmw_escape_header escape;  		struct { -			struct { -				uint32_t cmdType; -				uint32_t streamId; -			} header; -			struct { -				uint32_t registerId; -				uint32_t value; -			} items[SVGA_VIDEO_PITCH_3 + 1]; -		} body; -		struct vmw_escape_video_flush flush; +			uint32_t cmdType; +			uint32_t streamId; +		} header;  	} *cmds; -	uint32_t offset; -	int i, ret; +	struct { +		uint32_t registerId; +		uint32_t value; +	} *items; -	for (;;) { -		cmds = vmw_fifo_reserve(dev_priv, sizeof(*cmds)); -		if (cmds) -			break; +	/* defines are a index needs + 1 */ +	if (have_so) +		num_items = SVGA_VIDEO_DST_SCREEN_ID + 1; +	else +		num_items = SVGA_VIDEO_PITCH_3 + 1; -		ret = vmw_fallback_wait(dev_priv, false, true, 0, -					interruptible, 3*HZ); -		if (interruptible && ret == -ERESTARTSYS) -			return ret; -		else -			BUG_ON(ret != 0); +	fifo_size = sizeof(*cmds) + sizeof(*flush) + sizeof(*items) * num_items; + +	cmds = vmw_fifo_reserve(dev_priv, fifo_size); +	/* hardware has hung, can't do anything here */ +	if (!cmds) +		return -ENOMEM; + +	items = (typeof(items))&cmds[1]; +	flush = (struct vmw_escape_video_flush *)&items[num_items]; + +	/* the size is header + number of items */ +	fill_escape(&cmds->escape, sizeof(*items) * (num_items + 1)); + +	cmds->header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS; +	cmds->header.streamId = arg->stream_id; + +	/* the IDs are neatly numbered */ +	for (i = 0; i < num_items; i++) +		items[i].registerId = i; + +	vmw_bo_get_guest_ptr(&buf->base, &ptr); +	ptr.offset += arg->offset; + +	items[SVGA_VIDEO_ENABLED].value     = true; +	items[SVGA_VIDEO_FLAGS].value       = arg->flags; +	items[SVGA_VIDEO_DATA_OFFSET].value = ptr.offset; +	items[SVGA_VIDEO_FORMAT].value      = arg->format; +	items[SVGA_VIDEO_COLORKEY].value    = arg->color_key; +	items[SVGA_VIDEO_SIZE].value        = arg->size; +	items[SVGA_VIDEO_WIDTH].value       = arg->width; +	items[SVGA_VIDEO_HEIGHT].value      = arg->height; +	items[SVGA_VIDEO_SRC_X].value       = arg->src.x; +	items[SVGA_VIDEO_SRC_Y].value       = arg->src.y; +	items[SVGA_VIDEO_SRC_WIDTH].value   = arg->src.w; +	items[SVGA_VIDEO_SRC_HEIGHT].value  = arg->src.h; +	items[SVGA_VIDEO_DST_X].value       = arg->dst.x; +	items[SVGA_VIDEO_DST_Y].value       = arg->dst.y; +	items[SVGA_VIDEO_DST_WIDTH].value   = arg->dst.w; +	items[SVGA_VIDEO_DST_HEIGHT].value  = arg->dst.h; +	items[SVGA_VIDEO_PITCH_1].value     = arg->pitch[0]; +	items[SVGA_VIDEO_PITCH_2].value     = arg->pitch[1]; +	items[SVGA_VIDEO_PITCH_3].value     = arg->pitch[2]; +	if (have_so) { +		items[SVGA_VIDEO_DATA_GMRID].value    = ptr.gmrId; +		items[SVGA_VIDEO_DST_SCREEN_ID].value = SVGA_ID_INVALID;  	} -	fill_escape(&cmds->escape, sizeof(cmds->body)); -	cmds->body.header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS; -	cmds->body.header.streamId = arg->stream_id; - -	for (i = 0; i <= SVGA_VIDEO_PITCH_3; i++) -		cmds->body.items[i].registerId = i; - -	offset = buf->base.offset + arg->offset; - -	cmds->body.items[SVGA_VIDEO_ENABLED].value     = true; -	cmds->body.items[SVGA_VIDEO_FLAGS].value       = arg->flags; -	cmds->body.items[SVGA_VIDEO_DATA_OFFSET].value = offset; -	cmds->body.items[SVGA_VIDEO_FORMAT].value      = arg->format; -	cmds->body.items[SVGA_VIDEO_COLORKEY].value    = arg->color_key; -	cmds->body.items[SVGA_VIDEO_SIZE].value        = arg->size; -	cmds->body.items[SVGA_VIDEO_WIDTH].value       = arg->width; -	cmds->body.items[SVGA_VIDEO_HEIGHT].value      = arg->height; -	cmds->body.items[SVGA_VIDEO_SRC_X].value       = arg->src.x; -	cmds->body.items[SVGA_VIDEO_SRC_Y].value       = arg->src.y; -	cmds->body.items[SVGA_VIDEO_SRC_WIDTH].value   = arg->src.w; -	cmds->body.items[SVGA_VIDEO_SRC_HEIGHT].value  = arg->src.h; -	cmds->body.items[SVGA_VIDEO_DST_X].value       = arg->dst.x; -	cmds->body.items[SVGA_VIDEO_DST_Y].value       = arg->dst.y; -	cmds->body.items[SVGA_VIDEO_DST_WIDTH].value   = arg->dst.w; -	cmds->body.items[SVGA_VIDEO_DST_HEIGHT].value  = arg->dst.h; -	cmds->body.items[SVGA_VIDEO_PITCH_1].value     = arg->pitch[0]; -	cmds->body.items[SVGA_VIDEO_PITCH_2].value     = arg->pitch[1]; -	cmds->body.items[SVGA_VIDEO_PITCH_3].value     = arg->pitch[2]; - -	fill_flush(&cmds->flush, arg->stream_id); +	fill_flush(flush, arg->stream_id); -	vmw_fifo_commit(dev_priv, sizeof(*cmds)); +	vmw_fifo_commit(dev_priv, fifo_size);  	return 0;  } @@ -248,6 +219,25 @@ static int vmw_overlay_send_stop(struct vmw_private *dev_priv,  }  /** + * Move a buffer to vram or gmr if @pin is set, else unpin the buffer. + * + * With the introduction of screen objects buffers could now be + * used with GMRs instead of being locked to vram. + */ +static int vmw_overlay_move_buffer(struct vmw_private *dev_priv, +				   struct vmw_dma_buffer *buf, +				   bool pin, bool inter) +{ +	if (!pin) +		return vmw_dmabuf_unpin(dev_priv, buf, inter); + +	if (!dev_priv->sou_priv) +		return vmw_dmabuf_to_vram(dev_priv, buf, true, inter); + +	return vmw_dmabuf_to_vram_or_gmr(dev_priv, buf, true, inter); +} + +/**   * Stop or pause a stream.   *   * If the stream is paused the no evict flag is removed from the buffer @@ -279,8 +269,8 @@ static int vmw_overlay_stop(struct vmw_private *dev_priv,  			return ret;  		/* We just remove the NO_EVICT flag so no -ENOMEM */ -		ret = vmw_dmabuf_pin_in_vram(dev_priv, stream->buf, false, -					     interruptible); +		ret = vmw_overlay_move_buffer(dev_priv, stream->buf, false, +					      interruptible);  		if (interruptible && ret == -ERESTARTSYS)  			return ret;  		else @@ -342,7 +332,7 @@ static int vmw_overlay_update_stream(struct vmw_private *dev_priv,  	/* We don't start the old stream if we are interrupted.  	 * Might return -ENOMEM if it can't fit the buffer in vram.  	 */ -	ret = vmw_dmabuf_pin_in_vram(dev_priv, buf, true, interruptible); +	ret = vmw_overlay_move_buffer(dev_priv, buf, true, interruptible);  	if (ret)  		return ret; @@ -351,7 +341,8 @@ static int vmw_overlay_update_stream(struct vmw_private *dev_priv,  		/* This one needs to happen no matter what. We only remove  		 * the NO_EVICT flag so this is safe from -ENOMEM.  		 */ -		BUG_ON(vmw_dmabuf_pin_in_vram(dev_priv, buf, false, false) != 0); +		BUG_ON(vmw_overlay_move_buffer(dev_priv, buf, false, false) +		       != 0);  		return ret;  	} @@ -459,6 +450,14 @@ int vmw_overlay_pause_all(struct vmw_private *dev_priv)  	return 0;  } + +static bool vmw_overlay_available(const struct vmw_private *dev_priv) +{ +	return (dev_priv->overlay_priv != NULL &&  +		((dev_priv->fifo.capabilities & VMW_OVERLAY_CAP_MASK) == +		 VMW_OVERLAY_CAP_MASK)); +} +  int vmw_overlay_ioctl(struct drm_device *dev, void *data,  		      struct drm_file *file_priv)  { @@ -471,7 +470,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data,  	struct vmw_resource *res;  	int ret; -	if (!overlay) +	if (!vmw_overlay_available(dev_priv))  		return -ENOSYS;  	ret = vmw_user_stream_lookup(dev_priv, tfile, &arg->stream_id, &res); @@ -502,7 +501,7 @@ out_unlock:  int vmw_overlay_num_overlays(struct vmw_private *dev_priv)  { -	if (!dev_priv->overlay_priv) +	if (!vmw_overlay_available(dev_priv))  		return 0;  	return VMW_MAX_NUM_STREAMS; @@ -513,7 +512,7 @@ int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv)  	struct vmw_overlay *overlay = dev_priv->overlay_priv;  	int i, k; -	if (!overlay) +	if (!vmw_overlay_available(dev_priv))  		return 0;  	mutex_lock(&overlay->mutex); @@ -579,17 +578,10 @@ int vmw_overlay_init(struct vmw_private *dev_priv)  	if (dev_priv->overlay_priv)  		return -EINVAL; -	if (!(dev_priv->fifo.capabilities & SVGA_FIFO_CAP_VIDEO) && -	     (dev_priv->fifo.capabilities & SVGA_FIFO_CAP_ESCAPE)) { -		DRM_INFO("hardware doesn't support overlays\n"); -		return -ENOSYS; -	} - -	overlay = kmalloc(sizeof(*overlay), GFP_KERNEL); +	overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);  	if (!overlay)  		return -ENOMEM; -	memset(overlay, 0, sizeof(*overlay));  	mutex_init(&overlay->mutex);  	for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {  		overlay->stream[i].buf = NULL;  | 
