root/drivers/dma-buf/dma-resv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dma_resv_list_alloc
  2. dma_resv_list_free
  3. dma_resv_init
  4. dma_resv_fini
  5. dma_resv_reserve_shared
  6. dma_resv_add_shared_fence
  7. dma_resv_add_excl_fence
  8. dma_resv_copy_fences
  9. dma_resv_get_fences_rcu
  10. dma_resv_wait_timeout_rcu
  11. dma_resv_test_signaled_single
  12. dma_resv_test_signaled_rcu

   1 /*
   2  * Copyright (C) 2012-2014 Canonical Ltd (Maarten Lankhorst)
   3  *
   4  * Based on bo.c which bears the following copyright notice,
   5  * but is dual licensed:
   6  *
   7  * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
   8  * All Rights Reserved.
   9  *
  10  * Permission is hereby granted, free of charge, to any person obtaining a
  11  * copy of this software and associated documentation files (the
  12  * "Software"), to deal in the Software without restriction, including
  13  * without limitation the rights to use, copy, modify, merge, publish,
  14  * distribute, sub license, and/or sell copies of the Software, and to
  15  * permit persons to whom the Software is furnished to do so, subject to
  16  * the following conditions:
  17  *
  18  * The above copyright notice and this permission notice (including the
  19  * next paragraph) shall be included in all copies or substantial portions
  20  * of the Software.
  21  *
  22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  25  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  26  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  27  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  28  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  29  *
  30  **************************************************************************/
  31 /*
  32  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
  33  */
  34 
  35 #include <linux/dma-resv.h>
  36 #include <linux/export.h>
  37 
  38 /**
  39  * DOC: Reservation Object Overview
  40  *
  41  * The reservation object provides a mechanism to manage shared and
  42  * exclusive fences associated with a buffer.  A reservation object
  43  * can have attached one exclusive fence (normally associated with
  44  * write operations) or N shared fences (read operations).  The RCU
  45  * mechanism is used to protect read access to fences from locked
  46  * write-side updates.
  47  */
  48 
  49 DEFINE_WD_CLASS(reservation_ww_class);
  50 EXPORT_SYMBOL(reservation_ww_class);
  51 
  52 struct lock_class_key reservation_seqcount_class;
  53 EXPORT_SYMBOL(reservation_seqcount_class);
  54 
  55 const char reservation_seqcount_string[] = "reservation_seqcount";
  56 EXPORT_SYMBOL(reservation_seqcount_string);
  57 
  58 /**
  59  * dma_resv_list_alloc - allocate fence list
  60  * @shared_max: number of fences we need space for
  61  *
  62  * Allocate a new dma_resv_list and make sure to correctly initialize
  63  * shared_max.
  64  */
  65 static struct dma_resv_list *dma_resv_list_alloc(unsigned int shared_max)
  66 {
  67         struct dma_resv_list *list;
  68 
  69         list = kmalloc(offsetof(typeof(*list), shared[shared_max]), GFP_KERNEL);
  70         if (!list)
  71                 return NULL;
  72 
  73         list->shared_max = (ksize(list) - offsetof(typeof(*list), shared)) /
  74                 sizeof(*list->shared);
  75 
  76         return list;
  77 }
  78 
  79 /**
  80  * dma_resv_list_free - free fence list
  81  * @list: list to free
  82  *
  83  * Free a dma_resv_list and make sure to drop all references.
  84  */
  85 static void dma_resv_list_free(struct dma_resv_list *list)
  86 {
  87         unsigned int i;
  88 
  89         if (!list)
  90                 return;
  91 
  92         for (i = 0; i < list->shared_count; ++i)
  93                 dma_fence_put(rcu_dereference_protected(list->shared[i], true));
  94 
  95         kfree_rcu(list, rcu);
  96 }
  97 
  98 /**
  99  * dma_resv_init - initialize a reservation object
 100  * @obj: the reservation object
 101  */
 102 void dma_resv_init(struct dma_resv *obj)
 103 {
 104         ww_mutex_init(&obj->lock, &reservation_ww_class);
 105 
 106         __seqcount_init(&obj->seq, reservation_seqcount_string,
 107                         &reservation_seqcount_class);
 108         RCU_INIT_POINTER(obj->fence, NULL);
 109         RCU_INIT_POINTER(obj->fence_excl, NULL);
 110 }
 111 EXPORT_SYMBOL(dma_resv_init);
 112 
 113 /**
 114  * dma_resv_fini - destroys a reservation object
 115  * @obj: the reservation object
 116  */
 117 void dma_resv_fini(struct dma_resv *obj)
 118 {
 119         struct dma_resv_list *fobj;
 120         struct dma_fence *excl;
 121 
 122         /*
 123          * This object should be dead and all references must have
 124          * been released to it, so no need to be protected with rcu.
 125          */
 126         excl = rcu_dereference_protected(obj->fence_excl, 1);
 127         if (excl)
 128                 dma_fence_put(excl);
 129 
 130         fobj = rcu_dereference_protected(obj->fence, 1);
 131         dma_resv_list_free(fobj);
 132         ww_mutex_destroy(&obj->lock);
 133 }
 134 EXPORT_SYMBOL(dma_resv_fini);
 135 
 136 /**
 137  * dma_resv_reserve_shared - Reserve space to add shared fences to
 138  * a dma_resv.
 139  * @obj: reservation object
 140  * @num_fences: number of fences we want to add
 141  *
 142  * Should be called before dma_resv_add_shared_fence().  Must
 143  * be called with obj->lock held.
 144  *
 145  * RETURNS
 146  * Zero for success, or -errno
 147  */
 148 int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
 149 {
 150         struct dma_resv_list *old, *new;
 151         unsigned int i, j, k, max;
 152 
 153         dma_resv_assert_held(obj);
 154 
 155         old = dma_resv_get_list(obj);
 156 
 157         if (old && old->shared_max) {
 158                 if ((old->shared_count + num_fences) <= old->shared_max)
 159                         return 0;
 160                 else
 161                         max = max(old->shared_count + num_fences,
 162                                   old->shared_max * 2);
 163         } else {
 164                 max = 4;
 165         }
 166 
 167         new = dma_resv_list_alloc(max);
 168         if (!new)
 169                 return -ENOMEM;
 170 
 171         /*
 172          * no need to bump fence refcounts, rcu_read access
 173          * requires the use of kref_get_unless_zero, and the
 174          * references from the old struct are carried over to
 175          * the new.
 176          */
 177         for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) {
 178                 struct dma_fence *fence;
 179 
 180                 fence = rcu_dereference_protected(old->shared[i],
 181                                                   dma_resv_held(obj));
 182                 if (dma_fence_is_signaled(fence))
 183                         RCU_INIT_POINTER(new->shared[--k], fence);
 184                 else
 185                         RCU_INIT_POINTER(new->shared[j++], fence);
 186         }
 187         new->shared_count = j;
 188 
 189         /*
 190          * We are not changing the effective set of fences here so can
 191          * merely update the pointer to the new array; both existing
 192          * readers and new readers will see exactly the same set of
 193          * active (unsignaled) shared fences. Individual fences and the
 194          * old array are protected by RCU and so will not vanish under
 195          * the gaze of the rcu_read_lock() readers.
 196          */
 197         rcu_assign_pointer(obj->fence, new);
 198 
 199         if (!old)
 200                 return 0;
 201 
 202         /* Drop the references to the signaled fences */
 203         for (i = k; i < max; ++i) {
 204                 struct dma_fence *fence;
 205 
 206                 fence = rcu_dereference_protected(new->shared[i],
 207                                                   dma_resv_held(obj));
 208                 dma_fence_put(fence);
 209         }
 210         kfree_rcu(old, rcu);
 211 
 212         return 0;
 213 }
 214 EXPORT_SYMBOL(dma_resv_reserve_shared);
 215 
 216 /**
 217  * dma_resv_add_shared_fence - Add a fence to a shared slot
 218  * @obj: the reservation object
 219  * @fence: the shared fence to add
 220  *
 221  * Add a fence to a shared slot, obj->lock must be held, and
 222  * dma_resv_reserve_shared() has been called.
 223  */
 224 void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
 225 {
 226         struct dma_resv_list *fobj;
 227         struct dma_fence *old;
 228         unsigned int i, count;
 229 
 230         dma_fence_get(fence);
 231 
 232         dma_resv_assert_held(obj);
 233 
 234         fobj = dma_resv_get_list(obj);
 235         count = fobj->shared_count;
 236 
 237         preempt_disable();
 238         write_seqcount_begin(&obj->seq);
 239 
 240         for (i = 0; i < count; ++i) {
 241 
 242                 old = rcu_dereference_protected(fobj->shared[i],
 243                                                 dma_resv_held(obj));
 244                 if (old->context == fence->context ||
 245                     dma_fence_is_signaled(old))
 246                         goto replace;
 247         }
 248 
 249         BUG_ON(fobj->shared_count >= fobj->shared_max);
 250         old = NULL;
 251         count++;
 252 
 253 replace:
 254         RCU_INIT_POINTER(fobj->shared[i], fence);
 255         /* pointer update must be visible before we extend the shared_count */
 256         smp_store_mb(fobj->shared_count, count);
 257 
 258         write_seqcount_end(&obj->seq);
 259         preempt_enable();
 260         dma_fence_put(old);
 261 }
 262 EXPORT_SYMBOL(dma_resv_add_shared_fence);
 263 
 264 /**
 265  * dma_resv_add_excl_fence - Add an exclusive fence.
 266  * @obj: the reservation object
 267  * @fence: the shared fence to add
 268  *
 269  * Add a fence to the exclusive slot.  The obj->lock must be held.
 270  */
 271 void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
 272 {
 273         struct dma_fence *old_fence = dma_resv_get_excl(obj);
 274         struct dma_resv_list *old;
 275         u32 i = 0;
 276 
 277         dma_resv_assert_held(obj);
 278 
 279         old = dma_resv_get_list(obj);
 280         if (old)
 281                 i = old->shared_count;
 282 
 283         if (fence)
 284                 dma_fence_get(fence);
 285 
 286         preempt_disable();
 287         write_seqcount_begin(&obj->seq);
 288         /* write_seqcount_begin provides the necessary memory barrier */
 289         RCU_INIT_POINTER(obj->fence_excl, fence);
 290         if (old)
 291                 old->shared_count = 0;
 292         write_seqcount_end(&obj->seq);
 293         preempt_enable();
 294 
 295         /* inplace update, no shared fences */
 296         while (i--)
 297                 dma_fence_put(rcu_dereference_protected(old->shared[i],
 298                                                 dma_resv_held(obj)));
 299 
 300         dma_fence_put(old_fence);
 301 }
 302 EXPORT_SYMBOL(dma_resv_add_excl_fence);
 303 
 304 /**
 305 * dma_resv_copy_fences - Copy all fences from src to dst.
 306 * @dst: the destination reservation object
 307 * @src: the source reservation object
 308 *
 309 * Copy all fences from src to dst. dst-lock must be held.
 310 */
 311 int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
 312 {
 313         struct dma_resv_list *src_list, *dst_list;
 314         struct dma_fence *old, *new;
 315         unsigned i;
 316 
 317         dma_resv_assert_held(dst);
 318 
 319         rcu_read_lock();
 320         src_list = rcu_dereference(src->fence);
 321 
 322 retry:
 323         if (src_list) {
 324                 unsigned shared_count = src_list->shared_count;
 325 
 326                 rcu_read_unlock();
 327 
 328                 dst_list = dma_resv_list_alloc(shared_count);
 329                 if (!dst_list)
 330                         return -ENOMEM;
 331 
 332                 rcu_read_lock();
 333                 src_list = rcu_dereference(src->fence);
 334                 if (!src_list || src_list->shared_count > shared_count) {
 335                         kfree(dst_list);
 336                         goto retry;
 337                 }
 338 
 339                 dst_list->shared_count = 0;
 340                 for (i = 0; i < src_list->shared_count; ++i) {
 341                         struct dma_fence *fence;
 342 
 343                         fence = rcu_dereference(src_list->shared[i]);
 344                         if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
 345                                      &fence->flags))
 346                                 continue;
 347 
 348                         if (!dma_fence_get_rcu(fence)) {
 349                                 dma_resv_list_free(dst_list);
 350                                 src_list = rcu_dereference(src->fence);
 351                                 goto retry;
 352                         }
 353 
 354                         if (dma_fence_is_signaled(fence)) {
 355                                 dma_fence_put(fence);
 356                                 continue;
 357                         }
 358 
 359                         rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], fence);
 360                 }
 361         } else {
 362                 dst_list = NULL;
 363         }
 364 
 365         new = dma_fence_get_rcu_safe(&src->fence_excl);
 366         rcu_read_unlock();
 367 
 368         src_list = dma_resv_get_list(dst);
 369         old = dma_resv_get_excl(dst);
 370 
 371         preempt_disable();
 372         write_seqcount_begin(&dst->seq);
 373         /* write_seqcount_begin provides the necessary memory barrier */
 374         RCU_INIT_POINTER(dst->fence_excl, new);
 375         RCU_INIT_POINTER(dst->fence, dst_list);
 376         write_seqcount_end(&dst->seq);
 377         preempt_enable();
 378 
 379         dma_resv_list_free(src_list);
 380         dma_fence_put(old);
 381 
 382         return 0;
 383 }
 384 EXPORT_SYMBOL(dma_resv_copy_fences);
 385 
 386 /**
 387  * dma_resv_get_fences_rcu - Get an object's shared and exclusive
 388  * fences without update side lock held
 389  * @obj: the reservation object
 390  * @pfence_excl: the returned exclusive fence (or NULL)
 391  * @pshared_count: the number of shared fences returned
 392  * @pshared: the array of shared fence ptrs returned (array is krealloc'd to
 393  * the required size, and must be freed by caller)
 394  *
 395  * Retrieve all fences from the reservation object. If the pointer for the
 396  * exclusive fence is not specified the fence is put into the array of the
 397  * shared fences as well. Returns either zero or -ENOMEM.
 398  */
 399 int dma_resv_get_fences_rcu(struct dma_resv *obj,
 400                             struct dma_fence **pfence_excl,
 401                             unsigned *pshared_count,
 402                             struct dma_fence ***pshared)
 403 {
 404         struct dma_fence **shared = NULL;
 405         struct dma_fence *fence_excl;
 406         unsigned int shared_count;
 407         int ret = 1;
 408 
 409         do {
 410                 struct dma_resv_list *fobj;
 411                 unsigned int i, seq;
 412                 size_t sz = 0;
 413 
 414                 shared_count = i = 0;
 415 
 416                 rcu_read_lock();
 417                 seq = read_seqcount_begin(&obj->seq);
 418 
 419                 fence_excl = rcu_dereference(obj->fence_excl);
 420                 if (fence_excl && !dma_fence_get_rcu(fence_excl))
 421                         goto unlock;
 422 
 423                 fobj = rcu_dereference(obj->fence);
 424                 if (fobj)
 425                         sz += sizeof(*shared) * fobj->shared_max;
 426 
 427                 if (!pfence_excl && fence_excl)
 428                         sz += sizeof(*shared);
 429 
 430                 if (sz) {
 431                         struct dma_fence **nshared;
 432 
 433                         nshared = krealloc(shared, sz,
 434                                            GFP_NOWAIT | __GFP_NOWARN);
 435                         if (!nshared) {
 436                                 rcu_read_unlock();
 437 
 438                                 dma_fence_put(fence_excl);
 439                                 fence_excl = NULL;
 440 
 441                                 nshared = krealloc(shared, sz, GFP_KERNEL);
 442                                 if (nshared) {
 443                                         shared = nshared;
 444                                         continue;
 445                                 }
 446 
 447                                 ret = -ENOMEM;
 448                                 break;
 449                         }
 450                         shared = nshared;
 451                         shared_count = fobj ? fobj->shared_count : 0;
 452                         for (i = 0; i < shared_count; ++i) {
 453                                 shared[i] = rcu_dereference(fobj->shared[i]);
 454                                 if (!dma_fence_get_rcu(shared[i]))
 455                                         break;
 456                         }
 457                 }
 458 
 459                 if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
 460                         while (i--)
 461                                 dma_fence_put(shared[i]);
 462                         dma_fence_put(fence_excl);
 463                         goto unlock;
 464                 }
 465 
 466                 ret = 0;
 467 unlock:
 468                 rcu_read_unlock();
 469         } while (ret);
 470 
 471         if (pfence_excl)
 472                 *pfence_excl = fence_excl;
 473         else if (fence_excl)
 474                 shared[shared_count++] = fence_excl;
 475 
 476         if (!shared_count) {
 477                 kfree(shared);
 478                 shared = NULL;
 479         }
 480 
 481         *pshared_count = shared_count;
 482         *pshared = shared;
 483         return ret;
 484 }
 485 EXPORT_SYMBOL_GPL(dma_resv_get_fences_rcu);
 486 
 487 /**
 488  * dma_resv_wait_timeout_rcu - Wait on reservation's objects
 489  * shared and/or exclusive fences.
 490  * @obj: the reservation object
 491  * @wait_all: if true, wait on all fences, else wait on just exclusive fence
 492  * @intr: if true, do interruptible wait
 493  * @timeout: timeout value in jiffies or zero to return immediately
 494  *
 495  * RETURNS
 496  * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
 497  * greater than zer on success.
 498  */
 499 long dma_resv_wait_timeout_rcu(struct dma_resv *obj,
 500                                bool wait_all, bool intr,
 501                                unsigned long timeout)
 502 {
 503         struct dma_fence *fence;
 504         unsigned seq, shared_count;
 505         long ret = timeout ? timeout : 1;
 506         int i;
 507 
 508 retry:
 509         shared_count = 0;
 510         seq = read_seqcount_begin(&obj->seq);
 511         rcu_read_lock();
 512         i = -1;
 513 
 514         fence = rcu_dereference(obj->fence_excl);
 515         if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
 516                 if (!dma_fence_get_rcu(fence))
 517                         goto unlock_retry;
 518 
 519                 if (dma_fence_is_signaled(fence)) {
 520                         dma_fence_put(fence);
 521                         fence = NULL;
 522                 }
 523 
 524         } else {
 525                 fence = NULL;
 526         }
 527 
 528         if (wait_all) {
 529                 struct dma_resv_list *fobj = rcu_dereference(obj->fence);
 530 
 531                 if (fobj)
 532                         shared_count = fobj->shared_count;
 533 
 534                 for (i = 0; !fence && i < shared_count; ++i) {
 535                         struct dma_fence *lfence = rcu_dereference(fobj->shared[i]);
 536 
 537                         if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
 538                                      &lfence->flags))
 539                                 continue;
 540 
 541                         if (!dma_fence_get_rcu(lfence))
 542                                 goto unlock_retry;
 543 
 544                         if (dma_fence_is_signaled(lfence)) {
 545                                 dma_fence_put(lfence);
 546                                 continue;
 547                         }
 548 
 549                         fence = lfence;
 550                         break;
 551                 }
 552         }
 553 
 554         rcu_read_unlock();
 555         if (fence) {
 556                 if (read_seqcount_retry(&obj->seq, seq)) {
 557                         dma_fence_put(fence);
 558                         goto retry;
 559                 }
 560 
 561                 ret = dma_fence_wait_timeout(fence, intr, ret);
 562                 dma_fence_put(fence);
 563                 if (ret > 0 && wait_all && (i + 1 < shared_count))
 564                         goto retry;
 565         }
 566         return ret;
 567 
 568 unlock_retry:
 569         rcu_read_unlock();
 570         goto retry;
 571 }
 572 EXPORT_SYMBOL_GPL(dma_resv_wait_timeout_rcu);
 573 
 574 
 575 static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence)
 576 {
 577         struct dma_fence *fence, *lfence = passed_fence;
 578         int ret = 1;
 579 
 580         if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) {
 581                 fence = dma_fence_get_rcu(lfence);
 582                 if (!fence)
 583                         return -1;
 584 
 585                 ret = !!dma_fence_is_signaled(fence);
 586                 dma_fence_put(fence);
 587         }
 588         return ret;
 589 }
 590 
 591 /**
 592  * dma_resv_test_signaled_rcu - Test if a reservation object's
 593  * fences have been signaled.
 594  * @obj: the reservation object
 595  * @test_all: if true, test all fences, otherwise only test the exclusive
 596  * fence
 597  *
 598  * RETURNS
 599  * true if all fences signaled, else false
 600  */
 601 bool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool test_all)
 602 {
 603         unsigned seq, shared_count;
 604         int ret;
 605 
 606         rcu_read_lock();
 607 retry:
 608         ret = true;
 609         shared_count = 0;
 610         seq = read_seqcount_begin(&obj->seq);
 611 
 612         if (test_all) {
 613                 unsigned i;
 614 
 615                 struct dma_resv_list *fobj = rcu_dereference(obj->fence);
 616 
 617                 if (fobj)
 618                         shared_count = fobj->shared_count;
 619 
 620                 for (i = 0; i < shared_count; ++i) {
 621                         struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
 622 
 623                         ret = dma_resv_test_signaled_single(fence);
 624                         if (ret < 0)
 625                                 goto retry;
 626                         else if (!ret)
 627                                 break;
 628                 }
 629 
 630                 if (read_seqcount_retry(&obj->seq, seq))
 631                         goto retry;
 632         }
 633 
 634         if (!shared_count) {
 635                 struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl);
 636 
 637                 if (fence_excl) {
 638                         ret = dma_resv_test_signaled_single(fence_excl);
 639                         if (ret < 0)
 640                                 goto retry;
 641 
 642                         if (read_seqcount_retry(&obj->seq, seq))
 643                                 goto retry;
 644                 }
 645         }
 646 
 647         rcu_read_unlock();
 648         return ret;
 649 }
 650 EXPORT_SYMBOL_GPL(dma_resv_test_signaled_rcu);

/* [<][>][^][v][top][bottom][index][help] */