From a3cdcbfa8fb1fccfe48d359da86e99546610c562 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Fri, 10 Oct 2008 12:01:37 -0700 Subject: mlx4_core: Add QP range reservation support To allow allocating an aligned range of consecutive QP numbers, add an interface to reserve an aligned range of QP numbers and have the QP allocation function always take a QP number. This will be used for RSS support in the mlx4_en Ethernet driver and also potentially by IPoIB RSS support. Signed-off-by: Yevgeny Petrilin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/qp.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/infiniband/hw') diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index baa01deb243..39167a797f9 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -451,6 +451,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, struct ib_qp_init_attr *init_attr, struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp) { + int qpn; int err; mutex_init(&qp->mutex); @@ -545,9 +546,17 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, } } - err = mlx4_qp_alloc(dev->dev, sqpn, &qp->mqp); + if (sqpn) { + qpn = sqpn; + } else { + err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn); + if (err) + goto err_wrid; + } + + err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp); if (err) - goto err_wrid; + goto err_qpn; /* * Hardware wants QPN written in big-endian order (after @@ -560,6 +569,10 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, return 0; +err_qpn: + if (!sqpn) + mlx4_qp_release_range(dev->dev, qpn, 1); + err_wrid: if (pd->uobject) { if (!init_attr->srq) @@ -655,6 +668,10 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, mlx4_ib_unlock_cqs(send_cq, recv_cq); mlx4_qp_free(dev->dev, &qp->mqp); + + if (!is_sqp(dev, qp)) + mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1); + mlx4_mtt_cleanup(dev->dev, &qp->mtt); if (is_user) { -- cgit v1.2.3 From 0540bbbe455e123a1692d26205ad1a29983883b0 Mon Sep 17 00:00:00 2001 From: Hoang-Nam Nguyen Date: Fri, 10 Oct 2008 14:40:39 -0700 Subject: IB/ehca: Don't allow creating UC QP with SRQ This patch prevents a UC QP to be created attached to an SRQ, since current firmware does not support this feature. Signed-off-by: Michael Faath Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_qp.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/infiniband/hw') diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 4dbe2870e01..40b578d601c 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -502,6 +502,12 @@ static struct ehca_qp *internal_create_qp( if (init_attr->srq) { my_srq = container_of(init_attr->srq, struct ehca_qp, ib_srq); + if (qp_type == IB_QPT_UC) { + ehca_err(pd->device, "UC with SRQ not supported"); + atomic_dec(&shca->num_qps); + return ERR_PTR(-EINVAL); + } + has_srq = 1; parms.ext_type = EQPT_SRQBASE; parms.srq_qpn = my_srq->real_qp_num; -- cgit v1.2.3 From dc35fac9e936c6cc6ad825fc7e4455468d10adc6 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 15 Oct 2008 10:50:34 -0700 Subject: RDMA/cxgb3: Remove cmid reference on tid allocation failures The error path in iwch_connect() can fail to drop the cmid reference, which will cause the process to hang when destroying the cmid. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch_cm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/infiniband/hw') diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index c325c44807e..44e936e48a3 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -1942,6 +1942,7 @@ fail4: fail3: cxgb3_free_atid(ep->com.tdev, ep->atid); fail2: + cm_id->rem_ref(cm_id); put_ep(&ep->com); out: return err; -- cgit v1.2.3 From 7ff93f8b7ecbc36e7ffc5c11a61643821c1bfee5 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Wed, 22 Oct 2008 15:38:42 -0700 Subject: mlx4_core: Multiple port type support Multi-protocol adapters support different port types. Each consumer of mlx4_core queries for supported port types; in particular mlx4_ib can no longer assume that all physical ports belong to it. Port type is configured through a sysfs interface. When the type of a port is changed, all mlx4 interfaces are unregistered, and then registered again with the new port types. Signed-off-by: Yevgeny Petrilin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/mad.c | 6 +++--- drivers/infiniband/hw/mlx4/main.c | 11 +++++++++-- drivers/infiniband/hw/mlx4/mlx4_ib.h | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/infiniband/hw') diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index cdca3a511e1..606f1e2ef28 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -298,7 +298,7 @@ int mlx4_ib_mad_init(struct mlx4_ib_dev *dev) int p, q; int ret; - for (p = 0; p < dev->dev->caps.num_ports; ++p) + for (p = 0; p < dev->num_ports; ++p) for (q = 0; q <= 1; ++q) { agent = ib_register_mad_agent(&dev->ib_dev, p + 1, q ? IB_QPT_GSI : IB_QPT_SMI, @@ -314,7 +314,7 @@ int mlx4_ib_mad_init(struct mlx4_ib_dev *dev) return 0; err: - for (p = 0; p < dev->dev->caps.num_ports; ++p) + for (p = 0; p < dev->num_ports; ++p) for (q = 0; q <= 1; ++q) if (dev->send_agent[p][q]) ib_unregister_mad_agent(dev->send_agent[p][q]); @@ -327,7 +327,7 @@ void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev) struct ib_mad_agent *agent; int p, q; - for (p = 0; p < dev->dev->caps.num_ports; ++p) { + for (p = 0; p < dev->num_ports; ++p) { for (q = 0; q <= 1; ++q) { agent = dev->send_agent[p][q]; dev->send_agent[p][q] = NULL; diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index a3c2851c054..2e80f8f47b0 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -574,7 +574,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->ib_dev.owner = THIS_MODULE; ibdev->ib_dev.node_type = RDMA_NODE_IB_CA; ibdev->ib_dev.local_dma_lkey = dev->caps.reserved_lkey; - ibdev->ib_dev.phys_port_cnt = dev->caps.num_ports; + ibdev->num_ports = 0; + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) + ibdev->num_ports++; + ibdev->ib_dev.phys_port_cnt = ibdev->num_ports; ibdev->ib_dev.num_comp_vectors = 1; ibdev->ib_dev.dma_device = &dev->pdev->dev; @@ -691,7 +694,7 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) struct mlx4_ib_dev *ibdev = ibdev_ptr; int p; - for (p = 1; p <= dev->caps.num_ports; ++p) + for (p = 1; p <= ibdev->num_ports; ++p) mlx4_CLOSE_PORT(dev, p); mlx4_ib_mad_cleanup(ibdev); @@ -706,6 +709,10 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, enum mlx4_dev_event event, int port) { struct ib_event ibev; + struct mlx4_ib_dev *ibdev = to_mdev((struct ib_device *) ibdev_ptr); + + if (port > ibdev->num_ports) + return; switch (event) { case MLX4_DEV_EVENT_PORT_UP: diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 6e2b0dc21b6..9974e886b8d 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -162,6 +162,7 @@ struct mlx4_ib_ah { struct mlx4_ib_dev { struct ib_device ib_dev; struct mlx4_dev *dev; + int num_ports; void __iomem *uar_map; struct mlx4_uar priv_uar; -- cgit v1.2.3 From 19f4282149147b4a3e8c670373dc73ddd5d5facc Mon Sep 17 00:00:00 2001 From: Stefan Roscher Date: Wed, 22 Oct 2008 15:52:31 -0700 Subject: IB/ehca: Fix reported max number of QPs and CQs in systems with >1 adapter Because ehca adapters can differ in the maximum number of QPs and CQs we have to save the maximum number of these ressources per adapter and not globally per ehca driver. This fix introduces 2 new members to the shca structure to store the maximum value for QPs and CQs per adapter. The module parameters are now used as initial values for those variables. If a user selects an invalid number of CQs or QPs we don't print an error any longer, instead we will inform the user with a warning and set the values to the respective maximum supported by the HW. Signed-off-by: Stefan Roscher Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_classes.h | 2 ++ drivers/infiniband/hw/ehca/ehca_cq.c | 4 ++-- drivers/infiniband/hw/ehca/ehca_main.c | 35 ++++++++++++++++++------------- drivers/infiniband/hw/ehca/ehca_qp.c | 4 ++-- 4 files changed, 26 insertions(+), 19 deletions(-) (limited to 'drivers/infiniband/hw') diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 5d7b7855afb..4df887af66a 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -128,6 +128,8 @@ struct ehca_shca { /* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */ u32 hca_cap_mr_pgsize; int max_mtu; + int max_num_qps; + int max_num_cqs; atomic_t num_cqs; atomic_t num_qps; }; diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 33647a95eb9..2f4c28a3027 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -132,9 +132,9 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, if (cqe >= 0xFFFFFFFF - 64 - additional_cqe) return ERR_PTR(-EINVAL); - if (!atomic_add_unless(&shca->num_cqs, 1, ehca_max_cq)) { + if (!atomic_add_unless(&shca->num_cqs, 1, shca->max_num_cqs)) { ehca_err(device, "Unable to create CQ, max number of %i " - "CQs reached.", ehca_max_cq); + "CQs reached.", shca->max_num_cqs); ehca_err(device, "To increase the maximum number of CQs " "use the number_of_cqs module parameter.\n"); return ERR_PTR(-ENOSPC); diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 598844d2edc..086959a0cbe 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -366,22 +366,23 @@ static int ehca_sense_attributes(struct ehca_shca *shca) shca->hca_cap_mr_pgsize |= pgsize_map[i + 1]; /* Set maximum number of CQs and QPs to calculate EQ size */ - if (ehca_max_qp == -1) - ehca_max_qp = min_t(int, rblock->max_qp, EHCA_MAX_NUM_QUEUES); - else if (ehca_max_qp < 1 || ehca_max_qp > rblock->max_qp) { - ehca_gen_err("Requested number of QPs is out of range (1 - %i) " - "specified by HW", rblock->max_qp); - ret = -EINVAL; - goto sense_attributes1; + if (shca->max_num_qps == -1) + shca->max_num_qps = min_t(int, rblock->max_qp, + EHCA_MAX_NUM_QUEUES); + else if (shca->max_num_qps < 1 || shca->max_num_qps > rblock->max_qp) { + ehca_gen_warn("The requested number of QPs is out of range " + "(1 - %i) specified by HW. Value is set to %i", + rblock->max_qp, rblock->max_qp); + shca->max_num_qps = rblock->max_qp; } - if (ehca_max_cq == -1) - ehca_max_cq = min_t(int, rblock->max_cq, EHCA_MAX_NUM_QUEUES); - else if (ehca_max_cq < 1 || ehca_max_cq > rblock->max_cq) { - ehca_gen_err("Requested number of CQs is out of range (1 - %i) " - "specified by HW", rblock->max_cq); - ret = -EINVAL; - goto sense_attributes1; + if (shca->max_num_cqs == -1) + shca->max_num_cqs = min_t(int, rblock->max_cq, + EHCA_MAX_NUM_QUEUES); + else if (shca->max_num_cqs < 1 || shca->max_num_cqs > rblock->max_cq) { + ehca_gen_warn("The requested number of CQs is out of range " + "(1 - %i) specified by HW. Value is set to %i", + rblock->max_cq, rblock->max_cq); } /* query max MTU from first port -- it's the same for all ports */ @@ -733,9 +734,13 @@ static int __devinit ehca_probe(struct of_device *dev, ehca_gen_err("Cannot allocate shca memory."); return -ENOMEM; } + mutex_init(&shca->modify_mutex); atomic_set(&shca->num_cqs, 0); atomic_set(&shca->num_qps, 0); + shca->max_num_qps = ehca_max_qp; + shca->max_num_cqs = ehca_max_cq; + for (i = 0; i < ARRAY_SIZE(shca->sport); i++) spin_lock_init(&shca->sport[i].mod_sqp_lock); @@ -755,7 +760,7 @@ static int __devinit ehca_probe(struct of_device *dev, goto probe1; } - eq_size = 2 * ehca_max_cq + 4 * ehca_max_qp; + eq_size = 2 * shca->max_num_cqs + 4 * shca->max_num_qps; /* create event queues */ ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size); if (ret) { diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 40b578d601c..4d54b9f6456 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -465,9 +465,9 @@ static struct ehca_qp *internal_create_qp( u32 swqe_size = 0, rwqe_size = 0, ib_qp_num; unsigned long flags; - if (!atomic_add_unless(&shca->num_qps, 1, ehca_max_qp)) { + if (!atomic_add_unless(&shca->num_qps, 1, shca->max_num_qps)) { ehca_err(pd->device, "Unable to create QP, max number of %i " - "QPs reached.", ehca_max_qp); + "QPs reached.", shca->max_num_qps); ehca_err(pd->device, "To increase the maximum number of QPs " "use the number_of_qps module parameter.\n"); return ERR_PTR(-ENOSPC); -- cgit v1.2.3 From 263c24a2bbbaca75805ed231e8346d86410af9d0 Mon Sep 17 00:00:00 2001 From: Stefan Roscher Date: Wed, 22 Oct 2008 15:54:38 -0700 Subject: IB/ehca: Reject dynamic memory add/remove when ehca adapter is present Since the ehca device driver does not support dynamic memory add and remove operations, the driver must explicitly reject such requests in order to prevent unpredictable behaviors related to existing memory regions that cover all of memory being used by InfiniBand protocols in the kernel. The solution (for now at least) is to add a memory notifier to the ehca device driver and if a request for dynamic memory add or remove comes in, ehca will always reject it. The user can add or remove memory by hot-removing the ehca adapter, performing the memory operation, and then hot-adding the ehca adapter back. Signed-off-by: Stefan Roscher Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_main.c | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers/infiniband/hw') diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 086959a0cbe..bb02a86aa52 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -44,6 +44,8 @@ #include #endif +#include +#include #include "ehca_classes.h" #include "ehca_iverbs.h" #include "ehca_mrmw.h" @@ -969,6 +971,41 @@ void ehca_poll_eqs(unsigned long data) spin_unlock(&shca_list_lock); } +static int ehca_mem_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + static unsigned long ehca_dmem_warn_time; + + switch (action) { + case MEM_CANCEL_OFFLINE: + case MEM_CANCEL_ONLINE: + case MEM_ONLINE: + case MEM_OFFLINE: + return NOTIFY_OK; + case MEM_GOING_ONLINE: + case MEM_GOING_OFFLINE: + /* only ok if no hca is attached to the lpar */ + spin_lock(&shca_list_lock); + if (list_empty(&shca_list)) { + spin_unlock(&shca_list_lock); + return NOTIFY_OK; + } else { + spin_unlock(&shca_list_lock); + if (printk_timed_ratelimit(&ehca_dmem_warn_time, + 30 * 1000)) + ehca_gen_err("DMEM operations are not allowed" + "as long as an ehca adapter is" + "attached to the LPAR"); + return NOTIFY_BAD; + } + } + return NOTIFY_OK; +} + +static struct notifier_block ehca_mem_nb = { + .notifier_call = ehca_mem_notifier, +}; + static int __init ehca_module_init(void) { int ret; @@ -996,6 +1033,12 @@ static int __init ehca_module_init(void) goto module_init2; } + ret = register_memory_notifier(&ehca_mem_nb); + if (ret) { + ehca_gen_err("Failed registering memory add/remove notifier"); + goto module_init3; + } + if (ehca_poll_all_eqs != 1) { ehca_gen_err("WARNING!!!"); ehca_gen_err("It is possible to lose interrupts."); @@ -1008,6 +1051,9 @@ static int __init ehca_module_init(void) return 0; +module_init3: + ibmebus_unregister_driver(&ehca_driver); + module_init2: ehca_destroy_slab_caches(); @@ -1023,6 +1069,8 @@ static void __exit ehca_module_exit(void) ibmebus_unregister_driver(&ehca_driver); + unregister_memory_notifier(&ehca_mem_nb); + ehca_destroy_slab_caches(); ehca_destroy_comp_pool(); -- cgit v1.2.3