Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vmwgfx_overlay.c
Go to the documentation of this file.
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 <drm/drmP.h>
30 #include "vmwgfx_drv.h"
31 
32 #include <drm/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 {
41  bool claimed;
42  bool paused;
44 };
45 
49 struct vmw_overlay {
50  /*
51  * Each stream is a single overlay. In Xv these are called ports.
52  */
53  struct mutex mutex;
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 
66 };
67 
71 };
72 
73 static inline void fill_escape(struct vmw_escape_header *header,
74  uint32_t size)
75 {
76  header->cmd = SVGA_CMD_ESCAPE;
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));
86  cmd->flush.streamId = stream_id;
87 }
88 
95 static int vmw_overlay_send_put(struct vmw_private *dev_priv,
96  struct vmw_dma_buffer *buf,
98  bool interruptible)
99 {
101  size_t fifo_size;
102  bool have_so = dev_priv->sou_priv ? true : false;
103  int i, num_items;
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;
169  }
170 
171  fill_flush(flush, arg->stream_id);
172 
173  vmw_fifo_commit(dev_priv, fifo_size);
174 
175  return 0;
176 }
177 
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;
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 
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 
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 
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 
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 
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 
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 
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);
489 
490  return ret;
491 }
492 
494 {
495  if (!dev_priv->overlay_priv)
496  return 0;
497 
498  return VMW_MAX_NUM_STREAMS;
499 }
500 
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 }