bnxt_re: Adding bug fix patches
authorSelvin Xavier <selvin.xavier@broadcom.com>
Tue, 5 Sep 2017 18:07:30 +0000 (11:07 -0700)
committerSelvin Xavier <selvin.xavier@broadcom.com>
Tue, 5 Sep 2017 18:07:30 +0000 (11:07 -0700)
Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
linux-next-cherry-picks/0057-RDMA-bnxt_re-Allocate-multiple-notification-queues.patch [new file with mode: 0644]
linux-next-cherry-picks/0058-RDMA-bnxt_re-Implement-the-alloc-get_hw_stats-callba.patch [new file with mode: 0644]
linux-next-pending/0005-bnxt_re-Fix-update-of-qplib_qp.mtu-when-modified.patch [new file with mode: 0644]
linux-next-pending/0006-bnxt_re-Stop-issuing-further-cmds-to-FW-once-a-cmd-t.patch [new file with mode: 0644]
linux-next-pending/0007-bnxt_re-Fix-compare-and-swap-atomic-operands.patch [new file with mode: 0644]
linux-next-pending/0008-bnxt_re-Free-up-devices-in-module_exit-path.patch [new file with mode: 0644]
linux-next-pending/0009-bnxt_re-Fix-race-between-the-netdev-register-and-unr.patch [new file with mode: 0644]
linux-next-pending/0010-bnxt_re-Fix-memory-leak-in-FRMR-path.patch [new file with mode: 0644]
linux-next-pending/0011-bnxt_re-Don-t-issue-cmd-to-delete-GID-for-QP1-GID-en.patch [new file with mode: 0644]

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 (file)
index 0000000..649dbad
--- /dev/null
@@ -0,0 +1,368 @@
+From 51b369d812cbf75c413f6013ad0cc21c74a8506a Mon Sep 17 00:00:00 2001
+From: Selvin Xavier <selvin.xavier@broadcom.com>
+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 <ray.jui@broadcom.com>
+Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+---
+ 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 (file)
index 0000000..bfe62e8
--- /dev/null
@@ -0,0 +1,243 @@
+From 1ff20f41833618b9e67af709c38a00b4dc2188e2 Mon Sep 17 00:00:00 2001
+From: Somnath Kotur <somnath.kotur@broadcom.com>
+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 <somnath.kotur@broadcom.com>
+Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
+Reviewed-by: Leon Romanovsky <leonro@mellanox.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+---
+ 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 <linux/interrupt.h>
++#include <linux/types.h>
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/prefetch.h>
++#include <linux/delay.h>
++
++#include <rdma/ib_addr.h>
++
++#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 <rdma/bnxt_re-abi.h>
+ #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 (file)
index 0000000..39e8425
--- /dev/null
@@ -0,0 +1,39 @@
+From f957acb58c6baac68afd181810ac69f94a1216d7 Mon Sep 17 00:00:00 2001
+From: Devesh Sharma <devesh.sharma@broadcom.com>
+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 <narender.reddy@broadcom.com>
+Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com>
+Signed-off-by: Somnath Kotur <somnath.kotur@broadcom.com>
+---
+ 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 (file)
index 0000000..cc59cb4
--- /dev/null
@@ -0,0 +1,58 @@
+From 976ef742be965ec507694748646beb9c29db2d2d Mon Sep 17 00:00:00 2001
+From: Somnath Kotur <somnath.kotur@broadcom.com>
+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 <somnath.kotur@broadcom.com>
+---
+ 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 (file)
index 0000000..ffd124b
--- /dev/null
@@ -0,0 +1,30 @@
+From fc14e62c1c9264ad8031d48be47c4dcbdacde50b Mon Sep 17 00:00:00 2001
+From: Devesh Sharma <devesh.sharma@broadcom.com>
+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 <devesh.sharma@broadcom.com>
+Signed-off-by: Somnath Kotur <somnath.kotur@broadcom.com>
+---
+ 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 (file)
index 0000000..41f9c50
--- /dev/null
@@ -0,0 +1,43 @@
+From 02c7a08645e0b65fc7ae3b4e5e40ef1b1a0846fb Mon Sep 17 00:00:00 2001
+From: Somnath Kotur <somnath.kotur@broadcom.com>
+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 <somnath.kotur@broadcom.com>
+---
+ 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 (file)
index 0000000..d6aa31c
--- /dev/null
@@ -0,0 +1,84 @@
+From accf29a7b3bc4de2b91d98c5da7ede6313742018 Mon Sep 17 00:00:00 2001
+From: Somnath Kotur <somnath.kotur@broadcom.com>
+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 <somnath.kotur@broadcom.com>
+---
+ 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 (file)
index 0000000..6c91f38
--- /dev/null
@@ -0,0 +1,36 @@
+From 7dca8017cf003bc87e40020aa9324792c9437be8 Mon Sep 17 00:00:00 2001
+From: Selvin Xavier <selvin.xavier@broadcom.com>
+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 <selvin.xavier@broadcom.com>
+Signed-off-by: Somnath Kotur <somnath.kotur@broadcom.com>
+---
+ 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 (file)
index 0000000..e717387
--- /dev/null
@@ -0,0 +1,69 @@
+From 12773a01423842b4c90eec1050c3773121fe5e43 Mon Sep 17 00:00:00 2001
+From: Somnath Kotur <somnath.kotur@broadcom.com>
+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 <somnath.kotur@broadcom.com>
+---
+ 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
+