bnxt_en: Implement new method to reserve rings.
authorMichael Chan <michael.chan@broadcom.com>
Wed, 17 Jan 2018 08:21:09 +0000 (03:21 -0500)
committerDavid S. Miller <davem@davemloft.net>
Wed, 17 Jan 2018 19:48:26 +0000 (14:48 -0500)
The new method will call firmware to reserve the desired tx, rx, cmpl
rings, ring groups, stats context, and vnic resources.  A second query
call will check the actual resources that firmware is able to reserve.
The driver will then trim and adjust based on the actual resources
provided by firmware.  The driver will then reserve the final resources
in use.

This method is a more flexible way of using hardware resources.  The
resources are not fixed and can by adjusted by firmware.  The driver
adapts to the available resources that the firmware can reserve for
the driver.

Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnxt/bnxt.c

index 177c8f59892ba837cebe96397648c59f047dd697..6fc324f35df082471a7f19ae6ca16b887d5e34ed 100644 (file)
@@ -4498,6 +4498,42 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
        }
 }
 
+static int bnxt_hwrm_get_rings(struct bnxt *bp)
+{
+       struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
+       struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
+       struct hwrm_func_qcfg_input req = {0};
+       int rc;
+
+       if (bp->hwrm_spec_code < 0x10601)
+               return 0;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCFG, -1, -1);
+       req.fid = cpu_to_le16(0xffff);
+       mutex_lock(&bp->hwrm_cmd_lock);
+       rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (rc) {
+               mutex_unlock(&bp->hwrm_cmd_lock);
+               return -EIO;
+       }
+
+       hw_resc->resv_tx_rings = le16_to_cpu(resp->alloc_tx_rings);
+       if (bp->flags & BNXT_FLAG_NEW_RM) {
+               u16 cp, stats;
+
+               hw_resc->resv_rx_rings = le16_to_cpu(resp->alloc_rx_rings);
+               hw_resc->resv_hw_ring_grps =
+                       le32_to_cpu(resp->alloc_hw_ring_grps);
+               hw_resc->resv_vnics = le16_to_cpu(resp->alloc_vnics);
+               cp = le16_to_cpu(resp->alloc_cmpl_rings);
+               stats = le16_to_cpu(resp->alloc_stat_ctx);
+               cp = min_t(u16, cp, stats);
+               hw_resc->resv_cp_rings = cp;
+       }
+       mutex_unlock(&bp->hwrm_cmd_lock);
+       return 0;
+}
+
 /* Caller must hold bp->hwrm_cmd_lock */
 int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings)
 {
@@ -4517,33 +4553,190 @@ int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings)
        return rc;
 }
 
