int vmw_cursor_update_image(struct vmw_private *dev_priv,
			    u32 *image, u32 width, u32 height,
			    u32 hotspotX, u32 hotspotY)
{
	struct {
		u32 cmd;
		SVGAFifoCmdDefineAlphaCursor cursor;
	} *cmd;
	u32 image_size = width * height * 4;
	u32 cmd_size = sizeof(*cmd) + image_size;

	if (!image)
		return -EINVAL;

	cmd = vmw_fifo_reserve(dev_priv, cmd_size);
	if (unlikely(cmd == NULL)) {
		DRM_ERROR("Fifo reserve failed.\n");
		return -ENOMEM;
	}

	memset(cmd, 0, sizeof(*cmd));

	memcpy(&cmd[1], image, image_size);

	cmd->cmd = cpu_to_le32(SVGA_CMD_DEFINE_ALPHA_CURSOR);
	cmd->cursor.id = cpu_to_le32(0);
	cmd->cursor.width = cpu_to_le32(width);
	cmd->cursor.height = cpu_to_le32(height);
	cmd->cursor.hotspotX = cpu_to_le32(hotspotX);
	cmd->cursor.hotspotY = cpu_to_le32(hotspotY);

	vmw_fifo_commit(dev_priv, cmd_size);

	return 0;
}
Esempio n. 2
0
/**
 * 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;
}
Esempio n. 3
0
/**
 * vmw_stdu_update_st - Full update of a Screen Target
 *
 * @dev_priv: VMW DRM device
 * @stdu: display unit affected
 *
 * This function needs to be called whenever the content of a screen
 * target has changed completely. Typically as a result of a backing
 * surface change.
 *
 * RETURNS:
 * 0 on success, error code on failure
 */
static int vmw_stdu_update_st(struct vmw_private *dev_priv,
                              struct vmw_screen_target_display_unit *stdu)
{
    struct vmw_stdu_update *cmd;
    struct drm_crtc *crtc = &stdu->base.crtc;

    if (!stdu->defined) {
        DRM_ERROR("No screen target defined");
        return -EINVAL;
    }

    cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));

    if (unlikely(cmd == NULL)) {
        DRM_ERROR("Out of FIFO space updating a Screen Target\n");
        return -ENOMEM;
    }

    vmw_stdu_populate_update(cmd, stdu->base.unit, 0, crtc->mode.hdisplay,
                             0, crtc->mode.vdisplay);

    vmw_fifo_commit(dev_priv, sizeof(*cmd));

    return 0;
}
Esempio n. 4
0
static int vmw_gmr2_bind(struct vmw_private *dev_priv,
			 struct vmw_piter *iter,
			 unsigned long num_pages,
			 int gmr_id)
{
	SVGAFifoCmdDefineGMR2 define_cmd;
	SVGAFifoCmdRemapGMR2 remap_cmd;
	uint32_t *cmd;
	uint32_t *cmd_orig;
	uint32_t define_size = sizeof(define_cmd) + sizeof(*cmd);
	uint32_t remap_num = num_pages / VMW_PPN_PER_REMAP + ((num_pages % VMW_PPN_PER_REMAP) > 0);
	uint32_t remap_size = VMW_PPN_SIZE * num_pages + (sizeof(remap_cmd) + sizeof(*cmd)) * remap_num;
	uint32_t remap_pos = 0;
	uint32_t cmd_size = define_size + remap_size;
	uint32_t i;

	cmd_orig = cmd = vmw_fifo_reserve(dev_priv, cmd_size);
	if (unlikely(cmd == NULL))
		return -ENOMEM;

	define_cmd.gmrId = gmr_id;
	define_cmd.numPages = num_pages;

	*cmd++ = SVGA_CMD_DEFINE_GMR2;
	memcpy(cmd, &define_cmd, sizeof(define_cmd));
	cmd += sizeof(define_cmd) / sizeof(*cmd);

	/*
	 * Need to split the command if there are too many
	 * pages that goes into the gmr.
	 */

	remap_cmd.gmrId = gmr_id;
	remap_cmd.flags = (VMW_PPN_SIZE > sizeof(*cmd)) ?
		SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32;

	while (num_pages > 0) {
		unsigned long nr = min(num_pages, (unsigned long)VMW_PPN_PER_REMAP);

		remap_cmd.offsetPages = remap_pos;
		remap_cmd.numPages = nr;

		*cmd++ = SVGA_CMD_REMAP_GMR2;
		memcpy(cmd, &remap_cmd, sizeof(remap_cmd));
		cmd += sizeof(remap_cmd) / sizeof(*cmd);

		for (i = 0; i < nr; ++i) {
			if (VMW_PPN_SIZE <= 4)
				*cmd = vmw_piter_dma_addr(iter) >> PAGE_SHIFT;
			else
				*((uint64_t *)cmd) = vmw_piter_dma_addr(iter) >>
					PAGE_SHIFT;

			cmd += VMW_PPN_SIZE / sizeof(*cmd);
			vmw_piter_next(iter);
		}

		num_pages -= nr;
		remap_pos += nr;
	}
Esempio n. 5
0
/**
 * Send the fifo command to create a screen.
 */
static int vmw_sou_fifo_create(struct vmw_private *dev_priv,
			       struct vmw_screen_object_unit *sou,
			       uint32_t x, uint32_t y,
			       struct drm_display_mode *mode)
{
	size_t fifo_size;

	struct {
		struct {
			uint32_t cmdType;
		} header;
		SVGAScreenObject obj;
	} *cmd;

	BUG_ON(!sou->buffer);

	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_DEFINE_SCREEN;
	cmd->obj.structSize = sizeof(SVGAScreenObject);
	cmd->obj.id = sou->base.unit;
	cmd->obj.flags = SVGA_SCREEN_HAS_ROOT |
		(sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0);
	cmd->obj.size.width = mode->hdisplay;
	cmd->obj.size.height = mode->vdisplay;
	if (sou->base.is_implicit) {
		cmd->obj.root.x = x;
		cmd->obj.root.y = y;
	} else {
		cmd->obj.root.x = sou->base.gui_x;
		cmd->obj.root.y = sou->base.gui_y;
	}
	sou->base.set_gui_x = cmd->obj.root.x;
	sou->base.set_gui_y = cmd->obj.root.y;

	/* Ok to assume that buffer is pinned in vram */
	vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr);
	cmd->obj.backingStore.pitch = mode->hdisplay * 4;

	vmw_fifo_commit(dev_priv, fifo_size);

	sou->defined = true;

	return 0;
}
Esempio n. 6
0
static void vmw_gmr2_unbind(struct vmw_private *dev_priv,
			    int gmr_id)
{
	SVGAFifoCmdDefineGMR2 define_cmd;
	uint32_t define_size = sizeof(define_cmd) + 4;
	uint32_t *cmd;

	cmd = vmw_fifo_reserve(dev_priv, define_size);
	if (unlikely(cmd == NULL)) {
		DRM_ERROR("GMR2 unbind failed.\n");
		return;
	}
	define_cmd.gmrId = gmr_id;
	define_cmd.numPages = 0;

	*cmd++ = SVGA_CMD_DEFINE_GMR2;
	memcpy(cmd, &define_cmd, sizeof(define_cmd));

	vmw_fifo_commit(dev_priv, define_size);
}
Esempio n. 7
0
/**
 * vmw_stdu_define_st - Defines a Screen Target
 *
 * @dev_priv:  VMW DRM device
 * @stdu: display unit to create a Screen Target for
 * @mode: The mode to set.
 * @crtc_x: X coordinate of screen target relative to framebuffer origin.
 * @crtc_y: Y coordinate of screen target relative to framebuffer origin.
 *
 * Creates a STDU that we can used later.  This function is called whenever the
 * framebuffer size changes.
 *
 * RETURNs:
 * 0 on success, error code on failure
 */
