Merge tag 'drm-misc-next-2022-08-20-1' of git://anongit.freedesktop.org/drm/drm-misc...
[linux-block.git] / drivers / gpu / drm / ttm / ttm_bo.c
index 97184c33352662662bbd27de462eacb111045435..590110fdf59cde5c0b138ea13fe8e29b1a8a09f5 100644 (file)
@@ -117,12 +117,13 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
                                  struct ttm_operation_ctx *ctx,
                                  struct ttm_place *hop)
 {
-       struct ttm_resource_manager *old_man, *new_man;
        struct ttm_device *bdev = bo->bdev;
+       bool old_use_tt, new_use_tt;
        int ret;
 
-       old_man = ttm_manager_type(bdev, bo->resource->mem_type);
-       new_man = ttm_manager_type(bdev, mem->mem_type);
+       old_use_tt = bo->resource &&
+               ttm_manager_type(bdev, bo->resource->mem_type)->use_tt;
+       new_use_tt = ttm_manager_type(bdev, mem->mem_type)->use_tt;
 
        ttm_bo_unmap_virtual(bo);
 
@@ -130,11 +131,11 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
         * Create and bind a ttm if required.
         */
 
-       if (new_man->use_tt) {
+       if (new_use_tt) {
                /* Zero init the new TTM structure if the old location should
                 * have used one as well.
                 */
-               ret = ttm_tt_create(bo, old_man->use_tt);
+               ret = ttm_tt_create(bo, old_use_tt);
                if (ret)
                        goto out_err;
 
@@ -160,8 +161,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
        return 0;
 
 out_err:
-       new_man = ttm_manager_type(bdev, bo->resource->mem_type);
-       if (!new_man->use_tt)
+       if (!old_use_tt)
                ttm_bo_tt_destroy(bo);
 
        return ret;
@@ -904,7 +904,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
        /*
         * Check whether we need to move buffer.
         */
-       if (!ttm_resource_compat(bo->resource, placement)) {
+       if (!bo->resource || !ttm_resource_compat(bo->resource, placement)) {
                ret = ttm_bo_move_buffer(bo, placement, ctx);
                if (ret)
                        return ret;
@@ -921,36 +921,61 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
 }
 EXPORT_SYMBOL(ttm_bo_validate);
 
-int ttm_bo_init_reserved(struct ttm_device *bdev,
-                        struct ttm_buffer_object *bo,
-                        size_t size,
-                        enum ttm_bo_type type,
-                        struct ttm_placement *placement,
-                        uint32_t page_alignment,
-                        struct ttm_operation_ctx *ctx,
-                        struct sg_table *sg,
-                        struct dma_resv *resv,
+/**
+ * ttm_bo_init_reserved
+ *
+ * @bdev: Pointer to a ttm_device struct.
+ * @bo: Pointer to a ttm_buffer_object to be initialized.
+ * @type: Requested type of buffer object.
+ * @placement: Initial placement for buffer object.
+ * @alignment: Data alignment in pages.
+ * @ctx: TTM operation context for memory allocation.
+ * @sg: Scatter-gather table.
+ * @resv: Pointer to a dma_resv, or NULL to let ttm allocate one.
+ * @destroy: Destroy function. Use NULL for kfree().
+ *
+ * This function initializes a pre-allocated struct ttm_buffer_object.
+ * As this object may be part of a larger structure, this function,
+ * together with the @destroy function, enables driver-specific objects
+ * derived from a ttm_buffer_object.
+ *
+ * On successful return, the caller owns an object kref to @bo. The kref and
+ * list_kref are usually set to 1, but note that in some situations, other
+ * tasks may already be holding references to @bo as well.
+ * Furthermore, if resv == NULL, the buffer's reservation lock will be held,
+ * and it is the caller's responsibility to call ttm_bo_unreserve.
+ *
+ * If a failure occurs, the function will call the @destroy function. Thus,
+ * after a failure, dereferencing @bo is illegal and will likely cause memory
+ * corruption.
+ *
+ * Returns
+ * -ENOMEM: Out of memory.
+ * -EINVAL: Invalid placement flags.
+ * -ERESTARTSYS: Interrupted by signal while sleeping waiting for resources.
+ */
+int ttm_bo_init_reserved(struct ttm_device *bdev, struct ttm_buffer_object *bo,
+                        enum ttm_bo_type type, struct ttm_placement *placement,
+                        uint32_t alignment, struct ttm_operation_ctx *ctx,
+                        struct sg_table *sg, struct dma_resv *resv,
                         void (*destroy) (struct ttm_buffer_object *))
 {
        static const struct ttm_place sys_mem = { .mem_type = TTM_PL_SYSTEM };
-       bool locked;
        int ret;
 
-       bo->destroy = destroy;
        kref_init(&bo->kref);
        INIT_LIST_HEAD(&bo->ddestroy);
        bo->bdev = bdev;
        bo->type = type;
-       bo->page_alignment = page_alignment;
+       bo->page_alignment = alignment;
+       bo->destroy = destroy;
        bo->pin_count = 0;
        bo->sg = sg;
        bo->bulk_move = NULL;
-       if (resv) {
+       if (resv)
                bo->base.resv = resv;
-               dma_resv_assert_held(bo->base.resv);
-       } else {
+       else
                bo->base.resv = &bo->base._resv;
-       }
        atomic_inc(&ttm_glob.bo_count);
 
        ret = ttm_resource_alloc(bo, &sys_mem, &bo->resource);
@@ -963,50 +988,84 @@ int ttm_bo_init_reserved(struct ttm_device *bdev,
         * For ttm_bo_type_device buffers, allocate
         * address space from the device.
         */
-       if (bo->type == ttm_bo_type_device ||
-           bo->type == ttm_bo_type_sg)
+       if (bo->type == ttm_bo_type_device || bo->type == ttm_bo_type_sg) {
                ret = drm_vma_offset_add(bdev->vma_manager, &bo->base.vma_node,
-                                        bo->resource->num_pages);
+                                        PFN_UP(bo->base.size));
+               if (ret)
+                       goto err_put;
+       }
 
        /* passed reservation objects should already be locked,
         * since otherwise lockdep will be angered in radeon.
         */
-       if (!resv) {
-               locked = dma_resv_trylock(bo->base.resv);
-               WARN_ON(!locked);
-       }
+       if (!resv)
+               WARN_ON(!dma_resv_trylock(bo->base.resv));
+       else
+               dma_resv_assert_held(resv);
 
-       if (likely(!ret))
-               ret = ttm_bo_validate(bo, placement, ctx);
+       ret = ttm_bo_validate(bo, placement, ctx);
+       if (unlikely(ret))
+               goto err_unlock;
 
-       if (unlikely(ret)) {
-               if (!resv)
-                       ttm_bo_unreserve(bo);
+       return 0;
 
-               ttm_bo_put(bo);
-               return ret;
-       }
+err_unlock:
+       if (!resv)
+               dma_resv_unlock(bo->base.resv);
 
+err_put:
+       ttm_bo_put(bo);
        return ret;
 }
 EXPORT_SYMBOL(ttm_bo_init_reserved);
 
-int ttm_bo_init(struct ttm_device *bdev,
-               struct ttm_buffer_object *bo,
-               size_t size,
-               enum ttm_bo_type type,
-               struct ttm_placement *placement,
-               uint32_t page_alignment,
-               bool interruptible,
-               struct sg_table *sg,
-               struct dma_resv *resv,
-               void (*destroy) (struct ttm_buffer_object *))
+/**
+ * ttm_bo_init_validate
+ *
+ * @bdev: Pointer to a ttm_device struct.
+ * @bo: Pointer to a ttm_buffer_object to be initialized.
+ * @type: Requested type of buffer object.
+ * @placement: Initial placement for buffer object.
+ * @alignment: Data alignment in pages.
+ * @interruptible: If needing to sleep to wait for GPU resources,
+ * sleep interruptible.
+ * pinned in physical memory. If this behaviour is not desired, this member
+ * holds a pointer to a persistent shmem object. Typically, this would
+ * point to the shmem object backing a GEM object if TTM is used to back a
+ * GEM user interface.
+ * @sg: Scatter-gather table.
+ * @resv: Pointer to a dma_resv, or NULL to let ttm allocate one.
+ * @destroy: Destroy function. Use NULL for kfree().
+ *
+ * This function initializes a pre-allocated struct ttm_buffer_object.
+ * As this object may be part of a larger structure, this function,
+ * together with the @destroy function,
+ * enables driver-specific objects derived from a ttm_buffer_object.
+ *
+ * On successful return, the caller owns an object kref to @bo. The kref and
+ * list_kref are usually set to 1, but note that in some situations, other
+ * tasks may already be holding references to @bo as well.
+ *
+ * If a failure occurs, the function will call the @destroy function, Thus,
+ * after a failure, dereferencing @bo is illegal and will likely cause memory
+ * corruption.
+ *
+ * Returns
+ * -ENOMEM: Out of memory.
+ * -EINVAL: Invalid placement flags.
+ * -ERESTARTSYS: Interrupted by signal while sleeping waiting for resources.
+ */
+int ttm_bo_init_validate(struct ttm_device *bdev, struct ttm_buffer_object *bo,
+                        enum ttm_bo_type type, struct ttm_placement *placement,
+                        uint32_t alignment, bool interruptible,
+                        struct sg_table *sg, struct dma_resv *resv,
+                        void (*destroy) (struct ttm_buffer_object *))
 {
        struct ttm_operation_ctx ctx = { interruptible, false };
        int ret;
 
-       ret = ttm_bo_init_reserved(bdev, bo, size, type, placement,
-                                  page_alignment, &ctx, sg, resv, destroy);
+       ret = ttm_bo_init_reserved(bdev, bo, type, placement, alignment, &ctx,
+                                  sg, resv, destroy);
        if (ret)
                return ret;
 
@@ -1015,7 +1074,7 @@ int ttm_bo_init(struct ttm_device *bdev,
 
        return 0;
 }
-EXPORT_SYMBOL(ttm_bo_init);
+EXPORT_SYMBOL(ttm_bo_init_validate);
 
 /*
  * buffer object vm functions.