diff options
author | Yevgeny Petrilin <yevgenyp@mellanox.co.il> | 2011-03-22 18:37:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-23 15:24:18 -0400 |
commit | 0b7ca5a928e2271bbc225e9e1ac1f22e9fbee54f (patch) | |
tree | 8a24efdb4ceb6f28a8d49e942f80d397c06f4a5f | |
parent | 908222655b38005483d64385e06341a38647fdf1 (diff) |
mlx4: Changing interrupt scheme
Adding a pool of MSI-X vectors and EQs that can be used explicitly by mlx4_core
customers (mlx4_ib, mlx4_en). The consumers will assign their own names to the
interrupt vectors. Those vectors are not opened at mlx4 device initialization,
opened by demand.
Changed the max number of possible EQs according to the new scheme, no longer relies on
on number of cores.
The new functionality is exposed through mlx4_assign_eq() and mlx4_release_eq().
Customers that do not use the new API will get completion vectors as before.
Signed-off-by: Markuze Alex <markuze@mellanox.co.il>
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/mlx4/cq.c | 2 | ||||
-rw-r--r-- | drivers/net/mlx4/eq.c | 107 | ||||
-rw-r--r-- | drivers/net/mlx4/main.c | 20 | ||||
-rw-r--r-- | drivers/net/mlx4/mlx4.h | 6 | ||||
-rw-r--r-- | drivers/net/mlx4/profile.c | 4 | ||||
-rw-r--r-- | include/linux/mlx4/device.h | 8 |
6 files changed, 134 insertions, 13 deletions
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 7cd34e9c7c7e..bd8ef9f2fa71 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c | |||
@@ -198,7 +198,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, | |||
198 | u64 mtt_addr; | 198 | u64 mtt_addr; |
199 | int err; | 199 | int err; |
200 | 200 | ||
201 | if (vector >= dev->caps.num_comp_vectors) | 201 | if (vector > dev->caps.num_comp_vectors + dev->caps.comp_pool) |
202 | return -EINVAL; | 202 | return -EINVAL; |
203 | 203 | ||
204 | cq->vector = vector; | 204 | cq->vector = vector; |
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 552d0fce6f67..506cfd0372ec 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c | |||
@@ -42,7 +42,7 @@ | |||
42 | #include "fw.h" | 42 | #include "fw.h" |
43 | 43 | ||
44 | enum { | 44 | enum { |
45 | MLX4_IRQNAME_SIZE = 64 | 45 | MLX4_IRQNAME_SIZE = 32 |
46 | }; | 46 | }; |
47 | 47 | ||
48 | enum { | 48 | enum { |
@@ -317,8 +317,8 @@ static int mlx4_num_eq_uar(struct mlx4_dev *dev) | |||
317 | * we need to map, take the difference of highest index and | 317 | * we need to map, take the difference of highest index and |
318 | * the lowest index we'll use and add 1. | 318 | * the lowest index we'll use and add 1. |
319 | */ | 319 | */ |
320 | return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs) / 4 - | 320 | return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs + |
321 | dev->caps.reserved_eqs / 4 + 1; | 321 | dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1; |
322 | } | 322 | } |
323 | 323 | ||
324 | static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) | 324 | static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) |
@@ -496,16 +496,32 @@ static void mlx4_free_eq(struct mlx4_dev *dev, | |||
496 | static void mlx4_free_irqs(struct mlx4_dev *dev) | 496 | static void mlx4_free_irqs(struct mlx4_dev *dev) |
497 | { | 497 | { |
498 | struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; | 498 | struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; |
499 | int i; | 499 | struct mlx4_priv *priv = mlx4_priv(dev); |
500 | int i, vec; | ||
500 | 501 | ||
501 | if (eq_table->have_irq) | 502 | if (eq_table->have_irq) |
502 | free_irq(dev->pdev->irq, dev); | 503 | free_irq(dev->pdev->irq, dev); |
504 | |||
503 | for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) | 505 | for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) |
504 | if (eq_table->eq[i].have_irq) { | 506 | if (eq_table->eq[i].have_irq) { |
505 | free_irq(eq_table->eq[i].irq, eq_table->eq + i); | 507 | free_irq(eq_table->eq[i].irq, eq_table->eq + i); |
506 | eq_table->eq[i].have_irq = 0; | 508 | eq_table->eq[i].have_irq = 0; |
507 | } | 509 | } |
508 | 510 | ||
511 | for (i = 0; i < dev->caps.comp_pool; i++) { | ||
512 | /* | ||
513 | * Freeing the assigned irq's | ||
514 | * all bits should be 0, but we need to validate | ||
515 | */ | ||
516 | if (priv->msix_ctl.pool_bm & 1ULL << i) { | ||
517 | /* NO need protecting*/ | ||
518 | vec = dev->caps.num_comp_vectors + 1 + i; | ||
519 | free_irq(priv->eq_table.eq[vec].irq, | ||
520 | &priv->eq_table.eq[vec]); | ||
521 | } | ||
522 | } | ||
523 | |||
524 | |||
509 | kfree(eq_table->irq_names); | 525 | kfree(eq_table->irq_names); |
510 | } | 526 | } |
511 | 527 | ||
@@ -578,7 +594,8 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) | |||
578 | (priv->eq_table.inta_pin < 32 ? 4 : 0); | 594 | (priv->eq_table.inta_pin < 32 ? 4 : 0); |
579 | 595 | ||
580 | priv->eq_table.irq_names = | 596 | priv->eq_table.irq_names = |
581 | kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1), | 597 | kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 + |
598 | dev->caps.comp_pool), | ||
582 | GFP_KERNEL); | 599 | GFP_KERNEL); |
583 | if (!priv->eq_table.irq_names) { | 600 | if (!priv->eq_table.irq_names) { |
584 | err = -ENOMEM; | 601 | err = -ENOMEM; |
@@ -601,6 +618,22 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) | |||
601 | if (err) | 618 | if (err) |
602 | goto err_out_comp; | 619 | goto err_out_comp; |
603 | 620 | ||
621 | /*if additional completion vectors poolsize is 0 this loop will not run*/ | ||
622 | for (i = dev->caps.num_comp_vectors + 1; | ||
623 | i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) { | ||
624 | |||
625 | err = mlx4_create_eq(dev, dev->caps.num_cqs - | ||
626 | dev->caps.reserved_cqs + | ||
627 | MLX4_NUM_SPARE_EQE, | ||
628 | (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, | ||
629 | &priv->eq_table.eq[i]); | ||
630 | if (err) { | ||
631 | --i; | ||
632 | goto err_out_unmap; | ||
633 | } | ||
634 | } | ||
635 | |||
636 | |||
604 | if (dev->flags & MLX4_FLAG_MSI_X) { | 637 | if (dev->flags & MLX4_FLAG_MSI_X) { |
605 | const char *eq_name; | 638 | const char *eq_name; |
606 | 639 | ||
@@ -686,7 +719,7 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) | |||
686 | 719 | ||
687 | mlx4_free_irqs(dev); | 720 | mlx4_free_irqs(dev); |
688 | 721 | ||
689 | for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) | 722 | for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) |
690 | mlx4_free_eq(dev, &priv->eq_table.eq[i]); | 723 | mlx4_free_eq(dev, &priv->eq_table.eq[i]); |
691 | 724 | ||
692 | mlx4_unmap_clr_int(dev); | 725 | mlx4_unmap_clr_int(dev); |
@@ -743,3 +776,65 @@ int mlx4_test_interrupts(struct mlx4_dev *dev) | |||
743 | return err; | 776 | return err; |
744 | } | 777 | } |
745 | EXPORT_SYMBOL(mlx4_test_interrupts); | 778 | EXPORT_SYMBOL(mlx4_test_interrupts); |
779 | |||
780 | int mlx4_assign_eq(struct mlx4_dev *dev, char* name, int * vector) | ||
781 | { | ||
782 | |||
783 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
784 | int vec = 0, err = 0, i; | ||
785 | |||
786 | spin_lock(&priv->msix_ctl.pool_lock); | ||
787 | for (i = 0; !vec && i < dev->caps.comp_pool; i++) { | ||
788 | if (~priv->msix_ctl.pool_bm & 1ULL << i) { | ||
789 | priv->msix_ctl.pool_bm |= 1ULL << i; | ||
790 | vec = dev->caps.num_comp_vectors + 1 + i; | ||
791 | snprintf(priv->eq_table.irq_names + | ||
792 | vec * MLX4_IRQNAME_SIZE, | ||
793 | MLX4_IRQNAME_SIZE, "%s", name); | ||
794 | err = request_irq(priv->eq_table.eq[vec].irq, | ||
795 | mlx4_msi_x_interrupt, 0, | ||
796 | &priv->eq_table.irq_names[vec<<5], | ||
797 | priv->eq_table.eq + vec); | ||
798 | if (err) { | ||
799 | /*zero out bit by fliping it*/ | ||
800 | priv->msix_ctl.pool_bm ^= 1 << i; | ||
801 | vec = 0; | ||
802 | continue; | ||
803 | /*we dont want to break here*/ | ||
804 | } | ||
805 | eq_set_ci(&priv->eq_table.eq[vec], 1); | ||
806 | } | ||
807 | } | ||
808 | spin_unlock(&priv->msix_ctl.pool_lock); | ||
809 | |||
810 | if (vec) { | ||
811 | *vector = vec; | ||
812 | } else { | ||
813 | *vector = 0; | ||
814 | err = (i == dev->caps.comp_pool) ? -ENOSPC : err; | ||
815 | } | ||
816 | return err; | ||
817 | } | ||
818 | EXPORT_SYMBOL(mlx4_assign_eq); | ||
819 | |||
820 | void mlx4_release_eq(struct mlx4_dev *dev, int vec) | ||
821 | { | ||
822 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
823 | /*bm index*/ | ||
824 | int i = vec - dev->caps.num_comp_vectors - 1; | ||
825 | |||
826 | if (likely(i >= 0)) { | ||
827 | /*sanity check , making sure were not trying to free irq's | ||
828 | Belonging to a legacy EQ*/ | ||
829 | spin_lock(&priv->msix_ctl.pool_lock); | ||
830 | if (priv->msix_ctl.pool_bm & 1ULL << i) { | ||
831 | free_irq(priv->eq_table.eq[vec].irq, | ||
832 | &priv->eq_table.eq[vec]); | ||
833 | priv->msix_ctl.pool_bm &= ~(1ULL << i); | ||
834 | } | ||
835 | spin_unlock(&priv->msix_ctl.pool_lock); | ||
836 | } | ||
837 | |||
838 | } | ||
839 | EXPORT_SYMBOL(mlx4_release_eq); | ||
840 | |||
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 2765a3ce9c24..517ca34f5b37 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c | |||
@@ -969,13 +969,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) | |||
969 | { | 969 | { |
970 | struct mlx4_priv *priv = mlx4_priv(dev); | 970 | struct mlx4_priv *priv = mlx4_priv(dev); |
971 | struct msix_entry *entries; | 971 | struct msix_entry *entries; |
972 | int nreq; | 972 | int nreq = min_t(int, dev->caps.num_ports * |
973 | min_t(int, num_online_cpus() + 1, MAX_MSIX_P_PORT) | ||
974 | + MSIX_LEGACY_SZ, MAX_MSIX); | ||
973 | int err; | 975 | int err; |
974 | int i; | 976 | int i; |
975 | 977 | ||
976 | if (msi_x) { | 978 | if (msi_x) { |
977 | nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, | 979 | nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, |
978 | num_possible_cpus() + 1); | 980 | nreq); |
979 | entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); | 981 | entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); |
980 | if (!entries) | 982 | if (!entries) |
981 | goto no_msi; | 983 | goto no_msi; |
@@ -998,7 +1000,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) | |||
998 | goto no_msi; | 1000 | goto no_msi; |
999 | } | 1001 | } |
1000 | 1002 | ||
1001 | dev->caps.num_comp_vectors = nreq - 1; | 1003 | if (nreq < |
1004 | MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) { | ||
1005 | /*Working in legacy mode , all EQ's shared*/ | ||
1006 | dev->caps.comp_pool = 0; | ||
1007 | dev->caps.num_comp_vectors = nreq - 1; | ||
1008 | } else { | ||
1009 | dev->caps.comp_pool = nreq - MSIX_LEGACY_SZ; | ||
1010 | dev->caps.num_comp_vectors = MSIX_LEGACY_SZ - 1; | ||
1011 | } | ||
1002 | for (i = 0; i < nreq; ++i) | 1012 | for (i = 0; i < nreq; ++i) |
1003 | priv->eq_table.eq[i].irq = entries[i].vector; | 1013 | priv->eq_table.eq[i].irq = entries[i].vector; |
1004 | 1014 | ||
@@ -1010,6 +1020,7 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) | |||
1010 | 1020 | ||
1011 | no_msi: | 1021 | no_msi: |
1012 | dev->caps.num_comp_vectors = 1; | 1022 | dev->caps.num_comp_vectors = 1; |
1023 | dev->caps.comp_pool = 0; | ||
1013 | 1024 | ||
1014 | for (i = 0; i < 2; ++i) | 1025 | for (i = 0; i < 2; ++i) |
1015 | priv->eq_table.eq[i].irq = dev->pdev->irq; | 1026 | priv->eq_table.eq[i].irq = dev->pdev->irq; |
@@ -1151,6 +1162,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1151 | if (err) | 1162 | if (err) |
1152 | goto err_close; | 1163 | goto err_close; |
1153 | 1164 | ||
1165 | priv->msix_ctl.pool_bm = 0; | ||
1166 | spin_lock_init(&priv->msix_ctl.pool_lock); | ||
1167 | |||
1154 | mlx4_enable_msi_x(dev); | 1168 | mlx4_enable_msi_x(dev); |
1155 | 1169 | ||
1156 | err = mlx4_setup_hca(dev); | 1170 | err = mlx4_setup_hca(dev); |
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 0da5bb7285b4..67ee8dacae79 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h | |||
@@ -282,6 +282,11 @@ struct mlx4_sense { | |||
282 | struct delayed_work sense_poll; | 282 | struct delayed_work sense_poll; |
283 | }; | 283 | }; |
284 | 284 | ||
285 | struct mlx4_msix_ctl { | ||
286 | u64 pool_bm; | ||
287 | spinlock_t pool_lock; | ||
288 | }; | ||
289 | |||
285 | struct mlx4_priv { | 290 | struct mlx4_priv { |
286 | struct mlx4_dev dev; | 291 | struct mlx4_dev dev; |
287 | 292 | ||
@@ -313,6 +318,7 @@ struct mlx4_priv { | |||
313 | struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; | 318 | struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; |
314 | struct mlx4_sense sense; | 319 | struct mlx4_sense sense; |
315 | struct mutex port_mutex; | 320 | struct mutex port_mutex; |
321 | struct mlx4_msix_ctl msix_ctl; | ||
316 | }; | 322 | }; |
317 | 323 | ||
318 | static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) | 324 | static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) |
diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c index e749f82865fe..b967647d0c76 100644 --- a/drivers/net/mlx4/profile.c +++ b/drivers/net/mlx4/profile.c | |||
@@ -107,9 +107,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, | |||
107 | profile[MLX4_RES_AUXC].num = request->num_qp; | 107 | profile[MLX4_RES_AUXC].num = request->num_qp; |
108 | profile[MLX4_RES_SRQ].num = request->num_srq; | 108 | profile[MLX4_RES_SRQ].num = request->num_srq; |
109 | profile[MLX4_RES_CQ].num = request->num_cq; | 109 | profile[MLX4_RES_CQ].num = request->num_cq; |
110 | profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, | 110 | profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, MAX_MSIX); |
111 | dev_cap->reserved_eqs + | ||
112 | num_possible_cpus() + 1); | ||
113 | profile[MLX4_RES_DMPT].num = request->num_mpt; | 111 | profile[MLX4_RES_DMPT].num = request->num_mpt; |
114 | profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; | 112 | profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; |
115 | profile[MLX4_RES_MTT].num = request->num_mtt; | 113 | profile[MLX4_RES_MTT].num = request->num_mtt; |
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 049214642036..78380823d827 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h | |||
@@ -39,6 +39,11 @@ | |||
39 | 39 | ||
40 | #include <asm/atomic.h> | 40 | #include <asm/atomic.h> |
41 | 41 | ||
42 | #define MAX_MSIX_P_PORT 17 | ||
43 | #define MAX_MSIX 64 | ||
44 | #define MSIX_LEGACY_SZ 4 | ||
45 | #define MIN_MSIX_P_PORT 5 | ||
46 | |||
42 | enum { | 47 | enum { |
43 | MLX4_FLAG_MSI_X = 1 << 0, | 48 | MLX4_FLAG_MSI_X = 1 << 0, |
44 | MLX4_FLAG_OLD_PORT_CMDS = 1 << 1, | 49 | MLX4_FLAG_OLD_PORT_CMDS = 1 << 1, |
@@ -223,6 +228,7 @@ struct mlx4_caps { | |||
223 | int num_eqs; | 228 | int num_eqs; |
224 | int reserved_eqs; | 229 | int reserved_eqs; |
225 | int num_comp_vectors; | 230 | int num_comp_vectors; |
231 | int comp_pool; | ||
226 | int num_mpts; | 232 | int num_mpts; |
227 | int num_mtt_segs; | 233 | int num_mtt_segs; |
228 | int mtts_per_seg; | 234 | int mtts_per_seg; |
@@ -526,5 +532,7 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, | |||
526 | int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); | 532 | int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); |
527 | int mlx4_SYNC_TPT(struct mlx4_dev *dev); | 533 | int mlx4_SYNC_TPT(struct mlx4_dev *dev); |
528 | int mlx4_test_interrupts(struct mlx4_dev *dev); | 534 | int mlx4_test_interrupts(struct mlx4_dev *dev); |
535 | int mlx4_assign_eq(struct mlx4_dev *dev, char* name , int* vector); | ||
536 | void mlx4_release_eq(struct mlx4_dev *dev, int vec); | ||
529 | 537 | ||
530 | #endif /* MLX4_DEVICE_H */ | 538 | #endif /* MLX4_DEVICE_H */ |