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