/** * Send stop command to hw. * * Returns * -ERESTARTSYS if interrupted by a signal. */ static int vmw_overlay_send_stop(struct vmw_private *dev_priv, uint32_t stream_id, bool interruptible) { struct { struct vmw_escape_header escape; SVGAEscapeVideoSetRegs body; struct vmw_escape_video_flush flush; } *cmds; int ret; for (;;) { cmds = vmw_fifo_reserve(dev_priv, sizeof(*cmds)); if (cmds) break; ret = vmw_fallback_wait(dev_priv, false, true, 0, interruptible, 3*HZ); if (interruptible && ret == -ERESTARTSYS) return ret; else BUG_ON(ret != 0); } fill_escape(&cmds->escape, sizeof(cmds->body)); cmds->body.header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS; cmds->body.header.streamId = stream_id; cmds->body.items[0].registerId = SVGA_VIDEO_ENABLED; cmds->body.items[0].value = false; fill_flush(&cmds->flush, stream_id); vmw_fifo_commit(dev_priv, sizeof(*cmds)); return 0; }
int vmw_wait_seqno(struct vmw_private *dev_priv, bool lazy, uint32_t seqno, bool interruptible, unsigned long timeout) { long ret; struct vmw_fifo_state *fifo = &dev_priv->fifo; if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) return 0; if (likely(vmw_seqno_passed(dev_priv, seqno))) return 0; vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE)) return vmw_fallback_wait(dev_priv, lazy, true, seqno, interruptible, timeout); if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) return vmw_fallback_wait(dev_priv, lazy, false, seqno, interruptible, timeout); vmw_seqno_waiter_add(dev_priv); if (interruptible) ret = wait_event_interruptible_timeout (dev_priv->fence_queue, vmw_seqno_passed(dev_priv, seqno), timeout); else ret = wait_event_timeout (dev_priv->fence_queue, vmw_seqno_passed(dev_priv, seqno), timeout); vmw_seqno_waiter_remove(dev_priv); if (unlikely(ret == 0)) ret = -EBUSY; else if (likely(ret > 0)) ret = 0; return ret; }
/** * Send the fifo command to destroy a screen. */ static int vmw_sou_fifo_destroy(struct vmw_private *dev_priv, struct vmw_screen_object_unit *sou) { size_t fifo_size; int ret; struct { struct { uint32_t cmdType; } header; SVGAFifoCmdDestroyScreen body; } *cmd; /* no need to do anything */ if (unlikely(!sou->defined)) return 0; fifo_size = sizeof(*cmd); cmd = vmw_fifo_reserve(dev_priv, fifo_size); /* the hardware has hung, nothing we can do about it here */ if (unlikely(cmd == NULL)) { DRM_ERROR("Fifo reserve failed.\n"); return -ENOMEM; } memset(cmd, 0, fifo_size); cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN; cmd->body.screenId = sou->base.unit; vmw_fifo_commit(dev_priv, fifo_size); /* Force sync */ ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ); if (unlikely(ret != 0)) DRM_ERROR("Failed to sync with HW"); else sou->defined = false; return ret; }
/** * vmw_stdu_destroy_st - Destroy a Screen Target * * @dev_priv: VMW DRM device * @stdu: display unit to destroy */ static int vmw_stdu_destroy_st(struct vmw_private *dev_priv, struct vmw_screen_target_display_unit *stdu) { int ret; struct { SVGA3dCmdHeader header; SVGA3dCmdDestroyGBScreenTarget body; } *cmd; /* Nothing to do if not successfully defined */ if (unlikely(!stdu->defined)) return 0; cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); if (unlikely(cmd == NULL)) { DRM_ERROR("Out of FIFO space, screen target not destroyed\n"); return -ENOMEM; } cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SCREENTARGET; cmd->header.size = sizeof(cmd->body); cmd->body.stid = stdu->base.unit; vmw_fifo_commit(dev_priv, sizeof(*cmd)); /* Force sync */ ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ); if (unlikely(ret != 0)) DRM_ERROR("Failed to sync with HW"); stdu->defined = false; return ret; }
/** * Send put command to hw. * * Returns * -ERESTARTSYS if interrupted by a signal. */ static int vmw_overlay_send_put(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, struct drm_vmw_control_stream_arg *arg, bool interruptible) { struct { struct vmw_escape_header escape; struct { struct { uint32_t cmdType; uint32_t streamId; } header; struct { uint32_t registerId; uint32_t value; } items[SVGA_VIDEO_PITCH_3 + 1]; } body; struct vmw_escape_video_flush flush; } *cmds; uint32_t offset; int i, ret; for (;;) { cmds = vmw_fifo_reserve(dev_priv, sizeof(*cmds)); if (cmds) break; ret = vmw_fallback_wait(dev_priv, false, true, 0, interruptible, 3*HZ); if (interruptible && ret == -ERESTARTSYS) return ret; else BUG_ON(ret != 0); } fill_escape(&cmds->escape, sizeof(cmds->body)); cmds->body.header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS; cmds->body.header.streamId = arg->stream_id; for (i = 0; i <= SVGA_VIDEO_PITCH_3; i++) cmds->body.items[i].registerId = i; offset = buf->base.offset + arg->offset; cmds->body.items[SVGA_VIDEO_ENABLED].value = true; cmds->body.items[SVGA_VIDEO_FLAGS].value = arg->flags; cmds->body.items[SVGA_VIDEO_DATA_OFFSET].value = offset; cmds->body.items[SVGA_VIDEO_FORMAT].value = arg->format; cmds->body.items[SVGA_VIDEO_COLORKEY].value = arg->color_key; cmds->body.items[SVGA_VIDEO_SIZE].value = arg->size; cmds->body.items[SVGA_VIDEO_WIDTH].value = arg->width; cmds->body.items[SVGA_VIDEO_HEIGHT].value = arg->height; cmds->body.items[SVGA_VIDEO_SRC_X].value = arg->src.x; cmds->body.items[SVGA_VIDEO_SRC_Y].value = arg->src.y; cmds->body.items[SVGA_VIDEO_SRC_WIDTH].value = arg->src.w; cmds->body.items[SVGA_VIDEO_SRC_HEIGHT].value = arg->src.h; cmds->body.items[SVGA_VIDEO_DST_X].value = arg->dst.x; cmds->body.items[SVGA_VIDEO_DST_Y].value = arg->dst.y; cmds->body.items[SVGA_VIDEO_DST_WIDTH].value = arg->dst.w; cmds->body.items[SVGA_VIDEO_DST_HEIGHT].value = arg->dst.h; cmds->body.items[SVGA_VIDEO_PITCH_1].value = arg->pitch[0]; cmds->body.items[SVGA_VIDEO_PITCH_2].value = arg->pitch[1]; cmds->body.items[SVGA_VIDEO_PITCH_3].value = arg->pitch[2]; fill_flush(&cmds->flush, arg->stream_id); vmw_fifo_commit(dev_priv, sizeof(*cmds)); return 0; }
int vmw_wait_fence(struct vmw_private *dev_priv, bool lazy, uint32_t sequence, bool interruptible, unsigned long timeout) { long ret; unsigned long irq_flags; struct vmw_fifo_state *fifo = &dev_priv->fifo; if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) return 0; if (likely(vmw_fence_signaled(dev_priv, sequence))) return 0; vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE)) return vmw_fallback_wait(dev_priv, lazy, true, sequence, interruptible, timeout); if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) return vmw_fallback_wait(dev_priv, lazy, false, sequence, interruptible, timeout); mutex_lock(&dev_priv->hw_mutex); if (atomic_add_return(1, &dev_priv->fence_queue_waiters) > 0) { spin_lock_irqsave(&dev_priv->irq_lock, irq_flags); outl(SVGA_IRQFLAG_ANY_FENCE, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); vmw_write(dev_priv, SVGA_REG_IRQMASK, vmw_read(dev_priv, SVGA_REG_IRQMASK) | SVGA_IRQFLAG_ANY_FENCE); spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); } mutex_unlock(&dev_priv->hw_mutex); if (interruptible) ret = wait_event_interruptible_timeout (dev_priv->fence_queue, vmw_fence_signaled(dev_priv, sequence), timeout); else ret = wait_event_timeout (dev_priv->fence_queue, vmw_fence_signaled(dev_priv, sequence), timeout); if (unlikely(ret == 0)) ret = -EBUSY; else if (likely(ret > 0)) ret = 0; mutex_lock(&dev_priv->hw_mutex); if (atomic_dec_and_test(&dev_priv->fence_queue_waiters)) { spin_lock_irqsave(&dev_priv->irq_lock, irq_flags); vmw_write(dev_priv, SVGA_REG_IRQMASK, vmw_read(dev_priv, SVGA_REG_IRQMASK) & ~SVGA_IRQFLAG_ANY_FENCE); spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); } mutex_unlock(&dev_priv->hw_mutex); return ret; }