linux/drivers/dma-buf/st-dma-fence-chain.c
<<
>>
Prefs
   1// SPDX-License-Identifier: MIT
   2
   3/*
   4 * Copyright © 2019 Intel Corporation
   5 */
   6
   7#include <linux/delay.h>
   8#include <linux/dma-fence.h>
   9#include <linux/dma-fence-chain.h>
  10#include <linux/kernel.h>
  11#include <linux/kthread.h>
  12#include <linux/mm.h>
  13#include <linux/sched/signal.h>
  14#include <linux/slab.h>
  15#include <linux/spinlock.h>
  16#include <linux/random.h>
  17
  18#include "selftest.h"
  19
  20#define CHAIN_SZ (4 << 10)
  21
  22static struct kmem_cache *slab_fences;
  23
  24static inline struct mock_fence {
  25        struct dma_fence base;
  26        spinlock_t lock;
  27} *to_mock_fence(struct dma_fence *f) {
  28        return container_of(f, struct mock_fence, base);
  29}
  30
  31static const char *mock_name(struct dma_fence *f)
  32{
  33        return "mock";
  34}
  35
  36static void mock_fence_release(struct dma_fence *f)
  37{
  38        kmem_cache_free(slab_fences, to_mock_fence(f));
  39}
  40
  41static const struct dma_fence_ops mock_ops = {
  42        .get_driver_name = mock_name,
  43        .get_timeline_name = mock_name,
  44        .release = mock_fence_release,
  45};
  46
  47static struct dma_fence *mock_fence(void)
  48{
  49        struct mock_fence *f;
  50
  51        f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
  52        if (!f)
  53                return NULL;
  54
  55        spin_lock_init(&f->lock);
  56        dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
  57
  58        return &f->base;
  59}
  60
  61static struct dma_fence *mock_chain(struct dma_fence *prev,
  62                                    struct dma_fence *fence,
  63                                    u64 seqno)
  64{
  65        struct dma_fence_chain *f;
  66
  67        f = dma_fence_chain_alloc();
  68        if (!f)
  69                return NULL;
  70
  71        dma_fence_chain_init(f, dma_fence_get(prev), dma_fence_get(fence),
  72                             seqno);
  73
  74        return &f->base;
  75}
  76
  77static int sanitycheck(void *arg)
  78{
  79        struct dma_fence *f, *chain;
  80        int err = 0;
  81
  82        f = mock_fence();
  83        if (!f)
  84                return -ENOMEM;
  85
  86        chain = mock_chain(NULL, f, 1);
  87        if (!chain)
  88                err = -ENOMEM;
  89
  90        dma_fence_signal(f);
  91        dma_fence_put(f);
  92
  93        dma_fence_put(chain);
  94
  95        return err;
  96}
  97
  98struct fence_chains {
  99        unsigned int chain_length;
 100        struct dma_fence **fences;
 101        struct dma_fence **chains;
 102
 103        struct dma_fence *tail;
 104};
 105
 106static uint64_t seqno_inc(unsigned int i)
 107{
 108        return i + 1;
 109}
 110
 111static int fence_chains_init(struct fence_chains *fc, unsigned int count,
 112                             uint64_t (*seqno_fn)(unsigned int))
 113{
 114        unsigned int i;
 115        int err = 0;
 116
 117        fc->chains = kvmalloc_array(count, sizeof(*fc->chains),
 118                                    GFP_KERNEL | __GFP_ZERO);
 119        if (!fc->chains)
 120                return -ENOMEM;
 121
 122        fc->fences = kvmalloc_array(count, sizeof(*fc->fences),
 123                                    GFP_KERNEL | __GFP_ZERO);
 124        if (!fc->fences) {
 125                err = -ENOMEM;
 126                goto err_chains;
 127        }
 128
 129        fc->tail = NULL;
 130        for (i = 0; i < count; i++) {
 131                fc->fences[i] = mock_fence();
 132                if (!fc->fences[i]) {
 133                        err = -ENOMEM;
 134                        goto unwind;
 135                }
 136
 137                fc->chains[i] = mock_chain(fc->tail,
 138                                           fc->fences[i],
 139                                           seqno_fn(i));
 140                if (!fc->chains[i]) {
 141                        err = -ENOMEM;
 142                        goto unwind;
 143                }
 144
 145                fc->tail = fc->chains[i];
 146        }
 147
 148        fc->chain_length = i;
 149        return 0;
 150
 151unwind:
 152        for (i = 0; i < count; i++) {
 153                dma_fence_put(fc->fences[i]);
 154                dma_fence_put(fc->chains[i]);
 155        }
 156        kvfree(fc->fences);
 157err_chains:
 158        kvfree(fc->chains);
 159        return err;
 160}
 161
 162static void fence_chains_fini(struct fence_chains *fc)
 163{
 164        unsigned int i;
 165
 166        for (i = 0; i < fc->chain_length; i++) {
 167                dma_fence_signal(fc->fences[i]);
 168                dma_fence_put(fc->fences[i]);
 169        }
 170        kvfree(fc->fences);
 171
 172        for (i = 0; i < fc->chain_length; i++)
 173                dma_fence_put(fc->chains[i]);
 174        kvfree(fc->chains);
 175}
 176
 177static int find_seqno(void *arg)
 178{
 179        struct fence_chains fc;
 180        struct dma_fence *fence;
 181        int err;
 182        int i;
 183
 184        err = fence_chains_init(&fc, 64, seqno_inc);
 185        if (err)
 186                return err;
 187
 188        fence = dma_fence_get(fc.tail);
 189        err = dma_fence_chain_find_seqno(&fence, 0);
 190        dma_fence_put(fence);
 191        if (err) {
 192                pr_err("Reported %d for find_seqno(0)!\n", err);
 193                goto err;
 194        }
 195
 196        for (i = 0; i < fc.chain_length; i++) {
 197                fence = dma_fence_get(fc.tail);
 198                err = dma_fence_chain_find_seqno(&fence, i + 1);
 199                dma_fence_put(fence);
 200                if (err) {
 201                        pr_err("Reported %d for find_seqno(%d:%d)!\n",
 202                               err, fc.chain_length + 1, i + 1);
 203                        goto err;
 204                }
 205                if (fence != fc.chains[i]) {
 206                        pr_err("Incorrect fence reported by find_seqno(%d:%d)\n",
 207                               fc.chain_length + 1, i + 1);
 208                        err = -EINVAL;
 209                        goto err;
 210                }
 211
 212                dma_fence_get(fence);
 213                err = dma_fence_chain_find_seqno(&fence, i + 1);
 214                dma_fence_put(fence);
 215                if (err) {
 216                        pr_err("Error reported for finding self\n");
 217                        goto err;
 218                }
 219                if (fence != fc.chains[i]) {
 220                        pr_err("Incorrect fence reported by find self\n");
 221                        err = -EINVAL;
 222                        goto err;
 223                }
 224
 225                dma_fence_get(fence);
 226                err = dma_fence_chain_find_seqno(&fence, i + 2);
 227                dma_fence_put(fence);
 228                if (!err) {
 229                        pr_err("Error not reported for future fence: find_seqno(%d:%d)!\n",
 230                               i + 1, i + 2);
 231                        err = -EINVAL;
 232                        goto err;
 233                }
 234
 235                dma_fence_get(fence);
 236                err = dma_fence_chain_find_seqno(&fence, i);
 237                dma_fence_put(fence);
 238                if (err) {
 239                        pr_err("Error reported for previous fence!\n");
 240                        goto err;
 241                }
 242                if (i > 0 && fence != fc.chains[i - 1]) {
 243                        pr_err("Incorrect fence reported by find_seqno(%d:%d)\n",
 244                               i + 1, i);
 245                        err = -EINVAL;
 246                        goto err;
 247                }
 248        }
 249
 250err:
 251        fence_chains_fini(&fc);
 252        return err;
 253}
 254
 255static int find_signaled(void *arg)
 256{
 257        struct fence_chains fc;
 258        struct dma_fence *fence;
 259        int err;
 260
 261        err = fence_chains_init(&fc, 2, seqno_inc);
 262        if (err)
 263                return err;
 264
 265        dma_fence_signal(fc.fences[0]);
 266
 267        fence = dma_fence_get(fc.tail);
 268        err = dma_fence_chain_find_seqno(&fence, 1);
 269        dma_fence_put(fence);
 270        if (err) {
 271                pr_err("Reported %d for find_seqno()!\n", err);
 272                goto err;
 273        }
 274
 275        if (fence && fence != fc.chains[0]) {
 276                pr_err("Incorrect chain-fence.seqno:%lld reported for completed seqno:1\n",
 277                       fence->seqno);
 278
 279                dma_fence_get(fence);
 280                err = dma_fence_chain_find_seqno(&fence, 1);
 281                dma_fence_put(fence);
 282                if (err)
 283                        pr_err("Reported %d for finding self!\n", err);
 284
 285                err = -EINVAL;
 286        }
 287
 288err:
 289        fence_chains_fini(&fc);
 290        return err;
 291}
 292
 293static int find_out_of_order(void *arg)
 294{
 295        struct fence_chains fc;
 296        struct dma_fence *fence;
 297        int err;
 298
 299        err = fence_chains_init(&fc, 3, seqno_inc);
 300        if (err)
 301                return err;
 302
 303        dma_fence_signal(fc.fences[1]);
 304
 305        fence = dma_fence_get(fc.tail);
 306        err = dma_fence_chain_find_seqno(&fence, 2);
 307        dma_fence_put(fence);
 308        if (err) {
 309                pr_err("Reported %d for find_seqno()!\n", err);
 310                goto err;
 311        }
 312
 313        /*
 314         * We signaled the middle fence (2) of the 1-2-3 chain. The behavior
 315         * of the dma-fence-chain is to make us wait for all the fences up to
 316         * the point we want. Since fence 1 is still not signaled, this what
 317         * we should get as fence to wait upon (fence 2 being garbage
 318         * collected during the traversal of the chain).
 319         */
 320        if (fence != fc.chains[0]) {
 321                pr_err("Incorrect chain-fence.seqno:%lld reported for completed seqno:2\n",
 322                       fence ? fence->seqno : 0);
 323
 324                err = -EINVAL;
 325        }
 326
 327err:
 328        fence_chains_fini(&fc);
 329        return err;
 330}
 331
 332static uint64_t seqno_inc2(unsigned int i)
 333{
 334        return 2 * i + 2;
 335}
 336
 337static int find_gap(void *arg)
 338{
 339        struct fence_chains fc;
 340        struct dma_fence *fence;
 341        int err;
 342        int i;
 343
 344        err = fence_chains_init(&fc, 64, seqno_inc2);
 345        if (err)
 346                return err;
 347
 348        for (i = 0; i < fc.chain_length; i++) {
 349                fence = dma_fence_get(fc.tail);
 350                err = dma_fence_chain_find_seqno(&fence, 2 * i + 1);
 351                dma_fence_put(fence);
 352                if (err) {
 353                        pr_err("Reported %d for find_seqno(%d:%d)!\n",
 354                               err, fc.chain_length + 1, 2 * i + 1);
 355                        goto err;
 356                }
 357                if (fence != fc.chains[i]) {
 358                        pr_err("Incorrect fence.seqno:%lld reported by find_seqno(%d:%d)\n",
 359                               fence->seqno,
 360                               fc.chain_length + 1,
 361                               2 * i + 1);
 362                        err = -EINVAL;
 363                        goto err;
 364                }
 365
 366                dma_fence_get(fence);
 367                err = dma_fence_chain_find_seqno(&fence, 2 * i + 2);
 368                dma_fence_put(fence);
 369                if (err) {
 370                        pr_err("Error reported for finding self\n");
 371                        goto err;
 372                }
 373                if (fence != fc.chains[i]) {
 374                        pr_err("Incorrect fence reported by find self\n");
 375                        err = -EINVAL;
 376                        goto err;
 377                }
 378        }
 379
 380err:
 381        fence_chains_fini(&fc);
 382        return err;
 383}
 384
 385struct find_race {
 386        struct fence_chains fc;
 387        atomic_t children;
 388};
 389
 390static int __find_race(void *arg)
 391{
 392        struct find_race *data = arg;
 393        int err = 0;
 394
 395        while (!kthread_should_stop()) {
 396                struct dma_fence *fence = dma_fence_get(data->fc.tail);
 397                int seqno;
 398
 399                seqno = prandom_u32_max(data->fc.chain_length) + 1;
 400
 401                err = dma_fence_chain_find_seqno(&fence, seqno);
 402                if (err) {
 403                        pr_err("Failed to find fence seqno:%d\n",
 404                               seqno);
 405                        dma_fence_put(fence);
 406                        break;
 407                }
 408                if (!fence)
 409                        goto signal;
 410
 411                /*
 412                 * We can only find ourselves if we are on fence we were
 413                 * looking for.
 414                 */
 415                if (fence->seqno == seqno) {
 416                        err = dma_fence_chain_find_seqno(&fence, seqno);
 417                        if (err) {
 418                                pr_err("Reported an invalid fence for find-self:%d\n",
 419                                       seqno);
 420                                dma_fence_put(fence);
 421                                break;
 422                        }
 423                }
 424
 425                dma_fence_put(fence);
 426
 427signal:
 428                seqno = prandom_u32_max(data->fc.chain_length - 1);
 429                dma_fence_signal(data->fc.fences[seqno]);
 430                cond_resched();
 431        }
 432
 433        if (atomic_dec_and_test(&data->children))
 434                wake_up_var(&data->children);
 435        return err;
 436}
 437
 438static int find_race(void *arg)
 439{
 440        struct find_race data;
 441        int ncpus = num_online_cpus();
 442        struct task_struct **threads;
 443        unsigned long count;
 444        int err;
 445        int i;
 446
 447        err = fence_chains_init(&data.fc, CHAIN_SZ, seqno_inc);
 448        if (err)
 449                return err;
 450
 451        threads = kmalloc_array(ncpus, sizeof(*threads), GFP_KERNEL);
 452        if (!threads) {
 453                err = -ENOMEM;
 454                goto err;
 455        }
 456
 457        atomic_set(&data.children, 0);
 458        for (i = 0; i < ncpus; i++) {
 459                threads[i] = kthread_run(__find_race, &data, "dmabuf/%d", i);
 460                if (IS_ERR(threads[i])) {
 461                        ncpus = i;
 462                        break;
 463                }
 464                atomic_inc(&data.children);
 465                get_task_struct(threads[i]);
 466        }
 467
 468        wait_var_event_timeout(&data.children,
 469                               !atomic_read(&data.children),
 470                               5 * HZ);
 471
 472        for (i = 0; i < ncpus; i++) {
 473                int ret;
 474
 475                ret = kthread_stop(threads[i]);
 476                if (ret && !err)
 477                        err = ret;
 478                put_task_struct(threads[i]);
 479        }
 480        kfree(threads);
 481
 482        count = 0;
 483        for (i = 0; i < data.fc.chain_length; i++)
 484                if (dma_fence_is_signaled(data.fc.fences[i]))
 485                        count++;
 486        pr_info("Completed %lu cycles\n", count);
 487
 488err:
 489        fence_chains_fini(&data.fc);
 490        return err;
 491}
 492
 493static int signal_forward(void *arg)
 494{
 495        struct fence_chains fc;
 496        int err;
 497        int i;
 498
 499        err = fence_chains_init(&fc, 64, seqno_inc);
 500        if (err)
 501                return err;
 502
 503        for (i = 0; i < fc.chain_length; i++) {
 504                dma_fence_signal(fc.fences[i]);
 505
 506                if (!dma_fence_is_signaled(fc.chains[i])) {
 507                        pr_err("chain[%d] not signaled!\n", i);
 508                        err = -EINVAL;
 509                        goto err;
 510                }
 511
 512                if (i + 1 < fc.chain_length &&
 513                    dma_fence_is_signaled(fc.chains[i + 1])) {
 514                        pr_err("chain[%d] is signaled!\n", i);
 515                        err = -EINVAL;
 516                        goto err;
 517                }
 518        }
 519
 520err:
 521        fence_chains_fini(&fc);
 522        return err;
 523}
 524
 525static int signal_backward(void *arg)
 526{
 527        struct fence_chains fc;
 528        int err;
 529        int i;
 530
 531        err = fence_chains_init(&fc, 64, seqno_inc);
 532        if (err)
 533                return err;
 534
 535        for (i = fc.chain_length; i--; ) {
 536                dma_fence_signal(fc.fences[i]);
 537
 538                if (i > 0 && dma_fence_is_signaled(fc.chains[i])) {
 539                        pr_err("chain[%d] is signaled!\n", i);
 540                        err = -EINVAL;
 541                        goto err;
 542                }
 543        }
 544
 545        for (i = 0; i < fc.chain_length; i++) {
 546                if (!dma_fence_is_signaled(fc.chains[i])) {
 547                        pr_err("chain[%d] was not signaled!\n", i);
 548                        err = -EINVAL;
 549                        goto err;
 550                }
 551        }
 552
 553err:
 554        fence_chains_fini(&fc);
 555        return err;
 556}
 557
 558static int __wait_fence_chains(void *arg)
 559{
 560        struct fence_chains *fc = arg;
 561
 562        if (dma_fence_wait(fc->tail, false))
 563                return -EIO;
 564
 565        return 0;
 566}
 567
 568static int wait_forward(void *arg)
 569{
 570        struct fence_chains fc;
 571        struct task_struct *tsk;
 572        int err;
 573        int i;
 574
 575        err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
 576        if (err)
 577                return err;
 578
 579        tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
 580        if (IS_ERR(tsk)) {
 581                err = PTR_ERR(tsk);
 582                goto err;
 583        }
 584        get_task_struct(tsk);
 585        yield_to(tsk, true);
 586
 587        for (i = 0; i < fc.chain_length; i++)
 588                dma_fence_signal(fc.fences[i]);
 589
 590        err = kthread_stop(tsk);
 591        put_task_struct(tsk);
 592
 593err:
 594        fence_chains_fini(&fc);
 595        return err;
 596}
 597
 598static int wait_backward(void *arg)
 599{
 600        struct fence_chains fc;
 601        struct task_struct *tsk;
 602        int err;
 603        int i;
 604
 605        err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
 606        if (err)
 607                return err;
 608
 609        tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
 610        if (IS_ERR(tsk)) {
 611                err = PTR_ERR(tsk);
 612                goto err;
 613        }
 614        get_task_struct(tsk);
 615        yield_to(tsk, true);
 616
 617        for (i = fc.chain_length; i--; )
 618                dma_fence_signal(fc.fences[i]);
 619
 620        err = kthread_stop(tsk);
 621        put_task_struct(tsk);
 622
 623err:
 624        fence_chains_fini(&fc);
 625        return err;
 626}
 627
 628static void randomise_fences(struct fence_chains *fc)
 629{
 630        unsigned int count = fc->chain_length;
 631
 632        /* Fisher-Yates shuffle courtesy of Knuth */
 633        while (--count) {
 634                unsigned int swp;
 635
 636                swp = prandom_u32_max(count + 1);
 637                if (swp == count)
 638                        continue;
 639
 640                swap(fc->fences[count], fc->fences[swp]);
 641        }
 642}
 643
 644static int wait_random(void *arg)
 645{
 646        struct fence_chains fc;
 647        struct task_struct *tsk;
 648        int err;
 649        int i;
 650
 651        err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
 652        if (err)
 653                return err;
 654
 655        randomise_fences(&fc);
 656
 657        tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
 658        if (IS_ERR(tsk)) {
 659                err = PTR_ERR(tsk);
 660                goto err;
 661        }
 662        get_task_struct(tsk);
 663        yield_to(tsk, true);
 664
 665        for (i = 0; i < fc.chain_length; i++)
 666                dma_fence_signal(fc.fences[i]);
 667
 668        err = kthread_stop(tsk);
 669        put_task_struct(tsk);
 670
 671err:
 672        fence_chains_fini(&fc);
 673        return err;
 674}
 675
 676int dma_fence_chain(void)
 677{
 678        static const struct subtest tests[] = {
 679                SUBTEST(sanitycheck),
 680                SUBTEST(find_seqno),
 681                SUBTEST(find_signaled),
 682                SUBTEST(find_out_of_order),
 683                SUBTEST(find_gap),
 684                SUBTEST(find_race),
 685                SUBTEST(signal_forward),
 686                SUBTEST(signal_backward),
 687                SUBTEST(wait_forward),
 688                SUBTEST(wait_backward),
 689                SUBTEST(wait_random),
 690        };
 691        int ret;
 692
 693        pr_info("sizeof(dma_fence_chain)=%zu\n",
 694                sizeof(struct dma_fence_chain));
 695
 696        slab_fences = KMEM_CACHE(mock_fence,
 697                                 SLAB_TYPESAFE_BY_RCU |
 698                                 SLAB_HWCACHE_ALIGN);
 699        if (!slab_fences)
 700                return -ENOMEM;
 701
 702        ret = subtests(tests, NULL);
 703
 704        kmem_cache_destroy(slab_fences);
 705        return ret;
 706}
 707