diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c')
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 227 |
1 files changed, 106 insertions, 121 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index bb6e6a096d2..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,57 +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_bo_global *glob = bo->glob; - 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 (buf->gmr_bound) { - vmw_gmr_unbind(dev_priv, buf->gmr_id); - spin_lock(&glob->lru_lock); - ida_remove(&dev_priv->gmr_ida, buf->gmr_id); - spin_unlock(&glob->lru_lock); - buf->gmr_bound = NULL; - } - - if (pin) - overlay_placement = &vmw_vram_ne_placement; - - ret = ttm_bo_validate(bo, overlay_placement, interruptible, false); - - ttm_bo_unreserve(bo); - -err: - ttm_read_unlock(&dev_priv->active_master->lock); - - return ret; -} - -/** * Send put command to hw. * * Returns @@ -148,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; } @@ -257,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 @@ -288,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 @@ -351,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; @@ -360,13 +341,16 @@ 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; } if (stream->buf != buf) stream->buf = vmw_dmabuf_reference(buf); stream->saved = *arg; + /* stream is no longer stopped/paused */ + stream->paused = false; return 0; } @@ -466,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) { @@ -478,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); @@ -509,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; @@ -520,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); @@ -586,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(GFP_KERNEL, sizeof(*overlay)); + 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; |
