root/drivers/net/ethernet/mellanox/mlx4/alloc.c

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

DEFINITIONS

This source file includes following definitions.
  1. mlx4_bitmap_alloc
  2. mlx4_bitmap_free
  3. find_aligned_range
  4. mlx4_bitmap_alloc_range
  5. mlx4_bitmap_avail
  6. mlx4_bitmap_masked_value
  7. mlx4_bitmap_free_range
  8. mlx4_bitmap_init
  9. mlx4_bitmap_cleanup
  10. mlx4_zone_allocator_create
  11. mlx4_zone_add_one
  12. __mlx4_zone_remove_one_entry
  13. mlx4_zone_allocator_destroy
  14. __mlx4_alloc_from_zone
  15. __mlx4_free_from_zone
  16. __mlx4_find_zone_by_uid
  17. mlx4_zone_get_bitmap
  18. mlx4_zone_remove_one
  19. __mlx4_find_zone_by_uid_unique
  20. mlx4_zone_alloc_entries
  21. mlx4_zone_free_entries
  22. mlx4_zone_free_entries_unique
  23. mlx4_buf_direct_alloc
  24. mlx4_buf_alloc
  25. mlx4_buf_free
  26. mlx4_alloc_db_pgdir
  27. mlx4_alloc_db_from_pgdir
  28. mlx4_db_alloc
  29. mlx4_db_free
  30. mlx4_alloc_hwq_res
  31. mlx4_free_hwq_res

   1 /*
   2  * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
   3  * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
   4  *
   5  * This software is available to you under a choice of one of two
   6  * licenses.  You may choose to be licensed under the terms of the GNU
   7  * General Public License (GPL) Version 2, available from the file
   8  * COPYING in the main directory of this source tree, or the
   9  * OpenIB.org BSD license below:
  10  *
  11  *     Redistribution and use in source and binary forms, with or
  12  *     without modification, are permitted provided that the following
  13  *     conditions are met:
  14  *
  15  *      - Redistributions of source code must retain the above
  16  *        copyright notice, this list of conditions and the following
  17  *        disclaimer.
  18  *
  19  *      - Redistributions in binary form must reproduce the above
  20  *        copyright notice, this list of conditions and the following
  21  *        disclaimer in the documentation and/or other materials
  22  *        provided with the distribution.
  23  *
  24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  31  * SOFTWARE.
  32  */
  33 
  34 #include <linux/errno.h>
  35 #include <linux/slab.h>
  36 #include <linux/mm.h>
  37 #include <linux/export.h>
  38 #include <linux/bitmap.h>
  39 #include <linux/dma-mapping.h>
  40 #include <linux/vmalloc.h>
  41 
  42 #include "mlx4.h"
  43 
  44 u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap)
  45 {
  46         u32 obj;
  47 
  48         spin_lock(&bitmap->lock);
  49 
  50         obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last);
  51         if (obj >= bitmap->max) {
  52                 bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
  53                                 & bitmap->mask;
  54                 obj = find_first_zero_bit(bitmap->table, bitmap->max);
  55         }
  56 
  57         if (obj < bitmap->max) {
  58                 set_bit(obj, bitmap->table);
  59                 bitmap->last = (obj + 1);
  60                 if (bitmap->last == bitmap->max)
  61                         bitmap->last = 0;
  62                 obj |= bitmap->top;
  63         } else
  64                 obj = -1;
  65 
  66         if (obj != -1)
  67                 --bitmap->avail;
  68 
  69         spin_unlock(&bitmap->lock);
  70 
  71         return obj;
  72 }
  73 
  74 void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj, int use_rr)
  75 {
  76         mlx4_bitmap_free_range(bitmap, obj, 1, use_rr);
  77 }
  78 
  79 static unsigned long find_aligned_range(unsigned long *bitmap,
  80                                         u32 start, u32 nbits,
  81                                         int len, int align, u32 skip_mask)
  82 {
  83         unsigned long end, i;
  84 
  85 again:
  86         start = ALIGN(start, align);
  87 
  88         while ((start < nbits) && (test_bit(start, bitmap) ||
  89                                    (start & skip_mask)))
  90                 start += align;
  91 
  92         if (start >= nbits)
  93                 return -1;
  94 
  95         end = start+len;
  96         if (end > nbits)
  97                 return -1;
  98 
  99         for (i = start + 1; i < end; i++) {
 100                 if (test_bit(i, bitmap) || ((u32)i & skip_mask)) {
 101                         start = i + 1;
 102                         goto again;
 103                 }
 104         }
 105 
 106         return start;
 107 }
 108 
 109 u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt,
 110                             int align, u32 skip_mask)
 111 {
 112         u32 obj;
 113 
 114         if (likely(cnt == 1 && align == 1 && !skip_mask))
 115                 return mlx4_bitmap_alloc(bitmap);
 116 
 117         spin_lock(&bitmap->lock);
 118 
 119         obj = find_aligned_range(bitmap->table, bitmap->last,
 120                                  bitmap->max, cnt, align, skip_mask);
 121         if (obj >= bitmap->max) {
 122                 bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
 123                                 & bitmap->mask;
 124                 obj = find_aligned_range(bitmap->table, 0, bitmap->max,
 125                                          cnt, align, skip_mask);
 126         }
 127 
 128         if (obj < bitmap->max) {
 129                 bitmap_set(bitmap->table, obj, cnt);
 130                 if (obj == bitmap->last) {
 131                         bitmap->last = (obj + cnt);
 132                         if (bitmap->last >= bitmap->max)
 133                                 bitmap->last = 0;
 134                 }
 135                 obj |= bitmap->top;
 136         } else
 137                 obj = -1;
 138 
 139         if (obj != -1)
 140                 bitmap->avail -= cnt;
 141 
 142         spin_unlock(&bitmap->lock);
 143 
 144         return obj;
 145 }
 146 
 147 u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap)
 148 {
 149         return bitmap->avail;
 150 }
 151 
 152 static u32 mlx4_bitmap_masked_value(struct mlx4_bitmap *bitmap, u32 obj)
 153 {
 154         return obj & (bitmap->max + bitmap->reserved_top - 1);
 155 }
 156 
 157 void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt,
 158                             int use_rr)
 159 {
 160         obj &= bitmap->max + bitmap->reserved_top - 1;
 161 
 162         spin_lock(&bitmap->lock);
 163         if (!use_rr) {
 164                 bitmap->last = min(bitmap->last, obj);
 165                 bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
 166                                 & bitmap->mask;
 167         }
 168         bitmap_clear(bitmap->table, obj, cnt);
 169         bitmap->avail += cnt;
 170         spin_unlock(&bitmap->lock);
 171 }
 172 
 173 int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
 174                      u32 reserved_bot, u32 reserved_top)
 175 {
 176         /* num must be a power of 2 */
 177         if (num != roundup_pow_of_two(num))
 178                 return -EINVAL;
 179 
 180         bitmap->last = 0;
 181         bitmap->top  = 0;
 182         bitmap->max  = num - reserved_top;
 183         bitmap->mask = mask;
 184         bitmap->reserved_top = reserved_top;
 185         bitmap->avail = num - reserved_top - reserved_bot;
 186         bitmap->effective_len = bitmap->avail;
 187         spin_lock_init(&bitmap->lock);
 188         bitmap->table = bitmap_zalloc(bitmap->max, GFP_KERNEL);
 189         if (!bitmap->table)
 190                 return -ENOMEM;
 191 
 192         bitmap_set(bitmap->table, 0, reserved_bot);
 193 
 194         return 0;
 195 }
 196 
 197 void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap)
 198 {
 199         bitmap_free(bitmap->table);
 200 }
 201 
 202 struct mlx4_zone_allocator {
 203         struct list_head                entries;
 204         struct list_head                prios;
 205         u32                             last_uid;
 206         u32                             mask;
 207         /* protect the zone_allocator from concurrent accesses */
 208         spinlock_t                      lock;
 209         enum mlx4_zone_alloc_flags      flags;
 210 };
 211 
 212 struct mlx4_zone_entry {
 213         struct list_head                list;
 214         struct list_head                prio_list;
 215         u32                             uid;
 216         struct mlx4_zone_allocator      *allocator;
 217         struct mlx4_bitmap              *bitmap;
 218         int                             use_rr;
 219         int                             priority;
 220         int                             offset;
 221         enum mlx4_zone_flags            flags;
 222 };
 223 
 224 struct mlx4_zone_allocator *mlx4_zone_allocator_create(enum mlx4_zone_alloc_flags flags)
 225 {
 226         struct mlx4_zone_allocator *zones = kmalloc(sizeof(*zones), GFP_KERNEL);
 227 
 228         if (NULL == zones)
 229                 return NULL;
 230 
 231         INIT_LIST_HEAD(&zones->entries);
 232         INIT_LIST_HEAD(&zones->prios);
 233         spin_lock_init(&zones->lock);
 234         zones->last_uid = 0;
 235         zones->mask = 0;
 236         zones->flags = flags;
 237 
 238         return zones;
 239 }
 240 
 241 int mlx4_zone_add_one(struct mlx4_zone_allocator *zone_alloc,
 242                       struct mlx4_bitmap *bitmap,
 243                       u32 flags,
 244                       int priority,
 245                       int offset,
 246                       u32 *puid)
 247 {
 248         u32 mask = mlx4_bitmap_masked_value(bitmap, (u32)-1);
 249         struct mlx4_zone_entry *it;
 250         struct mlx4_zone_entry *zone = kmalloc(sizeof(*zone), GFP_KERNEL);
 251 
 252         if (NULL == zone)
 253                 return -ENOMEM;
 254 
 255         zone->flags = flags;
 256         zone->bitmap = bitmap;
 257         zone->use_rr = (flags & MLX4_ZONE_USE_RR) ? MLX4_USE_RR : 0;
 258         zone->priority = priority;
 259         zone->offset = offset;
 260 
 261         spin_lock(&zone_alloc->lock);
 262 
 263         zone->uid = zone_alloc->last_uid++;
 264         zone->allocator = zone_alloc;
 265 
 266         if (zone_alloc->mask < mask)
 267                 zone_alloc->mask = mask;
 268 
 269         list_for_each_entry(it, &zone_alloc->prios, prio_list)
 270                 if (it->priority >= priority)
 271                         break;
 272 
 273         if (&it->prio_list == &zone_alloc->prios || it->priority > priority)
 274                 list_add_tail(&zone->prio_list, &it->prio_list);
 275         list_add_tail(&zone->list, &it->list);
 276 
 277         spin_unlock(&zone_alloc->lock);
 278 
 279         *puid = zone->uid;
 280 
 281         return 0;
 282 }
 283 
 284 /* Should be called under a lock */
 285 static void __mlx4_zone_remove_one_entry(struct mlx4_zone_entry *entry)
 286 {
 287         struct mlx4_zone_allocator *zone_alloc = entry->allocator;
 288 
 289         if (!list_empty(&entry->prio_list)) {
 290                 /* Check if we need to add an alternative node to the prio list */
 291                 if (!list_is_last(&entry->list, &zone_alloc->entries)) {
 292                         struct mlx4_zone_entry *next = list_first_entry(&entry->list,
 293                                                                         typeof(*next),
 294                                                                         list);
 295 
 296                         if (next->priority == entry->priority)
 297                                 list_add_tail(&next->prio_list, &entry->prio_list);
 298                 }
 299 
 300                 list_del(&entry->prio_list);
 301         }
 302 
 303         list_del(&entry->list);
 304 
 305         if (zone_alloc->flags & MLX4_ZONE_ALLOC_FLAGS_NO_OVERLAP) {
 306                 u32 mask = 0;
 307                 struct mlx4_zone_entry *it;
 308 
 309                 list_for_each_entry(it, &zone_alloc->prios, prio_list) {
 310                         u32 cur_mask = mlx4_bitmap_masked_value(it->bitmap, (u32)-1);
 311 
 312                         if (mask < cur_mask)
 313                                 mask = cur_mask;
 314                 }
 315                 zone_alloc->mask = mask;
 316         }
 317 }
 318 
 319 void mlx4_zone_allocator_destroy(struct mlx4_zone_allocator *zone_alloc)
 320 {
 321         struct mlx4_zone_entry *zone, *tmp;
 322 
 323         spin_lock(&zone_alloc->lock);
 324 
 325         list_for_each_entry_safe(zone, tmp, &zone_alloc->entries, list) {
 326                 list_del(&zone->list);
 327                 list_del(&zone->prio_list);
 328                 kfree(zone);
 329         }
 330 
 331         spin_unlock(&zone_alloc->lock);
 332         kfree(zone_alloc);
 333 }
 334 
 335 /* Should be called under a lock */
 336 static u32 __mlx4_alloc_from_zone(struct mlx4_zone_entry *zone, int count,
 337                                   int align, u32 skip_mask, u32 *puid)
 338 {
 339         u32 uid = 0;
 340         u32 res;
 341         struct mlx4_zone_allocator *zone_alloc = zone->allocator;
 342         struct mlx4_zone_entry *curr_node;
 343 
 344         res = mlx4_bitmap_alloc_range(zone->bitmap, count,
 345                                       align, skip_mask);
 346 
 347         if (res != (u32)-1) {
 348                 res += zone->offset;
 349                 uid = zone->uid;
 350                 goto out;
 351         }
 352 
 353         list_for_each_entry(curr_node, &zone_alloc->prios, prio_list) {
 354                 if (unlikely(curr_node->priority == zone->priority))
 355                         break;
 356         }
 357 
 358         if (zone->flags & MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO) {
 359                 struct mlx4_zone_entry *it = curr_node;
 360 
 361                 list_for_each_entry_continue_reverse(it, &zone_alloc->entries, list) {
 362                         res = mlx4_bitmap_alloc_range(it->bitmap, count,
 363                                                       align, skip_mask);
 364                         if (res != (u32)-1) {
 365                                 res += it->offset;
 366                                 uid = it->uid;
 367                                 goto out;
 368                         }
 369                 }
 370         }
 371 
 372         if (zone->flags & MLX4_ZONE_ALLOW_ALLOC_FROM_EQ_PRIO) {
 373                 struct mlx4_zone_entry *it = curr_node;
 374 
 375                 list_for_each_entry_from(it, &zone_alloc->entries, list) {
 376                         if (unlikely(it == zone))
 377                                 continue;
 378 
 379                         if (unlikely(it->priority != curr_node->priority))
 380                                 break;
 381 
 382                         res = mlx4_bitmap_alloc_range(it->bitmap, count,
 383                                                       align, skip_mask);
 384                         if (res != (u32)-1) {
 385                                 res += it->offset;
 386                                 uid = it->uid;
 387                                 goto out;
 388                         }
 389                 }
 390         }
 391 
 392         if (zone->flags & MLX4_ZONE_FALLBACK_TO_HIGHER_PRIO) {
 393                 if (list_is_last(&curr_node->prio_list, &zone_alloc->prios))
 394                         goto out;
 395 
 396                 curr_node = list_first_entry(&curr_node->prio_list,
 397                                              typeof(*curr_node),
 398                                              prio_list);
 399 
 400                 list_for_each_entry_from(curr_node, &zone_alloc->entries, list) {
 401                         res = mlx4_bitmap_alloc_range(curr_node->bitmap, count,
 402                                                       align, skip_mask);
 403                         if (res != (u32)-1) {
 404                                 res += curr_node->offset;
 405                                 uid = curr_node->uid;
 406                                 goto out;
 407                         }
 408                 }
 409         }
 410 
 411 out:
 412         if (NULL != puid && res != (u32)-1)
 413                 *puid = uid;
 414         return res;
 415 }
 416 
 417 /* Should be called under a lock */
 418 static void __mlx4_free_from_zone(struct mlx4_zone_entry *zone, u32 obj,
 419                                   u32 count)
 420 {
 421         mlx4_bitmap_free_range(zone->bitmap, obj - zone->offset, count, zone->use_rr);
 422 }
 423 
 424 /* Should be called under a lock */
 425 static struct mlx4_zone_entry *__mlx4_find_zone_by_uid(
 426                 struct mlx4_zone_allocator *zones, u32 uid)
 427 {
 428         struct mlx4_zone_entry *zone;
 429 
 430         list_for_each_entry(zone, &zones->entries, list) {
 431                 if (zone->uid == uid)
 432                         return zone;
 433         }
 434 
 435         return NULL;
 436 }
 437 
 438 struct mlx4_bitmap *mlx4_zone_get_bitmap(struct mlx4_zone_allocator *zones, u32 uid)
 439 {
 440         struct mlx4_zone_entry *zone;
 441         struct mlx4_bitmap *bitmap;
 442 
 443         spin_lock(&zones->lock);
 444 
 445         zone = __mlx4_find_zone_by_uid(zones, uid);
 446 
 447         bitmap = zone == NULL ? NULL : zone->bitmap;
 448 
 449         spin_unlock(&zones->lock);
 450 
 451         return bitmap;
 452 }
 453 
 454 int mlx4_zone_remove_one(struct mlx4_zone_allocator *zones, u32 uid)
 455 {
 456         struct mlx4_zone_entry *zone;
 457         int res = 0;
 458 
 459         spin_lock(&zones->lock);
 460 
 461         zone = __mlx4_find_zone_by_uid(zones, uid);
 462 
 463         if (NULL == zone) {
 464                 res = -1;
 465                 goto out;
 466         }
 467 
 468         __mlx4_zone_remove_one_entry(zone);
 469 
 470 out:
 471         spin_unlock(&zones->lock);
 472         kfree(zone);
 473 
 474         return res;
 475 }
 476 
 477 /* Should be called under a lock */
 478 static struct mlx4_zone_entry *__mlx4_find_zone_by_uid_unique(
 479                 struct mlx4_zone_allocator *zones, u32 obj)
 480 {
 481         struct mlx4_zone_entry *zone, *zone_candidate = NULL;
 482         u32 dist = (u32)-1;
 483 
 484         /* Search for the smallest zone that this obj could be
 485          * allocated from. This is done in order to handle
 486          * situations when small bitmaps are allocated from bigger
 487          * bitmaps (and the allocated space is marked as reserved in
 488          * the bigger bitmap.
 489          */
 490         list_for_each_entry(zone, &zones->entries, list) {
 491                 if (obj >= zone->offset) {
 492                         u32 mobj = (obj - zone->offset) & zones->mask;
 493 
 494                         if (mobj < zone->bitmap->max) {
 495                                 u32 curr_dist = zone->bitmap->effective_len;
 496 
 497                                 if (curr_dist < dist) {
 498                                         dist = curr_dist;
 499                                         zone_candidate = zone;
 500                                 }
 501                         }
 502                 }
 503         }
 504 
 505         return zone_candidate;
 506 }
 507 
 508 u32 mlx4_zone_alloc_entries(struct mlx4_zone_allocator *zones, u32 uid, int count,
 509                             int align, u32 skip_mask, u32 *puid)
 510 {
 511         struct mlx4_zone_entry *zone;
 512         int res = -1;
 513 
 514         spin_lock(&zones->lock);
 515 
 516         zone = __mlx4_find_zone_by_uid(zones, uid);
 517 
 518         if (NULL == zone)
 519                 goto out;
 520 
 521         res = __mlx4_alloc_from_zone(zone, count, align, skip_mask, puid);
 522 
 523 out:
 524         spin_unlock(&zones->lock);
 525 
 526         return res;
 527 }
 528 
 529 u32 mlx4_zone_free_entries(struct mlx4_zone_allocator *zones, u32 uid, u32 obj, u32 count)
 530 {
 531         struct mlx4_zone_entry *zone;
 532         int res = 0;
 533 
 534         spin_lock(&zones->lock);
 535 
 536         zone = __mlx4_find_zone_by_uid(zones, uid);
 537 
 538         if (NULL == zone) {
 539                 res = -1;
 540                 goto out;
 541         }
 542 
 543         __mlx4_free_from_zone(zone, obj, count);
 544 
 545 out:
 546         spin_unlock(&zones->lock);
 547 
 548         return res;
 549 }
 550 
 551 u32 mlx4_zone_free_entries_unique(struct mlx4_zone_allocator *zones, u32 obj, u32 count)
 552 {
 553         struct mlx4_zone_entry *zone;
 554         int res;
 555 
 556         if (!(zones->flags & MLX4_ZONE_ALLOC_FLAGS_NO_OVERLAP))
 557                 return -EFAULT;
 558 
 559         spin_lock(&zones->lock);
 560 
 561         zone = __mlx4_find_zone_by_uid_unique(zones, obj);
 562 
 563         if (NULL == zone) {
 564                 res = -1;
 565                 goto out;
 566         }
 567 
 568         __mlx4_free_from_zone(zone, obj, count);
 569         res = 0;
 570 
 571 out:
 572         spin_unlock(&zones->lock);
 573 
 574         return res;
 575 }
 576 
 577 static int mlx4_buf_direct_alloc(struct mlx4_dev *dev, int size,
 578                                  struct mlx4_buf *buf)
 579 {
 580         dma_addr_t t;
 581 
 582         buf->nbufs        = 1;
 583         buf->npages       = 1;
 584         buf->page_shift   = get_order(size) + PAGE_SHIFT;
 585         buf->direct.buf   =
 586                 dma_alloc_coherent(&dev->persist->pdev->dev, size, &t,
 587                                    GFP_KERNEL);
 588         if (!buf->direct.buf)
 589                 return -ENOMEM;
 590 
 591         buf->direct.map = t;
 592 
 593         while (t & ((1 << buf->page_shift) - 1)) {
 594                 --buf->page_shift;
 595                 buf->npages *= 2;
 596         }
 597 
 598         return 0;
 599 }
 600 
 601 /* Handling for queue buffers -- we allocate a bunch of memory and
 602  * register it in a memory region at HCA virtual address 0. If the
 603  *  requested size is > max_direct, we split the allocation into
 604  *  multiple pages, so we don't require too much contiguous memory.
 605  */
 606 int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
 607                    struct mlx4_buf *buf)
 608 {
 609         if (size <= max_direct) {
 610                 return mlx4_buf_direct_alloc(dev, size, buf);
 611         } else {
 612                 dma_addr_t t;
 613                 int i;
 614 
 615                 buf->direct.buf = NULL;
 616                 buf->nbufs      = DIV_ROUND_UP(size, PAGE_SIZE);
 617                 buf->npages     = buf->nbufs;
 618                 buf->page_shift  = PAGE_SHIFT;
 619                 buf->page_list   = kcalloc(buf->nbufs, sizeof(*buf->page_list),
 620                                            GFP_KERNEL);
 621                 if (!buf->page_list)
 622                         return -ENOMEM;
 623 
 624                 for (i = 0; i < buf->nbufs; ++i) {
 625                         buf->page_list[i].buf =
 626                                 dma_alloc_coherent(&dev->persist->pdev->dev,
 627                                                    PAGE_SIZE, &t, GFP_KERNEL);
 628                         if (!buf->page_list[i].buf)
 629                                 goto err_free;
 630 
 631                         buf->page_list[i].map = t;
 632                 }
 633         }
 634 
 635         return 0;
 636 
 637 err_free:
 638         mlx4_buf_free(dev, size, buf);
 639 
 640         return -ENOMEM;
 641 }
 642 EXPORT_SYMBOL_GPL(mlx4_buf_alloc);
 643 
 644 void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
 645 {
 646         if (buf->nbufs == 1) {
 647                 dma_free_coherent(&dev->persist->pdev->dev, size,
 648                                   buf->direct.buf, buf->direct.map);
 649         } else {
 650                 int i;
 651 
 652                 for (i = 0; i < buf->nbufs; ++i)
 653                         if (buf->page_list[i].buf)
 654                                 dma_free_coherent(&dev->persist->pdev->dev,
 655                                                   PAGE_SIZE,
 656                                                   buf->page_list[i].buf,
 657                                                   buf->page_list[i].map);
 658                 kfree(buf->page_list);
 659         }
 660 }
 661 EXPORT_SYMBOL_GPL(mlx4_buf_free);
 662 
 663 static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device)
 664 {
 665         struct mlx4_db_pgdir *pgdir;
 666 
 667         pgdir = kzalloc(sizeof(*pgdir), GFP_KERNEL);
 668         if (!pgdir)
 669                 return NULL;
 670 
 671         bitmap_fill(pgdir->order1, MLX4_DB_PER_PAGE / 2);
 672         pgdir->bits[0] = pgdir->order0;
 673         pgdir->bits[1] = pgdir->order1;
 674         pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE,
 675                                             &pgdir->db_dma, GFP_KERNEL);
 676         if (!pgdir->db_page) {
 677                 kfree(pgdir);
 678                 return NULL;
 679         }
 680 
 681         return pgdir;
 682 }
 683 
 684 static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir,
 685                                     struct mlx4_db *db, int order)
 686 {
 687         int o;
 688         int i;
 689 
 690         for (o = order; o <= 1; ++o) {
 691                 i = find_first_bit(pgdir->bits[o], MLX4_DB_PER_PAGE >> o);
 692                 if (i < MLX4_DB_PER_PAGE >> o)
 693                         goto found;
 694         }
 695 
 696         return -ENOMEM;
 697 
 698 found:
 699         clear_bit(i, pgdir->bits[o]);
 700 
 701         i <<= o;
 702 
 703         if (o > order)
 704                 set_bit(i ^ 1, pgdir->bits[order]);
 705 
 706         db->u.pgdir = pgdir;
 707         db->index   = i;
 708         db->db      = pgdir->db_page + db->index;
 709         db->dma     = pgdir->db_dma  + db->index * 4;
 710         db->order   = order;
 711 
 712         return 0;
 713 }
 714 
 715 int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order)
 716 {
 717         struct mlx4_priv *priv = mlx4_priv(dev);
 718         struct mlx4_db_pgdir *pgdir;
 719         int ret = 0;
 720 
 721         mutex_lock(&priv->pgdir_mutex);
 722 
 723         list_for_each_entry(pgdir, &priv->pgdir_list, list)
 724                 if (!mlx4_alloc_db_from_pgdir(pgdir, db, order))
 725                         goto out;
 726 
 727         pgdir = mlx4_alloc_db_pgdir(&dev->persist->pdev->dev);
 728         if (!pgdir) {
 729                 ret = -ENOMEM;
 730                 goto out;
 731         }
 732 
 733         list_add(&pgdir->list, &priv->pgdir_list);
 734 
 735         /* This should never fail -- we just allocated an empty page: */
 736         WARN_ON(mlx4_alloc_db_from_pgdir(pgdir, db, order));
 737 
 738 out:
 739         mutex_unlock(&priv->pgdir_mutex);
 740 
 741         return ret;
 742 }
 743 EXPORT_SYMBOL_GPL(mlx4_db_alloc);
 744 
 745 void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db)
 746 {
 747         struct mlx4_priv *priv = mlx4_priv(dev);
 748         int o;
 749         int i;
 750 
 751         mutex_lock(&priv->pgdir_mutex);
 752 
 753         o = db->order;
 754         i = db->index;
 755 
 756         if (db->order == 0 && test_bit(i ^ 1, db->u.pgdir->order0)) {
 757                 clear_bit(i ^ 1, db->u.pgdir->order0);
 758                 ++o;
 759         }
 760         i >>= o;
 761         set_bit(i, db->u.pgdir->bits[o]);
 762 
 763         if (bitmap_full(db->u.pgdir->order1, MLX4_DB_PER_PAGE / 2)) {
 764                 dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
 765                                   db->u.pgdir->db_page, db->u.pgdir->db_dma);
 766                 list_del(&db->u.pgdir->list);
 767                 kfree(db->u.pgdir);
 768         }
 769 
 770         mutex_unlock(&priv->pgdir_mutex);
 771 }
 772 EXPORT_SYMBOL_GPL(mlx4_db_free);
 773 
 774 int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
 775                        int size)
 776 {
 777         int err;
 778 
 779         err = mlx4_db_alloc(dev, &wqres->db, 1);
 780         if (err)
 781                 return err;
 782 
 783         *wqres->db.db = 0;
 784 
 785         err = mlx4_buf_direct_alloc(dev, size, &wqres->buf);
 786         if (err)
 787                 goto err_db;
 788 
 789         err = mlx4_mtt_init(dev, wqres->buf.npages, wqres->buf.page_shift,
 790                             &wqres->mtt);
 791         if (err)
 792                 goto err_buf;
 793 
 794         err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf);
 795         if (err)
 796                 goto err_mtt;
 797 
 798         return 0;
 799 
 800 err_mtt:
 801         mlx4_mtt_cleanup(dev, &wqres->mtt);
 802 err_buf:
 803         mlx4_buf_free(dev, size, &wqres->buf);
 804 err_db:
 805         mlx4_db_free(dev, &wqres->db);
 806 
 807         return err;
 808 }
 809 EXPORT_SYMBOL_GPL(mlx4_alloc_hwq_res);
 810 
 811 void mlx4_free_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
 812                        int size)
 813 {
 814         mlx4_mtt_cleanup(dev, &wqres->mtt);
 815         mlx4_buf_free(dev, size, &wqres->buf);
 816         mlx4_db_free(dev, &wqres->db);
 817 }
 818 EXPORT_SYMBOL_GPL(mlx4_free_hwq_res);

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