0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include <drm/ttm/ttm_placement.h>
0029
0030 #include "device_include/svga_overlay.h"
0031 #include "device_include/svga_escape.h"
0032
0033 #include "vmwgfx_drv.h"
0034
0035 #define VMW_MAX_NUM_STREAMS 1
0036 #define VMW_OVERLAY_CAP_MASK (SVGA_FIFO_CAP_VIDEO | SVGA_FIFO_CAP_ESCAPE)
0037
0038 struct vmw_stream {
0039 struct vmw_buffer_object *buf;
0040 bool claimed;
0041 bool paused;
0042 struct drm_vmw_control_stream_arg saved;
0043 };
0044
0045
0046
0047
0048 struct vmw_overlay {
0049
0050
0051
0052 struct mutex mutex;
0053 struct vmw_stream stream[VMW_MAX_NUM_STREAMS];
0054 };
0055
0056 static inline struct vmw_overlay *vmw_overlay(struct drm_device *dev)
0057 {
0058 struct vmw_private *dev_priv = vmw_priv(dev);
0059 return dev_priv ? dev_priv->overlay_priv : NULL;
0060 }
0061
0062 struct vmw_escape_header {
0063 uint32_t cmd;
0064 SVGAFifoCmdEscape body;
0065 };
0066
0067 struct vmw_escape_video_flush {
0068 struct vmw_escape_header escape;
0069 SVGAEscapeVideoFlush flush;
0070 };
0071
0072 static inline void fill_escape(struct vmw_escape_header *header,
0073 uint32_t size)
0074 {
0075 header->cmd = SVGA_CMD_ESCAPE;
0076 header->body.nsid = SVGA_ESCAPE_NSID_VMWARE;
0077 header->body.size = size;
0078 }
0079
0080 static inline void fill_flush(struct vmw_escape_video_flush *cmd,
0081 uint32_t stream_id)
0082 {
0083 fill_escape(&cmd->escape, sizeof(cmd->flush));
0084 cmd->flush.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_FLUSH;
0085 cmd->flush.streamId = stream_id;
0086 }
0087
0088
0089
0090
0091
0092
0093
0094 static int vmw_overlay_send_put(struct vmw_private *dev_priv,
0095 struct vmw_buffer_object *buf,
0096 struct drm_vmw_control_stream_arg *arg,
0097 bool interruptible)
0098 {
0099 struct vmw_escape_video_flush *flush;
0100 size_t fifo_size;
0101 bool have_so = (dev_priv->active_display_unit == vmw_du_screen_object);
0102 int i, num_items;
0103 SVGAGuestPtr ptr;
0104
0105 struct {
0106 struct vmw_escape_header escape;
0107 struct {
0108 uint32_t cmdType;
0109 uint32_t streamId;
0110 } header;
0111 } *cmds;
0112 struct {
0113 uint32_t registerId;
0114 uint32_t value;
0115 } *items;
0116
0117
0118 if (have_so)
0119 num_items = SVGA_VIDEO_DST_SCREEN_ID + 1;
0120 else
0121 num_items = SVGA_VIDEO_PITCH_3 + 1;
0122
0123 fifo_size = sizeof(*cmds) + sizeof(*flush) + sizeof(*items) * num_items;
0124
0125 cmds = VMW_CMD_RESERVE(dev_priv, fifo_size);
0126
0127 if (!cmds)
0128 return -ENOMEM;
0129
0130 items = (typeof(items))&cmds[1];
0131 flush = (struct vmw_escape_video_flush *)&items[num_items];
0132
0133
0134 fill_escape(&cmds->escape, sizeof(*items) * (num_items + 1));
0135
0136 cmds->header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
0137 cmds->header.streamId = arg->stream_id;
0138
0139
0140 for (i = 0; i < num_items; i++)
0141 items[i].registerId = i;
0142
0143 vmw_bo_get_guest_ptr(&buf->base, &ptr);
0144 ptr.offset += arg->offset;
0145
0146 items[SVGA_VIDEO_ENABLED].value = true;
0147 items[SVGA_VIDEO_FLAGS].value = arg->flags;
0148 items[SVGA_VIDEO_DATA_OFFSET].value = ptr.offset;
0149 items[SVGA_VIDEO_FORMAT].value = arg->format;
0150 items[SVGA_VIDEO_COLORKEY].value = arg->color_key;
0151 items[SVGA_VIDEO_SIZE].value = arg->size;
0152 items[SVGA_VIDEO_WIDTH].value = arg->width;
0153 items[SVGA_VIDEO_HEIGHT].value = arg->height;
0154 items[SVGA_VIDEO_SRC_X].value = arg->src.x;
0155 items[SVGA_VIDEO_SRC_Y].value = arg->src.y;
0156 items[SVGA_VIDEO_SRC_WIDTH].value = arg->src.w;
0157 items[SVGA_VIDEO_SRC_HEIGHT].value = arg->src.h;
0158 items[SVGA_VIDEO_DST_X].value = arg->dst.x;
0159 items[SVGA_VIDEO_DST_Y].value = arg->dst.y;
0160 items[SVGA_VIDEO_DST_WIDTH].value = arg->dst.w;
0161 items[SVGA_VIDEO_DST_HEIGHT].value = arg->dst.h;
0162 items[SVGA_VIDEO_PITCH_1].value = arg->pitch[0];
0163 items[SVGA_VIDEO_PITCH_2].value = arg->pitch[1];
0164 items[SVGA_VIDEO_PITCH_3].value = arg->pitch[2];
0165 if (have_so) {
0166 items[SVGA_VIDEO_DATA_GMRID].value = ptr.gmrId;
0167 items[SVGA_VIDEO_DST_SCREEN_ID].value = SVGA_ID_INVALID;
0168 }
0169
0170 fill_flush(flush, arg->stream_id);
0171
0172 vmw_cmd_commit(dev_priv, fifo_size);
0173
0174 return 0;
0175 }
0176
0177
0178
0179
0180
0181
0182
0183 static int vmw_overlay_send_stop(struct vmw_private *dev_priv,
0184 uint32_t stream_id,
0185 bool interruptible)
0186 {
0187 struct {
0188 struct vmw_escape_header escape;
0189 SVGAEscapeVideoSetRegs body;
0190 struct vmw_escape_video_flush flush;
0191 } *cmds;
0192 int ret;
0193
0194 for (;;) {
0195 cmds = VMW_CMD_RESERVE(dev_priv, sizeof(*cmds));
0196 if (cmds)
0197 break;
0198
0199 ret = vmw_fallback_wait(dev_priv, false, true, 0,
0200 interruptible, 3*HZ);
0201 if (interruptible && ret == -ERESTARTSYS)
0202 return ret;
0203 else
0204 BUG_ON(ret != 0);
0205 }
0206
0207 fill_escape(&cmds->escape, sizeof(cmds->body));
0208 cmds->body.header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
0209 cmds->body.header.streamId = stream_id;
0210 cmds->body.items[0].registerId = SVGA_VIDEO_ENABLED;
0211 cmds->body.items[0].value = false;
0212 fill_flush(&cmds->flush, stream_id);
0213
0214 vmw_cmd_commit(dev_priv, sizeof(*cmds));
0215
0216 return 0;
0217 }
0218
0219
0220
0221
0222
0223
0224
0225 static int vmw_overlay_move_buffer(struct vmw_private *dev_priv,
0226 struct vmw_buffer_object *buf,
0227 bool pin, bool inter)
0228 {
0229 if (!pin)
0230 return vmw_bo_unpin(dev_priv, buf, inter);
0231
0232 if (dev_priv->active_display_unit == vmw_du_legacy)
0233 return vmw_bo_pin_in_vram(dev_priv, buf, inter);
0234
0235 return vmw_bo_pin_in_vram_or_gmr(dev_priv, buf, inter);
0236 }
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 static int vmw_overlay_stop(struct vmw_private *dev_priv,
0251 uint32_t stream_id, bool pause,
0252 bool interruptible)
0253 {
0254 struct vmw_overlay *overlay = dev_priv->overlay_priv;
0255 struct vmw_stream *stream = &overlay->stream[stream_id];
0256 int ret;
0257
0258
0259 if (!stream->buf)
0260 return 0;
0261
0262
0263 if (!stream->paused) {
0264 ret = vmw_overlay_send_stop(dev_priv, stream_id,
0265 interruptible);
0266 if (ret)
0267 return ret;
0268
0269
0270 ret = vmw_overlay_move_buffer(dev_priv, stream->buf, false,
0271 interruptible);
0272 if (interruptible && ret == -ERESTARTSYS)
0273 return ret;
0274 else
0275 BUG_ON(ret != 0);
0276 }
0277
0278 if (!pause) {
0279 vmw_bo_unreference(&stream->buf);
0280 stream->paused = false;
0281 } else {
0282 stream->paused = true;
0283 }
0284
0285 return 0;
0286 }
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297 static int vmw_overlay_update_stream(struct vmw_private *dev_priv,
0298 struct vmw_buffer_object *buf,
0299 struct drm_vmw_control_stream_arg *arg,
0300 bool interruptible)
0301 {
0302 struct vmw_overlay *overlay = dev_priv->overlay_priv;
0303 struct vmw_stream *stream = &overlay->stream[arg->stream_id];
0304 int ret = 0;
0305
0306 if (!buf)
0307 return -EINVAL;
0308
0309 DRM_DEBUG(" %s: old %p, new %p, %spaused\n", __func__,
0310 stream->buf, buf, stream->paused ? "" : "not ");
0311
0312 if (stream->buf != buf) {
0313 ret = vmw_overlay_stop(dev_priv, arg->stream_id,
0314 false, interruptible);
0315 if (ret)
0316 return ret;
0317 } else if (!stream->paused) {
0318
0319
0320
0321 ret = vmw_overlay_send_put(dev_priv, buf, arg, interruptible);
0322 if (ret == 0)
0323 stream->saved = *arg;
0324 else
0325 BUG_ON(!interruptible);
0326
0327 return ret;
0328 }
0329
0330
0331
0332
0333 ret = vmw_overlay_move_buffer(dev_priv, buf, true, interruptible);
0334 if (ret)
0335 return ret;
0336
0337 ret = vmw_overlay_send_put(dev_priv, buf, arg, interruptible);
0338 if (ret) {
0339
0340
0341
0342 BUG_ON(vmw_overlay_move_buffer(dev_priv, buf, false, false)
0343 != 0);
0344 return ret;
0345 }
0346
0347 if (stream->buf != buf)
0348 stream->buf = vmw_bo_reference(buf);
0349 stream->saved = *arg;
0350
0351 stream->paused = false;
0352
0353 return 0;
0354 }
0355
0356
0357
0358
0359
0360
0361
0362
0363 int vmw_overlay_resume_all(struct vmw_private *dev_priv)
0364 {
0365 struct vmw_overlay *overlay = dev_priv->overlay_priv;
0366 int i, ret;
0367
0368 if (!overlay)
0369 return 0;
0370
0371 mutex_lock(&overlay->mutex);
0372
0373 for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
0374 struct vmw_stream *stream = &overlay->stream[i];
0375 if (!stream->paused)
0376 continue;
0377
0378 ret = vmw_overlay_update_stream(dev_priv, stream->buf,
0379 &stream->saved, false);
0380 if (ret != 0)
0381 DRM_INFO("%s: *warning* failed to resume stream %i\n",
0382 __func__, i);
0383 }
0384
0385 mutex_unlock(&overlay->mutex);
0386
0387 return 0;
0388 }
0389
0390
0391
0392
0393
0394
0395
0396
0397 int vmw_overlay_pause_all(struct vmw_private *dev_priv)
0398 {
0399 struct vmw_overlay *overlay = dev_priv->overlay_priv;
0400 int i, ret;
0401
0402 if (!overlay)
0403 return 0;
0404
0405 mutex_lock(&overlay->mutex);
0406
0407 for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
0408 if (overlay->stream[i].paused)
0409 DRM_INFO("%s: *warning* stream %i already paused\n",
0410 __func__, i);
0411 ret = vmw_overlay_stop(dev_priv, i, true, false);
0412 WARN_ON(ret != 0);
0413 }
0414
0415 mutex_unlock(&overlay->mutex);
0416
0417 return 0;
0418 }
0419
0420
0421 static bool vmw_overlay_available(const struct vmw_private *dev_priv)
0422 {
0423 return (dev_priv->overlay_priv != NULL &&
0424 ((vmw_fifo_caps(dev_priv) & VMW_OVERLAY_CAP_MASK) ==
0425 VMW_OVERLAY_CAP_MASK));
0426 }
0427
0428 int vmw_overlay_ioctl(struct drm_device *dev, void *data,
0429 struct drm_file *file_priv)
0430 {
0431 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
0432 struct vmw_private *dev_priv = vmw_priv(dev);
0433 struct vmw_overlay *overlay = dev_priv->overlay_priv;
0434 struct drm_vmw_control_stream_arg *arg =
0435 (struct drm_vmw_control_stream_arg *)data;
0436 struct vmw_buffer_object *buf;
0437 struct vmw_resource *res;
0438 int ret;
0439
0440 if (!vmw_overlay_available(dev_priv))
0441 return -ENOSYS;
0442
0443 ret = vmw_user_stream_lookup(dev_priv, tfile, &arg->stream_id, &res);
0444 if (ret)
0445 return ret;
0446
0447 mutex_lock(&overlay->mutex);
0448
0449 if (!arg->enabled) {
0450 ret = vmw_overlay_stop(dev_priv, arg->stream_id, false, true);
0451 goto out_unlock;
0452 }
0453
0454 ret = vmw_user_bo_lookup(file_priv, arg->handle, &buf);
0455 if (ret)
0456 goto out_unlock;
0457
0458 ret = vmw_overlay_update_stream(dev_priv, buf, arg, true);
0459
0460 vmw_bo_unreference(&buf);
0461
0462 out_unlock:
0463 mutex_unlock(&overlay->mutex);
0464 vmw_resource_unreference(&res);
0465
0466 return ret;
0467 }
0468
0469 int vmw_overlay_num_overlays(struct vmw_private *dev_priv)
0470 {
0471 if (!vmw_overlay_available(dev_priv))
0472 return 0;
0473
0474 return VMW_MAX_NUM_STREAMS;
0475 }
0476
0477 int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv)
0478 {
0479 struct vmw_overlay *overlay = dev_priv->overlay_priv;
0480 int i, k;
0481
0482 if (!vmw_overlay_available(dev_priv))
0483 return 0;
0484
0485 mutex_lock(&overlay->mutex);
0486
0487 for (i = 0, k = 0; i < VMW_MAX_NUM_STREAMS; i++)
0488 if (!overlay->stream[i].claimed)
0489 k++;
0490
0491 mutex_unlock(&overlay->mutex);
0492
0493 return k;
0494 }
0495
0496 int vmw_overlay_claim(struct vmw_private *dev_priv, uint32_t *out)
0497 {
0498 struct vmw_overlay *overlay = dev_priv->overlay_priv;
0499 int i;
0500
0501 if (!overlay)
0502 return -ENOSYS;
0503
0504 mutex_lock(&overlay->mutex);
0505
0506 for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
0507
0508 if (overlay->stream[i].claimed)
0509 continue;
0510
0511 overlay->stream[i].claimed = true;
0512 *out = i;
0513 mutex_unlock(&overlay->mutex);
0514 return 0;
0515 }
0516
0517 mutex_unlock(&overlay->mutex);
0518 return -ESRCH;
0519 }
0520
0521 int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id)
0522 {
0523 struct vmw_overlay *overlay = dev_priv->overlay_priv;
0524
0525 BUG_ON(stream_id >= VMW_MAX_NUM_STREAMS);
0526
0527 if (!overlay)
0528 return -ENOSYS;
0529
0530 mutex_lock(&overlay->mutex);
0531
0532 WARN_ON(!overlay->stream[stream_id].claimed);
0533 vmw_overlay_stop(dev_priv, stream_id, false, false);
0534 overlay->stream[stream_id].claimed = false;
0535
0536 mutex_unlock(&overlay->mutex);
0537 return 0;
0538 }
0539
0540 int vmw_overlay_init(struct vmw_private *dev_priv)
0541 {
0542 struct vmw_overlay *overlay;
0543 int i;
0544
0545 if (dev_priv->overlay_priv)
0546 return -EINVAL;
0547
0548 overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
0549 if (!overlay)
0550 return -ENOMEM;
0551
0552 mutex_init(&overlay->mutex);
0553 for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
0554 overlay->stream[i].buf = NULL;
0555 overlay->stream[i].paused = false;
0556 overlay->stream[i].claimed = false;
0557 }
0558
0559 dev_priv->overlay_priv = overlay;
0560
0561 return 0;
0562 }
0563
0564 int vmw_overlay_close(struct vmw_private *dev_priv)
0565 {
0566 struct vmw_overlay *overlay = dev_priv->overlay_priv;
0567 bool forgotten_buffer = false;
0568 int i;
0569
0570 if (!overlay)
0571 return -ENOSYS;
0572
0573 for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
0574 if (overlay->stream[i].buf) {
0575 forgotten_buffer = true;
0576 vmw_overlay_stop(dev_priv, i, false, false);
0577 }
0578 }
0579
0580 WARN_ON(forgotten_buffer);
0581
0582 dev_priv->overlay_priv = NULL;
0583 kfree(overlay);
0584
0585 return 0;
0586 }