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