aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/broadcom/bnx2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnx2.c')
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c106
1 files changed, 94 insertions, 12 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 021fb818007a..7105989ba658 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -2625,10 +2625,8 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2625 u32 val; 2625 u32 val;
2626 2626
2627 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL); 2627 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2628 if (good_mbuf == NULL) { 2628 if (good_mbuf == NULL)
2629 pr_err("Failed to allocate memory in %s\n", __func__);
2630 return -ENOMEM; 2629 return -ENOMEM;
2631 }
2632 2630
2633 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, 2631 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2634 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE); 2632 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
@@ -6248,7 +6246,16 @@ static int
6248bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi) 6246bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6249{ 6247{
6250 int cpus = num_online_cpus(); 6248 int cpus = num_online_cpus();
6251 int msix_vecs = min(cpus + 1, RX_MAX_RINGS); 6249 int msix_vecs;
6250
6251 if (!bp->num_req_rx_rings)
6252 msix_vecs = max(cpus + 1, bp->num_req_tx_rings);
6253 else if (!bp->num_req_tx_rings)
6254 msix_vecs = max(cpus, bp->num_req_rx_rings);
6255 else
6256 msix_vecs = max(bp->num_req_rx_rings, bp->num_req_tx_rings);
6257
6258 msix_vecs = min(msix_vecs, RX_MAX_RINGS);
6252 6259
6253 bp->irq_tbl[0].handler = bnx2_interrupt; 6260 bp->irq_tbl[0].handler = bnx2_interrupt;
6254 strcpy(bp->irq_tbl[0].name, bp->dev->name); 6261 strcpy(bp->irq_tbl[0].name, bp->dev->name);
@@ -6272,10 +6279,18 @@ bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6272 } 6279 }
6273 } 6280 }
6274 6281
6275 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs); 6282 if (!bp->num_req_tx_rings)
6283 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6284 else
6285 bp->num_tx_rings = min(bp->irq_nvecs, bp->num_req_tx_rings);
6286
6287 if (!bp->num_req_rx_rings)
6288 bp->num_rx_rings = bp->irq_nvecs;
6289 else
6290 bp->num_rx_rings = min(bp->irq_nvecs, bp->num_req_rx_rings);
6291
6276 netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings); 6292 netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings);
6277 6293
6278 bp->num_rx_rings = bp->irq_nvecs;
6279 return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings); 6294 return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings);
6280} 6295}
6281 6296
@@ -6550,6 +6565,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6550 } 6565 }
6551 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END; 6566 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6552 6567
6568 /* Sync BD data before updating TX mailbox */
6569 wmb();
6570
6553 netdev_tx_sent_queue(txq, skb->len); 6571 netdev_tx_sent_queue(txq, skb->len);
6554 6572
6555 prod = NEXT_TX_BD(prod); 6573 prod = NEXT_TX_BD(prod);
@@ -7164,7 +7182,7 @@ bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7164} 7182}
7165 7183
7166static int 7184static int
7167bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx) 7185bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx, bool reset_irq)
7168{ 7186{
7169 if (netif_running(bp->dev)) { 7187 if (netif_running(bp->dev)) {
7170 /* Reset will erase chipset stats; save them */ 7188 /* Reset will erase chipset stats; save them */
@@ -7172,7 +7190,12 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
7172 7190
7173 bnx2_netif_stop(bp, true); 7191 bnx2_netif_stop(bp, true);
7174 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); 7192 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
7175 __bnx2_free_irq(bp); 7193 if (reset_irq) {
7194 bnx2_free_irq(bp);
7195 bnx2_del_napi(bp);
7196 } else {
7197 __bnx2_free_irq(bp);
7198 }
7176 bnx2_free_skbs(bp); 7199 bnx2_free_skbs(bp);
7177 bnx2_free_mem(bp); 7200 bnx2_free_mem(bp);
7178 } 7201 }
@@ -7181,9 +7204,16 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
7181 bp->tx_ring_size = tx; 7204 bp->tx_ring_size = tx;
7182 7205
7183 if (netif_running(bp->dev)) { 7206 if (netif_running(bp->dev)) {
7184 int rc; 7207 int rc = 0;
7208
7209 if (reset_irq) {
7210 rc = bnx2_setup_int_mode(bp, disable_msi);
7211 bnx2_init_napi(bp);
7212 }
7213
7214 if (!rc)
7215 rc = bnx2_alloc_mem(bp);
7185 7216
7186 rc = bnx2_alloc_mem(bp);
7187 if (!rc) 7217 if (!rc)
7188 rc = bnx2_request_irq(bp); 7218 rc = bnx2_request_irq(bp);
7189 7219
@@ -7219,7 +7249,8 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7219 7249
7220 return -EINVAL; 7250 return -EINVAL;
7221 } 7251 }
7222 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending); 7252 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending,
7253 false);
7223 return rc; 7254 return rc;
7224} 7255}
7225 7256
@@ -7607,6 +7638,54 @@ bnx2_set_features(struct net_device *dev, netdev_features_t features)
7607 return 0; 7638 return 0;
7608} 7639}
7609 7640
7641static void bnx2_get_channels(struct net_device *dev,
7642 struct ethtool_channels *channels)
7643{
7644 struct bnx2 *bp = netdev_priv(dev);
7645 u32 max_rx_rings = 1;
7646 u32 max_tx_rings = 1;
7647
7648 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7649 max_rx_rings = RX_MAX_RINGS;
7650 max_tx_rings = TX_MAX_RINGS;
7651 }
7652
7653 channels->max_rx = max_rx_rings;
7654 channels->max_tx = max_tx_rings;
7655 channels->max_other = 0;
7656 channels->max_combined = 0;
7657 channels->rx_count = bp->num_rx_rings;
7658 channels->tx_count = bp->num_tx_rings;
7659 channels->other_count = 0;
7660 channels->combined_count = 0;
7661}
7662
7663static int bnx2_set_channels(struct net_device *dev,
7664 struct ethtool_channels *channels)
7665{
7666 struct bnx2 *bp = netdev_priv(dev);
7667 u32 max_rx_rings = 1;
7668 u32 max_tx_rings = 1;
7669 int rc = 0;
7670
7671 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7672 max_rx_rings = RX_MAX_RINGS;
7673 max_tx_rings = TX_MAX_RINGS;
7674 }
7675 if (channels->rx_count > max_rx_rings ||
7676 channels->tx_count > max_tx_rings)
7677 return -EINVAL;
7678
7679 bp->num_req_rx_rings = channels->rx_count;
7680 bp->num_req_tx_rings = channels->tx_count;
7681
7682 if (netif_running(dev))
7683 rc = bnx2_change_ring_size(bp, bp->rx_ring_size,
7684 bp->tx_ring_size, true);
7685
7686 return rc;
7687}
7688
7610static const struct ethtool_ops bnx2_ethtool_ops = { 7689static const struct ethtool_ops bnx2_ethtool_ops = {
7611 .get_settings = bnx2_get_settings, 7690 .get_settings = bnx2_get_settings,
7612 .set_settings = bnx2_set_settings, 7691 .set_settings = bnx2_set_settings,
@@ -7631,6 +7710,8 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
7631 .set_phys_id = bnx2_set_phys_id, 7710 .set_phys_id = bnx2_set_phys_id,
7632 .get_ethtool_stats = bnx2_get_ethtool_stats, 7711 .get_ethtool_stats = bnx2_get_ethtool_stats,
7633 .get_sset_count = bnx2_get_sset_count, 7712 .get_sset_count = bnx2_get_sset_count,
7713 .get_channels = bnx2_get_channels,
7714 .set_channels = bnx2_set_channels,
7634}; 7715};
7635 7716
7636/* Called with rtnl_lock */ 7717/* Called with rtnl_lock */
@@ -7712,7 +7793,8 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu)
7712 return -EINVAL; 7793 return -EINVAL;
7713 7794
7714 dev->mtu = new_mtu; 7795 dev->mtu = new_mtu;
7715 return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size); 7796 return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size,
7797 false);
7716} 7798}
7717 7799
7718#ifdef CONFIG_NET_POLL_CONTROLLER 7800#ifdef CONFIG_NET_POLL_CONTROLLER