linux/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
<<
>>
Prefs
   1/**************************************************************************
   2 *
   3 * Copyright © 2011-2015 VMware, Inc., Palo Alto, CA., USA
   4 * All Rights Reserved.
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a
   7 * copy of this software and associated documentation files (the
   8 * "Software"), to deal in the Software without restriction, including
   9 * without limitation the rights to use, copy, modify, merge, publish,
  10 * distribute, sub license, and/or sell copies of the Software, and to
  11 * permit persons to whom the Software is furnished to do so, subject to
  12 * the following conditions:
  13 *
  14 * The above copyright notice and this permission notice (including the
  15 * next paragraph) shall be included in all copies or substantial portions
  16 * of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
  25 *
  26 **************************************************************************/
  27
  28#include <drm/ttm/ttm_placement.h>
  29
  30#include <drm/drmP.h>
  31#include "vmwgfx_drv.h"
  32
  33
  34/**
  35 * vmw_dmabuf_pin_in_placement - Validate a buffer to placement.
  36 *
  37 * @dev_priv:  Driver private.
  38 * @buf:  DMA buffer to move.
  39 * @placement:  The placement to pin it.
  40 * @interruptible:  Use interruptible wait.
  41 *
  42 * Returns
  43 *  -ERESTARTSYS if interrupted by a signal.
  44 */
  45int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv,
  46                                struct vmw_dma_buffer *buf,
  47                                struct ttm_placement *placement,
  48                                bool interruptible)
  49{
  50        struct ttm_buffer_object *bo = &buf->base;
  51        int ret;
  52        uint32_t new_flags;
  53
  54        ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
  55        if (unlikely(ret != 0))
  56                return ret;
  57
  58        vmw_execbuf_release_pinned_bo(dev_priv);
  59
  60        ret = ttm_bo_reserve(bo, interruptible, false, NULL);
  61        if (unlikely(ret != 0))
  62                goto err;
  63
  64        if (buf->pin_count > 0)
  65                ret = ttm_bo_mem_compat(placement, &bo->mem,
  66                                        &new_flags) == true ? 0 : -EINVAL;
  67        else
  68                ret = ttm_bo_validate(bo, placement, interruptible, false);
  69
  70        if (!ret)
  71                vmw_bo_pin_reserved(buf, true);
  72
  73        ttm_bo_unreserve(bo);
  74
  75err:
  76        ttm_write_unlock(&dev_priv->reservation_sem);
  77        return ret;
  78}
  79
  80/**
  81 * vmw_dmabuf_pin_in_vram_or_gmr - Move a buffer to vram or gmr.
  82 *
  83 * This function takes the reservation_sem in write mode.
  84 * Flushes and unpins the query bo to avoid failures.
  85 *
  86 * @dev_priv:  Driver private.
  87 * @buf:  DMA buffer to move.
  88 * @pin:  Pin buffer if true.
  89 * @interruptible:  Use interruptible wait.
  90 *
  91 * Returns
  92 * -ERESTARTSYS if interrupted by a signal.
  93 */
  94int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv,
  95                                  struct vmw_dma_buffer *buf,
  96                                  bool interruptible)
  97{
  98        struct ttm_buffer_object *bo = &buf->base;
  99        int ret;
 100        uint32_t new_flags;
 101
 102        ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
 103        if (unlikely(ret != 0))
 104                return ret;
 105
 106        vmw_execbuf_release_pinned_bo(dev_priv);
 107
 108        ret = ttm_bo_reserve(bo, interruptible, false, NULL);
 109        if (unlikely(ret != 0))
 110                goto err;
 111
 112        if (buf->pin_count > 0) {
 113                ret = ttm_bo_mem_compat(&vmw_vram_gmr_placement, &bo->mem,
 114                                        &new_flags) == true ? 0 : -EINVAL;
 115                goto out_unreserve;
 116        }
 117
 118        ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible,
 119                              false);
 120        if (likely(ret == 0) || ret == -ERESTARTSYS)
 121                goto out_unreserve;
 122
 123        ret = ttm_bo_validate(bo, &vmw_vram_placement, interruptible, false);
 124
 125out_unreserve:
 126        if (!ret)
 127                vmw_bo_pin_reserved(buf, true);
 128
 129        ttm_bo_unreserve(bo);
 130err:
 131        ttm_write_unlock(&dev_priv->reservation_sem);
 132        return ret;
 133}
 134
 135/**
 136 * vmw_dmabuf_pin_in_vram - Move a buffer to vram.
 137 *
 138 * This function takes the reservation_sem in write mode.
 139 * Flushes and unpins the query bo to avoid failures.
 140 *
 141 * @dev_priv:  Driver private.
 142 * @buf:  DMA buffer to move.
 143 * @interruptible:  Use interruptible wait.
 144 *
 145 * Returns
 146 * -ERESTARTSYS if interrupted by a signal.
 147 */
 148int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv,
 149                           struct vmw_dma_buffer *buf,
 150                           bool interruptible)
 151{
 152        return vmw_dmabuf_pin_in_placement(dev_priv, buf, &vmw_vram_placement,
 153                                           interruptible);
 154}
 155
 156/**
 157 * vmw_dmabuf_pin_in_start_of_vram - Move a buffer to start of vram.
 158 *
 159 * This function takes the reservation_sem in write mode.
 160 * Flushes and unpins the query bo to avoid failures.
 161 *
 162 * @dev_priv:  Driver private.
 163 * @buf:  DMA buffer to pin.
 164 * @interruptible:  Use interruptible wait.
 165 *
 166 * Returns
 167 * -ERESTARTSYS if interrupted by a signal.
 168 */
 169int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv,
 170                                    struct vmw_dma_buffer *buf,
 171                                    bool interruptible)
 172{
 173        struct ttm_buffer_object *bo = &buf->base;
 174        struct ttm_placement placement;
 175        struct ttm_place place;
 176        int ret = 0;
 177        uint32_t new_flags;
 178
 179        place = vmw_vram_placement.placement[0];
 180        place.lpfn = bo->num_pages;
 181        placement.num_placement = 1;
 182        placement.placement = &place;
 183        placement.num_busy_placement = 1;
 184        placement.busy_placement = &place;
 185
 186        ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
 187        if (unlikely(ret != 0))
 188                return ret;
 189
 190        vmw_execbuf_release_pinned_bo(dev_priv);
 191        ret = ttm_bo_reserve(bo, interruptible, false, NULL);
 192        if (unlikely(ret != 0))
 193                goto err_unlock;
 194
 195        /*
 196         * Is this buffer already in vram but not at the start of it?
 197         * In that case, evict it first because TTM isn't good at handling
 198         * that situation.
 199         */
 200        if (bo->mem.mem_type == TTM_PL_VRAM &&
 201            bo->mem.start < bo->num_pages &&
 202            bo->mem.start > 0 &&
 203            buf->pin_count == 0)
 204                (void) ttm_bo_validate(bo, &vmw_sys_placement, false, false);
 205
 206        if (buf->pin_count > 0)
 207                ret = ttm_bo_mem_compat(&placement, &bo->mem,
 208                                        &new_flags) == true ? 0 : -EINVAL;
 209        else
 210                ret = ttm_bo_validate(bo, &placement, interruptible, false);
 211
 212        /* For some reason we didn't end up at the start of vram */
 213        WARN_ON(ret == 0 && bo->offset != 0);
 214        if (!ret)
 215                vmw_bo_pin_reserved(buf, true);
 216
 217        ttm_bo_unreserve(bo);
 218err_unlock:
 219        ttm_write_unlock(&dev_priv->reservation_sem);
 220
 221        return ret;
 222}
 223
 224/**
 225 * vmw_dmabuf_unpin - Unpin the buffer given buffer, does not move the buffer.
 226 *
 227 * This function takes the reservation_sem in write mode.
 228 *
 229 * @dev_priv:  Driver private.
 230 * @buf:  DMA buffer to unpin.
 231 * @interruptible:  Use interruptible wait.
 232 *
 233 * Returns
 234 * -ERESTARTSYS if interrupted by a signal.
 235 */
 236int vmw_dmabuf_unpin(struct vmw_private *dev_priv,
 237                     struct vmw_dma_buffer *buf,
 238                     bool interruptible)
 239{
 240        struct ttm_buffer_object *bo = &buf->base;
 241        int ret;
 242
 243        ret = ttm_read_lock(&dev_priv->reservation_sem, interruptible);
 244        if (unlikely(ret != 0))
 245                return ret;
 246
 247        ret = ttm_bo_reserve(bo, interruptible, false, NULL);
 248        if (unlikely(ret != 0))
 249                goto err;
 250
 251        vmw_bo_pin_reserved(buf, false);
 252
 253        ttm_bo_unreserve(bo);
 254
 255err:
 256        ttm_read_unlock(&dev_priv->reservation_sem);
 257        return ret;
 258}
 259
 260/**
 261 * vmw_bo_get_guest_ptr - Get the guest ptr representing the current placement
 262 * of a buffer.
 263 *
 264 * @bo: Pointer to a struct ttm_buffer_object. Must be pinned or reserved.
 265 * @ptr: SVGAGuestPtr returning the result.
 266 */
 267void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *bo,
 268                          SVGAGuestPtr *ptr)
 269{
 270        if (bo->mem.mem_type == TTM_PL_VRAM) {
 271                ptr->gmrId = SVGA_GMR_FRAMEBUFFER;
 272                ptr->offset = bo->offset;
 273        } else {
 274                ptr->gmrId = bo->mem.start;
 275                ptr->offset = 0;
 276        }
 277}
 278
 279
 280/**
 281 * vmw_bo_pin_reserved - Pin or unpin a buffer object without moving it.
 282 *
 283 * @vbo: The buffer object. Must be reserved.
 284 * @pin: Whether to pin or unpin.
 285 *
 286 */
 287void vmw_bo_pin_reserved(struct vmw_dma_buffer *vbo, bool pin)
 288{
 289        struct ttm_place pl;
 290        struct ttm_placement placement;
 291        struct ttm_buffer_object *bo = &vbo->base;
 292        uint32_t old_mem_type = bo->mem.mem_type;
 293        int ret;
 294
 295        lockdep_assert_held(&bo->resv->lock.base);
 296
 297        if (pin) {
 298                if (vbo->pin_count++ > 0)
 299                        return;
 300        } else {
 301                WARN_ON(vbo->pin_count <= 0);
 302                if (--vbo->pin_count > 0)
 303                        return;
 304        }
 305
 306        pl.fpfn = 0;
 307        pl.lpfn = 0;
 308        pl.flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB
 309                | TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED;
 310        if (pin)
 311                pl.flags |= TTM_PL_FLAG_NO_EVICT;
 312
 313        memset(&placement, 0, sizeof(placement));
 314        placement.num_placement = 1;
 315        placement.placement = &pl;
 316
 317        ret = ttm_bo_validate(bo, &placement, false, true);
 318
 319        BUG_ON(ret != 0 || bo->mem.mem_type != old_mem_type);
 320}
 321