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); }
/** * 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; }
/** * 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; }
/** * 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; }
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; }
/** * 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; }
static int vmw_gmr2_bind(struct vmw_private *dev_priv, struct page *pages[], 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 = page_to_pfn(*pages++); else *((uint64_t *)cmd) = page_to_pfn(*pages++); cmd += VMW_PPN_SIZE / sizeof(*cmd); } num_pages -= nr; remap_pos += nr; } BUG_ON(cmd != cmd_orig + cmd_size / sizeof(*cmd)); vmw_fifo_commit(dev_priv, cmd_size); return 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; }
/** * vmw_sou_readback_fifo_commit - Callback to submit a set of readback clips. * * @dirty: The closure structure. * * Commits a previously built command buffer of readback clips. */ static void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty) { vmw_fifo_commit(dirty->dev_priv, sizeof(struct vmw_kms_sou_readback_blit) * dirty->num_hits); }