diff options
Diffstat (limited to 'drivers/infiniband/hw/mlx5/mr.c')
-rw-r--r-- | drivers/infiniband/hw/mlx5/mr.c | 167 |
1 files changed, 122 insertions, 45 deletions
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 3453580b1eb2..039c3e40fcb4 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c | |||
@@ -35,11 +35,12 @@ | |||
35 | #include <linux/random.h> | 35 | #include <linux/random.h> |
36 | #include <linux/debugfs.h> | 36 | #include <linux/debugfs.h> |
37 | #include <linux/export.h> | 37 | #include <linux/export.h> |
38 | #include <linux/delay.h> | ||
38 | #include <rdma/ib_umem.h> | 39 | #include <rdma/ib_umem.h> |
39 | #include "mlx5_ib.h" | 40 | #include "mlx5_ib.h" |
40 | 41 | ||
41 | enum { | 42 | enum { |
42 | DEF_CACHE_SIZE = 10, | 43 | MAX_PENDING_REG_MR = 8, |
43 | }; | 44 | }; |
44 | 45 | ||
45 | enum { | 46 | enum { |
@@ -63,6 +64,51 @@ static int order2idx(struct mlx5_ib_dev *dev, int order) | |||
63 | return order - cache->ent[0].order; | 64 | return order - cache->ent[0].order; |
64 | } | 65 | } |
65 | 66 | ||
67 | static void reg_mr_callback(int status, void *context) | ||
68 | { | ||
69 | struct mlx5_ib_mr *mr = context; | ||
70 | struct mlx5_ib_dev *dev = mr->dev; | ||
71 | struct mlx5_mr_cache *cache = &dev->cache; | ||
72 | int c = order2idx(dev, mr->order); | ||
73 | struct mlx5_cache_ent *ent = &cache->ent[c]; | ||
74 | u8 key; | ||
75 | unsigned long flags; | ||
76 | |||
77 | spin_lock_irqsave(&ent->lock, flags); | ||
78 | ent->pending--; | ||
79 | spin_unlock_irqrestore(&ent->lock, flags); | ||
80 | if (status) { | ||
81 | mlx5_ib_warn(dev, "async reg mr failed. status %d\n", status); | ||
82 | kfree(mr); | ||
83 | dev->fill_delay = 1; | ||
84 | mod_timer(&dev->delay_timer, jiffies + HZ); | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | if (mr->out.hdr.status) { | ||
89 | mlx5_ib_warn(dev, "failed - status %d, syndorme 0x%x\n", | ||
90 | mr->out.hdr.status, | ||
91 | be32_to_cpu(mr->out.hdr.syndrome)); | ||
92 | kfree(mr); | ||
93 | dev->fill_delay = 1; | ||
94 | mod_timer(&dev->delay_timer, jiffies + HZ); | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | spin_lock_irqsave(&dev->mdev.priv.mkey_lock, flags); | ||
99 | key = dev->mdev.priv.mkey_key++; | ||
100 | spin_unlock_irqrestore(&dev->mdev.priv.mkey_lock, flags); | ||
101 | mr->mmr.key = mlx5_idx_to_mkey(be32_to_cpu(mr->out.mkey) & 0xffffff) | key; | ||
102 | |||
103 | cache->last_add = jiffies; | ||
104 | |||
105 | spin_lock_irqsave(&ent->lock, flags); | ||
106 | list_add_tail(&mr->list, &ent->head); | ||
107 | ent->cur++; | ||
108 | ent->size++; | ||
109 | spin_unlock_irqrestore(&ent->lock, flags); | ||
110 | } | ||
111 | |||
66 | static int add_keys(struct mlx5_ib_dev *dev, int c, int num) | 112 | static int add_keys(struct mlx5_ib_dev *dev, int c, int num) |
67 | { | 113 | { |
68 | struct mlx5_mr_cache *cache = &dev->cache; | 114 | struct mlx5_mr_cache *cache = &dev->cache; |
@@ -78,36 +124,39 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num) | |||
78 | return -ENOMEM; | 124 | return -ENOMEM; |
79 | 125 | ||
80 | for (i = 0; i < num; i++) { | 126 | for (i = 0; i < num; i++) { |
127 | if (ent->pending >= MAX_PENDING_REG_MR) { | ||
128 | err = -EAGAIN; | ||
129 | break; | ||
130 | } | ||
131 | |||
81 | mr = kzalloc(sizeof(*mr), GFP_KERNEL); | 132 | mr = kzalloc(sizeof(*mr), GFP_KERNEL); |
82 | if (!mr) { | 133 | if (!mr) { |
83 | err = -ENOMEM; | 134 | err = -ENOMEM; |
84 | goto out; | 135 | break; |
85 | } | 136 | } |
86 | mr->order = ent->order; | 137 | mr->order = ent->order; |
87 | mr->umred = 1; | 138 | mr->umred = 1; |
139 | mr->dev = dev; | ||
88 | in->seg.status = 1 << 6; | 140 | in->seg.status = 1 << 6; |
89 | in->seg.xlt_oct_size = cpu_to_be32((npages + 1) / 2); | 141 | in->seg.xlt_oct_size = cpu_to_be32((npages + 1) / 2); |
90 | in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); | 142 | in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); |
91 | in->seg.flags = MLX5_ACCESS_MODE_MTT | MLX5_PERM_UMR_EN; | 143 | in->seg.flags = MLX5_ACCESS_MODE_MTT | MLX5_PERM_UMR_EN; |
92 | in->seg.log2_page_size = 12; | 144 | in->seg.log2_page_size = 12; |
93 | 145 | ||
146 | spin_lock_irq(&ent->lock); | ||
147 | ent->pending++; | ||
148 | spin_unlock_irq(&ent->lock); | ||
149 | mr->start = jiffies; | ||
94 | err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, | 150 | err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, |
95 | sizeof(*in)); | 151 | sizeof(*in), reg_mr_callback, |
152 | mr, &mr->out); | ||
96 | if (err) { | 153 | if (err) { |
97 | mlx5_ib_warn(dev, "create mkey failed %d\n", err); | 154 | mlx5_ib_warn(dev, "create mkey failed %d\n", err); |
98 | kfree(mr); | 155 | kfree(mr); |
99 | goto out; | 156 | break; |
100 | } | 157 | } |
101 | cache->last_add = jiffies; | ||
102 | |||
103 | spin_lock(&ent->lock); | ||
104 | list_add_tail(&mr->list, &ent->head); | ||
105 | ent->cur++; | ||
106 | ent->size++; | ||
107 | spin_unlock(&ent->lock); | ||
108 | } | 158 | } |
109 | 159 | ||
110 | out: | ||
111 | kfree(in); | 160 | kfree(in); |
112 | return err; | 161 | return err; |
113 | } | 162 | } |
@@ -121,16 +170,16 @@ static void remove_keys(struct mlx5_ib_dev *dev, int c, int num) | |||
121 | int i; | 170 | int i; |
122 | 171 | ||
123 | for (i = 0; i < num; i++) { | 172 | for (i = 0; i < num; i++) { |
124 | spin_lock(&ent->lock); | 173 | spin_lock_irq(&ent->lock); |
125 | if (list_empty(&ent->head)) { | 174 | if (list_empty(&ent->head)) { |
126 | spin_unlock(&ent->lock); | 175 | spin_unlock_irq(&ent->lock); |
127 | return; | 176 | return; |
128 | } | 177 | } |
129 | mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list); | 178 | mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list); |
130 | list_del(&mr->list); | 179 | list_del(&mr->list); |
131 | ent->cur--; | 180 | ent->cur--; |
132 | ent->size--; | 181 | ent->size--; |
133 | spin_unlock(&ent->lock); | 182 | spin_unlock_irq(&ent->lock); |
134 | err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); | 183 | err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); |
135 | if (err) | 184 | if (err) |
136 | mlx5_ib_warn(dev, "failed destroy mkey\n"); | 185 | mlx5_ib_warn(dev, "failed destroy mkey\n"); |
@@ -162,9 +211,13 @@ static ssize_t size_write(struct file *filp, const char __user *buf, | |||
162 | return -EINVAL; | 211 | return -EINVAL; |
163 | 212 | ||
164 | if (var > ent->size) { | 213 | if (var > ent->size) { |
165 | err = add_keys(dev, c, var - ent->size); | 214 | do { |
166 | if (err) | 215 | err = add_keys(dev, c, var - ent->size); |
167 | return err; | 216 | if (err && err != -EAGAIN) |
217 | return err; | ||
218 | |||
219 | usleep_range(3000, 5000); | ||
220 | } while (err); | ||
168 | } else if (var < ent->size) { | 221 | } else if (var < ent->size) { |
169 | remove_keys(dev, c, ent->size - var); | 222 | remove_keys(dev, c, ent->size - var); |
170 | } | 223 | } |
@@ -280,23 +333,37 @@ static void __cache_work_func(struct mlx5_cache_ent *ent) | |||
280 | struct mlx5_ib_dev *dev = ent->dev; | 333 | struct mlx5_ib_dev *dev = ent->dev; |
281 | struct mlx5_mr_cache *cache = &dev->cache; | 334 | struct mlx5_mr_cache *cache = &dev->cache; |
282 | int i = order2idx(dev, ent->order); | 335 | int i = order2idx(dev, ent->order); |
336 | int err; | ||
283 | 337 | ||
284 | if (cache->stopped) | 338 | if (cache->stopped) |
285 | return; | 339 | return; |
286 | 340 | ||
287 | ent = &dev->cache.ent[i]; | 341 | ent = &dev->cache.ent[i]; |
288 | if (ent->cur < 2 * ent->limit) { | 342 | if (ent->cur < 2 * ent->limit && !dev->fill_delay) { |
289 | add_keys(dev, i, 1); | 343 | err = add_keys(dev, i, 1); |
290 | if (ent->cur < 2 * ent->limit) | 344 | if (ent->cur < 2 * ent->limit) { |
291 | queue_work(cache->wq, &ent->work); | 345 | if (err == -EAGAIN) { |
346 | mlx5_ib_dbg(dev, "returned eagain, order %d\n", | ||
347 | i + 2); | ||
348 | queue_delayed_work(cache->wq, &ent->dwork, | ||
349 | msecs_to_jiffies(3)); | ||
350 | } else if (err) { | ||
351 | mlx5_ib_warn(dev, "command failed order %d, err %d\n", | ||
352 | i + 2, err); | ||
353 | queue_delayed_work(cache->wq, &ent->dwork, | ||
354 | msecs_to_jiffies(1000)); | ||
355 | } else { | ||
356 | queue_work(cache->wq, &ent->work); | ||
357 | } | ||
358 | } | ||
292 | } else if (ent->cur > 2 * ent->limit) { | 359 | } else if (ent->cur > 2 * ent->limit) { |
293 | if (!someone_adding(cache) && | 360 | if (!someone_adding(cache) && |
294 | time_after(jiffies, cache->last_add + 60 * HZ)) { | 361 | time_after(jiffies, cache->last_add + 300 * HZ)) { |
295 | remove_keys(dev, i, 1); | 362 | remove_keys(dev, i, 1); |
296 | if (ent->cur > ent->limit) | 363 | if (ent->cur > ent->limit) |
297 | queue_work(cache->wq, &ent->work); | 364 | queue_work(cache->wq, &ent->work); |
298 | } else { | 365 | } else { |
299 | queue_delayed_work(cache->wq, &ent->dwork, 60 * HZ); | 366 | queue_delayed_work(cache->wq, &ent->dwork, 300 * HZ); |
300 | } | 367 | } |
301 | } | 368 | } |
302 | } | 369 | } |
@@ -336,18 +403,18 @@ static struct mlx5_ib_mr *alloc_cached_mr(struct mlx5_ib_dev *dev, int order) | |||
336 | 403 | ||
337 | mlx5_ib_dbg(dev, "order %d, cache index %d\n", ent->order, i); | 404 | mlx5_ib_dbg(dev, "order %d, cache index %d\n", ent->order, i); |
338 | 405 | ||
339 | spin_lock(&ent->lock); | 406 | spin_lock_irq(&ent->lock); |
340 | if (!list_empty(&ent->head)) { | 407 | if (!list_empty(&ent->head)) { |
341 | mr = list_first_entry(&ent->head, struct mlx5_ib_mr, | 408 | mr = list_first_entry(&ent->head, struct mlx5_ib_mr, |
342 | list); | 409 | list); |
343 | list_del(&mr->list); | 410 | list_del(&mr->list); |
344 | ent->cur--; | 411 | ent->cur--; |
345 | spin_unlock(&ent->lock); | 412 | spin_unlock_irq(&ent->lock); |
346 | if (ent->cur < ent->limit) | 413 | if (ent->cur < ent->limit) |
347 | queue_work(cache->wq, &ent->work); | 414 | queue_work(cache->wq, &ent->work); |
348 | break; | 415 | break; |
349 | } | 416 | } |
350 | spin_unlock(&ent->lock); | 417 | spin_unlock_irq(&ent->lock); |
351 | 418 | ||
352 | queue_work(cache->wq, &ent->work); | 419 | queue_work(cache->wq, &ent->work); |
353 | 420 | ||
@@ -374,12 +441,12 @@ static void free_cached_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) | |||
374 | return; | 441 | return; |
375 | } | 442 | } |
376 | ent = &cache->ent[c]; | 443 | ent = &cache->ent[c]; |
377 | spin_lock(&ent->lock); | 444 | spin_lock_irq(&ent->lock); |
378 | list_add_tail(&mr->list, &ent->head); | 445 | list_add_tail(&mr->list, &ent->head); |
379 | ent->cur++; | 446 | ent->cur++; |
380 | if (ent->cur > 2 * ent->limit) | 447 | if (ent->cur > 2 * ent->limit) |
381 | shrink = 1; | 448 | shrink = 1; |
382 | spin_unlock(&ent->lock); | 449 | spin_unlock_irq(&ent->lock); |
383 | 450 | ||
384 | if (shrink) | 451 | if (shrink) |
385 | queue_work(cache->wq, &ent->work); | 452 | queue_work(cache->wq, &ent->work); |
@@ -394,16 +461,16 @@ static void clean_keys(struct mlx5_ib_dev *dev, int c) | |||
394 | 461 | ||
395 | cancel_delayed_work(&ent->dwork); | 462 | cancel_delayed_work(&ent->dwork); |
396 | while (1) { | 463 | while (1) { |
397 | spin_lock(&ent->lock); | 464 | spin_lock_irq(&ent->lock); |
398 | if (list_empty(&ent->head)) { | 465 | if (list_empty(&ent->head)) { |
399 | spin_unlock(&ent->lock); | 466 | spin_unlock_irq(&ent->lock); |
400 | return; | 467 | return; |
401 | } | 468 | } |
402 | mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list); | 469 | mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list); |
403 | list_del(&mr->list); | 470 | list_del(&mr->list); |
404 | ent->cur--; | 471 | ent->cur--; |
405 | ent->size--; | 472 | ent->size--; |
406 | spin_unlock(&ent->lock); | 473 | spin_unlock_irq(&ent->lock); |
407 | err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); | 474 | err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); |
408 | if (err) | 475 | if (err) |
409 | mlx5_ib_warn(dev, "failed destroy mkey\n"); | 476 | mlx5_ib_warn(dev, "failed destroy mkey\n"); |
@@ -464,12 +531,18 @@ static void mlx5_mr_cache_debugfs_cleanup(struct mlx5_ib_dev *dev) | |||
464 | debugfs_remove_recursive(dev->cache.root); | 531 | debugfs_remove_recursive(dev->cache.root); |
465 | } | 532 | } |
466 | 533 | ||
534 | static void delay_time_func(unsigned long ctx) | ||
535 | { | ||
536 | struct mlx5_ib_dev *dev = (struct mlx5_ib_dev *)ctx; | ||
537 | |||
538 | dev->fill_delay = 0; | ||
539 | } | ||
540 | |||
467 | int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) | 541 | int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) |
468 | { | 542 | { |
469 | struct mlx5_mr_cache *cache = &dev->cache; | 543 | struct mlx5_mr_cache *cache = &dev->cache; |
470 | struct mlx5_cache_ent *ent; | 544 | struct mlx5_cache_ent *ent; |
471 | int limit; | 545 | int limit; |
472 | int size; | ||
473 | int err; | 546 | int err; |
474 | int i; | 547 | int i; |
475 | 548 | ||
@@ -479,6 +552,7 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) | |||
479 | return -ENOMEM; | 552 | return -ENOMEM; |
480 | } | 553 | } |
481 | 554 | ||
555 | setup_timer(&dev->delay_timer, delay_time_func, (unsigned long)dev); | ||
482 | for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) { | 556 | for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) { |
483 | INIT_LIST_HEAD(&cache->ent[i].head); | 557 | INIT_LIST_HEAD(&cache->ent[i].head); |
484 | spin_lock_init(&cache->ent[i].lock); | 558 | spin_lock_init(&cache->ent[i].lock); |
@@ -489,13 +563,11 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) | |||
489 | ent->order = i + 2; | 563 | ent->order = i + 2; |
490 | ent->dev = dev; | 564 | ent->dev = dev; |
491 | 565 | ||
492 | if (dev->mdev.profile->mask & MLX5_PROF_MASK_MR_CACHE) { | 566 | if (dev->mdev.profile->mask & MLX5_PROF_MASK_MR_CACHE) |
493 | size = dev->mdev.profile->mr_cache[i].size; | ||
494 | limit = dev->mdev.profile->mr_cache[i].limit; | 567 | limit = dev->mdev.profile->mr_cache[i].limit; |
495 | } else { | 568 | else |
496 | size = DEF_CACHE_SIZE; | ||
497 | limit = 0; | 569 | limit = 0; |
498 | } | 570 | |
499 | INIT_WORK(&ent->work, cache_work_func); | 571 | INIT_WORK(&ent->work, cache_work_func); |
500 | INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func); | 572 | INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func); |
501 | ent->limit = limit; | 573 | ent->limit = limit; |
@@ -522,6 +594,7 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev) | |||
522 | clean_keys(dev, i); | 594 | clean_keys(dev, i); |
523 | 595 | ||
524 | destroy_workqueue(dev->cache.wq); | 596 | destroy_workqueue(dev->cache.wq); |
597 | del_timer_sync(&dev->delay_timer); | ||
525 | 598 | ||
526 | return 0; | 599 | return 0; |
527 | } | 600 | } |
@@ -551,7 +624,8 @@ struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc) | |||
551 | seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); | 624 | seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); |
552 | seg->start_addr = 0; | 625 | seg->start_addr = 0; |
553 | 626 | ||
554 | err = mlx5_core_create_mkey(mdev, &mr->mmr, in, sizeof(*in)); | 627 | err = mlx5_core_create_mkey(mdev, &mr->mmr, in, sizeof(*in), NULL, NULL, |
628 | NULL); | ||
555 | if (err) | 629 | if (err) |
556 | goto err_in; | 630 | goto err_in; |
557 | 631 | ||
@@ -660,14 +734,14 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem, | |||
660 | int err; | 734 | int err; |
661 | int i; | 735 | int i; |
662 | 736 | ||
663 | for (i = 0; i < 10; i++) { | 737 | for (i = 0; i < 1; i++) { |
664 | mr = alloc_cached_mr(dev, order); | 738 | mr = alloc_cached_mr(dev, order); |
665 | if (mr) | 739 | if (mr) |
666 | break; | 740 | break; |
667 | 741 | ||
668 | err = add_keys(dev, order2idx(dev, order), 1); | 742 | err = add_keys(dev, order2idx(dev, order), 1); |
669 | if (err) { | 743 | if (err && err != -EAGAIN) { |
670 | mlx5_ib_warn(dev, "add_keys failed\n"); | 744 | mlx5_ib_warn(dev, "add_keys failed, err %d\n", err); |
671 | break; | 745 | break; |
672 | } | 746 | } |
673 | } | 747 | } |
@@ -759,8 +833,10 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr, | |||
759 | in->seg.xlt_oct_size = cpu_to_be32(get_octo_len(virt_addr, length, 1 << page_shift)); | 833 | in->seg.xlt_oct_size = cpu_to_be32(get_octo_len(virt_addr, length, 1 << page_shift)); |
760 | in->seg.log2_page_size = page_shift; | 834 | in->seg.log2_page_size = page_shift; |
761 | in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); | 835 | in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); |
762 | in->xlat_oct_act_size = cpu_to_be32(get_octo_len(virt_addr, length, 1 << page_shift)); | 836 | in->xlat_oct_act_size = cpu_to_be32(get_octo_len(virt_addr, length, |
763 | err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, inlen); | 837 | 1 << page_shift)); |
838 | err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, inlen, NULL, | ||
839 | NULL, NULL); | ||
764 | if (err) { | 840 | if (err) { |
765 | mlx5_ib_warn(dev, "create mkey failed\n"); | 841 | mlx5_ib_warn(dev, "create mkey failed\n"); |
766 | goto err_2; | 842 | goto err_2; |
@@ -944,7 +1020,8 @@ struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, | |||
944 | * TBD not needed - issue 197292 */ | 1020 | * TBD not needed - issue 197292 */ |
945 | in->seg.log2_page_size = PAGE_SHIFT; | 1021 | in->seg.log2_page_size = PAGE_SHIFT; |
946 | 1022 | ||
947 | err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, sizeof(*in)); | 1023 | err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, sizeof(*in), NULL, |
1024 | NULL, NULL); | ||
948 | kfree(in); | 1025 | kfree(in); |
949 | if (err) | 1026 | if (err) |
950 | goto err_free; | 1027 | goto err_free; |