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