-static int bnxt_hwrm_reserve_tx_rings(struct bnxt *bp, int *tx_rings)
+static int
+bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
+                          int ring_grps, int cp_rings, int vnics)
 {
        struct hwrm_func_cfg_input req = {0};
+       u32 enables = 0;
        int rc;
 
-       if (bp->hwrm_spec_code < 0x10601)
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
+       req.fid = cpu_to_le16(0xffff);
+       enables |= tx_rings ? FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS : 0;
+       req.num_tx_rings = cpu_to_le16(tx_rings);
+       if (bp->flags & BNXT_FLAG_NEW_RM) {
+               enables |= rx_rings ? FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS : 0;
+               enables |= cp_rings ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
+                                     FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
+               enables |= ring_grps ?
+                          FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0;
+               enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0;
+
+               req.num_rx_rings = cpu_to_le16(rx_rings);
+               req.num_hw_ring_grps = cpu_to_le16(ring_grps);
+               req.num_cmpl_rings = cpu_to_le16(cp_rings);
+               req.num_stat_ctxs = req.num_cmpl_rings;
+               req.num_vnics = cpu_to_le16(vnics);
+       }
+       if (!enables)
                return 0;
 
-       if (BNXT_VF(bp))
+       req.enables = cpu_to_le32(enables);
+       rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (rc)
+               return -ENOMEM;
+
+       if (bp->hwrm_spec_code < 0x10601)
+               bp->hw_resc.resv_tx_rings = tx_rings;
+
+       rc = bnxt_hwrm_get_rings(bp);
+       return rc;
+}
+
+static int
+bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
+                          int ring_grps, int cp_rings, int vnics)
+{
+       struct hwrm_func_vf_cfg_input req = {0};
+       u32 enables = 0;
+       int rc;
+
+       if (!(bp->flags & BNXT_FLAG_NEW_RM)) {
+               bp->hw_resc.resv_tx_rings = tx_rings;
                return 0;
+       }
 
-       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
-       req.fid = cpu_to_le16(0xffff);
-       req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS);
-       req.num_tx_rings = cpu_to_le16(*tx_rings);
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_CFG, -1, -1);
+       enables |= tx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_TX_RINGS : 0;
+       enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS : 0;
+       enables |= cp_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
+                             FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
+       enables |= ring_grps ? FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0;
+       enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0;
+
+       req.num_tx_rings = cpu_to_le16(tx_rings);
+       req.num_rx_rings = cpu_to_le16(rx_rings);
+       req.num_hw_ring_grps = cpu_to_le16(ring_grps);
+       req.num_cmpl_rings = cpu_to_le16(cp_rings);
+       req.num_stat_ctxs = req.num_cmpl_rings;
+       req.num_vnics = cpu_to_le16(vnics);
+
+       req.enables = cpu_to_le32(enables);
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (rc)
+               return -ENOMEM;
+
+       rc = bnxt_hwrm_get_rings(bp);
+       return rc;
+}
+
+static int bnxt_hwrm_reserve_rings(struct bnxt *bp, int tx, int rx, int grp,
+                                  int cp, int vnic)
+{
+       if (BNXT_PF(bp))
+               return bnxt_hwrm_reserve_pf_rings(bp, tx, rx, grp, cp, vnic);
+       else
+               return bnxt_hwrm_reserve_vf_rings(bp, tx, rx, grp, cp, vnic);
+}
+
+static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max,
+                          bool shared);
+
+static int __bnxt_reserve_rings(struct bnxt *bp)
+{
+       struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
+       int tx = bp->tx_nr_rings;
+       int rx = bp->rx_nr_rings;
+       int cp = bp->cp_nr_rings;
+       int grp, rx_rings, rc;
+       bool sh = false;
+       int vnic = 1;
+
+       if (bp->hwrm_spec_code < 0x10601)
+               return 0;
+
+       if (bp->flags & BNXT_FLAG_SHARED_RINGS)
+               sh = true;
+       if (bp->flags & BNXT_FLAG_RFS)
+               vnic = rx + 1;
+       if (bp->flags & BNXT_FLAG_AGG_RINGS)
+               rx <<= 1;
+
+       grp = bp->rx_nr_rings;
+       if (tx == hw_resc->resv_tx_rings &&
+           (!(bp->flags & BNXT_FLAG_NEW_RM) ||
+             (rx == hw_resc->resv_rx_rings &&
+              grp == hw_resc->resv_hw_ring_grps &&
+              cp == hw_resc->resv_cp_rings && vnic == hw_resc->resv_vnics)))
+               return 0;
+
+       rc = bnxt_hwrm_reserve_rings(bp, tx, rx, grp, cp, vnic);
        if (rc)
                return rc;
 
-       mutex_lock(&bp->hwrm_cmd_lock);
-       rc = __bnxt_hwrm_get_tx_rings(bp, 0xffff, tx_rings);
-       mutex_unlock(&bp->hwrm_cmd_lock);
-       if (!rc)
-               bp->hw_resc.resv_tx_rings = *tx_rings;
+       tx = hw_resc->resv_tx_rings;
+       if (bp->flags & BNXT_FLAG_NEW_RM) {
+               rx = hw_resc->resv_rx_rings;
+               cp = hw_resc->resv_cp_rings;
+               grp = hw_resc->resv_hw_ring_grps;
+               vnic = hw_resc->resv_vnics;
+       }
+
+       rx_rings = rx;
+       if (bp->flags & BNXT_FLAG_AGG_RINGS) {
+               if (rx >= 2) {
+                       rx_rings = rx >> 1;
+               } else {
+                       if (netif_running(bp->dev))
+                               return -ENOMEM;
+
+                       bp->flags &= ~BNXT_FLAG_AGG_RINGS;
+                       bp->flags |= BNXT_FLAG_NO_AGG_RINGS;
+                       bp->dev->hw_features &= ~NETIF_F_LRO;
+                       bp->dev->features &= ~NETIF_F_LRO;
+                       bnxt_set_ring_params(bp);
+               }
+       }
+       rx_rings = min_t(int, rx_rings, grp);
+       rc = bnxt_trim_rings(bp, &rx_rings, &tx, cp, sh);
+       if (bp->flags & BNXT_FLAG_AGG_RINGS)
+               rx = rx_rings << 1;
+       cp = sh ? max_t(int, tx, rx_rings) : tx + rx_rings;
+       bp->tx_nr_rings = tx;
+       bp->rx_nr_rings = rx_rings;
+       bp->cp_nr_rings = cp;
+
+       if (!tx || !rx || !cp || !grp || !vnic)
+               return -ENOMEM;
+
        return rc;
 }
 
