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