From 162f6a2f54dabdbfcede44f4c82918c112be8d19 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Tue, 5 Sep 2017 11:07:30 -0700 Subject: [PATCH] bnxt_re: Adding bug fix patches Signed-off-by: Selvin Xavier --- ...llocate-multiple-notification-queues.patch | 368 ++++++++++++++++++ ...lement-the-alloc-get_hw_stats-callba.patch | 243 ++++++++++++ ...update-of-qplib_qp.mtu-when-modified.patch | 39 ++ ...uing-further-cmds-to-FW-once-a-cmd-t.patch | 58 +++ ...Fix-compare-and-swap-atomic-operands.patch | 30 ++ ...-Free-up-devices-in-module_exit-path.patch | 43 ++ ...-between-the-netdev-register-and-unr.patch | 84 ++++ ...bnxt_re-Fix-memory-leak-in-FRMR-path.patch | 36 ++ ...sue-cmd-to-delete-GID-for-QP1-GID-en.patch | 69 ++++ 9 files changed, 970 insertions(+) create mode 100644 linux-next-cherry-picks/0057-RDMA-bnxt_re-Allocate-multiple-notification-queues.patch create mode 100644 linux-next-cherry-picks/0058-RDMA-bnxt_re-Implement-the-alloc-get_hw_stats-callba.patch create mode 100644 linux-next-pending/0005-bnxt_re-Fix-update-of-qplib_qp.mtu-when-modified.patch create mode 100644 linux-next-pending/0006-bnxt_re-Stop-issuing-further-cmds-to-FW-once-a-cmd-t.patch create mode 100644 linux-next-pending/0007-bnxt_re-Fix-compare-and-swap-atomic-operands.patch create mode 100644 linux-next-pending/0008-bnxt_re-Free-up-devices-in-module_exit-path.patch create mode 100644 linux-next-pending/0009-bnxt_re-Fix-race-between-the-netdev-register-and-unr.patch create mode 100644 linux-next-pending/0010-bnxt_re-Fix-memory-leak-in-FRMR-path.patch create mode 100644 linux-next-pending/0011-bnxt_re-Don-t-issue-cmd-to-delete-GID-for-QP1-GID-en.patch diff --git a/linux-next-cherry-picks/0057-RDMA-bnxt_re-Allocate-multiple-notification-queues.patch b/linux-next-cherry-picks/0057-RDMA-bnxt_re-Allocate-multiple-notification-queues.patch new file mode 100644 index 0000000..649dbad --- /dev/null +++ b/linux-next-cherry-picks/0057-RDMA-bnxt_re-Allocate-multiple-notification-queues.patch @@ -0,0 +1,368 @@ +From 51b369d812cbf75c413f6013ad0cc21c74a8506a Mon Sep 17 00:00:00 2001 +From: Selvin Xavier +Date: Sun, 30 Jul 2017 19:57:18 -0700 +Subject: [PATCH 1/9] RDMA/bnxt_re: Allocate multiple notification queues + +Enables multiple Interrupt vectors. Driver is requesting the max +MSIX vectors based on the number of online cpus and creates upto +9 MSIx vectors (1 for control path and 8 for data path). +A tasklet is created for each of these vectors. NQs are assigned +to CQs in round robin fashion. +This patch also adds IRQ affinity hint for the MSIX vector of each NQ. + +Signed-off-by: Ray Jui +Signed-off-by: Selvin Xavier +Signed-off-by: Doug Ledford +--- + drivers/infiniband/hw/bnxt_re/bnxt_re.h | 5 +- + drivers/infiniband/hw/bnxt_re/ib_verbs.c | 17 +++-- + drivers/infiniband/hw/bnxt_re/main.c | 106 +++++++++++++++++++------------ + drivers/infiniband/hw/bnxt_re/qplib_fp.c | 21 +++++- + drivers/infiniband/hw/bnxt_re/qplib_fp.h | 4 +- + 5 files changed, 104 insertions(+), 49 deletions(-) + +diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h +index 805088b..c7095c4 100644 +--- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h ++++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h +@@ -89,7 +89,7 @@ struct bnxt_re_sqp_entries { + }; + + #define BNXT_RE_MIN_MSIX 2 +-#define BNXT_RE_MAX_MSIX 16 ++#define BNXT_RE_MAX_MSIX 9 + #define BNXT_RE_AEQ_IDX 0 + #define BNXT_RE_NQ_IDX 1 + +@@ -120,7 +120,7 @@ struct bnxt_re_dev { + struct bnxt_qplib_rcfw rcfw; + + /* NQ */ +- struct bnxt_qplib_nq nq; ++ struct bnxt_qplib_nq nq[BNXT_RE_MAX_MSIX]; + + /* Device Resources */ + struct bnxt_qplib_dev_attr dev_attr; +@@ -144,6 +144,7 @@ struct bnxt_re_dev { + struct bnxt_re_qp *qp1_sqp; + struct bnxt_re_ah *sqp_ah; + struct bnxt_re_sqp_entries sqp_tbl[1024]; ++ atomic_t nq_alloc_cnt; + }; + + #define to_bnxt_re_dev(ptr, member) \ +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +index cc53e6d..97c3343 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +@@ -2356,6 +2356,7 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq) + struct bnxt_re_cq *cq = container_of(ib_cq, struct bnxt_re_cq, ib_cq); + struct bnxt_re_dev *rdev = cq->rdev; + int rc; ++ struct bnxt_qplib_nq *nq = cq->qplib_cq.nq; + + rc = bnxt_qplib_destroy_cq(&rdev->qplib_res, &cq->qplib_cq); + if (rc) { +@@ -2370,7 +2371,7 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq) + kfree(cq); + } + atomic_dec(&rdev->cq_count); +- rdev->nq.budget--; ++ nq->budget--; + return 0; + } + +@@ -2384,6 +2385,8 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev, + struct bnxt_re_cq *cq = NULL; + int rc, entries; + int cqe = attr->cqe; ++ struct bnxt_qplib_nq *nq = NULL; ++ unsigned int nq_alloc_cnt; + + /* Validate CQ fields */ + if (cqe < 1 || cqe > dev_attr->max_cq_wqes) { +@@ -2435,9 +2438,15 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev, + cq->qplib_cq.sghead = NULL; + cq->qplib_cq.nmap = 0; + } ++ /* ++ * Allocating the NQ in a round robin fashion. nq_alloc_cnt is a ++ * used for getting the NQ index. ++ */ ++ nq_alloc_cnt = atomic_inc_return(&rdev->nq_alloc_cnt); ++ nq = &rdev->nq[nq_alloc_cnt % (rdev->num_msix - 1)]; + cq->qplib_cq.max_wqe = entries; +- cq->qplib_cq.cnq_hw_ring_id = rdev->nq.ring_id; +- cq->qplib_cq.nq = &rdev->nq; ++ cq->qplib_cq.cnq_hw_ring_id = nq->ring_id; ++ cq->qplib_cq.nq = nq; + + rc = bnxt_qplib_create_cq(&rdev->qplib_res, &cq->qplib_cq); + if (rc) { +@@ -2447,7 +2456,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev, + + cq->ib_cq.cqe = entries; + cq->cq_period = cq->qplib_cq.period; +- rdev->nq.budget++; ++ nq->budget++; + + atomic_inc(&rdev->cq_count); + +diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c +index ea89024..91e584e 100644 +--- a/drivers/infiniband/hw/bnxt_re/main.c ++++ b/drivers/infiniband/hw/bnxt_re/main.c +@@ -163,7 +163,7 @@ static int bnxt_re_free_msix(struct bnxt_re_dev *rdev, bool lock_wait) + + static int bnxt_re_request_msix(struct bnxt_re_dev *rdev) + { +- int rc = 0, num_msix_want = BNXT_RE_MIN_MSIX, num_msix_got; ++ int rc = 0, num_msix_want = BNXT_RE_MAX_MSIX, num_msix_got; + struct bnxt_en_dev *en_dev; + + if (!rdev) +@@ -171,6 +171,8 @@ static int bnxt_re_request_msix(struct bnxt_re_dev *rdev) + + en_dev = rdev->en_dev; + ++ num_msix_want = min_t(u32, BNXT_RE_MAX_MSIX, num_online_cpus()); ++ + rtnl_lock(); + num_msix_got = en_dev->en_ops->bnxt_request_msix(en_dev, BNXT_ROCE_ULP, + rdev->msix_entries, +@@ -654,8 +656,12 @@ static int bnxt_re_cqn_handler(struct bnxt_qplib_nq *nq, + + static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev) + { +- if (rdev->nq.hwq.max_elements) +- bnxt_qplib_disable_nq(&rdev->nq); ++ int i; ++ ++ if (rdev->nq[0].hwq.max_elements) { ++ for (i = 1; i < rdev->num_msix; i++) ++ bnxt_qplib_disable_nq(&rdev->nq[i - 1]); ++ } + + if (rdev->qplib_res.rcfw) + bnxt_qplib_cleanup_res(&rdev->qplib_res); +@@ -663,31 +669,41 @@ static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev) + + static int bnxt_re_init_res(struct bnxt_re_dev *rdev) + { +- int rc = 0; ++ int rc = 0, i; + + bnxt_qplib_init_res(&rdev->qplib_res); + +- if (rdev->msix_entries[BNXT_RE_NQ_IDX].vector <= 0) +- return -EINVAL; ++ for (i = 1; i < rdev->num_msix ; i++) { ++ rc = bnxt_qplib_enable_nq(rdev->en_dev->pdev, &rdev->nq[i - 1], ++ i - 1, rdev->msix_entries[i].vector, ++ rdev->msix_entries[i].db_offset, ++ &bnxt_re_cqn_handler, NULL); + +- rc = bnxt_qplib_enable_nq(rdev->en_dev->pdev, &rdev->nq, +- rdev->msix_entries[BNXT_RE_NQ_IDX].vector, +- rdev->msix_entries[BNXT_RE_NQ_IDX].db_offset, +- &bnxt_re_cqn_handler, +- NULL); ++ if (rc) { ++ dev_err(rdev_to_dev(rdev), ++ "Failed to enable NQ with rc = 0x%x", rc); ++ goto fail; ++ } ++ } ++ return 0; ++fail: ++ return rc; ++} + +- if (rc) +- dev_err(rdev_to_dev(rdev), "Failed to enable NQ: %#x", rc); ++static void bnxt_re_free_nq_res(struct bnxt_re_dev *rdev, bool lock_wait) ++{ ++ int i; + +- return rc; ++ for (i = 0; i < rdev->num_msix - 1; i++) { ++ bnxt_re_net_ring_free(rdev, rdev->nq[i].ring_id, lock_wait); ++ bnxt_qplib_free_nq(&rdev->nq[i]); ++ } + } + + static void bnxt_re_free_res(struct bnxt_re_dev *rdev, bool lock_wait) + { +- if (rdev->nq.hwq.max_elements) { +- bnxt_re_net_ring_free(rdev, rdev->nq.ring_id, lock_wait); +- bnxt_qplib_free_nq(&rdev->nq); +- } ++ bnxt_re_free_nq_res(rdev, lock_wait); ++ + if (rdev->qplib_res.dpi_tbl.max) { + bnxt_qplib_dealloc_dpi(&rdev->qplib_res, + &rdev->qplib_res.dpi_tbl, +@@ -701,7 +717,7 @@ static void bnxt_re_free_res(struct bnxt_re_dev *rdev, bool lock_wait) + + static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) + { +- int rc = 0; ++ int rc = 0, i; + + /* Configure and allocate resources for qplib */ + rdev->qplib_res.rcfw = &rdev->rcfw; +@@ -718,30 +734,42 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) + &rdev->dpi_privileged, + rdev); + if (rc) +- goto fail; ++ goto dealloc_res; + +- rdev->nq.hwq.max_elements = BNXT_RE_MAX_CQ_COUNT + +- BNXT_RE_MAX_SRQC_COUNT + 2; +- rc = bnxt_qplib_alloc_nq(rdev->en_dev->pdev, &rdev->nq); +- if (rc) { +- dev_err(rdev_to_dev(rdev), +- "Failed to allocate NQ memory: %#x", rc); +- goto fail; +- } +- rc = bnxt_re_net_ring_alloc +- (rdev, rdev->nq.hwq.pbl[PBL_LVL_0].pg_map_arr, +- rdev->nq.hwq.pbl[rdev->nq.hwq.level].pg_count, +- HWRM_RING_ALLOC_CMPL, BNXT_QPLIB_NQE_MAX_CNT - 1, +- rdev->msix_entries[BNXT_RE_NQ_IDX].ring_idx, +- &rdev->nq.ring_id); +- if (rc) { +- dev_err(rdev_to_dev(rdev), +- "Failed to allocate NQ ring: %#x", rc); +- goto free_nq; ++ for (i = 0; i < rdev->num_msix - 1; i++) { ++ rdev->nq[i].hwq.max_elements = BNXT_RE_MAX_CQ_COUNT + ++ BNXT_RE_MAX_SRQC_COUNT + 2; ++ rc = bnxt_qplib_alloc_nq(rdev->en_dev->pdev, &rdev->nq[i]); ++ if (rc) { ++ dev_err(rdev_to_dev(rdev), "Alloc Failed NQ%d rc:%#x", ++ i, rc); ++ goto dealloc_dpi; ++ } ++ rc = bnxt_re_net_ring_alloc ++ (rdev, rdev->nq[i].hwq.pbl[PBL_LVL_0].pg_map_arr, ++ rdev->nq[i].hwq.pbl[rdev->nq[i].hwq.level].pg_count, ++ HWRM_RING_ALLOC_CMPL, ++ BNXT_QPLIB_NQE_MAX_CNT - 1, ++ rdev->msix_entries[i + 1].ring_idx, ++ &rdev->nq[i].ring_id); ++ if (rc) { ++ dev_err(rdev_to_dev(rdev), ++ "Failed to allocate NQ fw id with rc = 0x%x", ++ rc); ++ goto free_nq; ++ } + } + return 0; + free_nq: +- bnxt_qplib_free_nq(&rdev->nq); ++ for (i = 0; i < rdev->num_msix - 1; i++) ++ bnxt_qplib_free_nq(&rdev->nq[i]); ++dealloc_dpi: ++ bnxt_qplib_dealloc_dpi(&rdev->qplib_res, ++ &rdev->qplib_res.dpi_tbl, ++ &rdev->dpi_privileged); ++dealloc_res: ++ bnxt_qplib_free_res(&rdev->qplib_res); ++ + fail: + rdev->qplib_res.rcfw = NULL; + return rc; +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +index 31e15f3..e8afc47 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +@@ -365,6 +365,7 @@ void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq) + tasklet_kill(&nq->worker); + + if (nq->requested) { ++ irq_set_affinity_hint(nq->vector, NULL); + free_irq(nq->vector, nq); + nq->requested = false; + } +@@ -378,7 +379,7 @@ void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq) + } + + int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, +- int msix_vector, int bar_reg_offset, ++ int nq_idx, int msix_vector, int bar_reg_offset, + int (*cqn_handler)(struct bnxt_qplib_nq *nq, + struct bnxt_qplib_cq *), + int (*srqn_handler)(struct bnxt_qplib_nq *nq, +@@ -402,13 +403,25 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, + goto fail; + + nq->requested = false; +- rc = request_irq(nq->vector, bnxt_qplib_nq_irq, 0, "bnxt_qplib_nq", nq); ++ memset(nq->name, 0, 32); ++ sprintf(nq->name, "bnxt_qplib_nq-%d", nq_idx); ++ rc = request_irq(nq->vector, bnxt_qplib_nq_irq, 0, nq->name, nq); + if (rc) { + dev_err(&nq->pdev->dev, + "Failed to request IRQ for NQ: %#x", rc); + bnxt_qplib_disable_nq(nq); + goto fail; + } ++ ++ cpumask_clear(&nq->mask); ++ cpumask_set_cpu(nq_idx, &nq->mask); ++ rc = irq_set_affinity_hint(nq->vector, &nq->mask); ++ if (rc) { ++ dev_warn(&nq->pdev->dev, ++ "QPLIB: set affinity failed; vector: %d nq_idx: %d\n", ++ nq->vector, nq_idx); ++ } ++ + nq->requested = true; + nq->bar_reg = NQ_CONS_PCI_BAR_REGION; + nq->bar_reg_off = bar_reg_offset; +@@ -432,8 +445,10 @@ fail: + + void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq) + { +- if (nq->hwq.max_elements) ++ if (nq->hwq.max_elements) { + bnxt_qplib_free_hwq(nq->pdev, &nq->hwq); ++ nq->hwq.max_elements = 0; ++ } + } + + int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq) +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h +index 23a26d5..8ead70c 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h +@@ -407,6 +407,7 @@ struct bnxt_qplib_nq { + struct pci_dev *pdev; + + int vector; ++ cpumask_t mask; + int budget; + bool requested; + struct tasklet_struct worker; +@@ -425,6 +426,7 @@ struct bnxt_qplib_nq { + void *srq, + u8 event); + struct workqueue_struct *cqn_wq; ++ char name[32]; + }; + + struct bnxt_qplib_nq_work { +@@ -435,7 +437,7 @@ struct bnxt_qplib_nq_work { + + void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq); + int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, +- int msix_vector, int bar_reg_offset, ++ int nq_idx, int msix_vector, int bar_reg_offset, + int (*cqn_handler)(struct bnxt_qplib_nq *nq, + struct bnxt_qplib_cq *cq), + int (*srqn_handler)(struct bnxt_qplib_nq *nq, +-- +1.8.3.1 + diff --git a/linux-next-cherry-picks/0058-RDMA-bnxt_re-Implement-the-alloc-get_hw_stats-callba.patch b/linux-next-cherry-picks/0058-RDMA-bnxt_re-Implement-the-alloc-get_hw_stats-callba.patch new file mode 100644 index 0000000..bfe62e8 --- /dev/null +++ b/linux-next-cherry-picks/0058-RDMA-bnxt_re-Implement-the-alloc-get_hw_stats-callba.patch @@ -0,0 +1,243 @@ +From 1ff20f41833618b9e67af709c38a00b4dc2188e2 Mon Sep 17 00:00:00 2001 +From: Somnath Kotur +Date: Mon, 31 Jul 2017 02:15:30 -0700 +Subject: [PATCH 2/9] RDMA/bnxt_re: Implement the alloc/get_hw_stats callback + +Expose HW counters using the get_hw_stats callback + +Signed-off-by: Somnath Kotur +Signed-off-by: Selvin Xavier +Reviewed-by: Leon Romanovsky +Signed-off-by: Doug Ledford +--- + drivers/infiniband/hw/bnxt_re/Makefile | 2 +- + drivers/infiniband/hw/bnxt_re/hw_counters.c | 114 ++++++++++++++++++++++++++++ + drivers/infiniband/hw/bnxt_re/hw_counters.h | 62 +++++++++++++++ + drivers/infiniband/hw/bnxt_re/main.c | 4 + + 4 files changed, 181 insertions(+), 1 deletion(-) + create mode 100644 drivers/infiniband/hw/bnxt_re/hw_counters.c + create mode 100644 drivers/infiniband/hw/bnxt_re/hw_counters.h + +diff --git a/drivers/infiniband/hw/bnxt_re/Makefile b/drivers/infiniband/hw/bnxt_re/Makefile +index b7ff61f..bc61365 100644 +--- a/drivers/infiniband/hw/bnxt_re/Makefile ++++ b/drivers/infiniband/hw/bnxt_re/Makefile +@@ -3,4 +3,4 @@ ccflags-y := -I$(CWD)/drivers/net/ethernet/broadcom/bnxt + obj-$(CONFIG_INFINIBAND_BNXT_RE) += bnxt_re.o + bnxt_re-y := main.o ib_verbs.o \ + qplib_res.o qplib_rcfw.o \ +- qplib_sp.o qplib_fp.o ++ qplib_sp.o qplib_fp.o hw_counters.o +diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c +new file mode 100644 +index 0000000..7b28219 +--- /dev/null ++++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c +@@ -0,0 +1,114 @@ ++/* ++ * Broadcom NetXtreme-E RoCE driver. ++ * ++ * Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term ++ * Broadcom refers to Broadcom Limited and/or its subsidiaries. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE ++ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN ++ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Description: Statistics ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "bnxt_ulp.h" ++#include "roce_hsi.h" ++#include "qplib_res.h" ++#include "qplib_sp.h" ++#include "qplib_fp.h" ++#include "qplib_rcfw.h" ++#include "bnxt_re.h" ++#include "hw_counters.h" ++ ++static const char * const bnxt_re_stat_name[] = { ++ [BNXT_RE_ACTIVE_QP] = "active_qps", ++ [BNXT_RE_ACTIVE_SRQ] = "active_srqs", ++ [BNXT_RE_ACTIVE_CQ] = "active_cqs", ++ [BNXT_RE_ACTIVE_MR] = "active_mrs", ++ [BNXT_RE_ACTIVE_MW] = "active_mws", ++ [BNXT_RE_RX_PKTS] = "rx_pkts", ++ [BNXT_RE_RX_BYTES] = "rx_bytes", ++ [BNXT_RE_TX_PKTS] = "tx_pkts", ++ [BNXT_RE_TX_BYTES] = "tx_bytes", ++ [BNXT_RE_RECOVERABLE_ERRORS] = "recoverable_errors" ++}; ++ ++int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, ++ struct rdma_hw_stats *stats, ++ u8 port, int index) ++{ ++ struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev); ++ struct ctx_hw_stats *bnxt_re_stats = rdev->qplib_ctx.stats.dma; ++ ++ if (!port || !stats) ++ return -EINVAL; ++ ++ stats->value[BNXT_RE_ACTIVE_QP] = atomic_read(&rdev->qp_count); ++ stats->value[BNXT_RE_ACTIVE_SRQ] = atomic_read(&rdev->srq_count); ++ stats->value[BNXT_RE_ACTIVE_CQ] = atomic_read(&rdev->cq_count); ++ stats->value[BNXT_RE_ACTIVE_MR] = atomic_read(&rdev->mr_count); ++ stats->value[BNXT_RE_ACTIVE_MW] = atomic_read(&rdev->mw_count); ++ if (bnxt_re_stats) { ++ stats->value[BNXT_RE_RECOVERABLE_ERRORS] = ++ le64_to_cpu(bnxt_re_stats->tx_bcast_pkts); ++ stats->value[BNXT_RE_RX_PKTS] = ++ le64_to_cpu(bnxt_re_stats->rx_ucast_pkts); ++ stats->value[BNXT_RE_RX_BYTES] = ++ le64_to_cpu(bnxt_re_stats->rx_ucast_bytes); ++ stats->value[BNXT_RE_TX_PKTS] = ++ le64_to_cpu(bnxt_re_stats->tx_ucast_pkts); ++ stats->value[BNXT_RE_TX_BYTES] = ++ le64_to_cpu(bnxt_re_stats->tx_ucast_bytes); ++ } ++ return ARRAY_SIZE(bnxt_re_stat_name); ++} ++ ++struct rdma_hw_stats *bnxt_re_ib_alloc_hw_stats(struct ib_device *ibdev, ++ u8 port_num) ++{ ++ BUILD_BUG_ON(ARRAY_SIZE(bnxt_re_stat_name) != BNXT_RE_NUM_COUNTERS); ++ /* We support only per port stats */ ++ if (!port_num) ++ return NULL; ++ ++ return rdma_alloc_hw_stats_struct(bnxt_re_stat_name, ++ ARRAY_SIZE(bnxt_re_stat_name), ++ RDMA_HW_STATS_DEFAULT_LIFESPAN); ++} +diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h +new file mode 100644 +index 0000000..be0dc00 +--- /dev/null ++++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h +@@ -0,0 +1,62 @@ ++/* ++ * Broadcom NetXtreme-E RoCE driver. ++ * ++ * Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term ++ * Broadcom refers to Broadcom Limited and/or its subsidiaries. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE ++ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN ++ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Description: Statistics (header) ++ * ++ */ ++ ++#ifndef __BNXT_RE_HW_STATS_H__ ++#define __BNXT_RE_HW_STATS_H__ ++ ++enum bnxt_re_hw_stats { ++ BNXT_RE_ACTIVE_QP, ++ BNXT_RE_ACTIVE_SRQ, ++ BNXT_RE_ACTIVE_CQ, ++ BNXT_RE_ACTIVE_MR, ++ BNXT_RE_ACTIVE_MW, ++ BNXT_RE_RX_PKTS, ++ BNXT_RE_RX_BYTES, ++ BNXT_RE_TX_PKTS, ++ BNXT_RE_TX_BYTES, ++ BNXT_RE_RECOVERABLE_ERRORS, ++ BNXT_RE_NUM_COUNTERS ++}; ++ ++struct rdma_hw_stats *bnxt_re_ib_alloc_hw_stats(struct ib_device *ibdev, ++ u8 port_num); ++int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, ++ struct rdma_hw_stats *stats, ++ u8 port, int index); ++#endif /* __BNXT_RE_HW_STATS_H__ */ +diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c +index 91e584e..922565e 100644 +--- a/drivers/infiniband/hw/bnxt_re/main.c ++++ b/drivers/infiniband/hw/bnxt_re/main.c +@@ -65,6 +65,8 @@ + #include "ib_verbs.h" + #include + #include "bnxt.h" ++#include "hw_counters.h" ++ + static char version[] = + BNXT_RE_DESC " v" ROCE_DRV_MODULE_VERSION "\n"; + +@@ -516,6 +518,8 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev) + ibdev->alloc_ucontext = bnxt_re_alloc_ucontext; + ibdev->dealloc_ucontext = bnxt_re_dealloc_ucontext; + ibdev->mmap = bnxt_re_mmap; ++ ibdev->get_hw_stats = bnxt_re_ib_get_hw_stats; ++ ibdev->alloc_hw_stats = bnxt_re_ib_alloc_hw_stats; + + return ib_register_device(ibdev, NULL); + } +-- +1.8.3.1 + diff --git a/linux-next-pending/0005-bnxt_re-Fix-update-of-qplib_qp.mtu-when-modified.patch b/linux-next-pending/0005-bnxt_re-Fix-update-of-qplib_qp.mtu-when-modified.patch new file mode 100644 index 0000000..39e8425 --- /dev/null +++ b/linux-next-pending/0005-bnxt_re-Fix-update-of-qplib_qp.mtu-when-modified.patch @@ -0,0 +1,39 @@ +From f957acb58c6baac68afd181810ac69f94a1216d7 Mon Sep 17 00:00:00 2001 +From: Devesh Sharma +Date: Thu, 24 Aug 2017 14:21:55 +0530 +Subject: [PATCH 3/9] bnxt_re: Fix update of qplib_qp.mtu when modified + +The MTU value in the qplib_qp.mtu should be +consistent with whatever mtu was set during +INIT to RTR.The Next PSN and number of packets +are calculated based on this member in the qplib_qp structure. + +Signed-off-by: Narender Reddy +Signed-off-by: Devesh Sharma +Signed-off-by: Somnath Kotur +--- + drivers/infiniband/hw/bnxt_re/ib_verbs.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +index 97c3343..27235f2 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +@@ -1504,11 +1504,14 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, + qp->qplib_qp.modify_flags |= + CMDQ_MODIFY_QP_MODIFY_MASK_PATH_MTU; + qp->qplib_qp.path_mtu = __from_ib_mtu(qp_attr->path_mtu); ++ qp->qplib_qp.mtu = ib_mtu_enum_to_int(qp_attr->path_mtu); + } else if (qp_attr->qp_state == IB_QPS_RTR) { + qp->qplib_qp.modify_flags |= + CMDQ_MODIFY_QP_MODIFY_MASK_PATH_MTU; + qp->qplib_qp.path_mtu = + __from_ib_mtu(iboe_get_mtu(rdev->netdev->mtu)); ++ qp->qplib_qp.mtu = ++ ib_mtu_enum_to_int(iboe_get_mtu(rdev->netdev->mtu)); + } + + if (qp_attr_mask & IB_QP_TIMEOUT) { +-- +1.8.3.1 + diff --git a/linux-next-pending/0006-bnxt_re-Stop-issuing-further-cmds-to-FW-once-a-cmd-t.patch b/linux-next-pending/0006-bnxt_re-Stop-issuing-further-cmds-to-FW-once-a-cmd-t.patch new file mode 100644 index 0000000..cc59cb4 --- /dev/null +++ b/linux-next-pending/0006-bnxt_re-Stop-issuing-further-cmds-to-FW-once-a-cmd-t.patch @@ -0,0 +1,58 @@ +From 976ef742be965ec507694748646beb9c29db2d2d Mon Sep 17 00:00:00 2001 +From: Somnath Kotur +Date: Thu, 24 Aug 2017 15:02:13 +0530 +Subject: [PATCH 4/9] bnxt_re: Stop issuing further cmds to FW once a cmd times + out + +Once a cmd to FW times out(after 20s) it is reasonable to +assume the FW or atleast the control path is dead. +No point issuing further cmds to the FW as each subsequent cmd +with another 20s timeout will cascade resulting in unnecessary +traces and/or NMI Lockups. + +Signed-off-by: Somnath Kotur +--- + drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 4 ++++ + drivers/infiniband/hw/bnxt_re/qplib_rcfw.h | 3 ++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +index 391bb70..2bdb156 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +@@ -107,6 +107,9 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, + return -EINVAL; + } + ++ if (test_bit(FIRMWARE_TIMED_OUT, &rcfw->flags)) ++ return -ETIMEDOUT; ++ + /* Cmdq are in 16-byte units, each request can consume 1 or more + * cmdqe + */ +@@ -226,6 +229,7 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, + /* timed out */ + dev_err(&rcfw->pdev->dev, "QPLIB: cmdq[%#x]=%#x timedout (%d)msec", + cookie, opcode, RCFW_CMD_WAIT_TIME_MS); ++ set_bit(FIRMWARE_TIMED_OUT, &rcfw->flags); + return rc; + } + +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +index 0ed312f..85b16da 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +@@ -162,8 +162,9 @@ struct bnxt_qplib_rcfw { + unsigned long *cmdq_bitmap; + u32 bmap_size; + unsigned long flags; +-#define FIRMWARE_INITIALIZED_FLAG 1 ++#define FIRMWARE_INITIALIZED_FLAG BIT(0) + #define FIRMWARE_FIRST_FLAG BIT(31) ++#define FIRMWARE_TIMED_OUT BIT(3) + wait_queue_head_t waitq; + int (*aeq_handler)(struct bnxt_qplib_rcfw *, + struct creq_func_event *); +-- +1.8.3.1 + diff --git a/linux-next-pending/0007-bnxt_re-Fix-compare-and-swap-atomic-operands.patch b/linux-next-pending/0007-bnxt_re-Fix-compare-and-swap-atomic-operands.patch new file mode 100644 index 0000000..ffd124b --- /dev/null +++ b/linux-next-pending/0007-bnxt_re-Fix-compare-and-swap-atomic-operands.patch @@ -0,0 +1,30 @@ +From fc14e62c1c9264ad8031d48be47c4dcbdacde50b Mon Sep 17 00:00:00 2001 +From: Devesh Sharma +Date: Thu, 24 Aug 2017 15:13:01 +0530 +Subject: [PATCH 5/9] bnxt_re: Fix compare and swap atomic operands + +Driver must assign the user supplied compare/swap values in +the wqe to successfully complete the atomic compare and +swap operation. + +Signed-off-by: Devesh Sharma +Signed-off-by: Somnath Kotur +--- + drivers/infiniband/hw/bnxt_re/ib_verbs.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +index 27235f2..101b6ec 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +@@ -1979,6 +1979,7 @@ static int bnxt_re_build_atomic_wqe(struct ib_send_wr *wr, + switch (wr->opcode) { + case IB_WR_ATOMIC_CMP_AND_SWP: + wqe->type = BNXT_QPLIB_SWQE_TYPE_ATOMIC_CMP_AND_SWP; ++ wqe->atomic.cmp_data = atomic_wr(wr)->compare_add; + wqe->atomic.swap_data = atomic_wr(wr)->swap; + break; + case IB_WR_ATOMIC_FETCH_AND_ADD: +-- +1.8.3.1 + diff --git a/linux-next-pending/0008-bnxt_re-Free-up-devices-in-module_exit-path.patch b/linux-next-pending/0008-bnxt_re-Free-up-devices-in-module_exit-path.patch new file mode 100644 index 0000000..41f9c50 --- /dev/null +++ b/linux-next-pending/0008-bnxt_re-Free-up-devices-in-module_exit-path.patch @@ -0,0 +1,43 @@ +From 02c7a08645e0b65fc7ae3b4e5e40ef1b1a0846fb Mon Sep 17 00:00:00 2001 +From: Somnath Kotur +Date: Wed, 30 Aug 2017 09:33:29 +0530 +Subject: [PATCH 6/9] bnxt_re: Free up devices in module_exit path + +Clean up all devices added to the bnxt_re_dev_list in the +module_exit entry point. + +Signed-off-by: Somnath Kotur +--- + drivers/infiniband/hw/bnxt_re/main.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c +index 922565e..918e2ca 100644 +--- a/drivers/infiniband/hw/bnxt_re/main.c ++++ b/drivers/infiniband/hw/bnxt_re/main.c +@@ -1378,6 +1378,22 @@ err_netdev: + + static void __exit bnxt_re_mod_exit(void) + { ++ struct bnxt_re_dev *rdev; ++ LIST_HEAD(to_be_deleted); ++ ++ mutex_lock(&bnxt_re_dev_lock); ++ /* Free all adapter allocated resources */ ++ if (!list_empty(&bnxt_re_dev_list)) ++ list_splice_init(&bnxt_re_dev_list, &to_be_deleted); ++ mutex_unlock(&bnxt_re_dev_lock); ++ ++ list_for_each_entry(rdev, &to_be_deleted, list) { ++ dev_info(rdev_to_dev(rdev), "Unregistering Device"); ++ bnxt_re_dev_stop(rdev); ++ bnxt_re_ib_unreg(rdev, true); ++ bnxt_re_remove_one(rdev); ++ bnxt_re_dev_unreg(rdev); ++ } + unregister_netdevice_notifier(&bnxt_re_netdev_notifier); + if (bnxt_re_wq) + destroy_workqueue(bnxt_re_wq); +-- +1.8.3.1 + diff --git a/linux-next-pending/0009-bnxt_re-Fix-race-between-the-netdev-register-and-unr.patch b/linux-next-pending/0009-bnxt_re-Fix-race-between-the-netdev-register-and-unr.patch new file mode 100644 index 0000000..d6aa31c --- /dev/null +++ b/linux-next-pending/0009-bnxt_re-Fix-race-between-the-netdev-register-and-unr.patch @@ -0,0 +1,84 @@ +From accf29a7b3bc4de2b91d98c5da7ede6313742018 Mon Sep 17 00:00:00 2001 +From: Somnath Kotur +Date: Mon, 28 Aug 2017 13:55:17 +0530 +Subject: [PATCH 7/9] bnxt_re: Fix race between the netdev register and + unregister events + +Upon receipt of the NETDEV_REGISTER event from the netdev notifier chain, +the IB stack registration is spawned off to a workqueue since that also +requires an rtnl lock. +There could be 2 kinds of races between the NETDEV_REGISTER and the +NETDEV_UNREGISTER event handling. +a)The NETDEV_UNREGISTER event is received in rapid succession after +the NETDEV_REGISTER event even before the work queue got a chance to run. +b)The NETDEV_UNREGISTER event is received while the workqueue that handles +registration with the IB stack is still in progress. +Handle both the races with a bit flag that is set just before the work item +is queued and cleared in the workqueue after the event is handled just +before the workqueue item is freed. + +Signed-off-by: Somnath Kotur +--- + drivers/infiniband/hw/bnxt_re/bnxt_re.h | 12 +++++++----- + drivers/infiniband/hw/bnxt_re/main.c | 8 ++++++++ + 2 files changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h +index c7095c4..a8e931c 100644 +--- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h ++++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h +@@ -97,11 +97,13 @@ struct bnxt_re_dev { + struct ib_device ibdev; + struct list_head list; + unsigned long flags; +-#define BNXT_RE_FLAG_NETDEV_REGISTERED 0 +-#define BNXT_RE_FLAG_IBDEV_REGISTERED 1 +-#define BNXT_RE_FLAG_GOT_MSIX 2 +-#define BNXT_RE_FLAG_RCFW_CHANNEL_EN 8 +-#define BNXT_RE_FLAG_QOS_WORK_REG 16 ++#define BNXT_RE_FLAG_NETDEV_REGISTERED 0 ++#define BNXT_RE_FLAG_IBDEV_REGISTERED 1 ++#define BNXT_RE_FLAG_GOT_MSIX 2 ++#define BNXT_RE_FLAG_HAVE_L2_REF 3 ++#define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4 ++#define BNXT_RE_FLAG_QOS_WORK_REG 5 ++#define BNXT_RE_FLAG_TASK_IN_PROG 6 + struct net_device *netdev; + unsigned int version, major, minor; + struct bnxt_en_dev *en_dev; +diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c +index 918e2ca..76ac061 100644 +--- a/drivers/infiniband/hw/bnxt_re/main.c ++++ b/drivers/infiniband/hw/bnxt_re/main.c +@@ -1262,6 +1262,8 @@ static void bnxt_re_task(struct work_struct *work) + default: + break; + } ++ smp_mb__before_atomic(); ++ clear_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags); + kfree(re_work); + } + +@@ -1320,6 +1322,11 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier, + break; + + case NETDEV_UNREGISTER: ++ /* netdev notifier will call NETDEV_UNREGISTER again later since ++ * we are still holding the reference to the netdev ++ */ ++ if (test_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags)) ++ goto exit; + bnxt_re_ib_unreg(rdev, false); + bnxt_re_remove_one(rdev); + bnxt_re_dev_unreg(rdev); +@@ -1338,6 +1345,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier, + re_work->vlan_dev = (real_dev == netdev ? + NULL : netdev); + INIT_WORK(&re_work->work, bnxt_re_task); ++ set_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags); + queue_work(bnxt_re_wq, &re_work->work); + } + } +-- +1.8.3.1 + diff --git a/linux-next-pending/0010-bnxt_re-Fix-memory-leak-in-FRMR-path.patch b/linux-next-pending/0010-bnxt_re-Fix-memory-leak-in-FRMR-path.patch new file mode 100644 index 0000000..6c91f38 --- /dev/null +++ b/linux-next-pending/0010-bnxt_re-Fix-memory-leak-in-FRMR-path.patch @@ -0,0 +1,36 @@ +From 7dca8017cf003bc87e40020aa9324792c9437be8 Mon Sep 17 00:00:00 2001 +From: Selvin Xavier +Date: Thu, 24 Aug 2017 15:17:22 +0530 +Subject: [PATCH 8/9] bnxt_re: Fix memory leak in FRMR path + +This patch fixes a memory leak issue when alloc_mr is used. +mr->pages and mr->npages are used only in alloc_mr path. mr->pages +is allocated when alloc_mr is called or in the case of FRMR, while +creating the MR. mr->npages is updated only when the MR created +is used i.e. after invoking map_mr_sg verb, before data transfer. +In the dereg_mr path, if mr->npages is 0, driver ends up not freeing +the memory created. +Removing the npages check from the dereg_mr path for kernel consumers. + +Signed-off-by: Selvin Xavier +Signed-off-by: Somnath Kotur +--- + drivers/infiniband/hw/bnxt_re/ib_verbs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +index 101b6ec..5697df2 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +@@ -3134,7 +3134,7 @@ int bnxt_re_dereg_mr(struct ib_mr *ib_mr) + return rc; + } + +- if (mr->npages && mr->pages) { ++ if (mr->pages) { + rc = bnxt_qplib_free_fast_reg_page_list(&rdev->qplib_res, + &mr->qplib_frpl); + kfree(mr->pages); +-- +1.8.3.1 + diff --git a/linux-next-pending/0011-bnxt_re-Don-t-issue-cmd-to-delete-GID-for-QP1-GID-en.patch b/linux-next-pending/0011-bnxt_re-Don-t-issue-cmd-to-delete-GID-for-QP1-GID-en.patch new file mode 100644 index 0000000..e717387 --- /dev/null +++ b/linux-next-pending/0011-bnxt_re-Don-t-issue-cmd-to-delete-GID-for-QP1-GID-en.patch @@ -0,0 +1,69 @@ +From 12773a01423842b4c90eec1050c3773121fe5e43 Mon Sep 17 00:00:00 2001 +From: Somnath Kotur +Date: Thu, 24 Aug 2017 15:37:23 +0530 +Subject: [PATCH 9/9] bnxt_re: Don't issue cmd to delete GID for QP1 GID entry + before the QP is destroyed + +FW needs the 0th GID Entry in the Table to be preserved before +it's corresponding QP1 is deleted, else it will fail the cmd. +Check for the same and return to prevent error msg being logged for +cmd failure. + +Signed-off-by: Somnath Kotur +--- + drivers/infiniband/hw/bnxt_re/ib_verbs.c | 23 ++++++++++++++++++++--- + 1 file changed, 20 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +index 5697df2..dcddf19 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +@@ -388,6 +388,7 @@ int bnxt_re_del_gid(struct ib_device *ibdev, u8 port_num, + struct bnxt_re_gid_ctx *ctx, **ctx_tbl; + struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev); + struct bnxt_qplib_sgid_tbl *sgid_tbl = &rdev->qplib_res.sgid_tbl; ++ struct bnxt_qplib_gid *gid_to_del; + + /* Delete the entry from the hardware */ + ctx = *context; +@@ -397,11 +398,25 @@ int bnxt_re_del_gid(struct ib_device *ibdev, u8 port_num, + if (sgid_tbl && sgid_tbl->active) { + if (ctx->idx >= sgid_tbl->max) + return -EINVAL; ++ gid_to_del = &sgid_tbl->tbl[ctx->idx]; ++ /* DEL_GID is called in WQ context(netdevice_event_work_handler) ++ * or via the ib_unregister_device path. In the former case QP1 ++ * may not be destroyed yet, in which case just return as FW ++ * needs that entry to be present and will fail it's deletion. ++ * We could get invoked again after QP1 is destroyed OR get an ++ * ADD_GID call with a different GID value for the same index ++ * where we issue MODIFY_GID cmd to update the GID entry -- TBD ++ */ ++ if (ctx->idx == 0 && ++ rdma_link_local_addr((struct in6_addr *)gid_to_del) && ++ ctx->refcnt == 1 && rdev->qp1_sqp) { ++ dev_dbg(rdev_to_dev(rdev), ++ "Trying to delete GID0 while QP1 is alive\n"); ++ return -EFAULT; ++ } + ctx->refcnt--; + if (!ctx->refcnt) { +- rc = bnxt_qplib_del_sgid(sgid_tbl, +- &sgid_tbl->tbl[ctx->idx], +- true); ++ rc = bnxt_qplib_del_sgid(sgid_tbl, gid_to_del, true); + if (rc) { + dev_err(rdev_to_dev(rdev), + "Failed to remove GID: %#x", rc); +@@ -883,6 +898,8 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp) + + kfree(rdev->sqp_ah); + kfree(rdev->qp1_sqp); ++ rdev->qp1_sqp = NULL; ++ rdev->sqp_ah = NULL; + } + + if (!IS_ERR_OR_NULL(qp->rumem)) +-- +1.8.3.1 + -- 2.46.0