Path: blob/master/drivers/dma-buf/st-dma-fence-unwrap.c
26278 views
// SPDX-License-Identifier: MIT12/*3* Copyright (C) 2022 Advanced Micro Devices, Inc.4*/56#include <linux/dma-fence.h>7#include <linux/dma-fence-array.h>8#include <linux/dma-fence-chain.h>9#include <linux/dma-fence-unwrap.h>1011#include "selftest.h"1213#define CHAIN_SZ (4 << 10)1415struct mock_fence {16struct dma_fence base;17spinlock_t lock;18};1920static const char *mock_name(struct dma_fence *f)21{22return "mock";23}2425static const struct dma_fence_ops mock_ops = {26.get_driver_name = mock_name,27.get_timeline_name = mock_name,28};2930static struct dma_fence *__mock_fence(u64 context, u64 seqno)31{32struct mock_fence *f;3334f = kmalloc(sizeof(*f), GFP_KERNEL);35if (!f)36return NULL;3738spin_lock_init(&f->lock);39dma_fence_init(&f->base, &mock_ops, &f->lock, context, seqno);4041return &f->base;42}4344static struct dma_fence *mock_fence(void)45{46return __mock_fence(dma_fence_context_alloc(1), 1);47}4849static struct dma_fence *mock_array(unsigned int num_fences, ...)50{51struct dma_fence_array *array;52struct dma_fence **fences;53va_list valist;54int i;5556fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);57if (!fences)58goto error_put;5960va_start(valist, num_fences);61for (i = 0; i < num_fences; ++i)62fences[i] = va_arg(valist, typeof(*fences));63va_end(valist);6465array = dma_fence_array_create(num_fences, fences,66dma_fence_context_alloc(1),671, false);68if (!array)69goto error_free;70return &array->base;7172error_free:73kfree(fences);7475error_put:76va_start(valist, num_fences);77for (i = 0; i < num_fences; ++i)78dma_fence_put(va_arg(valist, typeof(*fences)));79va_end(valist);80return NULL;81}8283static struct dma_fence *mock_chain(struct dma_fence *prev,84struct dma_fence *fence)85{86struct dma_fence_chain *f;8788f = dma_fence_chain_alloc();89if (!f) {90dma_fence_put(prev);91dma_fence_put(fence);92return NULL;93}9495dma_fence_chain_init(f, prev, fence, 1);96return &f->base;97}9899static int sanitycheck(void *arg)100{101struct dma_fence *f, *chain, *array;102int err = 0;103104f = mock_fence();105if (!f)106return -ENOMEM;107108dma_fence_enable_sw_signaling(f);109110array = mock_array(1, f);111if (!array)112return -ENOMEM;113114chain = mock_chain(NULL, array);115if (!chain)116return -ENOMEM;117118dma_fence_put(chain);119return err;120}121122static int unwrap_array(void *arg)123{124struct dma_fence *fence, *f1, *f2, *array;125struct dma_fence_unwrap iter;126int err = 0;127128f1 = mock_fence();129if (!f1)130return -ENOMEM;131132dma_fence_enable_sw_signaling(f1);133134f2 = mock_fence();135if (!f2) {136dma_fence_put(f1);137return -ENOMEM;138}139140dma_fence_enable_sw_signaling(f2);141142array = mock_array(2, f1, f2);143if (!array)144return -ENOMEM;145146dma_fence_unwrap_for_each(fence, &iter, array) {147if (fence == f1) {148f1 = NULL;149} else if (fence == f2) {150f2 = NULL;151} else {152pr_err("Unexpected fence!\n");153err = -EINVAL;154}155}156157if (f1 || f2) {158pr_err("Not all fences seen!\n");159err = -EINVAL;160}161162dma_fence_put(array);163return err;164}165166static int unwrap_chain(void *arg)167{168struct dma_fence *fence, *f1, *f2, *chain;169struct dma_fence_unwrap iter;170int err = 0;171172f1 = mock_fence();173if (!f1)174return -ENOMEM;175176dma_fence_enable_sw_signaling(f1);177178f2 = mock_fence();179if (!f2) {180dma_fence_put(f1);181return -ENOMEM;182}183184dma_fence_enable_sw_signaling(f2);185186chain = mock_chain(f1, f2);187if (!chain)188return -ENOMEM;189190dma_fence_unwrap_for_each(fence, &iter, chain) {191if (fence == f1) {192f1 = NULL;193} else if (fence == f2) {194f2 = NULL;195} else {196pr_err("Unexpected fence!\n");197err = -EINVAL;198}199}200201if (f1 || f2) {202pr_err("Not all fences seen!\n");203err = -EINVAL;204}205206dma_fence_put(chain);207return err;208}209210static int unwrap_chain_array(void *arg)211{212struct dma_fence *fence, *f1, *f2, *array, *chain;213struct dma_fence_unwrap iter;214int err = 0;215216f1 = mock_fence();217if (!f1)218return -ENOMEM;219220dma_fence_enable_sw_signaling(f1);221222f2 = mock_fence();223if (!f2) {224dma_fence_put(f1);225return -ENOMEM;226}227228dma_fence_enable_sw_signaling(f2);229230array = mock_array(2, f1, f2);231if (!array)232return -ENOMEM;233234chain = mock_chain(NULL, array);235if (!chain)236return -ENOMEM;237238dma_fence_unwrap_for_each(fence, &iter, chain) {239if (fence == f1) {240f1 = NULL;241} else if (fence == f2) {242f2 = NULL;243} else {244pr_err("Unexpected fence!\n");245err = -EINVAL;246}247}248249if (f1 || f2) {250pr_err("Not all fences seen!\n");251err = -EINVAL;252}253254dma_fence_put(chain);255return err;256}257258static int unwrap_merge(void *arg)259{260struct dma_fence *fence, *f1, *f2, *f3;261struct dma_fence_unwrap iter;262int err = 0;263264f1 = mock_fence();265if (!f1)266return -ENOMEM;267268dma_fence_enable_sw_signaling(f1);269270f2 = mock_fence();271if (!f2) {272err = -ENOMEM;273goto error_put_f1;274}275276dma_fence_enable_sw_signaling(f2);277278f3 = dma_fence_unwrap_merge(f1, f2);279if (!f3) {280err = -ENOMEM;281goto error_put_f2;282}283284dma_fence_unwrap_for_each(fence, &iter, f3) {285if (fence == f1) {286dma_fence_put(f1);287f1 = NULL;288} else if (fence == f2) {289dma_fence_put(f2);290f2 = NULL;291} else {292pr_err("Unexpected fence!\n");293err = -EINVAL;294}295}296297if (f1 || f2) {298pr_err("Not all fences seen!\n");299err = -EINVAL;300}301302dma_fence_put(f3);303error_put_f2:304dma_fence_put(f2);305error_put_f1:306dma_fence_put(f1);307return err;308}309310static int unwrap_merge_duplicate(void *arg)311{312struct dma_fence *fence, *f1, *f2;313struct dma_fence_unwrap iter;314int err = 0;315316f1 = mock_fence();317if (!f1)318return -ENOMEM;319320dma_fence_enable_sw_signaling(f1);321322f2 = dma_fence_unwrap_merge(f1, f1);323if (!f2) {324err = -ENOMEM;325goto error_put_f1;326}327328dma_fence_unwrap_for_each(fence, &iter, f2) {329if (fence == f1) {330dma_fence_put(f1);331f1 = NULL;332} else {333pr_err("Unexpected fence!\n");334err = -EINVAL;335}336}337338if (f1) {339pr_err("Not all fences seen!\n");340err = -EINVAL;341}342343dma_fence_put(f2);344error_put_f1:345dma_fence_put(f1);346return err;347}348349static int unwrap_merge_seqno(void *arg)350{351struct dma_fence *fence, *f1, *f2, *f3, *f4;352struct dma_fence_unwrap iter;353int err = 0;354u64 ctx[2];355356ctx[0] = dma_fence_context_alloc(1);357ctx[1] = dma_fence_context_alloc(1);358359f1 = __mock_fence(ctx[1], 1);360if (!f1)361return -ENOMEM;362363dma_fence_enable_sw_signaling(f1);364365f2 = __mock_fence(ctx[1], 2);366if (!f2) {367err = -ENOMEM;368goto error_put_f1;369}370371dma_fence_enable_sw_signaling(f2);372373f3 = __mock_fence(ctx[0], 1);374if (!f3) {375err = -ENOMEM;376goto error_put_f2;377}378379dma_fence_enable_sw_signaling(f3);380381f4 = dma_fence_unwrap_merge(f1, f2, f3);382if (!f4) {383err = -ENOMEM;384goto error_put_f3;385}386387dma_fence_unwrap_for_each(fence, &iter, f4) {388if (fence == f3 && f2) {389dma_fence_put(f3);390f3 = NULL;391} else if (fence == f2 && !f3) {392dma_fence_put(f2);393f2 = NULL;394} else {395pr_err("Unexpected fence!\n");396err = -EINVAL;397}398}399400if (f2 || f3) {401pr_err("Not all fences seen!\n");402err = -EINVAL;403}404405dma_fence_put(f4);406error_put_f3:407dma_fence_put(f3);408error_put_f2:409dma_fence_put(f2);410error_put_f1:411dma_fence_put(f1);412return err;413}414415static int unwrap_merge_order(void *arg)416{417struct dma_fence *fence, *f1, *f2, *a1, *a2, *c1, *c2;418struct dma_fence_unwrap iter;419int err = 0;420421f1 = mock_fence();422if (!f1)423return -ENOMEM;424425dma_fence_enable_sw_signaling(f1);426427f2 = mock_fence();428if (!f2) {429dma_fence_put(f1);430return -ENOMEM;431}432433dma_fence_enable_sw_signaling(f2);434435a1 = mock_array(2, f1, f2);436if (!a1)437return -ENOMEM;438439c1 = mock_chain(NULL, dma_fence_get(f1));440if (!c1)441goto error_put_a1;442443c2 = mock_chain(c1, dma_fence_get(f2));444if (!c2)445goto error_put_a1;446447/*448* The fences in the chain are the same as in a1 but in oposite order,449* the dma_fence_merge() function should be able to handle that.450*/451a2 = dma_fence_unwrap_merge(a1, c2);452453dma_fence_unwrap_for_each(fence, &iter, a2) {454if (fence == f1) {455f1 = NULL;456if (!f2)457pr_err("Unexpected order!\n");458} else if (fence == f2) {459f2 = NULL;460if (f1)461pr_err("Unexpected order!\n");462} else {463pr_err("Unexpected fence!\n");464err = -EINVAL;465}466}467468if (f1 || f2) {469pr_err("Not all fences seen!\n");470err = -EINVAL;471}472473dma_fence_put(a2);474return err;475476error_put_a1:477dma_fence_put(a1);478return -ENOMEM;479}480481static int unwrap_merge_complex(void *arg)482{483struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5;484struct dma_fence_unwrap iter;485int err = -ENOMEM;486487f1 = mock_fence();488if (!f1)489return -ENOMEM;490491dma_fence_enable_sw_signaling(f1);492493f2 = mock_fence();494if (!f2)495goto error_put_f1;496497dma_fence_enable_sw_signaling(f2);498499f3 = dma_fence_unwrap_merge(f1, f2);500if (!f3)501goto error_put_f2;502503/* The resulting array has the fences in reverse */504f4 = mock_array(2, dma_fence_get(f2), dma_fence_get(f1));505if (!f4)506goto error_put_f3;507508/* Signaled fences should be filtered, the two arrays merged. */509f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub());510if (!f5)511goto error_put_f4;512513err = 0;514dma_fence_unwrap_for_each(fence, &iter, f5) {515if (fence == f1) {516dma_fence_put(f1);517f1 = NULL;518} else if (fence == f2) {519dma_fence_put(f2);520f2 = NULL;521} else {522pr_err("Unexpected fence!\n");523err = -EINVAL;524}525}526527if (f1 || f2) {528pr_err("Not all fences seen!\n");529err = -EINVAL;530}531532dma_fence_put(f5);533error_put_f4:534dma_fence_put(f4);535error_put_f3:536dma_fence_put(f3);537error_put_f2:538dma_fence_put(f2);539error_put_f1:540dma_fence_put(f1);541return err;542}543544static int unwrap_merge_complex_seqno(void *arg)545{546struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5, *f6, *f7;547struct dma_fence_unwrap iter;548int err = -ENOMEM;549u64 ctx[2];550551ctx[0] = dma_fence_context_alloc(1);552ctx[1] = dma_fence_context_alloc(1);553554f1 = __mock_fence(ctx[0], 2);555if (!f1)556return -ENOMEM;557558dma_fence_enable_sw_signaling(f1);559560f2 = __mock_fence(ctx[1], 1);561if (!f2)562goto error_put_f1;563564dma_fence_enable_sw_signaling(f2);565566f3 = __mock_fence(ctx[0], 1);567if (!f3)568goto error_put_f2;569570dma_fence_enable_sw_signaling(f3);571572f4 = __mock_fence(ctx[1], 2);573if (!f4)574goto error_put_f3;575576dma_fence_enable_sw_signaling(f4);577578f5 = mock_array(2, dma_fence_get(f1), dma_fence_get(f2));579if (!f5)580goto error_put_f4;581582f6 = mock_array(2, dma_fence_get(f3), dma_fence_get(f4));583if (!f6)584goto error_put_f5;585586f7 = dma_fence_unwrap_merge(f5, f6);587if (!f7)588goto error_put_f6;589590err = 0;591dma_fence_unwrap_for_each(fence, &iter, f7) {592if (fence == f1 && f4) {593dma_fence_put(f1);594f1 = NULL;595} else if (fence == f4 && !f1) {596dma_fence_put(f4);597f4 = NULL;598} else {599pr_err("Unexpected fence!\n");600err = -EINVAL;601}602}603604if (f1 || f4) {605pr_err("Not all fences seen!\n");606err = -EINVAL;607}608609dma_fence_put(f7);610error_put_f6:611dma_fence_put(f6);612error_put_f5:613dma_fence_put(f5);614error_put_f4:615dma_fence_put(f4);616error_put_f3:617dma_fence_put(f3);618error_put_f2:619dma_fence_put(f2);620error_put_f1:621dma_fence_put(f1);622return err;623}624625int dma_fence_unwrap(void)626{627static const struct subtest tests[] = {628SUBTEST(sanitycheck),629SUBTEST(unwrap_array),630SUBTEST(unwrap_chain),631SUBTEST(unwrap_chain_array),632SUBTEST(unwrap_merge),633SUBTEST(unwrap_merge_duplicate),634SUBTEST(unwrap_merge_seqno),635SUBTEST(unwrap_merge_order),636SUBTEST(unwrap_merge_complex),637SUBTEST(unwrap_merge_complex_seqno),638};639640return subtests(tests, NULL);641}642643644