diff options
author | Artemy Kovalyov <artemyko@mellanox.com> | 2017-01-18 09:58:10 -0500 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2017-02-14 11:41:18 -0500 |
commit | 49780d42dfc9ec0f4090c32ca59688449da1a1cd (patch) | |
tree | 17e4d73dc7665786268c4ad3afefa91b85ea7504 | |
parent | 94990b498969b420949a04294618f9509466b896 (diff) |
IB/mlx5: Expose MR cache for mlx5_ib
Allow other parts of mlx5_ib to use MR cache mechanism.
* Add new functions mlx5_mr_cache_alloc and mlx5_mr_cache_free
* Traditional MTT MKey buckets are limited by MAX_UMR_CACHE_ENTRY
Additinal buckets may be added above.
Signed-off-by: Artemy Kovalyov <artemyko@mellanox.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r-- | drivers/infiniband/hw/mlx5/mlx5_ib.h | 9 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx5/mr.c | 99 | ||||
-rw-r--r-- | include/linux/mlx5/driver.h | 3 |
3 files changed, 82 insertions, 29 deletions
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 13bef19649f2..efc44de3c7d7 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h | |||
@@ -541,6 +541,10 @@ struct mlx5_cache_ent { | |||
541 | struct dentry *dir; | 541 | struct dentry *dir; |
542 | char name[4]; | 542 | char name[4]; |
543 | u32 order; | 543 | u32 order; |
544 | u32 xlt; | ||
545 | u32 access_mode; | ||
546 | u32 page; | ||
547 | |||
544 | u32 size; | 548 | u32 size; |
545 | u32 cur; | 549 | u32 cur; |
546 | u32 miss; | 550 | u32 miss; |
@@ -555,6 +559,7 @@ struct mlx5_cache_ent { | |||
555 | struct work_struct work; | 559 | struct work_struct work; |
556 | struct delayed_work dwork; | 560 | struct delayed_work dwork; |
557 | int pending; | 561 | int pending; |
562 | struct completion compl; | ||
558 | }; | 563 | }; |
559 | 564 | ||
560 | struct mlx5_mr_cache { | 565 | struct mlx5_mr_cache { |
@@ -837,7 +842,9 @@ void mlx5_ib_copy_pas(u64 *old, u64 *new, int step, int num); | |||
837 | int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq); | 842 | int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq); |
838 | int mlx5_mr_cache_init(struct mlx5_ib_dev *dev); | 843 | int mlx5_mr_cache_init(struct mlx5_ib_dev *dev); |
839 | int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev); | 844 | int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev); |
840 | int mlx5_mr_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift); | 845 | |
846 | struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev, int entry); | ||
847 | void mlx5_mr_cache_free(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr); | ||
841 | int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask, | 848 | int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask, |
842 | struct ib_mr_status *mr_status); | 849 | struct ib_mr_status *mr_status); |
843 | struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd, | 850 | struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd, |
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 8cf2a67f9fb0..8f5b94d483e4 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c | |||
@@ -49,6 +49,7 @@ enum { | |||
49 | 49 | ||
50 | static int clean_mr(struct mlx5_ib_mr *mr); | 50 | static int clean_mr(struct mlx5_ib_mr *mr); |
51 | static int use_umr(struct mlx5_ib_dev *dev, int order); | 51 | static int use_umr(struct mlx5_ib_dev *dev, int order); |
52 | static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr); | ||
52 | 53 | ||
53 | static int destroy_mkey(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) | 54 | static int destroy_mkey(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) |
54 | { | 55 | { |
@@ -149,6 +150,9 @@ static void reg_mr_callback(int status, void *context) | |||
149 | if (err) | 150 | if (err) |
150 | pr_err("Error inserting to mkey tree. 0x%x\n", -err); | 151 | pr_err("Error inserting to mkey tree. 0x%x\n", -err); |
151 | write_unlock_irqrestore(&table->lock, flags); | 152 | write_unlock_irqrestore(&table->lock, flags); |
153 | |||
154 | if (!completion_done(&ent->compl)) | ||
155 | complete(&ent->compl); | ||
152 | } | 156 | } |
153 | 157 | ||
154 | static int add_keys(struct mlx5_ib_dev *dev, int c, int num) | 158 | static int add_keys(struct mlx5_ib_dev *dev, int c, int num) |
@@ -157,7 +161,6 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num) | |||
157 | struct mlx5_cache_ent *ent = &cache->ent[c]; | 161 | struct mlx5_cache_ent *ent = &cache->ent[c]; |
158 | int inlen = MLX5_ST_SZ_BYTES(create_mkey_in); | 162 | int inlen = MLX5_ST_SZ_BYTES(create_mkey_in); |
159 | struct mlx5_ib_mr *mr; | 163 | struct mlx5_ib_mr *mr; |
160 | int npages = 1 << ent->order; | ||
161 | void *mkc; | 164 | void *mkc; |
162 | u32 *in; | 165 | u32 *in; |
163 | int err = 0; | 166 | int err = 0; |
@@ -185,11 +188,11 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num) | |||
185 | 188 | ||
186 | MLX5_SET(mkc, mkc, free, 1); | 189 | MLX5_SET(mkc, mkc, free, 1); |
187 | MLX5_SET(mkc, mkc, umr_en, 1); | 190 | MLX5_SET(mkc, mkc, umr_en, 1); |
188 | MLX5_SET(mkc, mkc, access_mode, MLX5_MKC_ACCESS_MODE_MTT); | 191 | MLX5_SET(mkc, mkc, access_mode, ent->access_mode); |
189 | 192 | ||
190 | MLX5_SET(mkc, mkc, qpn, 0xffffff); | 193 | MLX5_SET(mkc, mkc, qpn, 0xffffff); |
191 | MLX5_SET(mkc, mkc, translations_octword_size, (npages + 1) / 2); | 194 | MLX5_SET(mkc, mkc, translations_octword_size, ent->xlt); |
192 | MLX5_SET(mkc, mkc, log_page_size, 12); | 195 | MLX5_SET(mkc, mkc, log_page_size, ent->page); |
193 | 196 | ||
194 | spin_lock_irq(&ent->lock); | 197 | spin_lock_irq(&ent->lock); |
195 | ent->pending++; | 198 | ent->pending++; |
@@ -447,6 +450,42 @@ static void cache_work_func(struct work_struct *work) | |||
447 | __cache_work_func(ent); | 450 | __cache_work_func(ent); |
448 | } | 451 | } |
449 | 452 | ||
453 | struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev, int entry) | ||
454 | { | ||
455 | struct mlx5_mr_cache *cache = &dev->cache; | ||
456 | struct mlx5_cache_ent *ent; | ||
457 | struct mlx5_ib_mr *mr; | ||
458 | int err; | ||
459 | |||
460 | if (entry < 0 || entry >= MAX_MR_CACHE_ENTRIES) { | ||
461 | mlx5_ib_err(dev, "cache entry %d is out of range\n", entry); | ||
462 | return NULL; | ||
463 | } | ||
464 | |||
465 | ent = &cache->ent[entry]; | ||
466 | while (1) { | ||
467 | spin_lock_irq(&ent->lock); | ||
468 | if (list_empty(&ent->head)) { | ||
469 | spin_unlock_irq(&ent->lock); | ||
470 | |||
471 | err = add_keys(dev, entry, 1); | ||
472 | if (err) | ||
473 | return ERR_PTR(err); | ||
474 | |||
475 | wait_for_completion(&ent->compl); | ||
476 | } else { | ||
477 | mr = list_first_entry(&ent->head, struct mlx5_ib_mr, | ||
478 | list); | ||
479 | list_del(&mr->list); | ||
480 | ent->cur--; | ||
481 | spin_unlock_irq(&ent->lock); | ||
482 | if (ent->cur < ent->limit) | ||
483 | queue_work(cache->wq, &ent->work); | ||
484 | return mr; | ||
485 | } | ||
486 | } | ||
487 | } | ||
488 | |||
450 | static struct mlx5_ib_mr *alloc_cached_mr(struct mlx5_ib_dev *dev, int order) | 489 | static struct mlx5_ib_mr *alloc_cached_mr(struct mlx5_ib_dev *dev, int order) |
451 | { | 490 | { |
452 | struct mlx5_mr_cache *cache = &dev->cache; | 491 | struct mlx5_mr_cache *cache = &dev->cache; |
@@ -456,12 +495,12 @@ static struct mlx5_ib_mr *alloc_cached_mr(struct mlx5_ib_dev *dev, int order) | |||
456 | int i; | 495 | int i; |
457 | 496 | ||
458 | c = order2idx(dev, order); | 497 | c = order2idx(dev, order); |
459 | if (c < 0 || c >= MAX_MR_CACHE_ENTRIES) { | 498 | if (c < 0 || c > MAX_UMR_CACHE_ENTRY) { |
460 | mlx5_ib_warn(dev, "order %d, cache index %d\n", order, c); | 499 | mlx5_ib_warn(dev, "order %d, cache index %d\n", order, c); |
461 | return NULL; | 500 | return NULL; |
462 | } | 501 | } |
463 | 502 | ||
464 | for (i = c; i < MAX_MR_CACHE_ENTRIES; i++) { | 503 | for (i = c; i < MAX_UMR_CACHE_ENTRY; i++) { |
465 | ent = &cache->ent[i]; | 504 | ent = &cache->ent[i]; |
466 | 505 | ||
467 | mlx5_ib_dbg(dev, "order %d, cache index %d\n", ent->order, i); | 506 | mlx5_ib_dbg(dev, "order %d, cache index %d\n", ent->order, i); |
@@ -488,7 +527,7 @@ static struct mlx5_ib_mr *alloc_cached_mr(struct mlx5_ib_dev *dev, int order) | |||
488 | return mr; | 527 | return mr; |
489 | } | 528 | } |
490 | 529 | ||
491 | static void free_cached_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) | 530 | void mlx5_mr_cache_free(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) |
492 | { | 531 | { |
493 | struct mlx5_mr_cache *cache = &dev->cache; | 532 | struct mlx5_mr_cache *cache = &dev->cache; |
494 | struct mlx5_cache_ent *ent; | 533 | struct mlx5_cache_ent *ent; |
@@ -500,6 +539,10 @@ static void free_cached_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) | |||
500 | mlx5_ib_warn(dev, "order %d, cache index %d\n", mr->order, c); | 539 | mlx5_ib_warn(dev, "order %d, cache index %d\n", mr->order, c); |
501 | return; | 540 | return; |
502 | } | 541 | } |
542 | |||
543 | if (unreg_umr(dev, mr)) | ||
544 | return; | ||
545 | |||
503 | ent = &cache->ent[c]; | 546 | ent = &cache->ent[c]; |
504 | spin_lock_irq(&ent->lock); | 547 | spin_lock_irq(&ent->lock); |
505 | list_add_tail(&mr->list, &ent->head); | 548 | list_add_tail(&mr->list, &ent->head); |
@@ -602,7 +645,6 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) | |||
602 | { | 645 | { |
603 | struct mlx5_mr_cache *cache = &dev->cache; | 646 | struct mlx5_mr_cache *cache = &dev->cache; |
604 | struct mlx5_cache_ent *ent; | 647 | struct mlx5_cache_ent *ent; |
605 | int limit; | ||
606 | int err; | 648 | int err; |
607 | int i; | 649 | int i; |
608 | 650 | ||
@@ -615,26 +657,33 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) | |||
615 | 657 | ||
616 | setup_timer(&dev->delay_timer, delay_time_func, (unsigned long)dev); | 658 | setup_timer(&dev->delay_timer, delay_time_func, (unsigned long)dev); |
617 | for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) { | 659 | for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) { |
618 | INIT_LIST_HEAD(&cache->ent[i].head); | ||
619 | spin_lock_init(&cache->ent[i].lock); | ||
620 | |||
621 | ent = &cache->ent[i]; | 660 | ent = &cache->ent[i]; |
622 | INIT_LIST_HEAD(&ent->head); | 661 | INIT_LIST_HEAD(&ent->head); |
623 | spin_lock_init(&ent->lock); | 662 | spin_lock_init(&ent->lock); |
624 | ent->order = i + 2; | 663 | ent->order = i + 2; |
625 | ent->dev = dev; | 664 | ent->dev = dev; |
665 | ent->limit = 0; | ||
626 | 666 | ||
627 | if ((dev->mdev->profile->mask & MLX5_PROF_MASK_MR_CACHE) && | 667 | init_completion(&ent->compl); |
628 | mlx5_core_is_pf(dev->mdev) && | ||
629 | use_umr(dev, ent->order)) | ||
630 | limit = dev->mdev->profile->mr_cache[i].limit; | ||
631 | else | ||
632 | limit = 0; | ||
633 | |||
634 | INIT_WORK(&ent->work, cache_work_func); | 668 | INIT_WORK(&ent->work, cache_work_func); |
635 | INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func); | 669 | INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func); |
636 | ent->limit = limit; | ||
637 | queue_work(cache->wq, &ent->work); | 670 | queue_work(cache->wq, &ent->work); |
671 | |||
672 | if (i > MAX_UMR_CACHE_ENTRY) | ||
673 | continue; | ||
674 | |||
675 | if (!use_umr(dev, ent->order)) | ||
676 | continue; | ||
677 | |||
678 | ent->page = PAGE_SHIFT; | ||
679 | ent->xlt = (1 << ent->order) * sizeof(struct mlx5_mtt) / | ||
680 | MLX5_IB_UMR_OCTOWORD; | ||
681 | ent->access_mode = MLX5_MKC_ACCESS_MODE_MTT; | ||
682 | if ((dev->mdev->profile->mask & MLX5_PROF_MASK_MR_CACHE) && | ||
683 | mlx5_core_is_pf(dev->mdev)) | ||
684 | ent->limit = dev->mdev->profile->mr_cache[i].limit; | ||
685 | else | ||
686 | ent->limit = 0; | ||
638 | } | 687 | } |
639 | 688 | ||
640 | err = mlx5_mr_cache_debugfs_init(dev); | 689 | err = mlx5_mr_cache_debugfs_init(dev); |
@@ -758,7 +807,7 @@ static int get_octo_len(u64 addr, u64 len, int page_size) | |||
758 | static int use_umr(struct mlx5_ib_dev *dev, int order) | 807 | static int use_umr(struct mlx5_ib_dev *dev, int order) |
759 | { | 808 | { |
760 | if (MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset)) | 809 | if (MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset)) |
761 | return order < MAX_MR_CACHE_ENTRIES + 2; | 810 | return order <= MAX_UMR_CACHE_ENTRY + 2; |
762 | return order <= MLX5_MAX_UMR_SHIFT; | 811 | return order <= MLX5_MAX_UMR_SHIFT; |
763 | } | 812 | } |
764 | 813 | ||
@@ -871,7 +920,7 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem, | |||
871 | MLX5_IB_UPD_XLT_ENABLE); | 920 | MLX5_IB_UPD_XLT_ENABLE); |
872 | 921 | ||
873 | if (err) { | 922 | if (err) { |
874 | free_cached_mr(dev, mr); | 923 | mlx5_mr_cache_free(dev, mr); |
875 | return ERR_PTR(err); | 924 | return ERR_PTR(err); |
876 | } | 925 | } |
877 | 926 | ||
@@ -1091,6 +1140,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_mr *ibmr, struct ib_pd *pd, | |||
1091 | goto err_2; | 1140 | goto err_2; |
1092 | } | 1141 | } |
1093 | mr->mmkey.type = MLX5_MKEY_MR; | 1142 | mr->mmkey.type = MLX5_MKEY_MR; |
1143 | mr->desc_size = sizeof(struct mlx5_mtt); | ||
1094 | mr->umem = umem; | 1144 | mr->umem = umem; |
1095 | mr->dev = dev; | 1145 | mr->dev = dev; |
1096 | mr->live = 1; | 1146 | mr->live = 1; |
@@ -1398,12 +1448,7 @@ static int clean_mr(struct mlx5_ib_mr *mr) | |||
1398 | return err; | 1448 | return err; |
1399 | } | 1449 | } |
1400 | } else { | 1450 | } else { |
1401 | err = unreg_umr(dev, mr); | 1451 | mlx5_mr_cache_free(dev, mr); |
1402 | if (err) { | ||
1403 | mlx5_ib_warn(dev, "failed unregister\n"); | ||
1404 | return err; | ||
1405 | } | ||
1406 | free_cached_mr(dev, mr); | ||
1407 | } | 1452 | } |
1408 | 1453 | ||
1409 | if (!umred) | 1454 | if (!umred) |
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index b8d69aeb1784..2534b8a0fd7b 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h | |||
@@ -1052,7 +1052,8 @@ enum { | |||
1052 | }; | 1052 | }; |
1053 | 1053 | ||
1054 | enum { | 1054 | enum { |
1055 | MAX_MR_CACHE_ENTRIES = 21, | 1055 | MAX_UMR_CACHE_ENTRY = 20, |
1056 | MAX_MR_CACHE_ENTRIES | ||
1056 | }; | 1057 | }; |
1057 | 1058 | ||
1058 | enum { | 1059 | enum { |