static int vmw_stdu_define_st(struct vmw_private *dev_priv,
                              struct vmw_screen_target_display_unit *stdu,
                              struct drm_display_mode *mode,
                              int crtc_x, int crtc_y)
{
    struct {
        SVGA3dCmdHeader header;
        SVGA3dCmdDefineGBScreenTarget body;
    } *cmd;

    cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));

    if (unlikely(cmd == NULL)) {
        DRM_ERROR("Out of FIFO space defining Screen Target\n");
        return -ENOMEM;
    }

    cmd->header.id   = SVGA_3D_CMD_DEFINE_GB_SCREENTARGET;
    cmd->header.size = sizeof(cmd->body);

    cmd->body.stid   = stdu->base.unit;
    cmd->body.width  = mode->hdisplay;
    cmd->body.height = mode->vdisplay;
    cmd->body.flags  = (0 == cmd->body.stid) ? SVGA_STFLAG_PRIMARY : 0;
    cmd->body.dpi    = 0;
    if (stdu->base.is_implicit) {
        cmd->body.xRoot  = crtc_x;
        cmd->body.yRoot  = crtc_y;
    } else {
        cmd->body.xRoot  = stdu->base.gui_x;
        cmd->body.yRoot  = stdu->base.gui_y;
    }
    stdu->base.set_gui_x = cmd->body.xRoot;
    stdu->base.set_gui_y = cmd->body.yRoot;

    vmw_fifo_commit(dev_priv, sizeof(*cmd));

    stdu->defined = true;

    return 0;
}
Esempio n. 8
0
/**
 * 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;
}
Esempio n. 9
0
/**
 * 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;
}
Esempio n. 10
0
/**
 * vmw_stdu_bind_st - Binds a surface to a Screen Target
 *
 * @dev_priv: VMW DRM device
 * @stdu: display unit affected
 * @res: Buffer to bind to the screen target.  Set to NULL to blank screen.
 *
 * Binding a surface to a Screen Target the same as flipping
 */
static int vmw_stdu_bind_st(struct vmw_private *dev_priv,
                            struct vmw_screen_target_display_unit *stdu,
                            struct vmw_resource *res)
{
    SVGA3dSurfaceImageId image;

    struct {
        SVGA3dCmdHeader header;
        SVGA3dCmdBindGBScreenTarget body;
    } *cmd;


    if (!stdu->defined) {
        DRM_ERROR("No screen target defined\n");
        return -EINVAL;
    }

    /* Set up image using information in vfb */
    memset(&image, 0, sizeof(image));
    image.sid = res ? res->id : SVGA3D_INVALID_ID;

    cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));

    if (unlikely(cmd == NULL)) {
        DRM_ERROR("Out of FIFO space binding a screen target\n");
        return -ENOMEM;
    }

    cmd->header.id   = SVGA_3D_CMD_BIND_GB_SCREENTARGET;
    cmd->header.size = sizeof(cmd->body);

    cmd->body.stid   = stdu->base.unit;
    cmd->body.image  = image;

    vmw_fifo_commit(dev_priv, sizeof(*cmd));

    return 0;
}
Esempio n. 11
0
static int do_dmabuf_define_gmrfb(struct vmw_private *dev_priv,
				  struct vmw_framebuffer *framebuffer)
{
	struct vmw_dma_buffer *buf =
		container_of(framebuffer, struct vmw_framebuffer_dmabuf,
			     base)->buffer;
	int depth = framebuffer->base.depth;
	struct {
		uint32_t header;
		SVGAFifoCmdDefineGMRFB body;
	} *cmd;

	/* Emulate RGBA support, contrary to svga_reg.h this is not
	 * supported by hosts. This is only a problem if we are reading
	 * this value later and expecting what we uploaded back.
	 */
	if (depth == 32)
		depth = 24;

	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
	if (!cmd) {
		DRM_ERROR("Out of fifo space for dirty framebuffer command.\n");
		return -ENOMEM;
	}

