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