1fb1d9738SJakob Bornecrantz /************************************************************************** 2fb1d9738SJakob Bornecrantz * 3fb1d9738SJakob Bornecrantz * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA 4fb1d9738SJakob Bornecrantz * All Rights Reserved. 5fb1d9738SJakob Bornecrantz * 6fb1d9738SJakob Bornecrantz * Permission is hereby granted, free of charge, to any person obtaining a 7fb1d9738SJakob Bornecrantz * copy of this software and associated documentation files (the 8fb1d9738SJakob Bornecrantz * "Software"), to deal in the Software without restriction, including 9fb1d9738SJakob Bornecrantz * without limitation the rights to use, copy, modify, merge, publish, 10fb1d9738SJakob Bornecrantz * distribute, sub license, and/or sell copies of the Software, and to 11fb1d9738SJakob Bornecrantz * permit persons to whom the Software is furnished to do so, subject to 12fb1d9738SJakob Bornecrantz * the following conditions: 13fb1d9738SJakob Bornecrantz * 14fb1d9738SJakob Bornecrantz * The above copyright notice and this permission notice (including the 15fb1d9738SJakob Bornecrantz * next paragraph) shall be included in all copies or substantial portions 16fb1d9738SJakob Bornecrantz * of the Software. 17fb1d9738SJakob Bornecrantz * 18fb1d9738SJakob Bornecrantz * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19fb1d9738SJakob Bornecrantz * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20fb1d9738SJakob Bornecrantz * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21fb1d9738SJakob Bornecrantz * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22fb1d9738SJakob Bornecrantz * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23fb1d9738SJakob Bornecrantz * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24fb1d9738SJakob Bornecrantz * USE OR OTHER DEALINGS IN THE SOFTWARE. 25fb1d9738SJakob Bornecrantz * 26fb1d9738SJakob Bornecrantz **************************************************************************/ 27fb1d9738SJakob Bornecrantz 28fb1d9738SJakob Bornecrantz 29fb1d9738SJakob Bornecrantz #include "drmP.h" 30fb1d9738SJakob Bornecrantz #include "vmwgfx_drv.h" 31fb1d9738SJakob Bornecrantz 32fb1d9738SJakob Bornecrantz #include "ttm/ttm_placement.h" 33fb1d9738SJakob Bornecrantz 34fb1d9738SJakob Bornecrantz #include "svga_overlay.h" 35fb1d9738SJakob Bornecrantz #include "svga_escape.h" 36fb1d9738SJakob Bornecrantz 37fb1d9738SJakob Bornecrantz #define VMW_MAX_NUM_STREAMS 1 38fb1d9738SJakob Bornecrantz 39fb1d9738SJakob Bornecrantz struct vmw_stream { 40fb1d9738SJakob Bornecrantz struct vmw_dma_buffer *buf; 41fb1d9738SJakob Bornecrantz bool claimed; 42fb1d9738SJakob Bornecrantz bool paused; 43fb1d9738SJakob Bornecrantz struct drm_vmw_control_stream_arg saved; 44fb1d9738SJakob Bornecrantz }; 45fb1d9738SJakob Bornecrantz 46fb1d9738SJakob Bornecrantz /** 47fb1d9738SJakob Bornecrantz * Overlay control 48fb1d9738SJakob Bornecrantz */ 49fb1d9738SJakob Bornecrantz struct vmw_overlay { 50fb1d9738SJakob Bornecrantz /* 51fb1d9738SJakob Bornecrantz * Each stream is a single overlay. In Xv these are called ports. 52fb1d9738SJakob Bornecrantz */ 53fb1d9738SJakob Bornecrantz struct mutex mutex; 54fb1d9738SJakob Bornecrantz struct vmw_stream stream[VMW_MAX_NUM_STREAMS]; 55fb1d9738SJakob Bornecrantz }; 56fb1d9738SJakob Bornecrantz 57fb1d9738SJakob Bornecrantz static inline struct vmw_overlay *vmw_overlay(struct drm_device *dev) 58fb1d9738SJakob Bornecrantz { 59fb1d9738SJakob Bornecrantz struct vmw_private *dev_priv = vmw_priv(dev); 60fb1d9738SJakob Bornecrantz return dev_priv ? dev_priv->overlay_priv : NULL; 61fb1d9738SJakob Bornecrantz } 62fb1d9738SJakob Bornecrantz 63fb1d9738SJakob Bornecrantz struct vmw_escape_header { 64fb1d9738SJakob Bornecrantz uint32_t cmd; 65fb1d9738SJakob Bornecrantz SVGAFifoCmdEscape body; 66fb1d9738SJakob Bornecrantz }; 67fb1d9738SJakob Bornecrantz 68fb1d9738SJakob Bornecrantz struct vmw_escape_video_flush { 69fb1d9738SJakob Bornecrantz struct vmw_escape_header escape; 70fb1d9738SJakob Bornecrantz SVGAEscapeVideoFlush flush; 71fb1d9738SJakob Bornecrantz }; 72fb1d9738SJakob Bornecrantz 73fb1d9738SJakob Bornecrantz static inline void fill_escape(struct vmw_escape_header *header, 74fb1d9738SJakob Bornecrantz uint32_t size) 75fb1d9738SJakob Bornecrantz { 76fb1d9738SJakob Bornecrantz header->cmd = SVGA_CMD_ESCAPE; 77fb1d9738SJakob Bornecrantz header->body.nsid = SVGA_ESCAPE_NSID_VMWARE; 78fb1d9738SJakob Bornecrantz header->body.size = size; 79fb1d9738SJakob Bornecrantz } 80fb1d9738SJakob Bornecrantz 81fb1d9738SJakob Bornecrantz static inline void fill_flush(struct vmw_escape_video_flush *cmd, 82fb1d9738SJakob Bornecrantz uint32_t stream_id) 83fb1d9738SJakob Bornecrantz { 84fb1d9738SJakob Bornecrantz fill_escape(&cmd->escape, sizeof(cmd->flush)); 85fb1d9738SJakob Bornecrantz cmd->flush.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_FLUSH; 86fb1d9738SJakob Bornecrantz cmd->flush.streamId = stream_id; 87fb1d9738SJakob Bornecrantz } 88fb1d9738SJakob Bornecrantz 89fb1d9738SJakob Bornecrantz /** 90fb1d9738SJakob Bornecrantz * Pin or unpin a buffer in vram. 91fb1d9738SJakob Bornecrantz * 92fb1d9738SJakob Bornecrantz * @dev_priv: Driver private. 93fb1d9738SJakob Bornecrantz * @buf: DMA buffer to pin or unpin. 94fb1d9738SJakob Bornecrantz * @pin: Pin buffer in vram if true. 95fb1d9738SJakob Bornecrantz * @interruptible: Use interruptible wait. 96fb1d9738SJakob Bornecrantz * 97fb1d9738SJakob Bornecrantz * Takes the current masters ttm lock in read. 98fb1d9738SJakob Bornecrantz * 99fb1d9738SJakob Bornecrantz * Returns 100fb1d9738SJakob Bornecrantz * -ERESTARTSYS if interrupted by a signal. 101fb1d9738SJakob Bornecrantz */ 102fb1d9738SJakob Bornecrantz static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, 103fb1d9738SJakob Bornecrantz struct vmw_dma_buffer *buf, 104fb1d9738SJakob Bornecrantz bool pin, bool interruptible) 105fb1d9738SJakob Bornecrantz { 106fb1d9738SJakob Bornecrantz struct ttm_buffer_object *bo = &buf->base; 107fb1d9738SJakob Bornecrantz struct ttm_placement *overlay_placement = &vmw_vram_placement; 108fb1d9738SJakob Bornecrantz int ret; 109fb1d9738SJakob Bornecrantz 110fb1d9738SJakob Bornecrantz ret = ttm_read_lock(&dev_priv->active_master->lock, interruptible); 111fb1d9738SJakob Bornecrantz if (unlikely(ret != 0)) 112fb1d9738SJakob Bornecrantz return ret; 113fb1d9738SJakob Bornecrantz 114fb1d9738SJakob Bornecrantz ret = ttm_bo_reserve(bo, interruptible, false, false, 0); 115fb1d9738SJakob Bornecrantz if (unlikely(ret != 0)) 116fb1d9738SJakob Bornecrantz goto err; 117fb1d9738SJakob Bornecrantz 118fb1d9738SJakob Bornecrantz if (pin) 119fb1d9738SJakob Bornecrantz overlay_placement = &vmw_vram_ne_placement; 120fb1d9738SJakob Bornecrantz 1219d87fa21SJerome Glisse ret = ttm_bo_validate(bo, overlay_placement, interruptible, false, false); 122fb1d9738SJakob Bornecrantz 123fb1d9738SJakob Bornecrantz ttm_bo_unreserve(bo); 124fb1d9738SJakob Bornecrantz 125fb1d9738SJakob Bornecrantz err: 126fb1d9738SJakob Bornecrantz ttm_read_unlock(&dev_priv->active_master->lock); 127fb1d9738SJakob Bornecrantz 128fb1d9738SJakob Bornecrantz return ret; 129fb1d9738SJakob Bornecrantz } 130fb1d9738SJakob Bornecrantz 131fb1d9738SJakob Bornecrantz /** 132fb1d9738SJakob Bornecrantz * Send put command to hw. 133fb1d9738SJakob Bornecrantz * 134fb1d9738SJakob Bornecrantz * Returns 135fb1d9738SJakob Bornecrantz * -ERESTARTSYS if interrupted by a signal. 136fb1d9738SJakob Bornecrantz */ 137fb1d9738SJakob Bornecrantz static int vmw_overlay_send_put(struct vmw_private *dev_priv, 138fb1d9738SJakob Bornecrantz struct vmw_dma_buffer *buf, 139fb1d9738SJakob Bornecrantz struct drm_vmw_control_stream_arg *arg, 140fb1d9738SJakob Bornecrantz bool interruptible) 141fb1d9738SJakob Bornecrantz { 142fb1d9738SJakob Bornecrantz struct { 143fb1d9738SJakob Bornecrantz struct vmw_escape_header escape; 144fb1d9738SJakob Bornecrantz struct { 145fb1d9738SJakob Bornecrantz struct { 146fb1d9738SJakob Bornecrantz uint32_t cmdType; 147fb1d9738SJakob Bornecrantz uint32_t streamId; 148fb1d9738SJakob Bornecrantz } header; 149fb1d9738SJakob Bornecrantz struct { 150fb1d9738SJakob Bornecrantz uint32_t registerId; 151fb1d9738SJakob Bornecrantz uint32_t value; 152fb1d9738SJakob Bornecrantz } items[SVGA_VIDEO_PITCH_3 + 1]; 153fb1d9738SJakob Bornecrantz } body; 154fb1d9738SJakob Bornecrantz struct vmw_escape_video_flush flush; 155fb1d9738SJakob Bornecrantz } *cmds; 156fb1d9738SJakob Bornecrantz uint32_t offset; 157fb1d9738SJakob Bornecrantz int i, ret; 158fb1d9738SJakob Bornecrantz 159fb1d9738SJakob Bornecrantz for (;;) { 160fb1d9738SJakob Bornecrantz cmds = vmw_fifo_reserve(dev_priv, sizeof(*cmds)); 161fb1d9738SJakob Bornecrantz if (cmds) 162fb1d9738SJakob Bornecrantz break; 163fb1d9738SJakob Bornecrantz 164fb1d9738SJakob Bornecrantz ret = vmw_fallback_wait(dev_priv, false, true, 0, 165fb1d9738SJakob Bornecrantz interruptible, 3*HZ); 166fb1d9738SJakob Bornecrantz if (interruptible && ret == -ERESTARTSYS) 167fb1d9738SJakob Bornecrantz return ret; 168fb1d9738SJakob Bornecrantz else 169fb1d9738SJakob Bornecrantz BUG_ON(ret != 0); 170fb1d9738SJakob Bornecrantz } 171fb1d9738SJakob Bornecrantz 172fb1d9738SJakob Bornecrantz fill_escape(&cmds->escape, sizeof(cmds->body)); 173fb1d9738SJakob Bornecrantz cmds->body.header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS; 174fb1d9738SJakob Bornecrantz cmds->body.header.streamId = arg->stream_id; 175fb1d9738SJakob Bornecrantz 176fb1d9738SJakob Bornecrantz for (i = 0; i <= SVGA_VIDEO_PITCH_3; i++) 177fb1d9738SJakob Bornecrantz cmds->body.items[i].registerId = i; 178fb1d9738SJakob Bornecrantz 179fb1d9738SJakob Bornecrantz offset = buf->base.offset + arg->offset; 180fb1d9738SJakob Bornecrantz 181fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_ENABLED].value = true; 182fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_FLAGS].value = arg->flags; 183fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_DATA_OFFSET].value = offset; 184fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_FORMAT].value = arg->format; 185fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_COLORKEY].value = arg->color_key; 186fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_SIZE].value = arg->size; 187fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_WIDTH].value = arg->width; 188fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_HEIGHT].value = arg->height; 189fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_SRC_X].value = arg->src.x; 190fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_SRC_Y].value = arg->src.y; 191fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_SRC_WIDTH].value = arg->src.w; 192fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_SRC_HEIGHT].value = arg->src.h; 193fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_DST_X].value = arg->dst.x; 194fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_DST_Y].value = arg->dst.y; 195fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_DST_WIDTH].value = arg->dst.w; 196fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_DST_HEIGHT].value = arg->dst.h; 197fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_PITCH_1].value = arg->pitch[0]; 198fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_PITCH_2].value = arg->pitch[1]; 199fb1d9738SJakob Bornecrantz cmds->body.items[SVGA_VIDEO_PITCH_3].value = arg->pitch[2]; 200fb1d9738SJakob Bornecrantz 201fb1d9738SJakob Bornecrantz fill_flush(&cmds->flush, arg->stream_id); 202fb1d9738SJakob Bornecrantz 203fb1d9738SJakob Bornecrantz vmw_fifo_commit(dev_priv, sizeof(*cmds)); 204fb1d9738SJakob Bornecrantz 205fb1d9738SJakob Bornecrantz return 0; 206fb1d9738SJakob Bornecrantz } 207fb1d9738SJakob Bornecrantz 208fb1d9738SJakob Bornecrantz /** 209fb1d9738SJakob Bornecrantz * Send stop command to hw. 210fb1d9738SJakob Bornecrantz * 211fb1d9738SJakob Bornecrantz * Returns 212fb1d9738SJakob Bornecrantz * -ERESTARTSYS if interrupted by a signal. 213fb1d9738SJakob Bornecrantz */ 214fb1d9738SJakob Bornecrantz static int vmw_overlay_send_stop(struct vmw_private *dev_priv, 215fb1d9738SJakob Bornecrantz uint32_t stream_id, 216fb1d9738SJakob Bornecrantz bool interruptible) 217fb1d9738SJakob Bornecrantz { 218fb1d9738SJakob Bornecrantz struct { 219fb1d9738SJakob Bornecrantz struct vmw_escape_header escape; 220fb1d9738SJakob Bornecrantz SVGAEscapeVideoSetRegs body; 221fb1d9738SJakob Bornecrantz struct vmw_escape_video_flush flush; 222fb1d9738SJakob Bornecrantz } *cmds; 223fb1d9738SJakob Bornecrantz int ret; 224fb1d9738SJakob Bornecrantz 225fb1d9738SJakob Bornecrantz for (;;) { 226fb1d9738SJakob Bornecrantz cmds = vmw_fifo_reserve(dev_priv, sizeof(*cmds)); 227fb1d9738SJakob Bornecrantz if (cmds) 228fb1d9738SJakob Bornecrantz break; 229fb1d9738SJakob Bornecrantz 230fb1d9738SJakob Bornecrantz ret = vmw_fallback_wait(dev_priv, false, true, 0, 231fb1d9738SJakob Bornecrantz interruptible, 3*HZ); 232fb1d9738SJakob Bornecrantz if (interruptible && ret == -ERESTARTSYS) 233fb1d9738SJakob Bornecrantz return ret; 234fb1d9738SJakob Bornecrantz else 235fb1d9738SJakob Bornecrantz BUG_ON(ret != 0); 236fb1d9738SJakob Bornecrantz } 237fb1d9738SJakob Bornecrantz 238fb1d9738SJakob Bornecrantz fill_escape(&cmds->escape, sizeof(cmds->body)); 239fb1d9738SJakob Bornecrantz cmds->body.header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS; 240fb1d9738SJakob Bornecrantz cmds->body.header.streamId = stream_id; 241fb1d9738SJakob Bornecrantz cmds->body.items[0].registerId = SVGA_VIDEO_ENABLED; 242fb1d9738SJakob Bornecrantz cmds->body.items[0].value = false; 243fb1d9738SJakob Bornecrantz fill_flush(&cmds->flush, stream_id); 244fb1d9738SJakob Bornecrantz 245fb1d9738SJakob Bornecrantz vmw_fifo_commit(dev_priv, sizeof(*cmds)); 246fb1d9738SJakob Bornecrantz 247fb1d9738SJakob Bornecrantz return 0; 248fb1d9738SJakob Bornecrantz } 249fb1d9738SJakob Bornecrantz 250fb1d9738SJakob Bornecrantz /** 251fb1d9738SJakob Bornecrantz * Stop or pause a stream. 252fb1d9738SJakob Bornecrantz * 253fb1d9738SJakob Bornecrantz * If the stream is paused the no evict flag is removed from the buffer 254fb1d9738SJakob Bornecrantz * but left in vram. This allows for instance mode_set to evict it 255fb1d9738SJakob Bornecrantz * should it need to. 256fb1d9738SJakob Bornecrantz * 257fb1d9738SJakob Bornecrantz * The caller must hold the overlay lock. 258fb1d9738SJakob Bornecrantz * 259fb1d9738SJakob Bornecrantz * @stream_id which stream to stop/pause. 260fb1d9738SJakob Bornecrantz * @pause true to pause, false to stop completely. 261fb1d9738SJakob Bornecrantz */ 262fb1d9738SJakob Bornecrantz static int vmw_overlay_stop(struct vmw_private *dev_priv, 263fb1d9738SJakob Bornecrantz uint32_t stream_id, bool pause, 264fb1d9738SJakob Bornecrantz bool interruptible) 265fb1d9738SJakob Bornecrantz { 266fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 267fb1d9738SJakob Bornecrantz struct vmw_stream *stream = &overlay->stream[stream_id]; 268fb1d9738SJakob Bornecrantz int ret; 269fb1d9738SJakob Bornecrantz 270fb1d9738SJakob Bornecrantz /* no buffer attached the stream is completely stopped */ 271fb1d9738SJakob Bornecrantz if (!stream->buf) 272fb1d9738SJakob Bornecrantz return 0; 273fb1d9738SJakob Bornecrantz 274fb1d9738SJakob Bornecrantz /* If the stream is paused this is already done */ 275fb1d9738SJakob Bornecrantz if (!stream->paused) { 276fb1d9738SJakob Bornecrantz ret = vmw_overlay_send_stop(dev_priv, stream_id, 277fb1d9738SJakob Bornecrantz interruptible); 278fb1d9738SJakob Bornecrantz if (ret) 279fb1d9738SJakob Bornecrantz return ret; 280fb1d9738SJakob Bornecrantz 281fb1d9738SJakob Bornecrantz /* We just remove the NO_EVICT flag so no -ENOMEM */ 282fb1d9738SJakob Bornecrantz ret = vmw_dmabuf_pin_in_vram(dev_priv, stream->buf, false, 283fb1d9738SJakob Bornecrantz interruptible); 284fb1d9738SJakob Bornecrantz if (interruptible && ret == -ERESTARTSYS) 285fb1d9738SJakob Bornecrantz return ret; 286fb1d9738SJakob Bornecrantz else 287fb1d9738SJakob Bornecrantz BUG_ON(ret != 0); 288fb1d9738SJakob Bornecrantz } 289fb1d9738SJakob Bornecrantz 290fb1d9738SJakob Bornecrantz if (!pause) { 291fb1d9738SJakob Bornecrantz vmw_dmabuf_unreference(&stream->buf); 292fb1d9738SJakob Bornecrantz stream->paused = false; 293fb1d9738SJakob Bornecrantz } else { 294fb1d9738SJakob Bornecrantz stream->paused = true; 295fb1d9738SJakob Bornecrantz } 296fb1d9738SJakob Bornecrantz 297fb1d9738SJakob Bornecrantz return 0; 298fb1d9738SJakob Bornecrantz } 299fb1d9738SJakob Bornecrantz 300fb1d9738SJakob Bornecrantz /** 301fb1d9738SJakob Bornecrantz * Update a stream and send any put or stop fifo commands needed. 302fb1d9738SJakob Bornecrantz * 303fb1d9738SJakob Bornecrantz * The caller must hold the overlay lock. 304fb1d9738SJakob Bornecrantz * 305fb1d9738SJakob Bornecrantz * Returns 306fb1d9738SJakob Bornecrantz * -ENOMEM if buffer doesn't fit in vram. 307fb1d9738SJakob Bornecrantz * -ERESTARTSYS if interrupted. 308fb1d9738SJakob Bornecrantz */ 309fb1d9738SJakob Bornecrantz static int vmw_overlay_update_stream(struct vmw_private *dev_priv, 310fb1d9738SJakob Bornecrantz struct vmw_dma_buffer *buf, 311fb1d9738SJakob Bornecrantz struct drm_vmw_control_stream_arg *arg, 312fb1d9738SJakob Bornecrantz bool interruptible) 313fb1d9738SJakob Bornecrantz { 314fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 315fb1d9738SJakob Bornecrantz struct vmw_stream *stream = &overlay->stream[arg->stream_id]; 316fb1d9738SJakob Bornecrantz int ret = 0; 317fb1d9738SJakob Bornecrantz 318fb1d9738SJakob Bornecrantz if (!buf) 319fb1d9738SJakob Bornecrantz return -EINVAL; 320fb1d9738SJakob Bornecrantz 321fb1d9738SJakob Bornecrantz DRM_DEBUG(" %s: old %p, new %p, %spaused\n", __func__, 322fb1d9738SJakob Bornecrantz stream->buf, buf, stream->paused ? "" : "not "); 323fb1d9738SJakob Bornecrantz 324fb1d9738SJakob Bornecrantz if (stream->buf != buf) { 325fb1d9738SJakob Bornecrantz ret = vmw_overlay_stop(dev_priv, arg->stream_id, 326fb1d9738SJakob Bornecrantz false, interruptible); 327fb1d9738SJakob Bornecrantz if (ret) 328fb1d9738SJakob Bornecrantz return ret; 329fb1d9738SJakob Bornecrantz } else if (!stream->paused) { 330fb1d9738SJakob Bornecrantz /* If the buffers match and not paused then just send 331fb1d9738SJakob Bornecrantz * the put command, no need to do anything else. 332fb1d9738SJakob Bornecrantz */ 333fb1d9738SJakob Bornecrantz ret = vmw_overlay_send_put(dev_priv, buf, arg, interruptible); 334fb1d9738SJakob Bornecrantz if (ret == 0) 335fb1d9738SJakob Bornecrantz stream->saved = *arg; 336fb1d9738SJakob Bornecrantz else 337fb1d9738SJakob Bornecrantz BUG_ON(!interruptible); 338fb1d9738SJakob Bornecrantz 339fb1d9738SJakob Bornecrantz return ret; 340fb1d9738SJakob Bornecrantz } 341fb1d9738SJakob Bornecrantz 342fb1d9738SJakob Bornecrantz /* We don't start the old stream if we are interrupted. 343fb1d9738SJakob Bornecrantz * Might return -ENOMEM if it can't fit the buffer in vram. 344fb1d9738SJakob Bornecrantz */ 345fb1d9738SJakob Bornecrantz ret = vmw_dmabuf_pin_in_vram(dev_priv, buf, true, interruptible); 346fb1d9738SJakob Bornecrantz if (ret) 347fb1d9738SJakob Bornecrantz return ret; 348fb1d9738SJakob Bornecrantz 349fb1d9738SJakob Bornecrantz ret = vmw_overlay_send_put(dev_priv, buf, arg, interruptible); 350fb1d9738SJakob Bornecrantz if (ret) { 351fb1d9738SJakob Bornecrantz /* This one needs to happen no matter what. We only remove 352fb1d9738SJakob Bornecrantz * the NO_EVICT flag so this is safe from -ENOMEM. 353fb1d9738SJakob Bornecrantz */ 354fb1d9738SJakob Bornecrantz BUG_ON(vmw_dmabuf_pin_in_vram(dev_priv, buf, false, false) != 0); 355fb1d9738SJakob Bornecrantz return ret; 356fb1d9738SJakob Bornecrantz } 357fb1d9738SJakob Bornecrantz 358fb1d9738SJakob Bornecrantz if (stream->buf != buf) 359fb1d9738SJakob Bornecrantz stream->buf = vmw_dmabuf_reference(buf); 360fb1d9738SJakob Bornecrantz stream->saved = *arg; 361792778e8SJakob Bornecrantz /* stream is no longer stopped/paused */ 362792778e8SJakob Bornecrantz stream->paused = false; 363fb1d9738SJakob Bornecrantz 364fb1d9738SJakob Bornecrantz return 0; 365fb1d9738SJakob Bornecrantz } 366fb1d9738SJakob Bornecrantz 367fb1d9738SJakob Bornecrantz /** 368fb1d9738SJakob Bornecrantz * Stop all streams. 369fb1d9738SJakob Bornecrantz * 370fb1d9738SJakob Bornecrantz * Used by the fb code when starting. 371fb1d9738SJakob Bornecrantz * 372fb1d9738SJakob Bornecrantz * Takes the overlay lock. 373fb1d9738SJakob Bornecrantz */ 374fb1d9738SJakob Bornecrantz int vmw_overlay_stop_all(struct vmw_private *dev_priv) 375fb1d9738SJakob Bornecrantz { 376fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 377fb1d9738SJakob Bornecrantz int i, ret; 378fb1d9738SJakob Bornecrantz 379fb1d9738SJakob Bornecrantz if (!overlay) 380fb1d9738SJakob Bornecrantz return 0; 381fb1d9738SJakob Bornecrantz 382fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 383fb1d9738SJakob Bornecrantz 384fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 385fb1d9738SJakob Bornecrantz struct vmw_stream *stream = &overlay->stream[i]; 386fb1d9738SJakob Bornecrantz if (!stream->buf) 387fb1d9738SJakob Bornecrantz continue; 388fb1d9738SJakob Bornecrantz 389fb1d9738SJakob Bornecrantz ret = vmw_overlay_stop(dev_priv, i, false, false); 390fb1d9738SJakob Bornecrantz WARN_ON(ret != 0); 391fb1d9738SJakob Bornecrantz } 392fb1d9738SJakob Bornecrantz 393fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 394fb1d9738SJakob Bornecrantz 395fb1d9738SJakob Bornecrantz return 0; 396fb1d9738SJakob Bornecrantz } 397fb1d9738SJakob Bornecrantz 398fb1d9738SJakob Bornecrantz /** 399fb1d9738SJakob Bornecrantz * Try to resume all paused streams. 400fb1d9738SJakob Bornecrantz * 401fb1d9738SJakob Bornecrantz * Used by the kms code after moving a new scanout buffer to vram. 402fb1d9738SJakob Bornecrantz * 403fb1d9738SJakob Bornecrantz * Takes the overlay lock. 404fb1d9738SJakob Bornecrantz */ 405fb1d9738SJakob Bornecrantz int vmw_overlay_resume_all(struct vmw_private *dev_priv) 406fb1d9738SJakob Bornecrantz { 407fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 408fb1d9738SJakob Bornecrantz int i, ret; 409fb1d9738SJakob Bornecrantz 410fb1d9738SJakob Bornecrantz if (!overlay) 411fb1d9738SJakob Bornecrantz return 0; 412fb1d9738SJakob Bornecrantz 413fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 414fb1d9738SJakob Bornecrantz 415fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 416fb1d9738SJakob Bornecrantz struct vmw_stream *stream = &overlay->stream[i]; 417fb1d9738SJakob Bornecrantz if (!stream->paused) 418fb1d9738SJakob Bornecrantz continue; 419fb1d9738SJakob Bornecrantz 420fb1d9738SJakob Bornecrantz ret = vmw_overlay_update_stream(dev_priv, stream->buf, 421fb1d9738SJakob Bornecrantz &stream->saved, false); 422fb1d9738SJakob Bornecrantz if (ret != 0) 423fb1d9738SJakob Bornecrantz DRM_INFO("%s: *warning* failed to resume stream %i\n", 424fb1d9738SJakob Bornecrantz __func__, i); 425fb1d9738SJakob Bornecrantz } 426fb1d9738SJakob Bornecrantz 427fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 428fb1d9738SJakob Bornecrantz 429fb1d9738SJakob Bornecrantz return 0; 430fb1d9738SJakob Bornecrantz } 431fb1d9738SJakob Bornecrantz 432fb1d9738SJakob Bornecrantz /** 433fb1d9738SJakob Bornecrantz * Pauses all active streams. 434fb1d9738SJakob Bornecrantz * 435fb1d9738SJakob Bornecrantz * Used by the kms code when moving a new scanout buffer to vram. 436fb1d9738SJakob Bornecrantz * 437fb1d9738SJakob Bornecrantz * Takes the overlay lock. 438fb1d9738SJakob Bornecrantz */ 439fb1d9738SJakob Bornecrantz int vmw_overlay_pause_all(struct vmw_private *dev_priv) 440fb1d9738SJakob Bornecrantz { 441fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 442fb1d9738SJakob Bornecrantz int i, ret; 443fb1d9738SJakob Bornecrantz 444fb1d9738SJakob Bornecrantz if (!overlay) 445fb1d9738SJakob Bornecrantz return 0; 446fb1d9738SJakob Bornecrantz 447fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 448fb1d9738SJakob Bornecrantz 449fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 450fb1d9738SJakob Bornecrantz if (overlay->stream[i].paused) 451fb1d9738SJakob Bornecrantz DRM_INFO("%s: *warning* stream %i already paused\n", 452fb1d9738SJakob Bornecrantz __func__, i); 453fb1d9738SJakob Bornecrantz ret = vmw_overlay_stop(dev_priv, i, true, false); 454fb1d9738SJakob Bornecrantz WARN_ON(ret != 0); 455fb1d9738SJakob Bornecrantz } 456fb1d9738SJakob Bornecrantz 457fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 458fb1d9738SJakob Bornecrantz 459fb1d9738SJakob Bornecrantz return 0; 460fb1d9738SJakob Bornecrantz } 461fb1d9738SJakob Bornecrantz 462fb1d9738SJakob Bornecrantz int vmw_overlay_ioctl(struct drm_device *dev, void *data, 463fb1d9738SJakob Bornecrantz struct drm_file *file_priv) 464fb1d9738SJakob Bornecrantz { 465fb1d9738SJakob Bornecrantz struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 466fb1d9738SJakob Bornecrantz struct vmw_private *dev_priv = vmw_priv(dev); 467fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 468fb1d9738SJakob Bornecrantz struct drm_vmw_control_stream_arg *arg = 469fb1d9738SJakob Bornecrantz (struct drm_vmw_control_stream_arg *)data; 470fb1d9738SJakob Bornecrantz struct vmw_dma_buffer *buf; 471fb1d9738SJakob Bornecrantz struct vmw_resource *res; 472fb1d9738SJakob Bornecrantz int ret; 473fb1d9738SJakob Bornecrantz 474fb1d9738SJakob Bornecrantz if (!overlay) 475fb1d9738SJakob Bornecrantz return -ENOSYS; 476fb1d9738SJakob Bornecrantz 477fb1d9738SJakob Bornecrantz ret = vmw_user_stream_lookup(dev_priv, tfile, &arg->stream_id, &res); 478fb1d9738SJakob Bornecrantz if (ret) 479fb1d9738SJakob Bornecrantz return ret; 480fb1d9738SJakob Bornecrantz 481fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 482fb1d9738SJakob Bornecrantz 483fb1d9738SJakob Bornecrantz if (!arg->enabled) { 484fb1d9738SJakob Bornecrantz ret = vmw_overlay_stop(dev_priv, arg->stream_id, false, true); 485fb1d9738SJakob Bornecrantz goto out_unlock; 486fb1d9738SJakob Bornecrantz } 487fb1d9738SJakob Bornecrantz 488fb1d9738SJakob Bornecrantz ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &buf); 489fb1d9738SJakob Bornecrantz if (ret) 490fb1d9738SJakob Bornecrantz goto out_unlock; 491fb1d9738SJakob Bornecrantz 492fb1d9738SJakob Bornecrantz ret = vmw_overlay_update_stream(dev_priv, buf, arg, true); 493fb1d9738SJakob Bornecrantz 494fb1d9738SJakob Bornecrantz vmw_dmabuf_unreference(&buf); 495fb1d9738SJakob Bornecrantz 496fb1d9738SJakob Bornecrantz out_unlock: 497fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 498fb1d9738SJakob Bornecrantz vmw_resource_unreference(&res); 499fb1d9738SJakob Bornecrantz 500fb1d9738SJakob Bornecrantz return ret; 501fb1d9738SJakob Bornecrantz } 502fb1d9738SJakob Bornecrantz 503fb1d9738SJakob Bornecrantz int vmw_overlay_num_overlays(struct vmw_private *dev_priv) 504fb1d9738SJakob Bornecrantz { 505fb1d9738SJakob Bornecrantz if (!dev_priv->overlay_priv) 506fb1d9738SJakob Bornecrantz return 0; 507fb1d9738SJakob Bornecrantz 508fb1d9738SJakob Bornecrantz return VMW_MAX_NUM_STREAMS; 509fb1d9738SJakob Bornecrantz } 510fb1d9738SJakob Bornecrantz 511fb1d9738SJakob Bornecrantz int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv) 512fb1d9738SJakob Bornecrantz { 513fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 514fb1d9738SJakob Bornecrantz int i, k; 515fb1d9738SJakob Bornecrantz 516fb1d9738SJakob Bornecrantz if (!overlay) 517fb1d9738SJakob Bornecrantz return 0; 518fb1d9738SJakob Bornecrantz 519fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 520fb1d9738SJakob Bornecrantz 521fb1d9738SJakob Bornecrantz for (i = 0, k = 0; i < VMW_MAX_NUM_STREAMS; i++) 522fb1d9738SJakob Bornecrantz if (!overlay->stream[i].claimed) 523fb1d9738SJakob Bornecrantz k++; 524fb1d9738SJakob Bornecrantz 525fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 526fb1d9738SJakob Bornecrantz 527fb1d9738SJakob Bornecrantz return k; 528fb1d9738SJakob Bornecrantz } 529fb1d9738SJakob Bornecrantz 530fb1d9738SJakob Bornecrantz int vmw_overlay_claim(struct vmw_private *dev_priv, uint32_t *out) 531fb1d9738SJakob Bornecrantz { 532fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 533fb1d9738SJakob Bornecrantz int i; 534fb1d9738SJakob Bornecrantz 535fb1d9738SJakob Bornecrantz if (!overlay) 536fb1d9738SJakob Bornecrantz return -ENOSYS; 537fb1d9738SJakob Bornecrantz 538fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 539fb1d9738SJakob Bornecrantz 540fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 541fb1d9738SJakob Bornecrantz 542fb1d9738SJakob Bornecrantz if (overlay->stream[i].claimed) 543fb1d9738SJakob Bornecrantz continue; 544fb1d9738SJakob Bornecrantz 545fb1d9738SJakob Bornecrantz overlay->stream[i].claimed = true; 546fb1d9738SJakob Bornecrantz *out = i; 547fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 548fb1d9738SJakob Bornecrantz return 0; 549fb1d9738SJakob Bornecrantz } 550fb1d9738SJakob Bornecrantz 551fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 552fb1d9738SJakob Bornecrantz return -ESRCH; 553fb1d9738SJakob Bornecrantz } 554fb1d9738SJakob Bornecrantz 555fb1d9738SJakob Bornecrantz int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id) 556fb1d9738SJakob Bornecrantz { 557fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 558fb1d9738SJakob Bornecrantz 559fb1d9738SJakob Bornecrantz BUG_ON(stream_id >= VMW_MAX_NUM_STREAMS); 560fb1d9738SJakob Bornecrantz 561fb1d9738SJakob Bornecrantz if (!overlay) 562fb1d9738SJakob Bornecrantz return -ENOSYS; 563fb1d9738SJakob Bornecrantz 564fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 565fb1d9738SJakob Bornecrantz 566fb1d9738SJakob Bornecrantz WARN_ON(!overlay->stream[stream_id].claimed); 567fb1d9738SJakob Bornecrantz vmw_overlay_stop(dev_priv, stream_id, false, false); 568fb1d9738SJakob Bornecrantz overlay->stream[stream_id].claimed = false; 569fb1d9738SJakob Bornecrantz 570fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 571fb1d9738SJakob Bornecrantz return 0; 572fb1d9738SJakob Bornecrantz } 573fb1d9738SJakob Bornecrantz 574fb1d9738SJakob Bornecrantz int vmw_overlay_init(struct vmw_private *dev_priv) 575fb1d9738SJakob Bornecrantz { 576fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay; 577fb1d9738SJakob Bornecrantz int i; 578fb1d9738SJakob Bornecrantz 579fb1d9738SJakob Bornecrantz if (dev_priv->overlay_priv) 580fb1d9738SJakob Bornecrantz return -EINVAL; 581fb1d9738SJakob Bornecrantz 582fb1d9738SJakob Bornecrantz if (!(dev_priv->fifo.capabilities & SVGA_FIFO_CAP_VIDEO) && 583fb1d9738SJakob Bornecrantz (dev_priv->fifo.capabilities & SVGA_FIFO_CAP_ESCAPE)) { 584fb1d9738SJakob Bornecrantz DRM_INFO("hardware doesn't support overlays\n"); 585fb1d9738SJakob Bornecrantz return -ENOSYS; 586fb1d9738SJakob Bornecrantz } 587fb1d9738SJakob Bornecrantz 588fb1d9738SJakob Bornecrantz overlay = kmalloc(GFP_KERNEL, sizeof(*overlay)); 589fb1d9738SJakob Bornecrantz if (!overlay) 590fb1d9738SJakob Bornecrantz return -ENOMEM; 591fb1d9738SJakob Bornecrantz 592fb1d9738SJakob Bornecrantz memset(overlay, 0, sizeof(*overlay)); 593fb1d9738SJakob Bornecrantz mutex_init(&overlay->mutex); 594fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 595fb1d9738SJakob Bornecrantz overlay->stream[i].buf = NULL; 596fb1d9738SJakob Bornecrantz overlay->stream[i].paused = false; 597fb1d9738SJakob Bornecrantz overlay->stream[i].claimed = false; 598fb1d9738SJakob Bornecrantz } 599fb1d9738SJakob Bornecrantz 600fb1d9738SJakob Bornecrantz dev_priv->overlay_priv = overlay; 601fb1d9738SJakob Bornecrantz 602fb1d9738SJakob Bornecrantz return 0; 603fb1d9738SJakob Bornecrantz } 604fb1d9738SJakob Bornecrantz 605fb1d9738SJakob Bornecrantz int vmw_overlay_close(struct vmw_private *dev_priv) 606fb1d9738SJakob Bornecrantz { 607fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 608fb1d9738SJakob Bornecrantz bool forgotten_buffer = false; 609fb1d9738SJakob Bornecrantz int i; 610fb1d9738SJakob Bornecrantz 611fb1d9738SJakob Bornecrantz if (!overlay) 612fb1d9738SJakob Bornecrantz return -ENOSYS; 613fb1d9738SJakob Bornecrantz 614fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 615fb1d9738SJakob Bornecrantz if (overlay->stream[i].buf) { 616fb1d9738SJakob Bornecrantz forgotten_buffer = true; 617fb1d9738SJakob Bornecrantz vmw_overlay_stop(dev_priv, i, false, false); 618fb1d9738SJakob Bornecrantz } 619fb1d9738SJakob Bornecrantz } 620fb1d9738SJakob Bornecrantz 621fb1d9738SJakob Bornecrantz WARN_ON(forgotten_buffer); 622fb1d9738SJakob Bornecrantz 623fb1d9738SJakob Bornecrantz dev_priv->overlay_priv = NULL; 624fb1d9738SJakob Bornecrantz kfree(overlay); 625fb1d9738SJakob Bornecrantz 626fb1d9738SJakob Bornecrantz return 0; 627fb1d9738SJakob Bornecrantz } 628