diff options
author | Michael Chan <michael.chan@broadcom.com> | 2018-03-31 20:54:21 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-01 06:24:20 +0300 |
commit | ec86f14ea5064e36ee111297bdb376dda4cba264 (patch) | |
tree | 36c5c4d46beff5912a23f55b65bdb5cafc95f7f1 /drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | |
parent | fbcfc8e4674156cb7eb3d8054bd4332142d2cc58 (diff) | |
download | linux-ec86f14ea5064e36ee111297bdb376dda4cba264.tar.xz |
bnxt_en: Add ULP calls to stop and restart IRQs.
When the driver needs to re-initailize the IRQ vectors, we make the
new ulp_irq_stop() call to tell the RDMA driver to disable and free
the IRQ vectors. After IRQ vectors have been re-initailized, we
make the ulp_irq_restart() call to tell the RDMA driver that
IRQs can be restarted.
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 81 |
1 files changed, 74 insertions, 7 deletions
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index 2583923df5a1..347e4f946eb2 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -1,6 +1,6 @@ /* Broadcom NetXtreme-C/E network driver. * - * Copyright (c) 2016 Broadcom Limited + * Copyright (c) 2016-2018 Broadcom Limited * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -101,13 +101,27 @@ static int bnxt_unregister_dev(struct bnxt_en_dev *edev, int ulp_id) return 0; } +static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent) +{ + struct bnxt_en_dev *edev = bp->edev; + int num_msix, idx, i; + + num_msix = edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested; + idx = edev->ulp_tbl[BNXT_ROCE_ULP].msix_base; + for (i = 0; i < num_msix; i++) { + ent[i].vector = bp->irq_tbl[idx + i].vector; + ent[i].ring_idx = idx + i; + ent[i].db_offset = (idx + i) * 0x80; + } +} + static int bnxt_req_msix_vecs(struct bnxt_en_dev *edev, int ulp_id, struct bnxt_msix_entry *ent, int num_msix) { struct net_device *dev = edev->net; struct bnxt *bp = netdev_priv(dev); int max_idx, max_cp_rings; - int avail_msix, i, idx; + int avail_msix, idx; int rc = 0; ASSERT_RTNL(); @@ -154,13 +168,10 @@ static int bnxt_req_msix_vecs(struct bnxt_en_dev *edev, int ulp_id, avail_msix = hw_resc->resv_cp_rings - bp->cp_nr_rings; edev->ulp_tbl[ulp_id].msix_requested = avail_msix; } - for (i = 0; i < avail_msix; i++) { - ent[i].vector = bp->irq_tbl[idx + i].vector; - ent[i].ring_idx = idx + i; - ent[i].db_offset = (idx + i) * 0x80; - } + bnxt_fill_msix_vecs(bp, ent); bnxt_set_max_func_irqs(bp, bnxt_get_max_func_irqs(bp) - avail_msix); bnxt_set_max_func_cp_rings(bp, max_cp_rings - avail_msix); + edev->flags |= BNXT_EN_FLAG_MSIX_REQUESTED; return avail_msix; } @@ -174,11 +185,15 @@ static int bnxt_free_msix_vecs(struct bnxt_en_dev *edev, int ulp_id) if (ulp_id != BNXT_ROCE_ULP) return -EINVAL; + if (!(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED)) + return 0; + max_cp_rings = bnxt_get_max_func_cp_rings(bp); msix_requested = edev->ulp_tbl[ulp_id].msix_requested; bnxt_set_max_func_cp_rings(bp, max_cp_rings + msix_requested); edev->ulp_tbl[ulp_id].msix_requested = 0; bnxt_set_max_func_irqs(bp, bnxt_get_max_func_irqs(bp) + msix_requested); + edev->flags &= ~BNXT_EN_FLAG_MSIX_REQUESTED; if (netif_running(dev)) { bnxt_close_nic(bp, true, false); bnxt_open_nic(bp, true, false); @@ -340,6 +355,58 @@ void bnxt_ulp_shutdown(struct bnxt *bp) } } +void bnxt_ulp_irq_stop(struct bnxt *bp) +{ + struct bnxt_en_dev *edev = bp->edev; + struct bnxt_ulp_ops *ops; + + if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED)) + return; + + if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) { + struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP]; + + if (!ulp->msix_requested) + return; + + ops = rtnl_dereference(ulp->ulp_ops); + if (!ops || !ops->ulp_irq_stop) + return; + ops->ulp_irq_stop(ulp->handle); + } +} + +void bnxt_ulp_irq_restart(struct bnxt *bp, int err) +{ + struct bnxt_en_dev *edev = bp->edev; + struct bnxt_ulp_ops *ops; + + if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED)) + return; + + if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) { + struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP]; + struct bnxt_msix_entry *ent = NULL; + + if (!ulp->msix_requested) + return; + + ops = rtnl_dereference(ulp->ulp_ops); + if (!ops || !ops->ulp_irq_restart) + return; + + if (!err) { + ent = kcalloc(ulp->msix_requested, sizeof(*ent), + GFP_KERNEL); + if (!ent) + return; + bnxt_fill_msix_vecs(bp, ent); + } + ops->ulp_irq_restart(ulp->handle, ent); + kfree(ent); + } +} + void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl) { u16 event_id = le16_to_cpu(cmpl->event_id); |