diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 191 |
1 files changed, 101 insertions, 90 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index 14399ee..f1a52f9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -87,6 +87,48 @@ 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 @@ -97,80 +139,68 @@ 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 { - uint32_t cmdType; - uint32_t streamId; - } header; + 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; } *cmds; - struct { - uint32_t registerId; - uint32_t value; - } *items; - - /* 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; - - fifo_size = sizeof(*cmds) + sizeof(*flush) + sizeof(*items) * num_items; + uint32_t offset; + int i, ret; - cmds = vmw_fifo_reserve(dev_priv, fifo_size); - /* hardware has hung, can't do anything here */ - if (!cmds) - return -ENOMEM; + for (;;) { + cmds = vmw_fifo_reserve(dev_priv, sizeof(*cmds)); + if (cmds) + break; - 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; + ret = vmw_fallback_wait(dev_priv, false, true, 0, + interruptible, 3*HZ); + if (interruptible && ret == -ERESTARTSYS) + return ret; + else + BUG_ON(ret != 0); } - fill_flush(flush, arg->stream_id); + 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); - vmw_fifo_commit(dev_priv, fifo_size); + vmw_fifo_commit(dev_priv, sizeof(*cmds)); return 0; } @@ -218,25 +248,6 @@ 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 @@ -268,8 +279,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_overlay_move_buffer(dev_priv, stream->buf, false, - interruptible); + ret = vmw_dmabuf_pin_in_vram(dev_priv, stream->buf, false, + interruptible); if (interruptible && ret == -ERESTARTSYS) return ret; else @@ -331,7 +342,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_overlay_move_buffer(dev_priv, buf, true, interruptible); + ret = vmw_dmabuf_pin_in_vram(dev_priv, buf, true, interruptible); if (ret) return ret; @@ -340,8 +351,7 @@ 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_overlay_move_buffer(dev_priv, buf, false, false) - != 0); + BUG_ON(vmw_dmabuf_pin_in_vram(dev_priv, buf, false, false) != 0); return ret; } @@ -575,10 +585,11 @@ int vmw_overlay_init(struct vmw_private *dev_priv) return -ENOSYS; } - overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); + overlay = kmalloc(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; |