diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnx2.c')
| -rw-r--r-- | drivers/net/ethernet/broadcom/bnx2.c | 138 | 
1 files changed, 92 insertions, 46 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index e838a3f74b6..67d2b004737 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -23,7 +23,6 @@  #include <linux/vmalloc.h>  #include <linux/interrupt.h>  #include <linux/pci.h> -#include <linux/init.h>  #include <linux/netdevice.h>  #include <linux/etherdevice.h>  #include <linux/skbuff.h> @@ -58,8 +57,8 @@  #include "bnx2_fw.h"  #define DRV_MODULE_NAME		"bnx2" -#define DRV_MODULE_VERSION	"2.2.4" -#define DRV_MODULE_RELDATE	"Aug 05, 2013" +#define DRV_MODULE_VERSION	"2.2.5" +#define DRV_MODULE_RELDATE	"December 20, 2013"  #define FW_MIPS_FILE_06		"bnx2/bnx2-mips-06-6.2.3.fw"  #define FW_RV2P_FILE_06		"bnx2/bnx2-rv2p-06-6.0.15.fw"  #define FW_MIPS_FILE_09		"bnx2/bnx2-mips-09-6.2.1b.fw" @@ -86,7 +85,7 @@ MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax);  static int disable_msi = 0; -module_param(disable_msi, int, 0); +module_param(disable_msi, int, S_IRUGO);  MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");  typedef enum { @@ -1197,6 +1196,8 @@ bnx2_copper_linkup(struct bnx2 *bp)  {  	u32 bmcr; +	bp->phy_flags &= ~BNX2_PHY_FLAG_MDIX; +  	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);  	if (bmcr & BMCR_ANENABLE) {  		u32 local_adv, remote_adv, common; @@ -1255,6 +1256,14 @@ bnx2_copper_linkup(struct bnx2 *bp)  		}  	} +	if (bp->link_up) { +		u32 ext_status; + +		bnx2_read_phy(bp, MII_BNX2_EXT_STATUS, &ext_status); +		if (ext_status & EXT_STATUS_MDIX) +			bp->phy_flags |= BNX2_PHY_FLAG_MDIX; +	} +  	return 0;  } @@ -2048,29 +2057,27 @@ bnx2_setup_copper_phy(struct bnx2 *bp)  __releases(&bp->phy_lock)  __acquires(&bp->phy_lock)  { -	u32 bmcr; +	u32 bmcr, adv_reg, new_adv = 0;  	u32 new_bmcr;  	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); +	bnx2_read_phy(bp, bp->mii_adv, &adv_reg); +	adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP | +		    ADVERTISE_PAUSE_ASYM); + +	new_adv = ADVERTISE_CSMA | ethtool_adv_to_mii_adv_t(bp->advertising); +  	if (bp->autoneg & AUTONEG_SPEED) { -		u32 adv_reg, adv1000_reg; -		u32 new_adv = 0; +		u32 adv1000_reg;  		u32 new_adv1000 = 0; -		bnx2_read_phy(bp, bp->mii_adv, &adv_reg); -		adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP | -			ADVERTISE_PAUSE_ASYM); +		new_adv |= bnx2_phy_get_pause_adv(bp);  		bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);  		adv1000_reg &= PHY_ALL_1000_SPEED; -		new_adv = ethtool_adv_to_mii_adv_t(bp->advertising); -		new_adv |= ADVERTISE_CSMA; -		new_adv |= bnx2_phy_get_pause_adv(bp); -  		new_adv1000 |= ethtool_adv_to_mii_ctrl1000_t(bp->advertising); -  		if ((adv1000_reg != new_adv1000) ||  			(adv_reg != new_adv) ||  			((bmcr & BMCR_ANENABLE) == 0)) { @@ -2090,6 +2097,10 @@ __acquires(&bp->phy_lock)  		return 0;  	} +	/* advertise nothing when forcing speed */ +	if (adv_reg != new_adv) +		bnx2_write_phy(bp, bp->mii_adv, new_adv); +  	new_bmcr = 0;  	if (bp->req_line_speed == SPEED_100) {  		new_bmcr |= BMCR_SPEED100; @@ -2341,9 +2352,15 @@ bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)  	}  	/* ethernet@wirespeed */ -	bnx2_write_phy(bp, 0x18, 0x7007); -	bnx2_read_phy(bp, 0x18, &val); -	bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4)); +	bnx2_write_phy(bp, MII_BNX2_AUX_CTL, AUX_CTL_MISC_CTL); +	bnx2_read_phy(bp, MII_BNX2_AUX_CTL, &val); +	val |=  AUX_CTL_MISC_CTL_WR | AUX_CTL_MISC_CTL_WIRESPEED; + +	/* auto-mdix */ +	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) +		val |=  AUX_CTL_MISC_CTL_AUTOMDIX; + +	bnx2_write_phy(bp, MII_BNX2_AUX_CTL, val);  	return 0;  } @@ -2490,6 +2507,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)  	bp->fw_wr_seq++;  	msg_data |= bp->fw_wr_seq; +	bp->fw_last_msg = msg_data;  	bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data); @@ -2868,7 +2886,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)  		sw_cons = BNX2_NEXT_TX_BD(sw_cons);  		tx_bytes += skb->len; -		dev_kfree_skb(skb); +		dev_kfree_skb_any(skb);  		tx_pkt++;  		if (tx_pkt == budget)  			break; @@ -3115,6 +3133,9 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)  	struct l2_fhdr *rx_hdr;  	int rx_pkt = 0, pg_ring_used = 0; +	if (budget <= 0) +		return rx_pkt; +  	hw_cons = bnx2_get_hw_rx_cons(bnapi);  	sw_cons = rxr->rx_cons;  	sw_prod = rxr->rx_prod; @@ -3234,7 +3255,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)  		if ((bp->dev->features & NETIF_F_RXHASH) &&  		    ((status & L2_FHDR_STATUS_USE_RXHASH) ==  		     L2_FHDR_STATUS_USE_RXHASH)) -			skb->rxhash = rx_hdr->l2_fhdr_hash; +			skb_set_hash(skb, rx_hdr->l2_fhdr_hash, +				     PKT_HASH_TYPE_L3);  		skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);  		napi_gro_receive(&bnapi->napi, skb); @@ -3982,8 +4004,23 @@ bnx2_setup_wol(struct bnx2 *bp)  			wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;  	} -	if (!(bp->flags & BNX2_FLAG_NO_WOL)) -		bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 1, 0); +	if (!(bp->flags & BNX2_FLAG_NO_WOL)) { +		u32 val; + +		wol_msg |= BNX2_DRV_MSG_DATA_WAIT3; +		if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) { +			bnx2_fw_sync(bp, wol_msg, 1, 0); +			return; +		} +		/* Tell firmware not to power down the PHY yet, otherwise +		 * the chip will take a long time to respond to MMIO reads. +		 */ +		val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE); +		bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, +			      val | BNX2_PORT_FEATURE_ASF_ENABLED); +		bnx2_fw_sync(bp, wol_msg, 1, 0); +		bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val); +	}  } @@ -4015,9 +4052,22 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)  			if (bp->wol)  				pci_set_power_state(bp->pdev, PCI_D3hot); -		} else { -			pci_set_power_state(bp->pdev, PCI_D3hot); +			break; + +		} +		if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) { +			u32 val; + +			/* Tell firmware not to power down the PHY yet, +			 * otherwise the other port may not respond to +			 * MMIO reads. +			 */ +			val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION); +			val &= ~BNX2_CONDITION_PM_STATE_MASK; +			val |= BNX2_CONDITION_PM_STATE_UNPREP; +			bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val);  		} +		pci_set_power_state(bp->pdev, PCI_D3hot);  		/* No more memory access after this point until  		 * device is brought back to D0. @@ -5761,8 +5811,8 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)  	if (!skb)  		return -ENOMEM;  	packet = skb_put(skb, pkt_size); -	memcpy(packet, bp->dev->dev_addr, 6); -	memset(packet + 6, 0x0, 8); +	memcpy(packet, bp->dev->dev_addr, ETH_ALEN); +	memset(packet + ETH_ALEN, 0x0, 8);  	for (i = 14; i < pkt_size; i++)  		packet[i] = (unsigned char) (i & 0xff); @@ -6188,7 +6238,7 @@ bnx2_free_irq(struct bnx2 *bp)  static void  bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)  { -	int i, total_vecs, rc; +	int i, total_vecs;  	struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];  	struct net_device *dev = bp->dev;  	const int len = sizeof(bp->irq_tbl[0].name); @@ -6211,16 +6261,9 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)  #ifdef BCM_CNIC  	total_vecs++;  #endif -	rc = -ENOSPC; -	while (total_vecs >= BNX2_MIN_MSIX_VEC) { -		rc = pci_enable_msix(bp->pdev, msix_ent, total_vecs); -		if (rc <= 0) -			break; -		if (rc > 0) -			total_vecs = rc; -	} - -	if (rc != 0) +	total_vecs = pci_enable_msix_range(bp->pdev, msix_ent, +					   BNX2_MIN_MSIX_VEC, total_vecs); +	if (total_vecs < 0)  		return;  	msix_vecs = total_vecs; @@ -6593,7 +6636,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)  	mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);  	if (dma_mapping_error(&bp->pdev->dev, mapping)) { -		dev_kfree_skb(skb); +		dev_kfree_skb_any(skb);  		return NETDEV_TX_OK;  	} @@ -6686,7 +6729,7 @@ dma_error:  			       PCI_DMA_TODEVICE);  	} -	dev_kfree_skb(skb); +	dev_kfree_skb_any(skb);  	return NETDEV_TX_OK;  } @@ -6865,10 +6908,16 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)  	if (netif_carrier_ok(dev)) {  		ethtool_cmd_speed_set(cmd, bp->line_speed);  		cmd->duplex = bp->duplex; +		if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES)) { +			if (bp->phy_flags & BNX2_PHY_FLAG_MDIX) +				cmd->eth_tp_mdix = ETH_TP_MDI_X; +			else +				cmd->eth_tp_mdix = ETH_TP_MDI; +		}  	}  	else { -		ethtool_cmd_speed_set(cmd, -1); -		cmd->duplex = -1; +		ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN); +		cmd->duplex = DUPLEX_UNKNOWN;  	}  	spin_unlock_bh(&bp->phy_lock); @@ -8413,7 +8462,6 @@ err_out_release:  err_out_disable:  	pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL);  err_out:  	return rc; @@ -8514,7 +8562,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	pci_set_drvdata(pdev, dev); -	memcpy(dev->dev_addr, bp->mac_addr, 6); +	memcpy(dev->dev_addr, bp->mac_addr, ETH_ALEN);  	dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |  		NETIF_F_TSO | NETIF_F_TSO_ECN | @@ -8546,7 +8594,6 @@ error:  	pci_iounmap(pdev, bp->regview);  	pci_release_regions(pdev);  	pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL);  err_free:  	free_netdev(dev);  	return rc; @@ -8578,9 +8625,9 @@ bnx2_remove_one(struct pci_dev *pdev)  	pci_release_regions(pdev);  	pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL);  } +#ifdef CONFIG_PM_SLEEP  static int  bnx2_suspend(struct device *device)  { @@ -8619,7 +8666,6 @@ bnx2_resume(struct device *device)  	return 0;  } -#ifdef CONFIG_PM_SLEEP  static SIMPLE_DEV_PM_OPS(bnx2_pm_ops, bnx2_suspend, bnx2_resume);  #define BNX2_PM_OPS (&bnx2_pm_ops)  | 