+static bool bnxt_need_reserve_rings(struct bnxt *bp)
+{
+       struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
+       int rx = bp->rx_nr_rings;
+       int vnic = 1;
+
+       if (bp->hwrm_spec_code < 0x10601)
+               return false;
+
+       if (hw_resc->resv_tx_rings != bp->tx_nr_rings)
+               return true;
+
+       if (bp->flags & BNXT_FLAG_RFS)
+               vnic = rx + 1;
+       if (bp->flags & BNXT_FLAG_AGG_RINGS)
+               rx <<= 1;
+       if ((bp->flags & BNXT_FLAG_NEW_RM) &&
+           (hw_resc->resv_rx_rings != rx ||
+            hw_resc->resv_cp_rings != bp->cp_nr_rings ||
+            hw_resc->resv_vnics != vnic))
+               return true;
+       return false;
+}
+
 static int bnxt_hwrm_check_tx_rings(struct bnxt *bp, int tx_rings)
 {
        struct hwrm_func_cfg_input req = {0};
@@ -5270,15 +5463,6 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
                                   rc);
                        goto err_out;
                }
-               if (bp->hw_resc.resv_tx_rings != bp->tx_nr_rings) {
-                       int tx = bp->tx_nr_rings;
-
-                       if (bnxt_hwrm_reserve_tx_rings(bp, &tx) ||
-                           tx < bp->tx_nr_rings) {
-                               rc = -ENOMEM;
-                               goto err_out;
-                       }
-               }
        }
 
        rc = bnxt_hwrm_ring_alloc(bp);
@@ -5637,6 +5821,36 @@ static void bnxt_clear_int_mode(struct bnxt *bp)
        bp->flags &= ~BNXT_FLAG_USING_MSIX;
 }
 
+static int bnxt_reserve_rings(struct bnxt *bp)
+{
+       int orig_cp = bp->hw_resc.resv_cp_rings;
+       int tcs = netdev_get_num_tc(bp->dev);
+       int rc;
+
+       if (!bnxt_need_reserve_rings(bp))
+               return 0;
+
+       rc = __bnxt_reserve_rings(bp);
+       if (rc) {
+               netdev_err(bp->dev, "ring reservation failure rc: %d\n", rc);
+               return rc;
+       }
+       if ((bp->flags & BNXT_FLAG_NEW_RM) && bp->cp_nr_rings > orig_cp) {
+               bnxt_clear_int_mode(bp);
+               rc = bnxt_init_int_mode(bp);
+               if (rc)
+                       return rc;
+       }
+       if (tcs && (bp->tx_nr_rings_per_tc * tcs != bp->tx_nr_rings)) {
+               netdev_err(bp->dev, "tx ring reservation failure\n");
+               netdev_reset_tc(bp->dev);
+               bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
+               return -ENOMEM;
+       }
+       bp->num_stat_ctxs = bp->cp_nr_rings;
+       return 0;
+}
+
 static void bnxt_free_irq(struct bnxt *bp)
 {
        struct bnxt_irq *irq;
@@ -6387,6 +6601,10 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
        bnxt_preset_reg_win(bp);
        netif_carrier_off(bp->dev);
        if (irq_re_init) {
+               rc = bnxt_reserve_rings(bp);
+               if (rc)
+                       return rc;
+
                rc = bnxt_setup_int_mode(bp);
                if (rc) {
                        netdev_err(bp->dev, "bnxt_setup_int_mode err: %x\n",
@@ -8062,16 +8280,20 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
                bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings;
        bp->tx_nr_rings = bp->tx_nr_rings_per_tc;
 
-       rc = bnxt_hwrm_reserve_tx_rings(bp, &bp->tx_nr_rings_per_tc);
+       rc = __bnxt_reserve_rings(bp);
        if (rc)
                netdev_warn(bp->dev, "Unable to reserve tx rings\n");
        bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
        if (sh)
                bnxt_trim_dflt_sh_rings(bp);
 
-       bp->tx_nr_rings = bp->tx_nr_rings_per_tc;
-       bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) :
-                              bp->tx_nr_rings + bp->rx_nr_rings;
+       /* Rings may have been trimmed, re-reserve the trimmed rings. */
+       if (bnxt_need_reserve_rings(bp)) {
+               rc = __bnxt_reserve_rings(bp);
+               if (rc)
+                       netdev_warn(bp->dev, "2nd rings reservation failed.\n");
+               bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
+       }
        bp->num_stat_ctxs = bp->cp_nr_rings;
        if (BNXT_CHIP_TYPE_NITRO_A0(bp)) {
                bp->rx_nr_rings++;