162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright © 2021 Intel Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/dma-fence.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <drm/ttm/ttm_bo.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "i915_deps.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/** 1462306a36Sopenharmony_ci * DOC: Set of utilities to dynamically collect dependencies into a 1562306a36Sopenharmony_ci * structure which is fed into the GT migration code. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Once we can do async unbinding, this is also needed to coalesce 1862306a36Sopenharmony_ci * the migration fence with the unbind fences if these are coalesced 1962306a36Sopenharmony_ci * post-migration. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * While collecting the individual dependencies, we store the refcounted 2262306a36Sopenharmony_ci * struct dma_fence pointers in a realloc-managed pointer array, since 2362306a36Sopenharmony_ci * that can be easily fed into a dma_fence_array. Other options are 2462306a36Sopenharmony_ci * available, like for example an xarray for similarity with drm/sched. 2562306a36Sopenharmony_ci * Can be changed easily if needed. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * A struct i915_deps need to be initialized using i915_deps_init(). 2862306a36Sopenharmony_ci * If i915_deps_add_dependency() or i915_deps_add_resv() return an 2962306a36Sopenharmony_ci * error code they will internally call i915_deps_fini(), which frees 3062306a36Sopenharmony_ci * all internal references and allocations. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Min number of fence pointers in the array when an allocation occurs. */ 3462306a36Sopenharmony_ci#define I915_DEPS_MIN_ALLOC_CHUNK 8U 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void i915_deps_reset_fences(struct i915_deps *deps) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci if (deps->fences != &deps->single) 3962306a36Sopenharmony_ci kfree(deps->fences); 4062306a36Sopenharmony_ci deps->num_deps = 0; 4162306a36Sopenharmony_ci deps->fences_size = 1; 4262306a36Sopenharmony_ci deps->fences = &deps->single; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/** 4662306a36Sopenharmony_ci * i915_deps_init - Initialize an i915_deps structure 4762306a36Sopenharmony_ci * @deps: Pointer to the i915_deps structure to initialize. 4862306a36Sopenharmony_ci * @gfp: The allocation mode for subsequenst allocations. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_civoid i915_deps_init(struct i915_deps *deps, gfp_t gfp) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci deps->fences = NULL; 5362306a36Sopenharmony_ci deps->gfp = gfp; 5462306a36Sopenharmony_ci i915_deps_reset_fences(deps); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/** 5862306a36Sopenharmony_ci * i915_deps_fini - Finalize an i915_deps structure 5962306a36Sopenharmony_ci * @deps: Pointer to the i915_deps structure to finalize. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * This function drops all fence references taken, conditionally frees and 6262306a36Sopenharmony_ci * then resets the fences array. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_civoid i915_deps_fini(struct i915_deps *deps) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci unsigned int i; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci for (i = 0; i < deps->num_deps; ++i) 6962306a36Sopenharmony_ci dma_fence_put(deps->fences[i]); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (deps->fences != &deps->single) 7262306a36Sopenharmony_ci kfree(deps->fences); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int i915_deps_grow(struct i915_deps *deps, struct dma_fence *fence, 7662306a36Sopenharmony_ci const struct ttm_operation_ctx *ctx) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci int ret; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (deps->num_deps >= deps->fences_size) { 8162306a36Sopenharmony_ci unsigned int new_size = 2 * deps->fences_size; 8262306a36Sopenharmony_ci struct dma_fence **new_fences; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci new_size = max(new_size, I915_DEPS_MIN_ALLOC_CHUNK); 8562306a36Sopenharmony_ci new_fences = kmalloc_array(new_size, sizeof(*new_fences), deps->gfp); 8662306a36Sopenharmony_ci if (!new_fences) 8762306a36Sopenharmony_ci goto sync; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci memcpy(new_fences, deps->fences, 9062306a36Sopenharmony_ci deps->fences_size * sizeof(*new_fences)); 9162306a36Sopenharmony_ci swap(new_fences, deps->fences); 9262306a36Sopenharmony_ci if (new_fences != &deps->single) 9362306a36Sopenharmony_ci kfree(new_fences); 9462306a36Sopenharmony_ci deps->fences_size = new_size; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci deps->fences[deps->num_deps++] = dma_fence_get(fence); 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cisync: 10062306a36Sopenharmony_ci if (ctx->no_wait_gpu && !dma_fence_is_signaled(fence)) { 10162306a36Sopenharmony_ci ret = -EBUSY; 10262306a36Sopenharmony_ci goto unref; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci ret = dma_fence_wait(fence, ctx->interruptible); 10662306a36Sopenharmony_ci if (ret) 10762306a36Sopenharmony_ci goto unref; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci ret = fence->error; 11062306a36Sopenharmony_ci if (ret) 11162306a36Sopenharmony_ci goto unref; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ciunref: 11662306a36Sopenharmony_ci i915_deps_fini(deps); 11762306a36Sopenharmony_ci return ret; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/** 12162306a36Sopenharmony_ci * i915_deps_sync - Wait for all the fences in the dependency collection 12262306a36Sopenharmony_ci * @deps: Pointer to the i915_deps structure the fences of which to wait for. 12362306a36Sopenharmony_ci * @ctx: Pointer to a struct ttm_operation_ctx indicating how the waits 12462306a36Sopenharmony_ci * should be performed. 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * This function waits for fences in the dependency collection. If it 12762306a36Sopenharmony_ci * encounters an error during the wait or a fence error, the wait for 12862306a36Sopenharmony_ci * further fences is aborted and the error returned. 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci * Return: Zero if successful, Negative error code on error. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ciint i915_deps_sync(const struct i915_deps *deps, const struct ttm_operation_ctx *ctx) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct dma_fence **fences = deps->fences; 13562306a36Sopenharmony_ci unsigned int i; 13662306a36Sopenharmony_ci int ret = 0; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci for (i = 0; i < deps->num_deps; ++i, ++fences) { 13962306a36Sopenharmony_ci if (ctx->no_wait_gpu && !dma_fence_is_signaled(*fences)) { 14062306a36Sopenharmony_ci ret = -EBUSY; 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ret = dma_fence_wait(*fences, ctx->interruptible); 14562306a36Sopenharmony_ci if (!ret) 14662306a36Sopenharmony_ci ret = (*fences)->error; 14762306a36Sopenharmony_ci if (ret) 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return ret; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/** 15562306a36Sopenharmony_ci * i915_deps_add_dependency - Add a fence to the dependency collection 15662306a36Sopenharmony_ci * @deps: Pointer to the i915_deps structure a fence is to be added to. 15762306a36Sopenharmony_ci * @fence: The fence to add. 15862306a36Sopenharmony_ci * @ctx: Pointer to a struct ttm_operation_ctx indicating how waits are to 15962306a36Sopenharmony_ci * be performed if waiting. 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * Adds a fence to the dependency collection, and takes a reference on it. 16262306a36Sopenharmony_ci * If the fence context is not zero and there was a later fence from the 16362306a36Sopenharmony_ci * same fence context already added, then the fence is not added to the 16462306a36Sopenharmony_ci * dependency collection. If the fence context is not zero and there was 16562306a36Sopenharmony_ci * an earlier fence already added, then the fence will replace the older 16662306a36Sopenharmony_ci * fence from the same context and the reference on the earlier fence will 16762306a36Sopenharmony_ci * be dropped. 16862306a36Sopenharmony_ci * If there is a failure to allocate memory to accommodate the new fence to 16962306a36Sopenharmony_ci * be added, the new fence will instead be waited for and an error may 17062306a36Sopenharmony_ci * be returned; depending on the value of @ctx, or if there was a fence 17162306a36Sopenharmony_ci * error. If an error was returned, the dependency collection will be 17262306a36Sopenharmony_ci * finalized and all fence reference dropped. 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * Return: 0 if success. Negative error code on error. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ciint i915_deps_add_dependency(struct i915_deps *deps, 17762306a36Sopenharmony_ci struct dma_fence *fence, 17862306a36Sopenharmony_ci const struct ttm_operation_ctx *ctx) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci unsigned int i; 18162306a36Sopenharmony_ci int ret; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (!fence) 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (dma_fence_is_signaled(fence)) { 18762306a36Sopenharmony_ci ret = fence->error; 18862306a36Sopenharmony_ci if (ret) 18962306a36Sopenharmony_ci i915_deps_fini(deps); 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci for (i = 0; i < deps->num_deps; ++i) { 19462306a36Sopenharmony_ci struct dma_fence *entry = deps->fences[i]; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (!entry->context || entry->context != fence->context) 19762306a36Sopenharmony_ci continue; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (dma_fence_is_later(fence, entry)) { 20062306a36Sopenharmony_ci dma_fence_put(entry); 20162306a36Sopenharmony_ci deps->fences[i] = dma_fence_get(fence); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return 0; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return i915_deps_grow(deps, fence, ctx); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/** 21162306a36Sopenharmony_ci * i915_deps_add_resv - Add the fences of a reservation object to a dependency 21262306a36Sopenharmony_ci * collection. 21362306a36Sopenharmony_ci * @deps: Pointer to the i915_deps structure a fence is to be added to. 21462306a36Sopenharmony_ci * @resv: The reservation object, then fences of which to add. 21562306a36Sopenharmony_ci * @ctx: Pointer to a struct ttm_operation_ctx indicating how waits are to 21662306a36Sopenharmony_ci * be performed if waiting. 21762306a36Sopenharmony_ci * 21862306a36Sopenharmony_ci * Calls i915_deps_add_depencency() on the indicated fences of @resv. 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * Return: Zero on success. Negative error code on error. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ciint i915_deps_add_resv(struct i915_deps *deps, struct dma_resv *resv, 22362306a36Sopenharmony_ci const struct ttm_operation_ctx *ctx) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct dma_resv_iter iter; 22662306a36Sopenharmony_ci struct dma_fence *fence; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci dma_resv_assert_held(resv); 22962306a36Sopenharmony_ci dma_resv_for_each_fence(&iter, resv, dma_resv_usage_rw(true), fence) { 23062306a36Sopenharmony_ci int ret = i915_deps_add_dependency(deps, fence, ctx); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (ret) 23362306a36Sopenharmony_ci return ret; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 238