Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright © 2021 Intel Corporation
0004  */
0005 
0006 #include <linux/dma-fence.h>
0007 #include <linux/slab.h>
0008 
0009 #include <drm/ttm/ttm_bo_api.h>
0010 
0011 #include "i915_deps.h"
0012 
0013 /**
0014  * DOC: Set of utilities to dynamically collect dependencies into a
0015  * structure which is fed into the GT migration code.
0016  *
0017  * Once we can do async unbinding, this is also needed to coalesce
0018  * the migration fence with the unbind fences if these are coalesced
0019  * post-migration.
0020  *
0021  * While collecting the individual dependencies, we store the refcounted
0022  * struct dma_fence pointers in a realloc-managed pointer array, since
0023  * that can be easily fed into a dma_fence_array. Other options are
0024  * available, like for example an xarray for similarity with drm/sched.
0025  * Can be changed easily if needed.
0026  *
0027  * A struct i915_deps need to be initialized using i915_deps_init().
0028  * If i915_deps_add_dependency() or i915_deps_add_resv() return an
0029  * error code they will internally call i915_deps_fini(), which frees
0030  * all internal references and allocations.
0031  */
0032 
0033 /* Min number of fence pointers in the array when an allocation occurs. */
0034 #define I915_DEPS_MIN_ALLOC_CHUNK 8U
0035 
0036 static void i915_deps_reset_fences(struct i915_deps *deps)
0037 {
0038     if (deps->fences != &deps->single)
0039         kfree(deps->fences);
0040     deps->num_deps = 0;
0041     deps->fences_size = 1;
0042     deps->fences = &deps->single;
0043 }
0044 
0045 /**
0046  * i915_deps_init - Initialize an i915_deps structure
0047  * @deps: Pointer to the i915_deps structure to initialize.
0048  * @gfp: The allocation mode for subsequenst allocations.
0049  */
0050 void i915_deps_init(struct i915_deps *deps, gfp_t gfp)
0051 {
0052     deps->fences = NULL;
0053     deps->gfp = gfp;
0054     i915_deps_reset_fences(deps);
0055 }
0056 
0057 /**
0058  * i915_deps_fini - Finalize an i915_deps structure
0059  * @deps: Pointer to the i915_deps structure to finalize.
0060  *
0061  * This function drops all fence references taken, conditionally frees and
0062  * then resets the fences array.
0063  */
0064 void i915_deps_fini(struct i915_deps *deps)
0065 {
0066     unsigned int i;
0067 
0068     for (i = 0; i < deps->num_deps; ++i)
0069         dma_fence_put(deps->fences[i]);
0070 
0071     if (deps->fences != &deps->single)
0072         kfree(deps->fences);
0073 }
0074 
0075 static int i915_deps_grow(struct i915_deps *deps, struct dma_fence *fence,
0076               const struct ttm_operation_ctx *ctx)
0077 {
0078     int ret;
0079 
0080     if (deps->num_deps >= deps->fences_size) {
0081         unsigned int new_size = 2 * deps->fences_size;
0082         struct dma_fence **new_fences;
0083 
0084         new_size = max(new_size, I915_DEPS_MIN_ALLOC_CHUNK);
0085         new_fences = kmalloc_array(new_size, sizeof(*new_fences), deps->gfp);
0086         if (!new_fences)
0087             goto sync;
0088 
0089         memcpy(new_fences, deps->fences,
0090                deps->fences_size * sizeof(*new_fences));
0091         swap(new_fences, deps->fences);
0092         if (new_fences != &deps->single)
0093             kfree(new_fences);
0094         deps->fences_size = new_size;
0095     }
0096     deps->fences[deps->num_deps++] = dma_fence_get(fence);
0097     return 0;
0098 
0099 sync:
0100     if (ctx->no_wait_gpu && !dma_fence_is_signaled(fence)) {
0101         ret = -EBUSY;
0102         goto unref;
0103     }
0104 
0105     ret = dma_fence_wait(fence, ctx->interruptible);
0106     if (ret)
0107         goto unref;
0108 
0109     ret = fence->error;
0110     if (ret)
0111         goto unref;
0112 
0113     return 0;
0114 
0115 unref:
0116     i915_deps_fini(deps);
0117     return ret;
0118 }
0119 
0120 /**
0121  * i915_deps_sync - Wait for all the fences in the dependency collection
0122  * @deps: Pointer to the i915_deps structure the fences of which to wait for.
0123  * @ctx: Pointer to a struct ttm_operation_ctx indicating how the waits
0124  * should be performed.
0125  *
0126  * This function waits for fences in the dependency collection. If it
0127  * encounters an error during the wait or a fence error, the wait for
0128  * further fences is aborted and the error returned.
0129  *
0130  * Return: Zero if successful, Negative error code on error.
0131  */
0132 int i915_deps_sync(const struct i915_deps *deps, const struct ttm_operation_ctx *ctx)
0133 {
0134     struct dma_fence **fences = deps->fences;
0135     unsigned int i;
0136     int ret = 0;
0137 
0138     for (i = 0; i < deps->num_deps; ++i, ++fences) {
0139         if (ctx->no_wait_gpu && !dma_fence_is_signaled(*fences)) {
0140             ret = -EBUSY;
0141             break;
0142         }
0143 
0144         ret = dma_fence_wait(*fences, ctx->interruptible);
0145         if (!ret)
0146             ret = (*fences)->error;
0147         if (ret)
0148             break;
0149     }
0150 
0151     return ret;
0152 }
0153 
0154 /**
0155  * i915_deps_add_dependency - Add a fence to the dependency collection
0156  * @deps: Pointer to the i915_deps structure a fence is to be added to.
0157  * @fence: The fence to add.
0158  * @ctx: Pointer to a struct ttm_operation_ctx indicating how waits are to
0159  * be performed if waiting.
0160  *
0161  * Adds a fence to the dependency collection, and takes a reference on it.
0162  * If the fence context is not zero and there was a later fence from the
0163  * same fence context already added, then the fence is not added to the
0164  * dependency collection. If the fence context is not zero and there was
0165  * an earlier fence already added, then the fence will replace the older
0166  * fence from the same context and the reference on the earlier fence will
0167  * be dropped.
0168  * If there is a failure to allocate memory to accommodate the new fence to
0169  * be added, the new fence will instead be waited for and an error may
0170  * be returned; depending on the value of @ctx, or if there was a fence
0171  * error. If an error was returned, the dependency collection will be
0172  * finalized and all fence reference dropped.
0173  *
0174  * Return: 0 if success. Negative error code on error.
0175  */
0176 int i915_deps_add_dependency(struct i915_deps *deps,
0177                  struct dma_fence *fence,
0178                  const struct ttm_operation_ctx *ctx)
0179 {
0180     unsigned int i;
0181     int ret;
0182 
0183     if (!fence)
0184         return 0;
0185 
0186     if (dma_fence_is_signaled(fence)) {
0187         ret = fence->error;
0188         if (ret)
0189             i915_deps_fini(deps);
0190         return ret;
0191     }
0192 
0193     for (i = 0; i < deps->num_deps; ++i) {
0194         struct dma_fence *entry = deps->fences[i];
0195 
0196         if (!entry->context || entry->context != fence->context)
0197             continue;
0198 
0199         if (dma_fence_is_later(fence, entry)) {
0200             dma_fence_put(entry);
0201             deps->fences[i] = dma_fence_get(fence);
0202         }
0203 
0204         return 0;
0205     }
0206 
0207     return i915_deps_grow(deps, fence, ctx);
0208 }
0209 
0210 /**
0211  * i915_deps_add_resv - Add the fences of a reservation object to a dependency
0212  * collection.
0213  * @deps: Pointer to the i915_deps structure a fence is to be added to.
0214  * @resv: The reservation object, then fences of which to add.
0215  * @ctx: Pointer to a struct ttm_operation_ctx indicating how waits are to
0216  * be performed if waiting.
0217  *
0218  * Calls i915_deps_add_depencency() on the indicated fences of @resv.
0219  *
0220  * Return: Zero on success. Negative error code on error.
0221  */
0222 int i915_deps_add_resv(struct i915_deps *deps, struct dma_resv *resv,
0223                const struct ttm_operation_ctx *ctx)
0224 {
0225     struct dma_resv_iter iter;
0226     struct dma_fence *fence;
0227 
0228     dma_resv_assert_held(resv);
0229     dma_resv_for_each_fence(&iter, resv, dma_resv_usage_rw(true), fence) {
0230         int ret = i915_deps_add_dependency(deps, fence, ctx);
0231 
0232         if (ret)
0233             return ret;
0234     }
0235 
0236     return 0;
0237 }