/** * vmw_dmabuf_to_placement - Validate a buffer to placement. * * @dev_priv: Driver private. * @buf: DMA buffer to move. * @pin: Pin buffer if true. * @interruptible: Use interruptible wait. * * May only be called by the current master since it assumes that the * master lock is the current master's lock. * This function takes the master's lock in write mode. * Flushes and unpins the query bo to avoid failures. * * Returns * -ERESTARTSYS if interrupted by a signal. */ int vmw_dmabuf_to_placement(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, struct ttm_placement *placement, bool interruptible) { struct vmw_master *vmaster = dev_priv->active_master; struct ttm_buffer_object *bo = &buf->base; int ret; ret = ttm_write_lock(&vmaster->lock, interruptible); if (unlikely(ret != 0)) return ret; vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, false, 0); if (unlikely(ret != 0)) goto err; ret = ttm_bo_validate(bo, placement, interruptible, false); ttm_bo_unreserve(bo); err: ttm_write_unlock(&vmaster->lock); return ret; }
/** * vmw_dmabuf_pin_in_vram_or_gmr - Move a buffer to vram or gmr. * * This function takes the reservation_sem in write mode. * Flushes and unpins the query bo to avoid failures. * * @dev_priv: Driver private. * @buf: DMA buffer to move. * @pin: Pin buffer if true. * @interruptible: Use interruptible wait. * * Returns * -ERESTARTSYS if interrupted by a signal. */ int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, bool interruptible) { struct ttm_buffer_object *bo = &buf->base; int ret; ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) return ret; vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, NULL); if (unlikely(ret != 0)) goto err; ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible, false); if (likely(ret == 0) || ret == -ERESTARTSYS) goto out_unreserve; ret = ttm_bo_validate(bo, &vmw_vram_placement, interruptible, false); out_unreserve: if (!ret) vmw_bo_pin_reserved(buf, true); ttm_bo_unreserve(bo); err: ttm_write_unlock(&dev_priv->reservation_sem); return ret; }
/** * vmw_dmabuf_pin_in_placement - Validate a buffer to placement. * * @dev_priv: Driver private. * @buf: DMA buffer to move. * @placement: The placement to pin it. * @interruptible: Use interruptible wait. * * Returns * -ERESTARTSYS if interrupted by a signal. */ int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, struct ttm_placement *placement, bool interruptible) { struct ttm_operation_ctx ctx = {interruptible, false }; struct ttm_buffer_object *bo = &buf->base; int ret; uint32_t new_flags; ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) return ret; vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, NULL); if (unlikely(ret != 0)) goto err; if (buf->pin_count > 0) ret = ttm_bo_mem_compat(placement, &bo->mem, &new_flags) == true ? 0 : -EINVAL; else ret = ttm_bo_validate(bo, placement, &ctx); if (!ret) vmw_bo_pin_reserved(buf, true); ttm_bo_unreserve(bo); err: ttm_write_unlock(&dev_priv->reservation_sem); return ret; }
/** * vmw_dmabuf_pin_in_start_of_vram - Move a buffer to start of vram. * * This function takes the reservation_sem in write mode. * Flushes and unpins the query bo to avoid failures. * * @dev_priv: Driver private. * @buf: DMA buffer to pin. * @interruptible: Use interruptible wait. * * Returns * -ERESTARTSYS if interrupted by a signal. */ int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, bool interruptible) { struct ttm_operation_ctx ctx = {interruptible, false }; struct ttm_buffer_object *bo = &buf->base; struct ttm_placement placement; struct ttm_place place; int ret = 0; uint32_t new_flags; place = vmw_vram_placement.placement[0]; place.lpfn = bo->num_pages; placement.num_placement = 1; placement.placement = &place; placement.num_busy_placement = 1; placement.busy_placement = &place; ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) return ret; vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, NULL); if (unlikely(ret != 0)) goto err_unlock; /* * Is this buffer already in vram but not at the start of it? * In that case, evict it first because TTM isn't good at handling * that situation. */ if (bo->mem.mem_type == TTM_PL_VRAM && bo->mem.start < bo->num_pages && bo->mem.start > 0 && buf->pin_count == 0) { ctx.interruptible = false; (void) ttm_bo_validate(bo, &vmw_sys_placement, &ctx); } if (buf->pin_count > 0) ret = ttm_bo_mem_compat(&placement, &bo->mem, &new_flags) == true ? 0 : -EINVAL; else ret = ttm_bo_validate(bo, &placement, &ctx); /* For some reason we didn't end up at the start of vram */ WARN_ON(ret == 0 && bo->offset != 0); if (!ret) vmw_bo_pin_reserved(buf, true); ttm_bo_unreserve(bo); err_unlock: ttm_write_unlock(&dev_priv->reservation_sem); return ret; }
/** * vmw_dmabuf_to_vram_or_gmr - Move a buffer to vram or gmr. * * May only be called by the current master since it assumes that the * master lock is the current master's lock. * This function takes the master's lock in write mode. * Flushes and unpins the query bo if @pin == true to avoid failures. * * @dev_priv: Driver private. * @buf: DMA buffer to move. * @pin: Pin buffer if true. * @interruptible: Use interruptible wait. * * Returns * -ERESTARTSYS if interrupted by a signal. */ int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, bool pin, bool interruptible) { struct vmw_master *vmaster = dev_priv->active_master; struct ttm_buffer_object *bo = &buf->base; struct ttm_placement *placement; int ret; ret = ttm_write_lock(&vmaster->lock, interruptible); if (unlikely(ret != 0)) return ret; if (pin) vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, false, 0); if (unlikely(ret != 0)) goto err; /** * Put BO in VRAM if there is space, otherwise as a GMR. * If there is no space in VRAM and GMR ids are all used up, * start evicting GMRs to make room. If the DMA buffer can't be * used as a GMR, this will return -ENOMEM. */ if (pin) placement = &vmw_vram_gmr_ne_placement; else placement = &vmw_vram_gmr_placement; ret = ttm_bo_validate(bo, placement, interruptible, false); if (likely(ret == 0) || ret == -ERESTARTSYS) goto err_unreserve; /** * If that failed, try VRAM again, this time evicting * previous contents. */ if (pin) placement = &vmw_vram_ne_placement; else placement = &vmw_vram_placement; ret = ttm_bo_validate(bo, placement, interruptible, false); err_unreserve: ttm_bo_unreserve(bo); err: ttm_write_unlock(&vmaster->lock); return ret; }
/** * vmw_svga_disable - Disable SVGA_MODE, and use of VRAM. Keep the fifo * running. * * @dev_priv: Pointer to device private struct. * Will empty VRAM. */ void vmw_svga_disable(struct vmw_private *dev_priv) { ttm_write_lock(&dev_priv->reservation_sem, false); spin_lock(&dev_priv->svga_lock); if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) { dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; spin_unlock(&dev_priv->svga_lock); if (ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM)) DRM_ERROR("Failed evicting VRAM buffers.\n"); vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE_HIDE | SVGA_REG_ENABLE_ENABLE); } else spin_unlock(&dev_priv->svga_lock); ttm_write_unlock(&dev_priv->reservation_sem); }
/** * vmw_dmabuf_to_start_of_vram - Move a buffer to start of vram. * * May only be called by the current master since it assumes that the * master lock is the current master's lock. * This function takes the master's lock in write mode. * Flushes and unpins the query bo if @pin == true to avoid failures. * * @dev_priv: Driver private. * @buf: DMA buffer to move. * @pin: Pin buffer in vram if true. * @interruptible: Use interruptible wait. * * Returns * -ERESTARTSYS if interrupted by a signal. */ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, bool pin, bool interruptible) { struct ttm_buffer_object *bo = &buf->base; struct ttm_placement placement; struct ttm_place place; int ret = 0; if (pin) place = vmw_vram_ne_placement.placement[0]; else place = vmw_vram_placement.placement[0]; place.lpfn = bo->num_pages; placement.num_placement = 1; placement.placement = &place; placement.num_busy_placement = 1; placement.busy_placement = &place; ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) return ret; if (pin) vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, false, NULL); if (unlikely(ret != 0)) goto err_unlock; /* Is this buffer already in vram but not at the start of it? */ if (bo->mem.mem_type == TTM_PL_VRAM && bo->mem.start < bo->num_pages && bo->mem.start > 0) (void) ttm_bo_validate(bo, &vmw_sys_placement, false, false); ret = ttm_bo_validate(bo, &placement, interruptible, false); /* For some reason we didn't up at the start of vram */ WARN_ON(ret == 0 && bo->offset != 0); ttm_bo_unreserve(bo); err_unlock: ttm_write_unlock(&dev_priv->reservation_sem); return ret; }