	cmd->header = SVGA_CMD_DEFINE_GMRFB;
	cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel;
	cmd->body.format.colorDepth = depth;
	cmd->body.format.reserved = 0;
	cmd->body.bytesPerLine = framebuffer->base.pitches[0];
	/* Buffer is reserved in vram or GMR */
	vmw_bo_get_guest_ptr(&buf->base, &cmd->body.ptr);
	vmw_fifo_commit(dev_priv, sizeof(*cmd));

	return 0;
}
Esempio n. 12
0
/**
 * 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 vmw_escape_video_flush *flush;
	size_t fifo_size;
	bool have_so = dev_priv->sou_priv ? true : false;
	int i, num_items;
	SVGAGuestPtr ptr;

	struct {
		struct vmw_escape_header escape;
		struct {
			uint32_t cmdType;
			uint32_t streamId;
		} header;
	} *cmds;
	struct {
		uint32_t registerId;
		uint32_t value;
	} *items;

	/* defines are a index needs + 1 */
	if (have_so)
		num_items = SVGA_VIDEO_DST_SCREEN_ID + 1;
	else
		num_items = SVGA_VIDEO_PITCH_3 + 1;

	fifo_size = sizeof(*cmds) + sizeof(*flush) + sizeof(*items) * num_items;

	cmds = vmw_fifo_reserve(dev_priv, fifo_size);
	/* hardware has hung, can't do anything here */
	if (!cmds)
		return -ENOMEM;

	items = (typeof(items))&cmds[1];
	flush = (struct vmw_escape_video_flush *)&items[num_items];

	/* the size is header + number of items */
	fill_escape(&cmds->escape, sizeof(*items) * (num_items + 1));

	cmds->header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
	cmds->header.streamId = arg->stream_id;

	/* the IDs are neatly numbered */
	for (i = 0; i < num_items; i++)
		items[i].registerId = i;

	vmw_bo_get_guest_ptr(&buf->base, &ptr);
	ptr.offset += arg->offset;

	items[SVGA_VIDEO_ENABLED].value     = true;
	items[SVGA_VIDEO_FLAGS].value       = arg->flags;
	items[SVGA_VIDEO_DATA_OFFSET].value = ptr.offset;
	items[SVGA_VIDEO_FORMAT].value      = arg->format;
	items[SVGA_VIDEO_COLORKEY].value    = arg->color_key;
	items[SVGA_VIDEO_SIZE].value        = arg->size;
	items[SVGA_VIDEO_WIDTH].value       = arg->width;
	items[SVGA_VIDEO_HEIGHT].value      = arg->height;
	items[SVGA_VIDEO_SRC_X].value       = arg->src.x;
	items[SVGA_VIDEO_SRC_Y].value       = arg->src.y;
	items[SVGA_VIDEO_SRC_WIDTH].value   = arg->src.w;
	items[SVGA_VIDEO_SRC_HEIGHT].value  = arg->src.h;
	items[SVGA_VIDEO_DST_X].value       = arg->dst.x;
	items[SVGA_VIDEO_DST_Y].value       = arg->dst.y;
	items[SVGA_VIDEO_DST_WIDTH].value   = arg->dst.w;
	items[SVGA_VIDEO_DST_HEIGHT].value  = arg->dst.h;
	items[SVGA_VIDEO_PITCH_1].value     = arg->pitch[0];
	items[SVGA_VIDEO_PITCH_2].value     = arg->pitch[1];
	items[SVGA_VIDEO_PITCH_3].value     = arg->pitch[2];
	if (have_so) {
		items[SVGA_VIDEO_DATA_GMRID].value    = ptr.gmrId;
		items[SVGA_VIDEO_DST_SCREEN_ID].value = SVGA_ID_INVALID;
	}

	fill_flush(flush, arg->stream_id);

	vmw_fifo_commit(dev_priv, fifo_size);

	return 0;
}
Esempio n. 13
0
/**
 * 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;
}