bnxt_en: Handle no aggregation ring gracefully.
authorMichael Chan <michael.chan@broadcom.com>
Thu, 29 Dec 2016 17:13:43 +0000 (12:13 -0500)
committerDavid S. Miller <davem@davemloft.net>
Thu, 29 Dec 2016 19:37:23 +0000 (14:37 -0500)
The current code assumes that we will always have at least 2 rx rings, 1
will be used as an aggregation ring for TPA and jumbo page placements.
However, it is possible, especially on a VF, that there is only 1 rx
ring available.  In this scenario, the current code will fail to initialize.
To handle it, we need to properly set up only 1 ring without aggregation.
Set a new flag BNXT_FLAG_NO_AGG_RINGS for this condition and add logic to
set up the chip to place RX data linearly into a single buffer per packet.

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
drivers/net/ethernet/broadcom/bnxt/bnxt.h

index 1f54a7a..98e9484 100644 (file)
@@ -2496,7 +2496,7 @@ void bnxt_set_ring_params(struct bnxt *bp)
                agg_factor = min_t(u32, 4, 65536 / BNXT_RX_PAGE_SIZE);
 
        bp->flags &= ~BNXT_FLAG_JUMBO;
-       if (rx_space > PAGE_SIZE) {
+       if (rx_space > PAGE_SIZE && !(bp->flags & BNXT_FLAG_NO_AGG_RINGS)) {
                u32 jumbo_factor;
 
                bp->flags |= BNXT_FLAG_JUMBO;
@@ -6174,6 +6174,9 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features)
        if (features & NETIF_F_LRO)
                flags |= BNXT_FLAG_LRO;
 
+       if (bp->flags & BNXT_FLAG_NO_AGG_RINGS)
+               flags &= ~BNXT_FLAG_TPA;
+
        if (features & NETIF_F_HW_VLAN_CTAG_RX)
                flags |= BNXT_FLAG_STRIP_VLAN;
 
@@ -7040,8 +7043,17 @@ static int bnxt_get_dflt_rings(struct bnxt *bp, int *max_rx, int *max_tx,
        int rc;
 
        rc = bnxt_get_max_rings(bp, max_rx, max_tx, shared);
-       if (rc)
-               return rc;
+       if (rc && (bp->flags & BNXT_FLAG_AGG_RINGS)) {
+               /* Not enough rings, try disabling agg rings. */
+               bp->flags &= ~BNXT_FLAG_AGG_RINGS;
+               rc = bnxt_get_max_rings(bp, max_rx, max_tx, shared);
+               if (rc)
+                       return rc;
+               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);
+       }
 
        if (bp->flags & BNXT_FLAG_ROCE_CAP) {
                int max_cp, max_stat, max_irq;
@@ -7236,7 +7248,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        bnxt_set_tpa_flags(bp);
        bnxt_set_ring_params(bp);
        bnxt_set_max_func_irqs(bp, max_irqs);
-       bnxt_set_dflt_rings(bp);
+       rc = bnxt_set_dflt_rings(bp);
+       if (rc) {
+               netdev_err(bp->dev, "Not enough rings available.\n");
+               rc = -ENOMEM;
+               goto init_err;
+       }
 
        /* Default RSS hash cfg. */
        bp->rss_hash_cfg = VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4 |
index d174729..f6b9b1c 100644 (file)
@@ -950,6 +950,7 @@ struct bnxt {
        #define BNXT_FLAG_ROCEV2_CAP    0x10000
        #define BNXT_FLAG_ROCE_CAP      (BNXT_FLAG_ROCEV1_CAP | \
                                         BNXT_FLAG_ROCEV2_CAP)
+       #define BNXT_FLAG_NO_AGG_RINGS  0x20000
        #define BNXT_FLAG_CHIP_NITRO_A0 0x1000000
 
        #define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA |             \