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 29760285e7SDavid Howells #include <drm/drmP.h> 30fb1d9738SJakob Bornecrantz #include "vmwgfx_drv.h" 31fb1d9738SJakob Bornecrantz 32760285e7SDavid Howells #include <drm/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 38dcb52271SThomas Hellstrom #define VMW_OVERLAY_CAP_MASK (SVGA_FIFO_CAP_VIDEO | SVGA_FIFO_CAP_ESCAPE) 39fb1d9738SJakob Bornecrantz 40fb1d9738SJakob Bornecrantz struct vmw_stream { 41fb1d9738SJakob Bornecrantz struct vmw_dma_buffer *buf; 42fb1d9738SJakob Bornecrantz bool claimed; 43fb1d9738SJakob Bornecrantz bool paused; 44fb1d9738SJakob Bornecrantz struct drm_vmw_control_stream_arg saved; 45fb1d9738SJakob Bornecrantz }; 46fb1d9738SJakob Bornecrantz 47fb1d9738SJakob Bornecrantz /** 48fb1d9738SJakob Bornecrantz * Overlay control 49fb1d9738SJakob Bornecrantz */ 50fb1d9738SJakob Bornecrantz struct vmw_overlay { 51fb1d9738SJakob Bornecrantz /* 52fb1d9738SJakob Bornecrantz * Each stream is a single overlay. In Xv these are called ports. 53fb1d9738SJakob Bornecrantz */ 54fb1d9738SJakob Bornecrantz struct mutex mutex; 55fb1d9738SJakob Bornecrantz struct vmw_stream stream[VMW_MAX_NUM_STREAMS]; 56fb1d9738SJakob Bornecrantz }; 57fb1d9738SJakob Bornecrantz 58fb1d9738SJakob Bornecrantz static inline struct vmw_overlay *vmw_overlay(struct drm_device *dev) 59fb1d9738SJakob Bornecrantz { 60fb1d9738SJakob Bornecrantz struct vmw_private *dev_priv = vmw_priv(dev); 61fb1d9738SJakob Bornecrantz return dev_priv ? dev_priv->overlay_priv : NULL; 62fb1d9738SJakob Bornecrantz } 63fb1d9738SJakob Bornecrantz 64fb1d9738SJakob Bornecrantz struct vmw_escape_header { 65fb1d9738SJakob Bornecrantz uint32_t cmd; 66fb1d9738SJakob Bornecrantz SVGAFifoCmdEscape body; 67fb1d9738SJakob Bornecrantz }; 68fb1d9738SJakob Bornecrantz 69fb1d9738SJakob Bornecrantz struct vmw_escape_video_flush { 70fb1d9738SJakob Bornecrantz struct vmw_escape_header escape; 71fb1d9738SJakob Bornecrantz SVGAEscapeVideoFlush flush; 72fb1d9738SJakob Bornecrantz }; 73fb1d9738SJakob Bornecrantz 74fb1d9738SJakob Bornecrantz static inline void fill_escape(struct vmw_escape_header *header, 75fb1d9738SJakob Bornecrantz uint32_t size) 76fb1d9738SJakob Bornecrantz { 77fb1d9738SJakob Bornecrantz header->cmd = SVGA_CMD_ESCAPE; 78fb1d9738SJakob Bornecrantz header->body.nsid = SVGA_ESCAPE_NSID_VMWARE; 79fb1d9738SJakob Bornecrantz header->body.size = size; 80fb1d9738SJakob Bornecrantz } 81fb1d9738SJakob Bornecrantz 82fb1d9738SJakob Bornecrantz static inline void fill_flush(struct vmw_escape_video_flush *cmd, 83fb1d9738SJakob Bornecrantz uint32_t stream_id) 84fb1d9738SJakob Bornecrantz { 85fb1d9738SJakob Bornecrantz fill_escape(&cmd->escape, sizeof(cmd->flush)); 86fb1d9738SJakob Bornecrantz cmd->flush.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_FLUSH; 87fb1d9738SJakob Bornecrantz cmd->flush.streamId = stream_id; 88fb1d9738SJakob Bornecrantz } 89fb1d9738SJakob Bornecrantz 90fb1d9738SJakob Bornecrantz /** 91fb1d9738SJakob Bornecrantz * Send put command to hw. 92fb1d9738SJakob Bornecrantz * 93fb1d9738SJakob Bornecrantz * Returns 94fb1d9738SJakob Bornecrantz * -ERESTARTSYS if interrupted by a signal. 95fb1d9738SJakob Bornecrantz */ 96fb1d9738SJakob Bornecrantz static int vmw_overlay_send_put(struct vmw_private *dev_priv, 97fb1d9738SJakob Bornecrantz struct vmw_dma_buffer *buf, 98fb1d9738SJakob Bornecrantz struct drm_vmw_control_stream_arg *arg, 99fb1d9738SJakob Bornecrantz bool interruptible) 100fb1d9738SJakob Bornecrantz { 10144031d25SJakob Bornecrantz struct vmw_escape_video_flush *flush; 10244031d25SJakob Bornecrantz size_t fifo_size; 103c8261a96SSinclair Yeh bool have_so = (dev_priv->active_display_unit == vmw_du_screen_object); 10444031d25SJakob Bornecrantz int i, num_items; 105b37a6b9aSThomas Hellstrom SVGAGuestPtr ptr; 10644031d25SJakob Bornecrantz 107fb1d9738SJakob Bornecrantz struct { 108fb1d9738SJakob Bornecrantz struct vmw_escape_header escape; 109fb1d9738SJakob Bornecrantz struct { 110fb1d9738SJakob Bornecrantz uint32_t cmdType; 111fb1d9738SJakob Bornecrantz uint32_t streamId; 112fb1d9738SJakob Bornecrantz } header; 11344031d25SJakob Bornecrantz } *cmds; 114fb1d9738SJakob Bornecrantz struct { 115fb1d9738SJakob Bornecrantz uint32_t registerId; 116fb1d9738SJakob Bornecrantz uint32_t value; 11744031d25SJakob Bornecrantz } *items; 118fb1d9738SJakob Bornecrantz 11944031d25SJakob Bornecrantz /* defines are a index needs + 1 */ 12044031d25SJakob Bornecrantz if (have_so) 12144031d25SJakob Bornecrantz num_items = SVGA_VIDEO_DST_SCREEN_ID + 1; 122fb1d9738SJakob Bornecrantz else 12344031d25SJakob Bornecrantz num_items = SVGA_VIDEO_PITCH_3 + 1; 12444031d25SJakob Bornecrantz 12544031d25SJakob Bornecrantz fifo_size = sizeof(*cmds) + sizeof(*flush) + sizeof(*items) * num_items; 12644031d25SJakob Bornecrantz 12744031d25SJakob Bornecrantz cmds = vmw_fifo_reserve(dev_priv, fifo_size); 12844031d25SJakob Bornecrantz /* hardware has hung, can't do anything here */ 12944031d25SJakob Bornecrantz if (!cmds) 13044031d25SJakob Bornecrantz return -ENOMEM; 13144031d25SJakob Bornecrantz 13244031d25SJakob Bornecrantz items = (typeof(items))&cmds[1]; 13344031d25SJakob Bornecrantz flush = (struct vmw_escape_video_flush *)&items[num_items]; 13444031d25SJakob Bornecrantz 13544031d25SJakob Bornecrantz /* the size is header + number of items */ 13644031d25SJakob Bornecrantz fill_escape(&cmds->escape, sizeof(*items) * (num_items + 1)); 13744031d25SJakob Bornecrantz 13844031d25SJakob Bornecrantz cmds->header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS; 13944031d25SJakob Bornecrantz cmds->header.streamId = arg->stream_id; 14044031d25SJakob Bornecrantz 14144031d25SJakob Bornecrantz /* the IDs are neatly numbered */ 14244031d25SJakob Bornecrantz for (i = 0; i < num_items; i++) 14344031d25SJakob Bornecrantz items[i].registerId = i; 14444031d25SJakob Bornecrantz 145b37a6b9aSThomas Hellstrom vmw_bo_get_guest_ptr(&buf->base, &ptr); 146b37a6b9aSThomas Hellstrom ptr.offset += arg->offset; 14744031d25SJakob Bornecrantz 14844031d25SJakob Bornecrantz items[SVGA_VIDEO_ENABLED].value = true; 14944031d25SJakob Bornecrantz items[SVGA_VIDEO_FLAGS].value = arg->flags; 150b37a6b9aSThomas Hellstrom items[SVGA_VIDEO_DATA_OFFSET].value = ptr.offset; 15144031d25SJakob Bornecrantz items[SVGA_VIDEO_FORMAT].value = arg->format; 15244031d25SJakob Bornecrantz items[SVGA_VIDEO_COLORKEY].value = arg->color_key; 15344031d25SJakob Bornecrantz items[SVGA_VIDEO_SIZE].value = arg->size; 15444031d25SJakob Bornecrantz items[SVGA_VIDEO_WIDTH].value = arg->width; 15544031d25SJakob Bornecrantz items[SVGA_VIDEO_HEIGHT].value = arg->height; 15644031d25SJakob Bornecrantz items[SVGA_VIDEO_SRC_X].value = arg->src.x; 15744031d25SJakob Bornecrantz items[SVGA_VIDEO_SRC_Y].value = arg->src.y; 15844031d25SJakob Bornecrantz items[SVGA_VIDEO_SRC_WIDTH].value = arg->src.w; 15944031d25SJakob Bornecrantz items[SVGA_VIDEO_SRC_HEIGHT].value = arg->src.h; 16044031d25SJakob Bornecrantz items[SVGA_VIDEO_DST_X].value = arg->dst.x; 16144031d25SJakob Bornecrantz items[SVGA_VIDEO_DST_Y].value = arg->dst.y; 16244031d25SJakob Bornecrantz items[SVGA_VIDEO_DST_WIDTH].value = arg->dst.w; 16344031d25SJakob Bornecrantz items[SVGA_VIDEO_DST_HEIGHT].value = arg->dst.h; 16444031d25SJakob Bornecrantz items[SVGA_VIDEO_PITCH_1].value = arg->pitch[0]; 16544031d25SJakob Bornecrantz items[SVGA_VIDEO_PITCH_2].value = arg->pitch[1]; 16644031d25SJakob Bornecrantz items[SVGA_VIDEO_PITCH_3].value = arg->pitch[2]; 16744031d25SJakob Bornecrantz if (have_so) { 168b37a6b9aSThomas Hellstrom items[SVGA_VIDEO_DATA_GMRID].value = ptr.gmrId; 16944031d25SJakob Bornecrantz items[SVGA_VIDEO_DST_SCREEN_ID].value = SVGA_ID_INVALID; 170fb1d9738SJakob Bornecrantz } 171fb1d9738SJakob Bornecrantz 17244031d25SJakob Bornecrantz fill_flush(flush, arg->stream_id); 173fb1d9738SJakob Bornecrantz 17444031d25SJakob Bornecrantz vmw_fifo_commit(dev_priv, fifo_size); 175fb1d9738SJakob Bornecrantz 176fb1d9738SJakob Bornecrantz return 0; 177fb1d9738SJakob Bornecrantz } 178fb1d9738SJakob Bornecrantz 179fb1d9738SJakob Bornecrantz /** 180fb1d9738SJakob Bornecrantz * Send stop command to hw. 181fb1d9738SJakob Bornecrantz * 182fb1d9738SJakob Bornecrantz * Returns 183fb1d9738SJakob Bornecrantz * -ERESTARTSYS if interrupted by a signal. 184fb1d9738SJakob Bornecrantz */ 185fb1d9738SJakob Bornecrantz static int vmw_overlay_send_stop(struct vmw_private *dev_priv, 186fb1d9738SJakob Bornecrantz uint32_t stream_id, 187fb1d9738SJakob Bornecrantz bool interruptible) 188fb1d9738SJakob Bornecrantz { 189fb1d9738SJakob Bornecrantz struct { 190fb1d9738SJakob Bornecrantz struct vmw_escape_header escape; 191fb1d9738SJakob Bornecrantz SVGAEscapeVideoSetRegs body; 192fb1d9738SJakob Bornecrantz struct vmw_escape_video_flush flush; 193fb1d9738SJakob Bornecrantz } *cmds; 194fb1d9738SJakob Bornecrantz int ret; 195fb1d9738SJakob Bornecrantz 196fb1d9738SJakob Bornecrantz for (;;) { 197fb1d9738SJakob Bornecrantz cmds = vmw_fifo_reserve(dev_priv, sizeof(*cmds)); 198fb1d9738SJakob Bornecrantz if (cmds) 199fb1d9738SJakob Bornecrantz break; 200fb1d9738SJakob Bornecrantz 201fb1d9738SJakob Bornecrantz ret = vmw_fallback_wait(dev_priv, false, true, 0, 202fb1d9738SJakob Bornecrantz interruptible, 3*HZ); 203fb1d9738SJakob Bornecrantz if (interruptible && ret == -ERESTARTSYS) 204fb1d9738SJakob Bornecrantz return ret; 205fb1d9738SJakob Bornecrantz else 206fb1d9738SJakob Bornecrantz BUG_ON(ret != 0); 207fb1d9738SJakob Bornecrantz } 208fb1d9738SJakob Bornecrantz 209fb1d9738SJakob Bornecrantz fill_escape(&cmds->escape, sizeof(cmds->body)); 210fb1d9738SJakob Bornecrantz cmds->body.header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS; 211fb1d9738SJakob Bornecrantz cmds->body.header.streamId = stream_id; 212fb1d9738SJakob Bornecrantz cmds->body.items[0].registerId = SVGA_VIDEO_ENABLED; 213fb1d9738SJakob Bornecrantz cmds->body.items[0].value = false; 214fb1d9738SJakob Bornecrantz fill_flush(&cmds->flush, stream_id); 215fb1d9738SJakob Bornecrantz 216fb1d9738SJakob Bornecrantz vmw_fifo_commit(dev_priv, sizeof(*cmds)); 217fb1d9738SJakob Bornecrantz 218fb1d9738SJakob Bornecrantz return 0; 219fb1d9738SJakob Bornecrantz } 220fb1d9738SJakob Bornecrantz 221fb1d9738SJakob Bornecrantz /** 22244031d25SJakob Bornecrantz * Move a buffer to vram or gmr if @pin is set, else unpin the buffer. 223d991ef03SJakob Bornecrantz * 22444031d25SJakob Bornecrantz * With the introduction of screen objects buffers could now be 22544031d25SJakob Bornecrantz * used with GMRs instead of being locked to vram. 226d991ef03SJakob Bornecrantz */ 227d991ef03SJakob Bornecrantz static int vmw_overlay_move_buffer(struct vmw_private *dev_priv, 228d991ef03SJakob Bornecrantz struct vmw_dma_buffer *buf, 229d991ef03SJakob Bornecrantz bool pin, bool inter) 230d991ef03SJakob Bornecrantz { 23144031d25SJakob Bornecrantz if (!pin) 232d991ef03SJakob Bornecrantz return vmw_dmabuf_unpin(dev_priv, buf, inter); 23344031d25SJakob Bornecrantz 234c8261a96SSinclair Yeh if (dev_priv->active_display_unit == vmw_du_legacy) 23544031d25SJakob Bornecrantz return vmw_dmabuf_to_vram(dev_priv, buf, true, inter); 23644031d25SJakob Bornecrantz 23744031d25SJakob Bornecrantz return vmw_dmabuf_to_vram_or_gmr(dev_priv, buf, true, inter); 238d991ef03SJakob Bornecrantz } 239d991ef03SJakob Bornecrantz 240d991ef03SJakob Bornecrantz /** 241fb1d9738SJakob Bornecrantz * Stop or pause a stream. 242fb1d9738SJakob Bornecrantz * 243fb1d9738SJakob Bornecrantz * If the stream is paused the no evict flag is removed from the buffer 244fb1d9738SJakob Bornecrantz * but left in vram. This allows for instance mode_set to evict it 245fb1d9738SJakob Bornecrantz * should it need to. 246fb1d9738SJakob Bornecrantz * 247fb1d9738SJakob Bornecrantz * The caller must hold the overlay lock. 248fb1d9738SJakob Bornecrantz * 249fb1d9738SJakob Bornecrantz * @stream_id which stream to stop/pause. 250fb1d9738SJakob Bornecrantz * @pause true to pause, false to stop completely. 251fb1d9738SJakob Bornecrantz */ 252fb1d9738SJakob Bornecrantz static int vmw_overlay_stop(struct vmw_private *dev_priv, 253fb1d9738SJakob Bornecrantz uint32_t stream_id, bool pause, 254fb1d9738SJakob Bornecrantz bool interruptible) 255fb1d9738SJakob Bornecrantz { 256fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 257fb1d9738SJakob Bornecrantz struct vmw_stream *stream = &overlay->stream[stream_id]; 258fb1d9738SJakob Bornecrantz int ret; 259fb1d9738SJakob Bornecrantz 260fb1d9738SJakob Bornecrantz /* no buffer attached the stream is completely stopped */ 261fb1d9738SJakob Bornecrantz if (!stream->buf) 262fb1d9738SJakob Bornecrantz return 0; 263fb1d9738SJakob Bornecrantz 264fb1d9738SJakob Bornecrantz /* If the stream is paused this is already done */ 265fb1d9738SJakob Bornecrantz if (!stream->paused) { 266fb1d9738SJakob Bornecrantz ret = vmw_overlay_send_stop(dev_priv, stream_id, 267fb1d9738SJakob Bornecrantz interruptible); 268fb1d9738SJakob Bornecrantz if (ret) 269fb1d9738SJakob Bornecrantz return ret; 270fb1d9738SJakob Bornecrantz 271fb1d9738SJakob Bornecrantz /* We just remove the NO_EVICT flag so no -ENOMEM */ 272d991ef03SJakob Bornecrantz ret = vmw_overlay_move_buffer(dev_priv, stream->buf, false, 273fb1d9738SJakob Bornecrantz interruptible); 274fb1d9738SJakob Bornecrantz if (interruptible && ret == -ERESTARTSYS) 275fb1d9738SJakob Bornecrantz return ret; 276fb1d9738SJakob Bornecrantz else 277fb1d9738SJakob Bornecrantz BUG_ON(ret != 0); 278fb1d9738SJakob Bornecrantz } 279fb1d9738SJakob Bornecrantz 280fb1d9738SJakob Bornecrantz if (!pause) { 281fb1d9738SJakob Bornecrantz vmw_dmabuf_unreference(&stream->buf); 282fb1d9738SJakob Bornecrantz stream->paused = false; 283fb1d9738SJakob Bornecrantz } else { 284fb1d9738SJakob Bornecrantz stream->paused = true; 285fb1d9738SJakob Bornecrantz } 286fb1d9738SJakob Bornecrantz 287fb1d9738SJakob Bornecrantz return 0; 288fb1d9738SJakob Bornecrantz } 289fb1d9738SJakob Bornecrantz 290fb1d9738SJakob Bornecrantz /** 291fb1d9738SJakob Bornecrantz * Update a stream and send any put or stop fifo commands needed. 292fb1d9738SJakob Bornecrantz * 293fb1d9738SJakob Bornecrantz * The caller must hold the overlay lock. 294fb1d9738SJakob Bornecrantz * 295fb1d9738SJakob Bornecrantz * Returns 296fb1d9738SJakob Bornecrantz * -ENOMEM if buffer doesn't fit in vram. 297fb1d9738SJakob Bornecrantz * -ERESTARTSYS if interrupted. 298fb1d9738SJakob Bornecrantz */ 299fb1d9738SJakob Bornecrantz static int vmw_overlay_update_stream(struct vmw_private *dev_priv, 300fb1d9738SJakob Bornecrantz struct vmw_dma_buffer *buf, 301fb1d9738SJakob Bornecrantz struct drm_vmw_control_stream_arg *arg, 302fb1d9738SJakob Bornecrantz bool interruptible) 303fb1d9738SJakob Bornecrantz { 304fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 305fb1d9738SJakob Bornecrantz struct vmw_stream *stream = &overlay->stream[arg->stream_id]; 306fb1d9738SJakob Bornecrantz int ret = 0; 307fb1d9738SJakob Bornecrantz 308fb1d9738SJakob Bornecrantz if (!buf) 309fb1d9738SJakob Bornecrantz return -EINVAL; 310fb1d9738SJakob Bornecrantz 311fb1d9738SJakob Bornecrantz DRM_DEBUG(" %s: old %p, new %p, %spaused\n", __func__, 312fb1d9738SJakob Bornecrantz stream->buf, buf, stream->paused ? "" : "not "); 313fb1d9738SJakob Bornecrantz 314fb1d9738SJakob Bornecrantz if (stream->buf != buf) { 315fb1d9738SJakob Bornecrantz ret = vmw_overlay_stop(dev_priv, arg->stream_id, 316fb1d9738SJakob Bornecrantz false, interruptible); 317fb1d9738SJakob Bornecrantz if (ret) 318fb1d9738SJakob Bornecrantz return ret; 319fb1d9738SJakob Bornecrantz } else if (!stream->paused) { 320fb1d9738SJakob Bornecrantz /* If the buffers match and not paused then just send 321fb1d9738SJakob Bornecrantz * the put command, no need to do anything else. 322fb1d9738SJakob Bornecrantz */ 323fb1d9738SJakob Bornecrantz ret = vmw_overlay_send_put(dev_priv, buf, arg, interruptible); 324fb1d9738SJakob Bornecrantz if (ret == 0) 325fb1d9738SJakob Bornecrantz stream->saved = *arg; 326fb1d9738SJakob Bornecrantz else 327fb1d9738SJakob Bornecrantz BUG_ON(!interruptible); 328fb1d9738SJakob Bornecrantz 329fb1d9738SJakob Bornecrantz return ret; 330fb1d9738SJakob Bornecrantz } 331fb1d9738SJakob Bornecrantz 332fb1d9738SJakob Bornecrantz /* We don't start the old stream if we are interrupted. 333fb1d9738SJakob Bornecrantz * Might return -ENOMEM if it can't fit the buffer in vram. 334fb1d9738SJakob Bornecrantz */ 335d991ef03SJakob Bornecrantz ret = vmw_overlay_move_buffer(dev_priv, buf, true, interruptible); 336fb1d9738SJakob Bornecrantz if (ret) 337fb1d9738SJakob Bornecrantz return ret; 338fb1d9738SJakob Bornecrantz 339fb1d9738SJakob Bornecrantz ret = vmw_overlay_send_put(dev_priv, buf, arg, interruptible); 340fb1d9738SJakob Bornecrantz if (ret) { 341fb1d9738SJakob Bornecrantz /* This one needs to happen no matter what. We only remove 342fb1d9738SJakob Bornecrantz * the NO_EVICT flag so this is safe from -ENOMEM. 343fb1d9738SJakob Bornecrantz */ 344d991ef03SJakob Bornecrantz BUG_ON(vmw_overlay_move_buffer(dev_priv, buf, false, false) 345d991ef03SJakob Bornecrantz != 0); 346fb1d9738SJakob Bornecrantz return ret; 347fb1d9738SJakob Bornecrantz } 348fb1d9738SJakob Bornecrantz 349fb1d9738SJakob Bornecrantz if (stream->buf != buf) 350fb1d9738SJakob Bornecrantz stream->buf = vmw_dmabuf_reference(buf); 351fb1d9738SJakob Bornecrantz stream->saved = *arg; 352792778e8SJakob Bornecrantz /* stream is no longer stopped/paused */ 353792778e8SJakob Bornecrantz stream->paused = false; 354fb1d9738SJakob Bornecrantz 355fb1d9738SJakob Bornecrantz return 0; 356fb1d9738SJakob Bornecrantz } 357fb1d9738SJakob Bornecrantz 358fb1d9738SJakob Bornecrantz /** 359fb1d9738SJakob Bornecrantz * Stop all streams. 360fb1d9738SJakob Bornecrantz * 361fb1d9738SJakob Bornecrantz * Used by the fb code when starting. 362fb1d9738SJakob Bornecrantz * 363fb1d9738SJakob Bornecrantz * Takes the overlay lock. 364fb1d9738SJakob Bornecrantz */ 365fb1d9738SJakob Bornecrantz int vmw_overlay_stop_all(struct vmw_private *dev_priv) 366fb1d9738SJakob Bornecrantz { 367fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 368fb1d9738SJakob Bornecrantz int i, ret; 369fb1d9738SJakob Bornecrantz 370fb1d9738SJakob Bornecrantz if (!overlay) 371fb1d9738SJakob Bornecrantz return 0; 372fb1d9738SJakob Bornecrantz 373fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 374fb1d9738SJakob Bornecrantz 375fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 376fb1d9738SJakob Bornecrantz struct vmw_stream *stream = &overlay->stream[i]; 377fb1d9738SJakob Bornecrantz if (!stream->buf) 378fb1d9738SJakob Bornecrantz continue; 379fb1d9738SJakob Bornecrantz 380fb1d9738SJakob Bornecrantz ret = vmw_overlay_stop(dev_priv, i, false, false); 381fb1d9738SJakob Bornecrantz WARN_ON(ret != 0); 382fb1d9738SJakob Bornecrantz } 383fb1d9738SJakob Bornecrantz 384fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 385fb1d9738SJakob Bornecrantz 386fb1d9738SJakob Bornecrantz return 0; 387fb1d9738SJakob Bornecrantz } 388fb1d9738SJakob Bornecrantz 389fb1d9738SJakob Bornecrantz /** 390fb1d9738SJakob Bornecrantz * Try to resume all paused streams. 391fb1d9738SJakob Bornecrantz * 392fb1d9738SJakob Bornecrantz * Used by the kms code after moving a new scanout buffer to vram. 393fb1d9738SJakob Bornecrantz * 394fb1d9738SJakob Bornecrantz * Takes the overlay lock. 395fb1d9738SJakob Bornecrantz */ 396fb1d9738SJakob Bornecrantz int vmw_overlay_resume_all(struct vmw_private *dev_priv) 397fb1d9738SJakob Bornecrantz { 398fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 399fb1d9738SJakob Bornecrantz int i, ret; 400fb1d9738SJakob Bornecrantz 401fb1d9738SJakob Bornecrantz if (!overlay) 402fb1d9738SJakob Bornecrantz return 0; 403fb1d9738SJakob Bornecrantz 404fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 405fb1d9738SJakob Bornecrantz 406fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 407fb1d9738SJakob Bornecrantz struct vmw_stream *stream = &overlay->stream[i]; 408fb1d9738SJakob Bornecrantz if (!stream->paused) 409fb1d9738SJakob Bornecrantz continue; 410fb1d9738SJakob Bornecrantz 411fb1d9738SJakob Bornecrantz ret = vmw_overlay_update_stream(dev_priv, stream->buf, 412fb1d9738SJakob Bornecrantz &stream->saved, false); 413fb1d9738SJakob Bornecrantz if (ret != 0) 414fb1d9738SJakob Bornecrantz DRM_INFO("%s: *warning* failed to resume stream %i\n", 415fb1d9738SJakob Bornecrantz __func__, i); 416fb1d9738SJakob Bornecrantz } 417fb1d9738SJakob Bornecrantz 418fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 419fb1d9738SJakob Bornecrantz 420fb1d9738SJakob Bornecrantz return 0; 421fb1d9738SJakob Bornecrantz } 422fb1d9738SJakob Bornecrantz 423fb1d9738SJakob Bornecrantz /** 424fb1d9738SJakob Bornecrantz * Pauses all active streams. 425fb1d9738SJakob Bornecrantz * 426fb1d9738SJakob Bornecrantz * Used by the kms code when moving a new scanout buffer to vram. 427fb1d9738SJakob Bornecrantz * 428fb1d9738SJakob Bornecrantz * Takes the overlay lock. 429fb1d9738SJakob Bornecrantz */ 430fb1d9738SJakob Bornecrantz int vmw_overlay_pause_all(struct vmw_private *dev_priv) 431fb1d9738SJakob Bornecrantz { 432fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 433fb1d9738SJakob Bornecrantz int i, ret; 434fb1d9738SJakob Bornecrantz 435fb1d9738SJakob Bornecrantz if (!overlay) 436fb1d9738SJakob Bornecrantz return 0; 437fb1d9738SJakob Bornecrantz 438fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 439fb1d9738SJakob Bornecrantz 440fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 441fb1d9738SJakob Bornecrantz if (overlay->stream[i].paused) 442fb1d9738SJakob Bornecrantz DRM_INFO("%s: *warning* stream %i already paused\n", 443fb1d9738SJakob Bornecrantz __func__, i); 444fb1d9738SJakob Bornecrantz ret = vmw_overlay_stop(dev_priv, i, true, false); 445fb1d9738SJakob Bornecrantz WARN_ON(ret != 0); 446fb1d9738SJakob Bornecrantz } 447fb1d9738SJakob Bornecrantz 448fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 449fb1d9738SJakob Bornecrantz 450fb1d9738SJakob Bornecrantz return 0; 451fb1d9738SJakob Bornecrantz } 452fb1d9738SJakob Bornecrantz 453dcb52271SThomas Hellstrom 454dcb52271SThomas Hellstrom static bool vmw_overlay_available(const struct vmw_private *dev_priv) 455dcb52271SThomas Hellstrom { 456dcb52271SThomas Hellstrom return (dev_priv->overlay_priv != NULL && 457dcb52271SThomas Hellstrom ((dev_priv->fifo.capabilities & VMW_OVERLAY_CAP_MASK) == 458dcb52271SThomas Hellstrom VMW_OVERLAY_CAP_MASK)); 459dcb52271SThomas Hellstrom } 460dcb52271SThomas Hellstrom 461fb1d9738SJakob Bornecrantz int vmw_overlay_ioctl(struct drm_device *dev, void *data, 462fb1d9738SJakob Bornecrantz struct drm_file *file_priv) 463fb1d9738SJakob Bornecrantz { 464fb1d9738SJakob Bornecrantz struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 465fb1d9738SJakob Bornecrantz struct vmw_private *dev_priv = vmw_priv(dev); 466fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 467fb1d9738SJakob Bornecrantz struct drm_vmw_control_stream_arg *arg = 468fb1d9738SJakob Bornecrantz (struct drm_vmw_control_stream_arg *)data; 469fb1d9738SJakob Bornecrantz struct vmw_dma_buffer *buf; 470fb1d9738SJakob Bornecrantz struct vmw_resource *res; 471fb1d9738SJakob Bornecrantz int ret; 472fb1d9738SJakob Bornecrantz 473dcb52271SThomas Hellstrom if (!vmw_overlay_available(dev_priv)) 474fb1d9738SJakob Bornecrantz return -ENOSYS; 475fb1d9738SJakob Bornecrantz 476fb1d9738SJakob Bornecrantz ret = vmw_user_stream_lookup(dev_priv, tfile, &arg->stream_id, &res); 477fb1d9738SJakob Bornecrantz if (ret) 478fb1d9738SJakob Bornecrantz return ret; 479fb1d9738SJakob Bornecrantz 480fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 481fb1d9738SJakob Bornecrantz 482fb1d9738SJakob Bornecrantz if (!arg->enabled) { 483fb1d9738SJakob Bornecrantz ret = vmw_overlay_stop(dev_priv, arg->stream_id, false, true); 484fb1d9738SJakob Bornecrantz goto out_unlock; 485fb1d9738SJakob Bornecrantz } 486fb1d9738SJakob Bornecrantz 487fb1d9738SJakob Bornecrantz ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &buf); 488fb1d9738SJakob Bornecrantz if (ret) 489fb1d9738SJakob Bornecrantz goto out_unlock; 490fb1d9738SJakob Bornecrantz 491fb1d9738SJakob Bornecrantz ret = vmw_overlay_update_stream(dev_priv, buf, arg, true); 492fb1d9738SJakob Bornecrantz 493fb1d9738SJakob Bornecrantz vmw_dmabuf_unreference(&buf); 494fb1d9738SJakob Bornecrantz 495fb1d9738SJakob Bornecrantz out_unlock: 496fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 497fb1d9738SJakob Bornecrantz vmw_resource_unreference(&res); 498fb1d9738SJakob Bornecrantz 499fb1d9738SJakob Bornecrantz return ret; 500fb1d9738SJakob Bornecrantz } 501fb1d9738SJakob Bornecrantz 502fb1d9738SJakob Bornecrantz int vmw_overlay_num_overlays(struct vmw_private *dev_priv) 503fb1d9738SJakob Bornecrantz { 504dcb52271SThomas Hellstrom if (!vmw_overlay_available(dev_priv)) 505fb1d9738SJakob Bornecrantz return 0; 506fb1d9738SJakob Bornecrantz 507fb1d9738SJakob Bornecrantz return VMW_MAX_NUM_STREAMS; 508fb1d9738SJakob Bornecrantz } 509fb1d9738SJakob Bornecrantz 510fb1d9738SJakob Bornecrantz int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv) 511fb1d9738SJakob Bornecrantz { 512fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 513fb1d9738SJakob Bornecrantz int i, k; 514fb1d9738SJakob Bornecrantz 515dcb52271SThomas Hellstrom if (!vmw_overlay_available(dev_priv)) 516fb1d9738SJakob Bornecrantz return 0; 517fb1d9738SJakob Bornecrantz 518fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 519fb1d9738SJakob Bornecrantz 520fb1d9738SJakob Bornecrantz for (i = 0, k = 0; i < VMW_MAX_NUM_STREAMS; i++) 521fb1d9738SJakob Bornecrantz if (!overlay->stream[i].claimed) 522fb1d9738SJakob Bornecrantz k++; 523fb1d9738SJakob Bornecrantz 524fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 525fb1d9738SJakob Bornecrantz 526fb1d9738SJakob Bornecrantz return k; 527fb1d9738SJakob Bornecrantz } 528fb1d9738SJakob Bornecrantz 529fb1d9738SJakob Bornecrantz int vmw_overlay_claim(struct vmw_private *dev_priv, uint32_t *out) 530fb1d9738SJakob Bornecrantz { 531fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 532fb1d9738SJakob Bornecrantz int i; 533fb1d9738SJakob Bornecrantz 534fb1d9738SJakob Bornecrantz if (!overlay) 535fb1d9738SJakob Bornecrantz return -ENOSYS; 536fb1d9738SJakob Bornecrantz 537fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 538fb1d9738SJakob Bornecrantz 539fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 540fb1d9738SJakob Bornecrantz 541fb1d9738SJakob Bornecrantz if (overlay->stream[i].claimed) 542fb1d9738SJakob Bornecrantz continue; 543fb1d9738SJakob Bornecrantz 544fb1d9738SJakob Bornecrantz overlay->stream[i].claimed = true; 545fb1d9738SJakob Bornecrantz *out = i; 546fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 547fb1d9738SJakob Bornecrantz return 0; 548fb1d9738SJakob Bornecrantz } 549fb1d9738SJakob Bornecrantz 550fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 551fb1d9738SJakob Bornecrantz return -ESRCH; 552fb1d9738SJakob Bornecrantz } 553fb1d9738SJakob Bornecrantz 554fb1d9738SJakob Bornecrantz int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id) 555fb1d9738SJakob Bornecrantz { 556fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 557fb1d9738SJakob Bornecrantz 558fb1d9738SJakob Bornecrantz BUG_ON(stream_id >= VMW_MAX_NUM_STREAMS); 559fb1d9738SJakob Bornecrantz 560fb1d9738SJakob Bornecrantz if (!overlay) 561fb1d9738SJakob Bornecrantz return -ENOSYS; 562fb1d9738SJakob Bornecrantz 563fb1d9738SJakob Bornecrantz mutex_lock(&overlay->mutex); 564fb1d9738SJakob Bornecrantz 565fb1d9738SJakob Bornecrantz WARN_ON(!overlay->stream[stream_id].claimed); 566fb1d9738SJakob Bornecrantz vmw_overlay_stop(dev_priv, stream_id, false, false); 567fb1d9738SJakob Bornecrantz overlay->stream[stream_id].claimed = false; 568fb1d9738SJakob Bornecrantz 569fb1d9738SJakob Bornecrantz mutex_unlock(&overlay->mutex); 570fb1d9738SJakob Bornecrantz return 0; 571fb1d9738SJakob Bornecrantz } 572fb1d9738SJakob Bornecrantz 573fb1d9738SJakob Bornecrantz int vmw_overlay_init(struct vmw_private *dev_priv) 574fb1d9738SJakob Bornecrantz { 575fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay; 576fb1d9738SJakob Bornecrantz int i; 577fb1d9738SJakob Bornecrantz 578fb1d9738SJakob Bornecrantz if (dev_priv->overlay_priv) 579fb1d9738SJakob Bornecrantz return -EINVAL; 580fb1d9738SJakob Bornecrantz 581f35119d6SRakib Mullick overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); 582fb1d9738SJakob Bornecrantz if (!overlay) 583fb1d9738SJakob Bornecrantz return -ENOMEM; 584fb1d9738SJakob Bornecrantz 585fb1d9738SJakob Bornecrantz mutex_init(&overlay->mutex); 586fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 587fb1d9738SJakob Bornecrantz overlay->stream[i].buf = NULL; 588fb1d9738SJakob Bornecrantz overlay->stream[i].paused = false; 589fb1d9738SJakob Bornecrantz overlay->stream[i].claimed = false; 590fb1d9738SJakob Bornecrantz } 591fb1d9738SJakob Bornecrantz 592fb1d9738SJakob Bornecrantz dev_priv->overlay_priv = overlay; 593fb1d9738SJakob Bornecrantz 594fb1d9738SJakob Bornecrantz return 0; 595fb1d9738SJakob Bornecrantz } 596fb1d9738SJakob Bornecrantz 597fb1d9738SJakob Bornecrantz int vmw_overlay_close(struct vmw_private *dev_priv) 598fb1d9738SJakob Bornecrantz { 599fb1d9738SJakob Bornecrantz struct vmw_overlay *overlay = dev_priv->overlay_priv; 600fb1d9738SJakob Bornecrantz bool forgotten_buffer = false; 601fb1d9738SJakob Bornecrantz int i; 602fb1d9738SJakob Bornecrantz 603fb1d9738SJakob Bornecrantz if (!overlay) 604fb1d9738SJakob Bornecrantz return -ENOSYS; 605fb1d9738SJakob Bornecrantz 606fb1d9738SJakob Bornecrantz for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { 607fb1d9738SJakob Bornecrantz if (overlay->stream[i].buf) { 608fb1d9738SJakob Bornecrantz forgotten_buffer = true; 609fb1d9738SJakob Bornecrantz vmw_overlay_stop(dev_priv, i, false, false); 610fb1d9738SJakob Bornecrantz } 611fb1d9738SJakob Bornecrantz } 612fb1d9738SJakob Bornecrantz 613fb1d9738SJakob Bornecrantz WARN_ON(forgotten_buffer); 614fb1d9738SJakob Bornecrantz 615fb1d9738SJakob Bornecrantz dev_priv->overlay_priv = NULL; 616fb1d9738SJakob Bornecrantz kfree(overlay); 617fb1d9738SJakob Bornecrantz 618fb1d9738SJakob Bornecrantz return 0; 619fb1d9738SJakob Bornecrantz } 620