Netdev List
 help / color / mirror / Atom feed
* [net-next 3/10] bnx2x: Fan failure early detection
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Check if fan failure happened before the driver was loaded and notify the user

Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x_main.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index ae8b7b5..d946c9e 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -5185,6 +5185,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
 	mmiowb();
 
 	bnx2x_int_enable(bp);
+
+	/* Check for SPIO5 */
+	bnx2x_attn_int_deasserted0(bp,
+		REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) &
+				   AEU_INPUTS_ATTN_BITS_SPIO5);
 }
 
 /* end of nic init */
-- 
1.5.4.3





^ permalink raw reply related

* [net-next 4/10] bnx2x: Adding some mmiowb
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Vlad Zolotarov

Signed-off-by: Vlad Zolotarov <vladz@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x_main.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index d946c9e..f20df6d 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -652,6 +652,11 @@ static void bnx2x_int_enable(struct bnx2x *bp)
 	   val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
 
 	REG_WR(bp, addr, val);
+	/*
+	 * Ensure that HC_CONFIG is written before leading/trailing edge config
+	 */
+	mmiowb();
+	barrier();
 
 	if (CHIP_IS_E1H(bp)) {
 		/* init leading/trailing edge */
@@ -666,6 +671,9 @@ static void bnx2x_int_enable(struct bnx2x *bp)
 		REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
 		REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
 	}
+
+	/* Make sure that interrupts are indeed enabled from here on */
+	mmiowb();
 }
 
 static void bnx2x_int_disable(struct bnx2x *bp)
@@ -739,6 +747,10 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
 	DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n",
 	   (*(u32 *)&igu_ack), hc_addr);
 	REG_WR(bp, hc_addr, (*(u32 *)&igu_ack));
+
+	/* Make sure that ACK is written */
+	mmiowb();
+	barrier();
 }
 
 static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
@@ -2429,9 +2441,14 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
 		bp->spq_prod_idx++;
 	}
 
+	/* Make sure that BD data is updated before writing the producer */
+	wmb();
+
 	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
 	       bp->spq_prod_idx);
 
+	mmiowb();
+
 	spin_unlock_bh(&bp->spq_lock);
 	return 0;
 }
-- 
1.5.4.3





^ permalink raw reply related

* [net-next 5/10] bnx2x: SMP-safe inter_sem
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Vlad Zolotarov

Signed-off-by: Vlad Zolotarov <vladz@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x_main.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index f20df6d..18c3803 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -706,6 +706,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
 
 	/* disable interrupt handling */
 	atomic_inc(&bp->intr_sem);
+	smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
 	if (disable_hw)
 		/* prevent the HW from sending interrupts */
 		bnx2x_int_disable(bp);
@@ -6642,7 +6644,12 @@ static void bnx2x_napi_disable(struct bnx2x *bp)
 
 static void bnx2x_netif_start(struct bnx2x *bp)
 {
-	if (atomic_dec_and_test(&bp->intr_sem)) {
+	int intr_sem;
+
+	intr_sem = atomic_dec_and_test(&bp->intr_sem);
+	smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
+	if (intr_sem) {
 		if (netif_running(bp->dev)) {
 			bnx2x_napi_enable(bp);
 			bnx2x_int_enable(bp);
@@ -8229,6 +8236,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
 
 	/* Disable interrupt handling until HW is initialized */
 	atomic_set(&bp->intr_sem, 1);
+	smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
 
 	mutex_init(&bp->port.phy_mutex);
 
-- 
1.5.4.3





^ permalink raw reply related

* [PATCH] macsonic, jazzsonic - fix oops on module unload
From: Finn Thain @ 2009-07-21 15:40 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Greg KH, Uwe Kleine-König
In-Reply-To: <alpine.OSX.2.00.0907220032230.796@silk.local>


Set the driver data before using it. Fixes an oops when doing rmmod.

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>

--- a/drivers/net/macsonic.c	2009-07-22 00:47:46.000000000 +1000
+++ b/drivers/net/macsonic.c	2009-07-22 00:49:39.000000000 +1000
@@ -575,6 +575,7 @@
  	lp = netdev_priv(dev);
  	lp->device = &pdev->dev;
  	SET_NETDEV_DEV(dev, &pdev->dev);
+	platform_set_drvdata(pdev, dev);

  	/* This will catch fatal stuff like -ENOMEM as well as success */
  	err = mac_onboard_sonic_probe(dev);
--- a/drivers/net/jazzsonic.c	2009-07-22 00:47:52.000000000 +1000
+++ b/drivers/net/jazzsonic.c	2009-07-22 00:52:41.000000000 +1000
@@ -222,6 +222,7 @@
  	lp = netdev_priv(dev);
  	lp->device = &pdev->dev;
  	SET_NETDEV_DEV(dev, &pdev->dev);
+	platform_set_drvdata(pdev, dev);

  	netdev_boot_setup_check(dev);


^ permalink raw reply

* [net-next 6/10] bnx2x: Update vlan_features
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Gerlitz

As noted by Or Gerlitz <ogerlitz@Voltaire.com>, the vlan_features was not
updated

Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x_main.c |   19 +++++++++++++++++--
 1 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 18c3803..b404a9b 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -9310,9 +9310,17 @@ static int bnx2x_set_tso(struct net_device *dev, u32 data)
 	if (data) {
 		dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
 		dev->features |= NETIF_F_TSO6;
+#ifdef BCM_VLAN
+		dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+		dev->vlan_features |= NETIF_F_TSO6;
+#endif
 	} else {
 		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
 		dev->features &= ~NETIF_F_TSO6;
+#ifdef BCM_VLAN
+		dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
+		dev->vlan_features &= ~NETIF_F_TSO6;
+#endif
 	}

 	return 0;
@@ -11143,12 +11151,19 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
 	dev->features |= NETIF_F_HW_CSUM;
 	if (bp->flags & USING_DAC_FLAG)
 		dev->features |= NETIF_F_HIGHDMA;
+	dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+	dev->features |= NETIF_F_TSO6;
 #ifdef BCM_VLAN
 	dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
 	bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
+
+	dev->vlan_features |= NETIF_F_SG;
+	dev->vlan_features |= NETIF_F_HW_CSUM;
+	if (bp->flags & USING_DAC_FLAG)
+		dev->vlan_features |= NETIF_F_HIGHDMA;
+	dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+	dev->vlan_features |= NETIF_F_TSO6;
 #endif
-	dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
-	dev->features |= NETIF_F_TSO6;

 	return 0;

--
1.5.4.3





^ permalink raw reply related

* [net-next 7/10] bnx2x: Supporting BCM8727 PHY
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Yaniv Rosner

Adding support for BCM8727 - a dual port SFP+ PHY. That includes verification of
the optic module vendor and part number - the list of approved modules resides
on the nvram and the module is verified by the FW. Since not all users would
like to use this verification feature, it can be disabled. The default behavior
is to issue a warning if the module is not approved, but still allow using it -
but it is also possible to disable the link if the module is not approved.

Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x.h      |    1 +
 drivers/net/bnx2x_hsi.h  |   25 +-
 drivers/net/bnx2x_link.c | 1095 +++++++++++++++++++++++++++++++++++++++-------
 drivers/net/bnx2x_link.h |   14 +-
 drivers/net/bnx2x_main.c |   67 +++-
 drivers/net/bnx2x_reg.h  |   26 +-
 6 files changed, 1049 insertions(+), 179 deletions(-)

diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 85a737c..8b6e83d 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -1006,6 +1006,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
 int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
 int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
 int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command);

 static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 			   int wait)
diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h
index 41c6dcb..7de83c4 100644
--- a/drivers/net/bnx2x_hsi.h
+++ b/drivers/net/bnx2x_hsi.h
@@ -248,6 +248,8 @@ struct port_hw_cfg {			    /* port 0: 0x12c  port 1: 0x2bc */
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726	    0x00000600
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481	    0x00000700
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101	    0x00000800
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727	    0x00000900
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC   0x00000a00
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE	    0x0000fd00
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN	    0x0000ff00

@@ -358,10 +360,16 @@ struct port_feat_cfg {			    /* port 0: 0x454  port 1: 0x4c8 */
 #define PORT_FEATURE_MBA_ENABLED		    0x02000000
 #define PORT_FEATURE_MFW_ENABLED		    0x04000000

-	/*  Check the optic vendor via i2c before allowing it to be used by
-	  SW */
-#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLED 	      0x00000000
-#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED		      0x08000000
+	/* Reserved bits: 28-29 */
+	/*  Check the optic vendor via i2c against a list of approved modules
+	  in a separate nvram image */
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK		      0xE0000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_SHIFT		      29
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT	      0x00000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER       0x20000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG	      0x40000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN	      0x60000000
+

 	u32 wol_config;
 	/* Default is used when driver sets to "auto" mode */
@@ -657,6 +665,12 @@ struct drv_func_mb {
 #define DRV_MSG_CODE_GET_UPGRADE_KEY			0x81000000
 #define DRV_MSG_CODE_GET_MANUF_KEY			0x82000000
 #define DRV_MSG_CODE_LOAD_L2B_PRAM			0x90000000
+	/*
+	 * The optic module verification commands requris bootcode
+	 * v5.0.6 or later
+	 */
+#define DRV_MSG_CODE_VRFY_OPT_MDL			0xa0000000
+#define REQ_BC_VER_4_VRFY_OPT_MDL			0x00050006

 #define BIOS_MSG_CODE_LIC_CHALLENGE			0xff010000
 #define BIOS_MSG_CODE_LIC_RESPONSE			0xff020000
@@ -691,6 +705,9 @@ struct drv_func_mb {
 #define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE		0x90220000
 #define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE		0x90230000
 #define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE		0x90240000
+#define FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS		0xa0100000
+#define FW_MSG_CODE_VRFY_OPT_MDL_INVLD_IMG		0xa0200000
+#define FW_MSG_CODE_VRFY_OPT_MDL_UNAPPROVED		0xa0300000

 #define FW_MSG_CODE_LIC_CHALLENGE			0xff010000
 #define FW_MSG_CODE_LIC_RESPONSE			0xff020000
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c
index ed648ac..b9c85a2 100644
--- a/drivers/net/bnx2x_link.c
+++ b/drivers/net/bnx2x_link.c
@@ -139,21 +139,26 @@
 	#define SFP_EEPROM_CON_TYPE_VAL_LC 		0x7
 	#define SFP_EEPROM_CON_TYPE_VAL_COPPER	0x21

+
+#define SFP_EEPROM_COMP_CODE_ADDR		0x3
+	#define SFP_EEPROM_COMP_CODE_SR_MASK	(1<<4)
+	#define SFP_EEPROM_COMP_CODE_LR_MASK	(1<<5)
+	#define SFP_EEPROM_COMP_CODE_LRM_MASK	(1<<6)
+
 #define SFP_EEPROM_FC_TX_TECH_ADDR		0x8
 	#define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
 	#define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE	 0x8
-#define SFP_EEPROM_VENDOR_NAME_ADDR		0x14
-#define SFP_EEPROM_VENDOR_NAME_SIZE 	16
+
 #define SFP_EEPROM_OPTIONS_ADDR 		0x40
 	#define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
 #define SFP_EEPROM_OPTIONS_SIZE 		2

-#define SFP_MODULE_TYPE_UNKNOWN 			0x0
-#define SFP_MODULE_TYPE_LC   			0x1
-#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE		0x2
-#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE	0x3
+#define EDC_MODE_LINEAR	 			0x0022
+#define EDC_MODE_LIMITING	 			0x0044
+#define EDC_MODE_PASSIVE_DAC 			0x0055
+
+

-#define SFP_LIMITING_MODE_VALUE 			0x0044
 /**********************************************************/
 /*                     INTERFACE                          */
 /**********************************************************/
@@ -793,6 +798,7 @@ static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
 	switch (ext_phy_type) {
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
 		/* All MDC/MDIO is directed through single EMAC */
 		if (REG_RD(bp, NIG_REG_PORT_SWAP))
 			emac_base = GRCBASE_EMAC0;
@@ -1887,6 +1893,10 @@ static void bnx2x_ext_phy_reset(struct link_params *params,
 				       MDIO_PMA_DEVAD,
 				       MDIO_PMA_REG_CTRL, 0xa040);
 			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+			break;
+
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:

 			/* Restore normal power mode*/
@@ -2171,13 +2181,15 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)

 }

-static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
-					  u8 ext_phy_addr, u32 shmem_base)
+static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
+						  u8 ext_phy_addr,
+						  u32 ext_phy_type,
+						  u32 shmem_base)
 {
 	/* Boot port from external ROM  */
 	/* EDC grst */
 	bnx2x_cl45_write(bp, port,
-		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+		       ext_phy_type,
 		       ext_phy_addr,
 		       MDIO_PMA_DEVAD,
 		       MDIO_PMA_REG_GEN_CTRL,
@@ -2185,21 +2197,21 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,

 	/* ucode reboot and rst */
 	bnx2x_cl45_write(bp, port,
-		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+		       ext_phy_type,
 		       ext_phy_addr,
 		       MDIO_PMA_DEVAD,
 		       MDIO_PMA_REG_GEN_CTRL,
 		       0x008c);

 	bnx2x_cl45_write(bp, port,
-		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+		       ext_phy_type,
 		       ext_phy_addr,
 		       MDIO_PMA_DEVAD,
 		       MDIO_PMA_REG_MISC_CTRL1, 0x0001);

 	/* Reset internal microprocessor */
 	bnx2x_cl45_write(bp, port,
-		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+		       ext_phy_type,
 		       ext_phy_addr,
 		       MDIO_PMA_DEVAD,
 		       MDIO_PMA_REG_GEN_CTRL,
@@ -2207,7 +2219,7 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,

 	/* Release srst bit */
 	bnx2x_cl45_write(bp, port,
-		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+		       ext_phy_type,
 		       ext_phy_addr,
 		       MDIO_PMA_DEVAD,
 		       MDIO_PMA_REG_GEN_CTRL,
@@ -2218,17 +2230,36 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,

 	/* Clear ser_boot_ctl bit */
 	bnx2x_cl45_write(bp, port,
-		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+		       ext_phy_type,
 		       ext_phy_addr,
 		       MDIO_PMA_DEVAD,
 		       MDIO_PMA_REG_MISC_CTRL1, 0x0000);

 	bnx2x_save_bcm_spirom_ver(bp, port,
-				PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+				ext_phy_type,
 				ext_phy_addr,
 				shmem_base);
 }

+static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
+					  u8 ext_phy_addr,
+					  u32 shmem_base)
+{
+	bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
+					 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+					 shmem_base);
+}
+
+static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
+					  u8 ext_phy_addr,
+					  u32 shmem_base)
+{
+	bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
+					 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+					 shmem_base);
+
+}
+
 static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
 {
 	struct bnx2x *bp = params->bp;
@@ -2258,9 +2289,10 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
 		       MDIO_PMA_REG_GEN_CTRL,
 		       MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);

+	/* Set PLL register value to be same like in P13 ver */
 	bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
 		       MDIO_PMA_DEVAD,
-		       MDIO_PMA_REG_GEN_CTRL2,
+		       MDIO_PMA_REG_PLL_CTRL,
 		       0x73A0);

 	/* Clear soft reset.
@@ -2285,15 +2317,16 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
 				params->shmem_base);
 }

-static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
-					u8 ext_phy_addr, u8 tx_en)
+static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
+				    u32 ext_phy_type, u8 ext_phy_addr,
+				    u8 tx_en)
 {
 	u16 val;
 	DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
 		 tx_en, port);
 	/* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
 	bnx2x_cl45_read(bp, port,
-		      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+		      ext_phy_type,
 		      ext_phy_addr,
 		      MDIO_PMA_DEVAD,
 		      MDIO_PMA_REG_PHY_IDENTIFIER,
@@ -2305,18 +2338,19 @@ static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
 		val |= (1<<15);

 	bnx2x_cl45_write(bp, port,
-		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+		       ext_phy_type,
 		       ext_phy_addr,
 		       MDIO_PMA_DEVAD,
 		       MDIO_PMA_REG_PHY_IDENTIFIER,
 		       val);
 }

-
-static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
-				     u8 byte_cnt, u8 *o_buf) {
+static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
+					  u16 addr, u8 byte_cnt, u8 *o_buf)
+{
 	struct bnx2x *bp = params->bp;
-	u16 val, i;
+	u16 val = 0;
+	u16 i;
 	u8 port = params->port;
 	u8 ext_phy_addr = ((params->ext_phy_config &
 			    PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
@@ -2332,7 +2366,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
 		       ext_phy_type,
 		       ext_phy_addr,
 		       MDIO_PMA_DEVAD,
-		       MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
+		       MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
 		       (byte_cnt | 0xa000));

 	/* Set the read command address */
@@ -2340,7 +2374,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
 		       ext_phy_type,
 		       ext_phy_addr,
 		       MDIO_PMA_DEVAD,
-		       MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
+		       MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
 		       addr);

 	/* Activate read command */
@@ -2348,7 +2382,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
 		       ext_phy_type,
 		       ext_phy_addr,
 		       MDIO_PMA_DEVAD,
-		       MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
+		       MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
 		       0x2c0f);

 	/* Wait up to 500us for command complete status */
@@ -2357,18 +2391,18 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
 			      ext_phy_type,
 			      ext_phy_addr,
 			      MDIO_PMA_DEVAD,
-			      MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
-		if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
-		    MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
+			      MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+		if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+		    MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
 			break;
 		udelay(5);
 	}

-	if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
-		    MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
+	if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
+		    MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
 		DP(NETIF_MSG_LINK,
 			 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
-			 (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
+			 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
 		return -EINVAL;
 	}

@@ -2387,29 +2421,147 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
 			      ext_phy_type,
 			      ext_phy_addr,
 			      MDIO_PMA_DEVAD,
-			      MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
-		if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
-		    MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
+			      MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+		if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+		    MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
 			return 0;;
 		msleep(1);
 	}
 	return -EINVAL;
 }

+static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
+					  u16 addr, u8 byte_cnt, u8 *o_buf)
+{
+	struct bnx2x *bp = params->bp;
+	u16 val, i;
+	u8 port = params->port;
+	u8 ext_phy_addr = ((params->ext_phy_config &
+			    PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+			   PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+	u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
+	if (byte_cnt > 16) {
+		DP(NETIF_MSG_LINK, "Reading from eeprom is"
+			    " is limited to 0xf\n");
+		return -EINVAL;
+	}
+
+	/* Need to read from 1.8000 to clear it */
+	bnx2x_cl45_read(bp, port,
+		      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+		      ext_phy_addr,
+		      MDIO_PMA_DEVAD,
+		      MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+		      &val);

-static u8 bnx2x_get_sfp_module_type(struct link_params *params,
-				  u8 *module_type)
+	/* Set the read command byte count */
+	bnx2x_cl45_write(bp, port,
+		       ext_phy_type,
+		       ext_phy_addr,
+		       MDIO_PMA_DEVAD,
+		       MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
+		       ((byte_cnt < 2) ? 2 : byte_cnt));
+
+	/* Set the read command address */
+	bnx2x_cl45_write(bp, port,
+		       ext_phy_type,
+		       ext_phy_addr,
+		       MDIO_PMA_DEVAD,
+		       MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
+		       addr);
+	/* Set the destination address */
+	bnx2x_cl45_write(bp, port,
+		       ext_phy_type,
+		       ext_phy_addr,
+		       MDIO_PMA_DEVAD,
+		       0x8004,
+		       MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
+
+	/* Activate read command */
+	bnx2x_cl45_write(bp, port,
+		       ext_phy_type,
+		       ext_phy_addr,
+		       MDIO_PMA_DEVAD,
+		       MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+		       0x8002);
+	/* Wait appropriate time for two-wire command to finish before
+	polling the status register */
+	msleep(1);
+
+	/* Wait up to 500us for command complete status */
+	for (i = 0; i < 100; i++) {
+		bnx2x_cl45_read(bp, port,
+			      ext_phy_type,
+			      ext_phy_addr,
+			      MDIO_PMA_DEVAD,
+			      MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+		if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+		    MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
+			break;
+		udelay(5);
+	}
+
+	if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
+		    MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
+		DP(NETIF_MSG_LINK,
+			 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
+			 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
+		return -EINVAL;
+	}
+
+	/* Read the buffer */
+	for (i = 0; i < byte_cnt; i++) {
+		bnx2x_cl45_read(bp, port,
+			      ext_phy_type,
+			      ext_phy_addr,
+			      MDIO_PMA_DEVAD,
+			      MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
+		o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
+	}
+
+	for (i = 0; i < 100; i++) {
+		bnx2x_cl45_read(bp, port,
+			      ext_phy_type,
+			      ext_phy_addr,
+			      MDIO_PMA_DEVAD,
+			      MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+		if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+		    MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
+			return 0;;
+		msleep(1);
+	}
+
+	return -EINVAL;
+}
+
+u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+				     u8 byte_cnt, u8 *o_buf)
+{
+	u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
+	if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+		return bnx2x_8726_read_sfp_module_eeprom(params, addr,
+						       byte_cnt, o_buf);
+	else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+		return bnx2x_8727_read_sfp_module_eeprom(params, addr,
+						       byte_cnt, o_buf);
+	return -EINVAL;
+}
+
+static u8 bnx2x_get_edc_mode(struct link_params *params,
+				  u16 *edc_mode)
 {
 	struct bnx2x *bp = params->bp;
-	u8 val;
-	*module_type = SFP_MODULE_TYPE_UNKNOWN;
+	u8 val, check_limiting_mode = 0;
+	*edc_mode = EDC_MODE_LIMITING;

 	/* First check for copper cable */
 	if (bnx2x_read_sfp_module_eeprom(params,
 				       SFP_EEPROM_CON_TYPE_ADDR,
 				       1,
 				       &val) != 0) {
-		DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
+		DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
 		return -EINVAL;
 	}

@@ -2433,13 +2585,13 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
 		if (copper_module_type &
 		    SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
 			DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
-			*module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
+			check_limiting_mode = 1;
 		} else if (copper_module_type &
 			SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
 				DP(NETIF_MSG_LINK, "Passive Copper"
 					    " cable detected\n");
-				*module_type =
-				      SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
+				*edc_mode =
+				      EDC_MODE_PASSIVE_DAC;
 		} else {
 			DP(NETIF_MSG_LINK, "Unknown copper-cable-"
 				     "type 0x%x !!!\n", copper_module_type);
@@ -2449,7 +2601,7 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
 	}
 	case SFP_EEPROM_CON_TYPE_VAL_LC:
 		DP(NETIF_MSG_LINK, "Optic module detected\n");
-		*module_type = SFP_MODULE_TYPE_LC;
+		check_limiting_mode = 1;
 		break;

 	default:
@@ -2457,89 +2609,92 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
 			 val);
 		return -EINVAL;
 	}
+
+	if (check_limiting_mode) {
+		u8 options[SFP_EEPROM_OPTIONS_SIZE];
+		if (bnx2x_read_sfp_module_eeprom(params,
+					       SFP_EEPROM_OPTIONS_ADDR,
+					       SFP_EEPROM_OPTIONS_SIZE,
+					       options) != 0) {
+			DP(NETIF_MSG_LINK, "Failed to read Option"
+				" field from module EEPROM\n");
+			return -EINVAL;
+		}
+		if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
+			*edc_mode = EDC_MODE_LINEAR;
+		else
+			*edc_mode = EDC_MODE_LIMITING;
+	}
+	DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
 	return 0;
 }

-
 /* This function read the relevant field from the module ( SFP+ ),
 	and verify it is compliant with this board */
-static u8 bnx2x_verify_sfp_module(struct link_params *params,
-				u8 module_type)
+static u8 bnx2x_verify_sfp_module(struct link_params *params)
 {
 	struct bnx2x *bp = params->bp;
-	u8 *str_p, *tmp_buf;
-	u16 i;
-
-#define COMPLIANCE_STR_CNT 6
-	u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
-		"FINISAR CORP.   ", "Amphenol"};
-	u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
-	/* Passive Copper cables are allowed to participate,
-	since the module is hardwired to the copper cable */
-
-	if (!(params->feature_config_flags &
-	     FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
+	u32 val;
+	u32 fw_resp;
+	char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
+	char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
+
+	val = REG_RD(bp, params->shmem_base +
+			 offsetof(struct shmem_region, dev_info.
+				  port_feature_config[params->port].config));
+	if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+	    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
 		DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
 		return 0;
 	}

-	if (module_type != SFP_MODULE_TYPE_LC) {
-		DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
+	/* Ask the FW to validate the module */
+	if (!(params->feature_config_flags &
+	      FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
+		DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
+			    "verification\n");
+		return -EINVAL;
+	}
+
+	fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
+	if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
+		DP(NETIF_MSG_LINK, "Approved module\n");
 		return 0;
 	}

-	/* In case of non copper cable or Active copper cable,
-		verify that the SFP+ module is compliant with this board*/
+	/* format the warning message */
 	if (bnx2x_read_sfp_module_eeprom(params,
 				       SFP_EEPROM_VENDOR_NAME_ADDR,
 				       SFP_EEPROM_VENDOR_NAME_SIZE,
-				       buf) != 0) {
-		DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
-			    " module EEPROM\n");
-		return -EINVAL;
-	}
-	for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
-		str_p = compliance_str[i];
-		tmp_buf = buf;
-		while (*str_p) {
-			if ((u8)(*tmp_buf) != (u8)(*str_p))
-				break;
-			str_p++;
-			tmp_buf++;
-		}
+				       (u8 *)vendor_name))
+		vendor_name[0] = '\0';
+	else
+		vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
+	if (bnx2x_read_sfp_module_eeprom(params,
+				       SFP_EEPROM_PART_NO_ADDR,
+				       SFP_EEPROM_PART_NO_SIZE,
+				       (u8 *)vendor_pn))
+		vendor_pn[0] = '\0';
+	else
+		vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';

-		if (!(*str_p)) {
-			DP(NETIF_MSG_LINK, "SFP+ Module verified, "
-				     "index=%x\n", i);
-			return 0;
-		}
-	}
-	DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
+	printk(KERN_INFO PFX  "Warning: "
+			 "Unqualified SFP+ module "
+			 "detected on %s, Port %d from %s part number %s\n"
+			, bp->dev->name, params->port,
+			vendor_name, vendor_pn);
 	return -EINVAL;
 }

-
 static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
-					u8 module_type)
+					u16 edc_mode)
 {
 	struct bnx2x *bp = params->bp;
 	u8 port = params->port;
-	u8 options[SFP_EEPROM_OPTIONS_SIZE];
-	u8 limiting_mode;
 	u8 ext_phy_addr = ((params->ext_phy_config &
 			    PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
 			   PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
 	u16 cur_limiting_mode;
-	if (bnx2x_read_sfp_module_eeprom(params,
-				       SFP_EEPROM_OPTIONS_ADDR,
-				       SFP_EEPROM_OPTIONS_SIZE,
-				       options) != 0) {
-		DP(NETIF_MSG_LINK, "Failed to read Option field from"
-			    " module EEPROM\n");
-		return -EINVAL;
-	}
-	limiting_mode = !(options[0] &
-			  SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);

 	bnx2x_cl45_read(bp, port,
 		      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
@@ -2550,26 +2705,23 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
 	DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
 		 cur_limiting_mode);

-	if (limiting_mode &&
-	    (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
+	if (edc_mode == EDC_MODE_LIMITING) {
 		DP(NETIF_MSG_LINK,
-			 "Module options = 0x%x.Setting LIMITING MODE\n",
-			 options[0]);
+			 "Setting LIMITING MODE\n");
 		bnx2x_cl45_write(bp, port,
 			       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
 			       ext_phy_addr,
 			       MDIO_PMA_DEVAD,
 			       MDIO_PMA_REG_ROM_VER2,
-			       SFP_LIMITING_MODE_VALUE);
+			       EDC_MODE_LIMITING);
 	} else { /* LRM mode ( default )*/

-		DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
-			 options[0]);
+		DP(NETIF_MSG_LINK, "Setting LRM MODE\n");

 		/* Changing to LRM mode takes quite few seconds.
 		So do it only if current mode is limiting
 		( default is LRM )*/
-		if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
+		if (cur_limiting_mode != EDC_MODE_LIMITING)
 			return 0;

 		bnx2x_cl45_write(bp, port,
@@ -2600,6 +2752,56 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
 	return 0;
 }

+static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
+					u16 edc_mode)
+{
+	struct bnx2x *bp = params->bp;
+	u8 port = params->port;
+	u16 phy_identifier;
+	u16 rom_ver2_val;
+	u8 ext_phy_addr = ((params->ext_phy_config &
+			    PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+			   PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+	bnx2x_cl45_read(bp, port,
+		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+		       ext_phy_addr,
+		       MDIO_PMA_DEVAD,
+		       MDIO_PMA_REG_PHY_IDENTIFIER,
+		       &phy_identifier);
+
+	bnx2x_cl45_write(bp, port,
+		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+		       ext_phy_addr,
+		       MDIO_PMA_DEVAD,
+		       MDIO_PMA_REG_PHY_IDENTIFIER,
+		       (phy_identifier & ~(1<<9)));
+
+	bnx2x_cl45_read(bp, port,
+		      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+		      ext_phy_addr,
+		      MDIO_PMA_DEVAD,
+		      MDIO_PMA_REG_ROM_VER2,
+		      &rom_ver2_val);
+	/* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
+	bnx2x_cl45_write(bp, port,
+		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+		       ext_phy_addr,
+		       MDIO_PMA_DEVAD,
+		       MDIO_PMA_REG_ROM_VER2,
+		       (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
+
+	bnx2x_cl45_write(bp, port,
+		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+		       ext_phy_addr,
+		       MDIO_PMA_DEVAD,
+		       MDIO_PMA_REG_PHY_IDENTIFIER,
+		       (phy_identifier | (1<<9)));
+
+	return 0;
+}
+
+
 static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
 {
 	u8 val;
@@ -2619,61 +2821,114 @@ static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
 	return -EINVAL;
 }

+static void bnx2x_8727_power_module(struct bnx2x *bp,
+				  struct link_params *params,
+				  u8 ext_phy_addr, u8 is_power_up) {
+	/* Make sure GPIOs are not using for LED mode */
+	u16 val;
+	u8 port = params->port;
+	/*
+	 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
+	 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
+	 * output
+	 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
+	 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
+	 * where the 1st bit is the over-current(only input), and 2nd bit is
+	 * for power( only output )
+	*/
+
+	/*
+	 * In case of NOC feature is disabled and power is up, set GPIO control
+	 *  as input to enable listening of over-current indication
+	 */
+
+	if (!(params->feature_config_flags &
+	      FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
+		val = (1<<4);
+	else
+		/*
+		 * Set GPIO control to OUTPUT, and set the power bit
+		 * to according to the is_power_up
+		 */
+		val = ((!(is_power_up)) << 1);
+
+	bnx2x_cl45_write(bp, port,
+		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+		       ext_phy_addr,
+		       MDIO_PMA_DEVAD,
+		       MDIO_PMA_REG_8727_GPIO_CTRL,
+		       val);
+}
+
 static u8 bnx2x_sfp_module_detection(struct link_params *params)
 {
 	struct bnx2x *bp = params->bp;
-	u8 module_type;
+	u16 edc_mode;
+	u8 rc = 0;
 	u8 ext_phy_addr = ((params->ext_phy_config &
 				PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
 				PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
 	u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
-	if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
-		DP(NETIF_MSG_LINK, "Module detection is not required "
-			    "for this phy\n");
-		return 0;
-	}
+	u32 val = REG_RD(bp, params->shmem_base +
+			     offsetof(struct shmem_region, dev_info.
+				     port_feature_config[params->port].config));

 	DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
 		 params->port);

-	if (bnx2x_get_sfp_module_type(params,
-				    &module_type) != 0) {
+	if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
 		DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
-		if (!(params->feature_config_flags &
-		      FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
-			/* In case module detection is disabled, it trys to
-			link up. The issue that can happen here is LRM /
-			LIMITING mode which set according to the module-type*/
-			DP(NETIF_MSG_LINK, "Unable to read module-type."
-				    "Probably due to Bit Stretching."
-				    " Proceeding...\n");
-		} else {
-			return -EINVAL;
-		}
-	} else if (bnx2x_verify_sfp_module(params, module_type) !=
+		return -EINVAL;
+	} else if (bnx2x_verify_sfp_module(params) !=
 		   0) {
 		/* check SFP+ module compatibility */
 		DP(NETIF_MSG_LINK, "Module verification failed!!\n");
+		rc = -EINVAL;
 		/* Turn on fault module-detected led */
 		bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
 				  MISC_REGISTERS_GPIO_HIGH,
 				  params->port);
-		return -EINVAL;
+		if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
+		    ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+		     PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
+			/* Shutdown SFP+ module */
+			DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
+			bnx2x_8727_power_module(bp, params,
+					      ext_phy_addr, 0);
+			return rc;
+		}
+	} else {
+		/* Turn off fault module-detected led */
+		DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
+		bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+					  MISC_REGISTERS_GPIO_LOW,
+					  params->port);
 	}

-	/* Turn off fault module-detected led */
-	bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
-			  MISC_REGISTERS_GPIO_LOW,
-			  params->port);
+	/* power up the SFP module */
+	if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+		bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);

-	/* Check and set limiting mode / LRM mode */
-	bnx2x_bcm8726_set_limiting_mode(params, module_type);
+	/* Check and set limiting mode / LRM mode on 8726.
+	On 8727 it is done automatically */
+	if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+		bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
+	else
+		bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
+	/*
+	 * Enable transmit for this module if the module is approved, or
+	 * if unapproved modules should also enable the Tx laser
+	 */
+	if (rc == 0 ||
+	    (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
+	    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+		bnx2x_sfp_set_transmitter(bp, params->port,
+					ext_phy_type, ext_phy_addr, 1);
+	else
+		bnx2x_sfp_set_transmitter(bp, params->port,
+					ext_phy_type, ext_phy_addr, 0);

-	/* Enable transmit for this module */
-	bnx2x_bcm8726_set_transmitter(bp, params->port,
-				    ext_phy_addr, 1);
-	return 0;
+	return rc;
 }

 void bnx2x_handle_module_detect_int(struct link_params *params)
@@ -2696,8 +2951,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
 				      MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
 				      port);

-		if (bnx2x_wait_for_sfp_module_initialized(params)
-		    == 0)
+		if (bnx2x_wait_for_sfp_module_initialized(params) ==
+		    0)
 			bnx2x_sfp_module_detection(params);
 		else
 			DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
@@ -2705,13 +2960,22 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
 		u8 ext_phy_addr = ((params->ext_phy_config &
 				    PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
 				   PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+		u32 ext_phy_type =
+			XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+		u32 val = REG_RD(bp, params->shmem_base +
+				     offsetof(struct shmem_region, dev_info.
+					      port_feature_config[params->port].
+					      config));
+
 		bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
 				      MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
 				      port);
 		/* Module was plugged out. */
 		/* Disable transmit for this module */
-		bnx2x_bcm8726_set_transmitter(bp, params->port,
-					    ext_phy_addr, 0);
+		if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+		    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+			bnx2x_sfp_set_transmitter(bp, params->port,
+						ext_phy_type, ext_phy_addr, 0);
 	}
 }

@@ -3160,6 +3424,9 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
 			driver is loaded, it reset all registers, including the
 			transmitter */
 			bnx2x_sfp_module_detection(params);
+
+			/* Set Flow control */
+			bnx2x_ext_phy_set_pause(params, vars);
 			if (params->req_line_speed == SPEED_1000) {
 				DP(NETIF_MSG_LINK, "Setting 1G force\n");
 				bnx2x_cl45_write(bp, params->port, ext_phy_type,
@@ -3450,6 +3717,187 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
 			   ((val & (1<<7)) > 0));
 			break;
 		}
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+		{
+			u16 tmp1;
+			u16 rx_alarm_ctrl_val;
+			u16 lasi_ctrl_val;
+
+			/* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
+
+			u16 mod_abs;
+			rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
+			lasi_ctrl_val = 0x0004;
+
+			DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
+			/* enable LASI */
+			bnx2x_cl45_write(bp, params->port,
+				       ext_phy_type,
+				       ext_phy_addr,
+				       MDIO_PMA_DEVAD,
+				       MDIO_PMA_REG_RX_ALARM_CTRL,
+				       rx_alarm_ctrl_val);
+
+			bnx2x_cl45_write(bp, params->port,
+				       ext_phy_type,
+				       ext_phy_addr,
+				       MDIO_PMA_DEVAD,
+				       MDIO_PMA_REG_LASI_CTRL,
+				       lasi_ctrl_val);
+
+			/* Initially configure  MOD_ABS to interrupt when
+			module is presence( bit 8) */
+			bnx2x_cl45_read(bp, params->port,
+				      ext_phy_type,
+				      ext_phy_addr,
+				      MDIO_PMA_DEVAD,
+				      MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+			/* Set EDC off by setting OPTXLOS signal input to low
+			(bit 9).
+			When the EDC is off it locks onto a reference clock and
+			avoids becoming 'lost'.*/
+			mod_abs &= ~((1<<8) | (1<<9));
+			bnx2x_cl45_write(bp, params->port,
+				       ext_phy_type,
+				       ext_phy_addr,
+				       MDIO_PMA_DEVAD,
+				       MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+			/* Make MOD_ABS give interrupt on change */
+			bnx2x_cl45_read(bp, params->port,
+				      ext_phy_type,
+				      ext_phy_addr,
+				      MDIO_PMA_DEVAD,
+				      MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+				      &val);
+			val |= (1<<12);
+			bnx2x_cl45_write(bp, params->port,
+				       ext_phy_type,
+				       ext_phy_addr,
+				       MDIO_PMA_DEVAD,
+				       MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+				       val);
+
+			/* Set 8727 GPIOs to input to allow reading from the
+			8727 GPIO0 status which reflect SFP+ module
+			over-current */
+
+			bnx2x_cl45_read(bp, params->port,
+				       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+				       ext_phy_addr,
+				       MDIO_PMA_DEVAD,
+				       MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+				       &val);
+			val &= 0xff8f; /* Reset bits 4-6 */
+			bnx2x_cl45_write(bp, params->port,
+				       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+				       ext_phy_addr,
+				       MDIO_PMA_DEVAD,
+				       MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+				       val);
+
+			bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
+			bnx2x_bcm8073_set_xaui_low_power_mode(params);
+
+			bnx2x_cl45_read(bp, params->port,
+				      ext_phy_type,
+				      ext_phy_addr,
+				      MDIO_PMA_DEVAD,
+				      MDIO_PMA_REG_M8051_MSGOUT_REG,
+				      &tmp1);
+
+			bnx2x_cl45_read(bp, params->port,
+				      ext_phy_type,
+				      ext_phy_addr,
+				      MDIO_PMA_DEVAD,
+				      MDIO_PMA_REG_RX_ALARM, &tmp1);
+
+			/* Set option 1G speed */
+			if (params->req_line_speed == SPEED_1000) {
+
+				DP(NETIF_MSG_LINK, "Setting 1G force\n");
+				bnx2x_cl45_write(bp, params->port,
+					       ext_phy_type,
+					       ext_phy_addr,
+					       MDIO_PMA_DEVAD,
+					       MDIO_PMA_REG_CTRL, 0x40);
+				bnx2x_cl45_write(bp, params->port,
+					       ext_phy_type,
+					       ext_phy_addr,
+					       MDIO_PMA_DEVAD,
+					       MDIO_PMA_REG_10G_CTRL2, 0xD);
+				bnx2x_cl45_read(bp, params->port,
+				      ext_phy_type,
+				      ext_phy_addr,
+				      MDIO_PMA_DEVAD,
+				      MDIO_PMA_REG_10G_CTRL2, &tmp1);
+				DP(NETIF_MSG_LINK, "1.7 = 0x%x \n", tmp1);
+
+			} else if ((params->req_line_speed ==
+				    SPEED_AUTO_NEG) &&
+				   ((params->speed_cap_mask &
+				     PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
+
+				DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
+				bnx2x_cl45_write(bp, params->port, ext_phy_type,
+					       ext_phy_addr, MDIO_AN_DEVAD,
+					       MDIO_PMA_REG_8727_MISC_CTRL, 0);
+				bnx2x_cl45_write(bp, params->port, ext_phy_type,
+					       ext_phy_addr, MDIO_AN_DEVAD,
+					       MDIO_AN_REG_CL37_AN, 0x1300);
+			} else {
+				/* Since the 8727 has only single reset pin,
+				need to set the 10G registers although it is
+				default */
+				bnx2x_cl45_write(bp, params->port, ext_phy_type,
+					       ext_phy_addr, MDIO_AN_DEVAD,
+					       MDIO_AN_REG_CTRL, 0x0020);
+				bnx2x_cl45_write(bp, params->port, ext_phy_type,
+					       ext_phy_addr, MDIO_AN_DEVAD,
+					       0x7, 0x0100);
+				bnx2x_cl45_write(bp, params->port, ext_phy_type,
+					       ext_phy_addr, MDIO_PMA_DEVAD,
+					       MDIO_PMA_REG_CTRL, 0x2040);
+				bnx2x_cl45_write(bp, params->port, ext_phy_type,
+					       ext_phy_addr, MDIO_PMA_DEVAD,
+					       MDIO_PMA_REG_10G_CTRL2, 0x0008);
+			}
+
+			/* Set 2-wire transfer rate to 400Khz since 100Khz
+			is not operational */
+			bnx2x_cl45_write(bp, params->port,
+				       ext_phy_type,
+				       ext_phy_addr,
+				       MDIO_PMA_DEVAD,
+				       MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
+				       0xa101);
+
+			/* Set TX PreEmphasis if needed */
+			if ((params->feature_config_flags &
+			     FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
+				DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
+					 "TX_CTRL2 0x%x\n",
+					 params->xgxs_config_tx[0],
+					 params->xgxs_config_tx[1]);
+				bnx2x_cl45_write(bp, params->port,
+					       ext_phy_type,
+					       ext_phy_addr,
+					       MDIO_PMA_DEVAD,
+					       MDIO_PMA_REG_8727_TX_CTRL1,
+					       params->xgxs_config_tx[0]);
+
+				bnx2x_cl45_write(bp, params->port,
+					       ext_phy_type,
+					       ext_phy_addr,
+					       MDIO_PMA_DEVAD,
+					       MDIO_PMA_REG_8727_TX_CTRL2,
+					       params->xgxs_config_tx[1]);
+			}
+
+			break;
+		}
+
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
 		{
 			u16 fw_ver1, fw_ver2;
@@ -3561,6 +4009,99 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
 	return rc;
 }

+static void bnx2x_8727_handle_mod_abs(struct link_params *params)
+{
+	struct bnx2x *bp = params->bp;
+	u16 mod_abs, rx_alarm_status;
+	u8 ext_phy_addr = ((params->ext_phy_config &
+			    PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+			   PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+	u32 val = REG_RD(bp, params->shmem_base +
+			     offsetof(struct shmem_region, dev_info.
+				      port_feature_config[params->port].
+				      config));
+	bnx2x_cl45_read(bp, params->port,
+		      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+		      ext_phy_addr,
+		      MDIO_PMA_DEVAD,
+		      MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+	if (mod_abs & (1<<8)) {
+
+		/* Module is absent */
+		DP(NETIF_MSG_LINK, "MOD_ABS indication "
+			    "show module is absent\n");
+
+		/* 1. Set mod_abs to detect next module
+		presence event
+		   2. Set EDC off by setting OPTXLOS signal input to low
+			(bit 9).
+			When the EDC is off it locks onto a reference clock and
+			avoids becoming 'lost'.*/
+		mod_abs &= ~((1<<8)|(1<<9));
+		bnx2x_cl45_write(bp, params->port,
+			       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+			       ext_phy_addr,
+			       MDIO_PMA_DEVAD,
+			       MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+		/* Clear RX alarm since it stays up as long as
+		the mod_abs wasn't changed */
+		bnx2x_cl45_read(bp, params->port,
+			      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+			      ext_phy_addr,
+			      MDIO_PMA_DEVAD,
+			      MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+	} else {
+		/* Module is present */
+		DP(NETIF_MSG_LINK, "MOD_ABS indication "
+			    "show module is present\n");
+		/* First thing, disable transmitter,
+		and if the module is ok, the
+		module_detection will enable it*/
+
+		/* 1. Set mod_abs to detect next module
+		absent event ( bit 8)
+		   2. Restore the default polarity of the OPRXLOS signal and
+		this signal will then correctly indicate the presence or
+		absence of the Rx signal. (bit 9) */
+		mod_abs |= ((1<<8)|(1<<9));
+		bnx2x_cl45_write(bp, params->port,
+		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+		       ext_phy_addr,
+		       MDIO_PMA_DEVAD,
+		       MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+		/* Clear RX alarm since it stays up as long as
+		the mod_abs wasn't changed. This is need to be done
+		before calling the module detection, otherwise it will clear
+		the link update alarm */
+		bnx2x_cl45_read(bp, params->port,
+			      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+			      ext_phy_addr,
+			      MDIO_PMA_DEVAD,
+			      MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+
+		if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+		    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+			bnx2x_sfp_set_transmitter(bp, params->port,
+					PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+					ext_phy_addr, 0);
+
+		if (bnx2x_wait_for_sfp_module_initialized(params)
+		    == 0)
+			bnx2x_sfp_module_detection(params);
+		else
+			DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
+	}
+
+	DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
+		 rx_alarm_status);
+	/* No need to check link status in case of
+	module plugged in/out */
+}
+

 static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
 				 struct link_vars *vars)
@@ -3602,8 +4143,19 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
 				      ext_phy_addr,
 				      MDIO_PMA_DEVAD,
 				      MDIO_PMA_REG_RX_SD, &rx_sd);
-			DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
-			ext_phy_link_up = (rx_sd & 0x1);
+
+			bnx2x_cl45_read(bp, params->port, ext_phy_type,
+				      ext_phy_addr,
+				      1,
+				      0xc809, &val1);
+			bnx2x_cl45_read(bp, params->port, ext_phy_type,
+				      ext_phy_addr,
+				      1,
+				      0xc809, &val1);
+
+			DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
+			ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9))
+					   && ((val1 & (1<<8)) == 0));
 			if (ext_phy_link_up)
 				vars->line_speed = SPEED_10000;
 			break;
@@ -3678,8 +4230,160 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
 				else
 					vars->line_speed = SPEED_10000;
 			}
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+		{
+			u16 link_status = 0;
+			u16 rx_alarm_status;
+			/* Check the LASI */
+			bnx2x_cl45_read(bp, params->port,
+				      ext_phy_type,
+				      ext_phy_addr,
+				      MDIO_PMA_DEVAD,
+				      MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+			DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
+				 rx_alarm_status);
+
+			bnx2x_cl45_read(bp, params->port,
+				      ext_phy_type,
+				      ext_phy_addr,
+				      MDIO_PMA_DEVAD,
+				      MDIO_PMA_REG_LASI_STATUS, &val1);
+
+			DP(NETIF_MSG_LINK,
+				 "8727 LASI status 0x%x\n",
+				 val1);
+
+			/* Clear MSG-OUT */
+			bnx2x_cl45_read(bp, params->port,
+				      ext_phy_type,
+				      ext_phy_addr,
+				      MDIO_PMA_DEVAD,
+				      MDIO_PMA_REG_M8051_MSGOUT_REG,
+				      &val1);
+
+			/*
+			 * If a module is present and there is need to check
+			 * for over current
+			 */
+			if (!(params->feature_config_flags &
+			      FEATURE_CONFIG_BCM8727_NOC) &&
+			    !(rx_alarm_status & (1<<5))) {
+				/* Check over-current using 8727 GPIO0 input*/
+				bnx2x_cl45_read(bp, params->port,
+					      ext_phy_type,
+					      ext_phy_addr,
+					      MDIO_PMA_DEVAD,
+					      MDIO_PMA_REG_8727_GPIO_CTRL,
+					      &val1);
+
+				if ((val1 & (1<<8)) == 0) {
+					DP(NETIF_MSG_LINK, "8727 Power fault"
+						 " has been detected on port"
+						 " %d\n", params->port);
+					printk(KERN_ERR PFX  "Error:  Power"
+						 " fault on %s Port %d has"
+						 " been detected and the"
+						 " power to that SFP+ module"
+						 " has been removed to prevent"
+						 " failure of the card. Please"
+						 " remove the SFP+ module and"
+						 " restart the system to clear"
+						 " this error.\n"
+			, bp->dev->name, params->port);
+					/*
+					 * Disable all RX_ALARMs except for
+					 * mod_abs
+					 */
+					bnx2x_cl45_write(bp, params->port,
+						     ext_phy_type,
+						     ext_phy_addr,
+						     MDIO_PMA_DEVAD,
+						     MDIO_PMA_REG_RX_ALARM_CTRL,
+						     (1<<5));
+
+					bnx2x_cl45_read(bp, params->port,
+						    ext_phy_type,
+						    ext_phy_addr,
+						    MDIO_PMA_DEVAD,
+						    MDIO_PMA_REG_PHY_IDENTIFIER,
+						    &val1);
+					/* Wait for module_absent_event */
+					val1 |= (1<<8);
+					bnx2x_cl45_write(bp, params->port,
+						    ext_phy_type,
+						    ext_phy_addr,
+						    MDIO_PMA_DEVAD,
+						    MDIO_PMA_REG_PHY_IDENTIFIER,
+						    val1);
+					/* Clear RX alarm */
+					bnx2x_cl45_read(bp, params->port,
+						      ext_phy_type,
+						      ext_phy_addr,
+						      MDIO_PMA_DEVAD,
+						      MDIO_PMA_REG_RX_ALARM,
+						      &rx_alarm_status);
+					break;
+				}
+			} /* Over current check */
+
+			/* When module absent bit is set, check module */
+			if (rx_alarm_status & (1<<5)) {
+				bnx2x_8727_handle_mod_abs(params);
+				/* Enable all mod_abs and link detection bits */
+				bnx2x_cl45_write(bp, params->port,
+					       ext_phy_type,
+					       ext_phy_addr,
+					       MDIO_PMA_DEVAD,
+					       MDIO_PMA_REG_RX_ALARM_CTRL,
+					       ((1<<5) | (1<<2)));
+			}
+
+			/* If transmitter is disabled,
+			ignore false link up indication */
+			bnx2x_cl45_read(bp, params->port,
+				      ext_phy_type,
+				      ext_phy_addr,
+				      MDIO_PMA_DEVAD,
+				      MDIO_PMA_REG_PHY_IDENTIFIER,
+				      &val1);
+			if (val1 & (1<<15)) {
+				DP(NETIF_MSG_LINK, "Tx is disabled\n");
+				ext_phy_link_up = 0;
+				break;
+			}
+
+			bnx2x_cl45_read(bp, params->port,
+				      ext_phy_type,
+				      ext_phy_addr,
+				      MDIO_PMA_DEVAD,
+				      MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
+				      &link_status);

+			/* Bits 0..2 --> speed detected,
+			   bits 13..15--> link is down */
+			if ((link_status & (1<<2)) &&
+			    (!(link_status & (1<<15)))) {
+				ext_phy_link_up = 1;
+				vars->line_speed = SPEED_10000;
+			} else if ((link_status & (1<<0)) &&
+				   (!(link_status & (1<<13)))) {
+				ext_phy_link_up = 1;
+				vars->line_speed = SPEED_1000;
+				DP(NETIF_MSG_LINK,
+					 "port %x: External link"
+					 " up in 1G\n", params->port);
+			} else {
+				ext_phy_link_up = 0;
+				DP(NETIF_MSG_LINK,
+					 "port %x: External link"
+					 " is down\n", params->port);
+			}
 			break;
+		}
+
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
 		{
@@ -4241,6 +4945,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
 		break;
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
@@ -4842,10 +5547,6 @@ static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
 		       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
 		       MDIO_PMA_DEVAD,
 		       MDIO_PMA_REG_GEN_CTRL, 0x0001);
-
-	/* Disable Transmitter */
-	bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
-
 }

 u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
@@ -4858,6 +5559,11 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
 	u32 chip_id = params->chip_id;
 	u8 port = params->port;
 	u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
+	u32 val = REG_RD(bp, params->shmem_base +
+			     offsetof(struct shmem_region, dev_info.
+				      port_feature_config[params->port].
+				      config));
+
 	/* disable attentions */

 	vars->link_status = 0;
@@ -4892,6 +5598,21 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
 			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+		{
+
+			/* Disable Transmitter */
+			u8 ext_phy_addr = ((params->ext_phy_config &
+				    PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+				   PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+			if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+			    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+				bnx2x_sfp_set_transmitter(bp, port,
+					PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+					ext_phy_addr, 0);
+			break;
+		}
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
 			DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
 				 "low power mode\n",
@@ -5216,6 +5937,74 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)

 }

+static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
+{
+	u8 ext_phy_addr[PORT_MAX];
+	s8 port;
+	u32 swap_val, swap_override;
+	DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
+	swap_val = REG_RD(bp,  NIG_REG_PORT_SWAP);
+	swap_override = REG_RD(bp,  NIG_REG_STRAP_OVERRIDE);
+
+	bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override));
+	msleep(5);
+
+	/* PART1 - Reset both phys */
+	for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+		/* Extract the ext phy address for the port */
+		u32 ext_phy_config = REG_RD(bp, shmem_base +
+					offsetof(struct shmem_region,
+		   dev_info.port_hw_config[port].external_phy_config));
+
+		/* disable attentions */
+		bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+			     (NIG_MASK_XGXS0_LINK_STATUS |
+			      NIG_MASK_XGXS0_LINK10G |
+			      NIG_MASK_SERDES0_LINK_STATUS |
+			      NIG_MASK_MI_INT));
+
+		ext_phy_addr[port] = ((ext_phy_config &
+					PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+					PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+		/* Reset the phy */
+		bnx2x_cl45_write(bp, port,
+			       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+			       ext_phy_addr[port],
+			       MDIO_PMA_DEVAD,
+			       MDIO_PMA_REG_CTRL,
+			       1<<15);
+	}
+
+	/* Add delay of 150ms after reset */
+	msleep(150);
+
+	/* PART2 - Download firmware to both phys */
+	for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+		u16 fw_ver1;
+
+		bnx2x_bcm8727_external_rom_boot(bp, port,
+					      ext_phy_addr[port], shmem_base);
+
+		bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+			      ext_phy_addr[port],
+			      MDIO_PMA_DEVAD,
+			      MDIO_PMA_REG_ROM_VER1, &fw_ver1);
+		if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
+			DP(NETIF_MSG_LINK,
+				 "bnx2x_8073_common_init_phy port %x:"
+				 "Download failed. fw version = 0x%x\n",
+				 port, fw_ver1);
+			return -EINVAL;
+		}
+
+	}
+
+
+
+	return 0;
+}
+

 static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
 {
@@ -5274,6 +6063,12 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
 		rc = bnx2x_8073_common_init_phy(bp, shmem_base);
 		break;
 	}
+
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
+		rc = bnx2x_8727_common_init_phy(bp, shmem_base);
+		break;
+
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
 		/* GPIO1 affects both ports, so there's need to pull
 		it for single port alone */
diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h
index 19a866d..d25ef45 100644
--- a/drivers/net/bnx2x_link.h
+++ b/drivers/net/bnx2x_link.h
@@ -39,7 +39,13 @@
 #define SPEED_15000		15000
 #define SPEED_16000		16000

-
+#define SFP_EEPROM_VENDOR_NAME_ADDR		0x14
+#define SFP_EEPROM_VENDOR_NAME_SIZE		16
+#define SFP_EEPROM_VENDOR_OUI_ADDR		0x25
+#define SFP_EEPROM_VENDOR_OUI_SIZE		3
+#define SFP_EEPROM_PART_NO_ADDR 		0x28
+#define SFP_EEPROM_PART_NO_SIZE		16
+#define PWR_FLT_ERR_MSG_LEN			250
 /***********************************************************/
 /*                         Structs                         */
 /***********************************************************/
@@ -91,7 +97,8 @@ struct link_params {
 	u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */
 	u32 feature_config_flags;
 #define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0)
-#define FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED	(2<<0)
+#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY	(1<<2)
+#define FEATURE_CONFIG_BCM8727_NOC			(1<<3)
 	/* Device pointer passed to all callback functions */
 	struct bnx2x *bp;
 };
@@ -181,4 +188,7 @@ u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars);
 u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base);


+u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+			      u8 byte_cnt, u8 *o_buf);
+
 #endif /* BNX2X_LINK_H */
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index b404a9b..197dbe4 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -2637,7 +2637,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
 {
 	int port = BP_PORT(bp);
 	int reg_offset;
-	u32 val;
+	u32 val, swap_val, swap_override;

 	reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
 			     MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
@@ -2661,6 +2661,17 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
 				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
 			break;

+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+			/* The PHY reset is controlled by GPIO 1 */
+			/* fake the port number to cancel the swap done in
+			   set_gpio() */
+			swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+			swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+			port = (swap_val && swap_override) ^ 1;
+			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
+			break;
+
 		default:
 			break;
 		}
@@ -5562,6 +5573,8 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
 				((phy_type ==
 				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) ||
 				 (phy_type ==
+				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
+				 (phy_type ==
 				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481));
 		}

@@ -5812,6 +5825,7 @@ static int bnx2x_init_common(struct bnx2x *bp)
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
 		bp->port.need_hw_lock = 1;
 		break;

@@ -6050,10 +6064,15 @@ static int bnx2x_init_port(struct bnx2x *bp)
 		break;

 	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
 		/* add SPIO 5 to group 0 */
-		val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+		{
+		u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+				       MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+		val = REG_RD(bp, reg_addr);
 		val |= AEU_INPUTS_ATTN_BITS_SPIO5;
-		REG_WR(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, val);
+		REG_WR(bp, reg_addr, val);
+		}
 		break;

 	default:
@@ -6203,7 +6222,7 @@ init_hw_err:
 }

 /* send the MCP a request, block until there is a reply */
-static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
 {
 	int func = BP_FUNC(bp);
 	u32 seq = ++bp->fw_seq;
@@ -7676,6 +7695,9 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
 		BNX2X_ERR("This driver needs bc_ver %X but found %X,"
 			  " please upgrade BC\n", BNX2X_BC_VER, val);
 	}
+	bp->link_params.feature_config_flags |=
+		(val >= REQ_BC_VER_4_VRFY_OPT_MDL) ?
+		FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0;

 	if (BP_E1HVN(bp) == 0) {
 		pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
@@ -7836,6 +7858,18 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
 					       SUPPORTED_Asym_Pause);
 			break;

+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10000baseT_Full |
+					       SUPPORTED_1000baseT_Full |
+					       SUPPORTED_Autoneg |
+					       SUPPORTED_FIBRE |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
 			BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
 				       ext_phy_type);
@@ -8099,6 +8133,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
 	bp->link_params.ext_phy_config =
 		SHMEM_RD(bp,
 			 dev_info.port_hw_config[port].external_phy_config);
+	/* BCM8727_NOC => BCM8727 no over current */
+	if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+	    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) {
+		bp->link_params.ext_phy_config &=
+			~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+		bp->link_params.ext_phy_config |=
+			PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727;
+		bp->link_params.feature_config_flags |=
+			FEATURE_CONFIG_BCM8727_NOC;
+	}
+
 	bp->link_params.speed_cap_mask =
 		SHMEM_RD(bp,
 			 dev_info.port_hw_config[port].speed_capability_mask);
@@ -8119,17 +8164,10 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
 		bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff);
 	}

-	config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
-	if (config & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED)
-		bp->link_params.feature_config_flags |=
-				FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
-	else
-		bp->link_params.feature_config_flags &=
-				~FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
-
 	/* If the device is capable of WoL, set the default state according
 	 * to the HW
 	 */
+	config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
 	bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
 		   (config & PORT_FEATURE_WOL_ENABLED));

@@ -8139,8 +8177,8 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
 		       bp->link_params.ext_phy_config,
 		       bp->link_params.speed_cap_mask, bp->port.link_config);

-	bp->link_params.switch_cfg = (bp->port.link_config &
-				      PORT_FEATURE_CONNECTED_SWITCH_MASK);
+	bp->link_params.switch_cfg |= (bp->port.link_config &
+				       PORT_FEATURE_CONNECTED_SWITCH_MASK);
 	bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg);

 	bnx2x_link_settings_requested(bp);
@@ -8336,6 +8374,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
 			cmd->port = PORT_FIBRE;
 			break;

diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h
index 6d77730..d771168 100644
--- a/drivers/net/bnx2x_reg.h
+++ b/drivers/net/bnx2x_reg.h
@@ -5845,25 +5845,33 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_PMA_REG_ROM_VER2		0xca1a
 #define MDIO_PMA_REG_EDC_FFE_MAIN	0xca1b
 #define MDIO_PMA_REG_PLL_BANDWIDTH	0xca1d
-#define MDIO_PMA_REG_GEN_CTRL2		0xca1e
+#define MDIO_PMA_REG_PLL_CTRL		0xca1e
 #define MDIO_PMA_REG_MISC_CTRL0 	0xca23
 #define MDIO_PMA_REG_LRM_MODE		0xca3f
 #define MDIO_PMA_REG_CDR_BANDWIDTH	0xca46
 #define MDIO_PMA_REG_MISC_CTRL1 	0xca85

-#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL 	0x8000
-#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK	0x000c
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE		0x0000
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE	0x0004
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IN_PROGRESS	0x0008
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_FAILED	0x000c
-#define MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT	0x8002
-#define MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR	0x8003
+#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL		0x8000
+#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK	0x000c
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE		0x0000
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE	0x0004
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IN_PROGRESS	0x0008
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_FAILED 	0x000c
+#define MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT	0x8002
+#define MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR	0x8003
 #define MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF	0xc820
 #define MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK 0xff
 #define MDIO_PMA_REG_8726_TX_CTRL1		0xca01
 #define MDIO_PMA_REG_8726_TX_CTRL2		0xca05

+#define MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR	0x8005
+#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF	0x8007
+#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK 0xff
+#define MDIO_PMA_REG_8727_MISC_CTRL		0x8309
+#define MDIO_PMA_REG_8727_TX_CTRL1		0xca02
+#define MDIO_PMA_REG_8727_TX_CTRL2		0xca05
+#define MDIO_PMA_REG_8727_PCS_OPT_CTRL		0xc808
+#define MDIO_PMA_REG_8727_GPIO_CTRL		0xc80e

 #define MDIO_PMA_REG_8073_CHIP_REV			0xc801
 #define MDIO_PMA_REG_8073_SPEED_LINK_STATUS		0xc820
--
1.5.4.3





^ permalink raw reply related

* [net-next 8/10] bnx2x: Set LED in loopback test
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x_link.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c
index b9c85a2..a24bc51 100644
--- a/drivers/net/bnx2x_link.c
+++ b/drivers/net/bnx2x_link.c
@@ -5494,6 +5494,11 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
 		}
 		REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
 			    params->port*4, 0);
+
+		bnx2x_set_led(bp, params->port, LED_MODE_OPER,
+			    vars->line_speed, params->hw_led_mode,
+			    params->chip_id);
+
 	} else
 	/* No loopback */
 	{
-- 
1.5.4.3





^ permalink raw reply related

* [net-next 9/10] bnx2x: Missing parenthesis might result with wrong casting
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 8b6e83d..8bd80fc 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -160,7 +160,7 @@ struct sw_rx_page {
 #define PAGES_PER_SGE			(1 << PAGES_PER_SGE_SHIFT)
 #define SGE_PAGE_SIZE			PAGE_SIZE
 #define SGE_PAGE_SHIFT			PAGE_SHIFT
-#define SGE_PAGE_ALIGN(addr)		PAGE_ALIGN((typeof(PAGE_SIZE))addr)
+#define SGE_PAGE_ALIGN(addr)		PAGE_ALIGN((typeof(PAGE_SIZE))(addr))
 
 /* SGE ring related macros */
 #define NUM_RX_SGE_PAGES		2
-- 
1.5.4.3





^ permalink raw reply related

* [net-next 10/10] Version 1.48.113-1
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x_main.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 197dbe4..c4c42b3 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -56,8 +56,8 @@
 #include "bnx2x_init_ops.h"
 #include "bnx2x_dump.h"
 
-#define DRV_MODULE_VERSION	"1.48.105-1"
-#define DRV_MODULE_RELDATE	"2009/04/22"
+#define DRV_MODULE_VERSION	"1.48.113-1"
+#define DRV_MODULE_RELDATE	"2009/07/21"
 #define BNX2X_BC_VER		0x040200
 
 #include <linux/firmware.h>
-- 
1.5.4.3





^ permalink raw reply related

* £1,000,000.00GBP
From: michael smith @ 2009-07-21 15:54 UTC (permalink / raw)
  To: uknl

Congrats...You are a winner of (1,000,000.00 GBP send your information to michaelsmith001.9.cn Name: Age: Address, Phone,Occupation, Country Choose option of delivery.(1)Courier Delivery (2)Bank
Transfer


^ permalink raw reply

* winner
From: Online Winner @ 2009-07-21 15:57 UTC (permalink / raw)
  To: in

One Million Great British 
pounds)was awarded to you by your email ID, for 
your prize claim, provide your name, country, sex, 
age, telephone, occupation.

Mr. Anthony Campbell
Email: britlotto@btinternet.com


^ permalink raw reply

* [PATCH net-next-2.6] can: sja1000: Add support for the new 4 channel EMS CPC-PCI cards
From: Wolfgang Grandegger @ 2009-07-21 16:23 UTC (permalink / raw)
  To: Linux Netdev List; +Cc: Socketcan-core, Sebastian Haas

This patch adds support to the ems_pci driver for the new, v2,
4 channel CPC-PCI/PCIe/104P CAN cards from EMS Dr. Thomas Wuensche.

Signed-off-by: Sebastian Haas <haas@ems-wuensche.com>
Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
---
 drivers/net/can/Kconfig           |    7 +
 drivers/net/can/sja1000/ems_pci.c |  152 +++++++++++++++++++++++++++-----------
 2 files changed, 112 insertions(+), 47 deletions(-)

Index: net-next-2.6/drivers/net/can/sja1000/ems_pci.c
===================================================================
--- net-next-2.6.orig/drivers/net/can/sja1000/ems_pci.c
+++ net-next-2.6/drivers/net/can/sja1000/ems_pci.c
@@ -32,13 +32,16 @@
 #define DRV_NAME  "ems_pci"
 
 MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards");
-MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card");
+MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe/104P CAN cards");
+MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe/104P CAN card");
 MODULE_LICENSE("GPL v2");
 
-#define EMS_PCI_MAX_CHAN 2
+#define EMS_PCI_V1_MAX_CHAN 2
+#define EMS_PCI_V2_MAX_CHAN 4
+#define EMS_PCI_MAX_CHAN    EMS_PCI_V2_MAX_CHAN
 
 struct ems_pci_card {
+	int version;
 	int channels;
 
 	struct pci_dev *pci_dev;
@@ -63,12 +66,22 @@ struct ems_pci_card {
 #define PITA2_MISC_CONFIG   0x04000000	/* Multiplexed parallel interface */
 
 /*
+ * Register definitions for the PLX 9030
+ */
+#define PLX_ICSR            0x4c   /* Interrupt Control/Status register */
+#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */
+#define PLX_ICSR_PCIINT_ENA 0x0040 /* PCI Interrupt Enable */
+#define PLX_ICSR_LINTI1_CLR 0x0400 /* Local Edge Triggerable Interrupt Clear */
+#define PLX_ICSR_ENA_CLR    (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \
+			     PLX_ICSR_LINTI1_CLR)
+
+/*
  * The board configuration is probably following:
  * RX1 is connected to ground.
  * TX1 is not connected.
  * CLKO is not connected.
  * Setting the OCR register to 0xDA is a good idea.
- * This means  normal output mode , push-pull and the correct polarity.
+ * This means normal output mode, push-pull and the correct polarity.
  */
 #define EMS_PCI_OCR         (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
 
@@ -79,17 +92,21 @@ struct ems_pci_card {
  * is driven by the first one CLKOUT output.
  */
 #define EMS_PCI_CDR             (CDR_CBP | CDR_CLKOUT_MASK)
-#define EMS_PCI_MEM_SIZE        4096  /* Size of the remapped io-memory */
+
+#define EMS_PCI_V1_BASE_BAR     1
+#define EMS_PCI_V1_MEM_SIZE     4096
+#define EMS_PCI_V2_BASE_BAR     2
+#define EMS_PCI_V2_MEM_SIZE     128
 #define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
 #define EMS_PCI_CAN_CTRL_SIZE   0x200 /* memory size for each controller */
 
-#define EMS_PCI_PORT_BYTES  0x4     /* Each register occupies 4 bytes */
-
-#define EMS_PCI_VENDOR_ID   0x110a  /* PCI device and vendor ID */
-#define EMS_PCI_DEVICE_ID   0x2104
-
 static struct pci_device_id ems_pci_tbl[] = {
-	{EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+	/* CPC-PCI v1 */
+	{PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,},
+	/* CPC-PCI v2 */
+	{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4000},
+	/* CPC-104P v2 */
+	{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4002},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
@@ -97,28 +114,47 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
 /*
  * Helper to read internal registers from card logic (not CAN)
  */
-static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port)
+static u8 ems_pci_v1_readb(struct ems_pci_card *card, unsigned int port)
 {
-	return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES));
+	return readb(card->base_addr + (port * 4));
 }
 
-static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port)
+static u8 ems_pci_v1_read_reg(const struct sja1000_priv *priv, int port)
 {
-	return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES));
+	return readb(priv->reg_base + (port * 4));
 }
 
-static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
+static void ems_pci_v1_write_reg(const struct sja1000_priv *priv,
+				 int port, u8 val)
 {
-	writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES));
+	writeb(val, priv->reg_base + (port * 4));
 }
 
-static void ems_pci_post_irq(const struct sja1000_priv *priv)
+static void ems_pci_v1_post_irq(const struct sja1000_priv *priv)
 {
 	struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
 
 	/* reset int flag of pita */
-	writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr
-		+ PITA2_ICR);
+	writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+	       card->conf_addr + PITA2_ICR);
+}
+
+static u8 ems_pci_v2_read_reg(const struct sja1000_priv *priv, int port)
+{
+	return readb(priv->reg_base + port);
+}
+
+static void ems_pci_v2_write_reg(const struct sja1000_priv *priv,
+				 int port, u8 val)
+{
+	writeb(val, priv->reg_base + port);
+}
+
+static void ems_pci_v2_post_irq(const struct sja1000_priv *priv)
+{
+	struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
+
+	writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR);
 }
 
 /*
@@ -130,12 +166,12 @@ static inline int ems_pci_check_chan(con
 	unsigned char res;
 
 	/* Make sure SJA1000 is in reset mode */
-	ems_pci_write_reg(priv, REG_MOD, 1);
+	priv->write_reg(priv, REG_MOD, 1);
 
-	ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN);
+	priv->write_reg(priv, REG_CDR, CDR_PELICAN);
 
 	/* read reset-values */
-	res = ems_pci_read_reg(priv, REG_CDR);
+	res = priv->read_reg(priv, REG_CDR);
 
 	if (res == CDR_PELICAN)
 		return 1;
@@ -188,6 +224,7 @@ static int __devinit ems_pci_add_card(st
 	struct sja1000_priv *priv;
 	struct net_device *dev;
 	struct ems_pci_card *card;
+	int max_chan, mem_size, base_bar;
 	int err, i;
 
 	/* Enabling PCI device */
@@ -210,37 +247,52 @@ static int __devinit ems_pci_add_card(st
 
 	card->channels = 0;
 
-	/* Remap PITA configuration space, and controller memory area */
-	card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE);
+	if (pdev->vendor == PCI_VENDOR_ID_PLX) {
+		card->version = 2; /* CPC-PCI v2 */
+		max_chan = EMS_PCI_V2_MAX_CHAN;
+		base_bar = EMS_PCI_V2_BASE_BAR;
+		mem_size = EMS_PCI_V2_MEM_SIZE;
+	} else {
+		card->version = 1; /* CPC-PCI v1 */
+		max_chan = EMS_PCI_V1_MAX_CHAN;
+		base_bar = EMS_PCI_V1_BASE_BAR;
+		mem_size = EMS_PCI_V1_MEM_SIZE;
+	}
+
+	/* Remap configuration space and controller memory area */
+	card->conf_addr = pci_iomap(pdev, 0, mem_size);
 	if (card->conf_addr == NULL) {
 		err = -ENOMEM;
 		goto failure_cleanup;
 	}
 
-	card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE);
+	card->base_addr = pci_iomap(pdev, base_bar, mem_size);
 	if (card->base_addr == NULL) {
 		err = -ENOMEM;
 		goto failure_cleanup;
 	}
 
-	/* Configure PITA-2 parallel interface (enable MUX) */
-	writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
-
-	/* Check for unique EMS CAN signature */
-	if (ems_pci_readb(card, 0) != 0x55 ||
-	    ems_pci_readb(card, 1) != 0xAA ||
-	    ems_pci_readb(card, 2) != 0x01 ||
-	    ems_pci_readb(card, 3) != 0xCB ||
-	    ems_pci_readb(card, 4) != 0x11) {
-		dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n");
-		err = -ENODEV;
-		goto failure_cleanup;
+	if (card->version == 1) {
+		/* Configure PITA-2 parallel interface (enable MUX) */
+		writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
+
+		/* Check for unique EMS CAN signature */
+		if (ems_pci_v1_readb(card, 0) != 0x55 ||
+		    ems_pci_v1_readb(card, 1) != 0xAA ||
+		    ems_pci_v1_readb(card, 2) != 0x01 ||
+		    ems_pci_v1_readb(card, 3) != 0xCB ||
+		    ems_pci_v1_readb(card, 4) != 0x11) {
+			dev_err(&pdev->dev,
+				"Not EMS Dr. Thomas Wuensche interface\n");
+			err = -ENODEV;
+			goto failure_cleanup;
+		}
 	}
 
 	ems_pci_card_reset(card);
 
 	/* Detect available channels */
-	for (i = 0; i < EMS_PCI_MAX_CHAN; i++) {
+	for (i = 0; i < max_chan; i++) {
 		dev = alloc_sja1000dev(0);
 		if (dev == NULL) {
 			err = -ENOMEM;
@@ -255,20 +307,32 @@ static int __devinit ems_pci_add_card(st
 		dev->irq = pdev->irq;
 		priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET
 					+ (i * EMS_PCI_CAN_CTRL_SIZE);
+		if (card->version == 1) {
+			priv->read_reg  = ems_pci_v1_read_reg;
+			priv->write_reg = ems_pci_v1_write_reg;
+			priv->post_irq  = ems_pci_v1_post_irq;
+		} else {
+			priv->read_reg  = ems_pci_v2_read_reg;
+			priv->write_reg = ems_pci_v2_write_reg;
+			priv->post_irq  = ems_pci_v2_post_irq;
+		}
 
 		/* Check if channel is present */
 		if (ems_pci_check_chan(priv)) {
-			priv->read_reg  = ems_pci_read_reg;
-			priv->write_reg = ems_pci_write_reg;
-			priv->post_irq  = ems_pci_post_irq;
 			priv->can.clock.freq = EMS_PCI_CAN_CLOCK;
 			priv->ocr = EMS_PCI_OCR;
 			priv->cdr = EMS_PCI_CDR;
 
 			SET_NETDEV_DEV(dev, &pdev->dev);
 
-			/* Enable interrupts from card */
-			writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR);
+			if (card->version == 1)
+				/* reset int flag of pita */
+				writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+				       card->conf_addr + PITA2_ICR);
+			else
+				/* enable IRQ in PLX 9030 */
+				writel(PLX_ICSR_ENA_CLR,
+				       card->conf_addr + PLX_ICSR);
 
 			/* Register SJA1000 device */
 			err = register_sja1000dev(dev);
Index: net-next-2.6/drivers/net/can/Kconfig
===================================================================
--- net-next-2.6.orig/drivers/net/can/Kconfig
+++ net-next-2.6/drivers/net/can/Kconfig
@@ -61,11 +61,12 @@ config CAN_SJA1000_OF_PLATFORM
 	  you may want to enable this option.
 
 config CAN_EMS_PCI
-	tristate "EMS CPC-PCI and CPC-PCIe Card"
+	tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card"
 	depends on PCI && CAN_SJA1000
 	---help---
-	  This driver is for the one or two channel CPC-PCI and CPC-PCIe
-	  cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+	  This driver is for the one, two or four channel CPC-PCI,
+	  CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
+	  (http://www.ems-wuensche.de).
 
 config CAN_KVASER_PCI
 	tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"

^ permalink raw reply

* Kernel oops on setting sky2 interfaces down
From: Rene Mayrhofer @ 2009-07-21 16:26 UTC (permalink / raw)
  To: netdev; +Cc: Richard Leitner


[-- Attachment #1.1: Type: text/plain, Size: 9599 bytes --]

Hi everybody,

[Please CC me in replies, I am not currently subscribed to this list.]

I have a fully reproducible kernel oops in the sky2 module in kernel
2.6.28.10. The kernel is a vanilla 2.6.28.10 (and I can't switch to
anything newer at this time because of missing squashfs-lzma support),
patched with PaX, netfilter-layer7, squashfs (with LZMA), and IMQ. The
base system is a Debian Lenny with some updates from testing/unstable.

Whenever interfaces using the sky2 module (this box has 8 network
interfaces in a 19" rack appliance) go down, the oops occurs:

[~]# ifdown -a --exclude=lo
[ 1535.000069] sky2 0000:01:00.0: error interrupt status=0xffffffff
[ 1535.006649] sky2 0000:01:00.0: PCI hardware error (0xffff)
[ 1535.012608] sky2 0000:01:00.0: PCI Express error (0xffffffff)
[ 1535.018821] sky2 wan: ram data read parity error
[ 1535.023827] sky2 wan: ram data write parity error
[ 1535.028913] sky2 wan: MAC parity error
[ 1535.032992] sky2 wan: RX parity error
[ 1535.036983] sky2 wan: TCP segmentation error
[ 1535.041655] general protection fault: 0000 [#1] PREEMPT SMP
[ 1535.045601] last sysfs file:
/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed

[ 1535.045601] Modules linked in: xt_multiport cpufreq_userspace xt_DSCP
xt_length xt_mark xt_dscp xt_MARK xt_CONNMARK xt_comment xt_policy
ipt_REDIRECT ip6t_LOG xt_tcpudp ip6table_mangle iptable_mangle
ip6table_filter ip6_tables sit tunnel4 8021q garp stp llc ipt_LOG
xt_limit xt_state iptable_nat iptable_filter ip_tables x_tables dm_mod
p4_clockmod speedstep_lib freq_table tun imq nf_nat_ftp nf_nat
nf_conntrack_ftp nf_conntrack_ipv6 nf_conntrack_ipv4 nf_conntrack
nf_defrag_ipv4 ipv6 evdev parport_pc parport serio_raw pcspkr i2c_i801
i2c_core iTCO_wdt rng_core intel_agp agpgart squashfs sqlzma unlzma loop
aufs exportfs nls_utf8 nls_cp437 ide_generic sd_mod ide_gd_mod
ata_generic pata_acpi ata_piix piix ide_pci_generic ide_core skge sky2
thermal_sys
[ 1535.045601]

[ 1535.045601] Pid: 9960, comm: mv Not tainted (2.6.28.10 #2)

[ 1535.045601] EIP: 0060:[<f808085a>] EFLAGS: 00010286 CPU: 0

[ 1535.045601] EIP is at sky2_mac_intr+0x22/0x9d [sky2]

[ 1535.045601] EAX: f8090f88 EBX: 00000001 ECX: 00000008 EDX: 000000ff

[ 1535.045601] ESI: 00000000 EDI: f682cb80 EBP: 00000080 ESP: f5f13ed4

[ 1535.045601]  DS: 0068 ES: 0068 FS: 00d8 GS: 0033 SS: 0068

[ 1535.045601] Process mv (pid: 9960, ti=f5f12000 task=f4a961c0
task.ti=f5f12000)

[ 1535.045601] Stack:

[ 1535.045601]  ff08340b f682cb88 ffffffff ffffffff f712b800 f80839d6
00000040 f682cb88

[ 1535.045601]  00000000 00000001 f682cb80 c082111a 00000000 00000000
00000003 f7014b80
[ 1535.045601]  c0a604e8 00000246 f7014b80 c0838f21 00000000 c0a604e8
00000101 c1d10124
[ 1535.045601] Call Trace:
[ 1535.045601]  [<f80839d6>] sky2_poll+0x1cb/0xbed [sky2]
[ 1535.045601]  [<c082111a>] __wake_up+0x29/0x39
[ 1535.045601]  [<c0a604e8>] _spin_unlock_irqrestore+0x22/0x39
[ 1535.045601]  [<c0838f21>] __queue_work+0x4d/0x5a
[ 1535.045601]  [<c0a604e8>] _spin_unlock_irqrestore+0x22/0x39
[ 1535.045601]  [<c09eda45>] net_rx_action+0xb8/0x1f6
[ 1535.045601]  [<c082f954>] __do_softirq+0x95/0x142
[ 1535.045601]  [<c082fa49>] do_softirq+0x48/0x57
[ 1535.045601]  [<c082fbc9>] irq_exit+0x3b/0x78
[ 1535.045601]  [<c081218f>] smp_apic_timer_interrupt+0x75/0x7f
[ 1535.045601]  [<c0804f48>] apic_timer_interrupt+0x28/0x30
[ 1535.045601]  [<c0a60000>] rwsem_down_failed_common+0xa4/0x175
[ 1535.045601] Code: c0 83 c4 14 5b 5e 5f 5d c3 55 89 d5 57 89 c7 56 53
89 d3 c1 e5 07 83 ec 04 8b 74 90 30 8d 85 08 0f 00 00 03 07 8a 10 88 54
24 03 <f6> 86 0d 05 00 00 02 74 12 0f b6 c2 50 56 68 84 5b 08 f8 e8 cd
[ 1535.045601] EIP: [<f808085a>] sky2_mac_intr+0x22/0x9d [sky2] SS:ESP
0068:f5f13ed4
[ 1535.302490] Kernel panic - not syncing: Fatal exception in interrupt
[ 1535.309412] Rebooting in 30 seconds..


Or even when doing it more slowly, interface by interface:

[~]# ifdown tun6to4; cat /proc/net/dev | cut -d: -f1 | grep -v Inter |
grep -v face | sort -u | while read iface; do echo $iface; ifdown
$iface; sleep 3s; done
hb

lo

dmz

lan
[ 1127.000261] sky2 0000:04:00.0: error interrupt status=0xffffffff
[ 1127.007348] sky2 0000:04:00.0: PCI hardware error (0xffff)
[ 1127.013745] sky2 0000:04:00.0: PCI Express error (0xffffffff)
[ 1127.020468] sky2 lan: ram data read parity error
[ 1127.025834] sky2 lan: ram data write parity error
[ 1127.031302] sky2 lan: MAC parity error
[ 1127.035671] sky2 lan: RX parity error
[ 1127.039910] sky2 lan: TCP segmentation error
[ 1127.045079] general protection fault: 0000 [#1] PREEMPT SMP
[ 1127.048879] last sysfs file:
/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed

[ 1127.048879] Modules linked in: xt_multiport cpufreq_userspace xt_DSCP
xt_length xt_mark xt_dscp xt_MARK xt_CONNMARK xt_comment xt_policy
ipt_REDIRECT ip6t_LOG xt_tcpudp ip6table_mangle iptable_mangle
ip6table_filter ip6_tables sit tunnel4 8021q garp stp llc ipt_LOG
xt_limit xt_state iptable_nat iptable_filter ip_tables x_tables dm_mod
p4_clockmod speedstep_lib freq_table tun imq nf_nat_ftp nf_nat
nf_conntrack_ftp nf_conntrack_ipv6 nf_conntrack_ipv4 nf_conntrack
nf_defrag_ipv4 ipv6 evdev parport_pc parport pcspkr serio_raw i2c_i801
i2c_core iTCO_wdt rng_core intel_agp agpgart squashfs sqlzma unlzma loop
aufs exportfs nls_utf8 nls_cp437 ide_generic sd_mod ide_gd_mod
ata_generic pata_acpi ata_piix piix ide_pci_generic ide_core skge sky2
thermal_sys
[ 1127.048879]

[ 1127.048879] Pid: 20150, comm: rndc Not tainted (2.6.28.10 #2)

[ 1127.048879] EIP: 0060:[<f808085a>] EFLAGS: 00010286 CPU: 0

[ 1127.048879] EIP is at sky2_mac_intr+0x22/0x9d [sky2]

[ 1127.048879] EAX: f80d8f88 EBX: 00000001 ECX: 00000008 EDX: 000000ff

[ 1127.048879] ESI: 00000000 EDI: f68c2a80 EBP: 00000080 ESP: eb83fb38

[ 1127.048879]  DS: 0068 ES: 0068 FS: 00d8 GS: 0000 SS: 0068

[ 1127.048879] Process rndc (pid: 20150, ti=eb83e000 task=f695bb00
task.ti=eb83e000)

[ 1127.048879] Stack:

[ 1127.048879]  ff08340b f68c2a88 ffffffff ffffffff f712c000 f80839d6
00000040 f68c2a88

[ 1127.048879]  c0a78d54 f70344e0 f68c2a80 f695bb00 c0a78d54 c0a604e8
c1d10980 c0a78d54

[ 1127.048879]  c0827013 00000000 0000000f 00000246 f70344e0 00000102
c0be5180 c0832dc6

[ 1127.048879] Call Trace:

[ 1127.048879]  [<f80839d6>] sky2_poll+0x1cb/0xbed [sky2]

[ 1127.048879]  [<c0a604e8>] _spin_unlock_irqrestore+0x22/0x39

[ 1127.048879]  [<c0827013>] try_to_wake_up+0x158/0x162

[ 1127.048879]  [<c0832dc6>] process_timeout+0x0/0x5

[ 1127.048879]  [<c09eda45>] net_rx_action+0xb8/0x1f6

[ 1127.048879]  [<c082f954>] __do_softirq+0x95/0x142

[ 1127.048879]  [<c082fa49>] do_softirq+0x48/0x57

[ 1127.048879]  [<c082fbc9>] irq_exit+0x3b/0x78

[ 1127.048879]  [<c081218f>] smp_apic_timer_interrupt+0x75/0x7f

[ 1127.048879]  [<c0804f48>] apic_timer_interrupt+0x28/0x30

[ 1127.048879]  [<c0867764>] get_page_from_freelist+0x2b8/0x3df

[ 1127.048879]  [<c0867ae0>] __alloc_pages_internal+0x98/0x37f

[ 1127.048879]  [<c0862ee0>] find_lock_page+0x10/0x43

[ 1127.048879]  [<c0a60555>] _spin_unlock+0x10/0x23

[ 1127.048879]  [<c086fb70>] __do_fault+0xaa/0x3bc

[ 1127.048879]  [<c08718e1>] handle_mm_fault+0x54a/0xbfa

[ 1127.048879]  [<c0a60555>] _spin_unlock+0x10/0x23

[ 1127.048879]  [<c089442d>] __d_lookup+0xfa/0x116

[ 1127.048879]  [<c088cb78>] do_lookup+0x53/0x153

[ 1127.048879]  [<c0893375>] dput+0x16/0xfc

[ 1127.048879]  [<c088eb25>] __link_path_walk+0xb01/0xbfb

[ 1127.048879]  [<c0a60555>] _spin_unlock+0x10/0x23

[ 1127.048879]  [<c086f05e>] kmap_high+0x17c/0x186

[ 1127.048879]  [<c0819b76>] default_spin_lock_flags+0x5/0x7

[ 1127.048879]  [<c081a64b>] do_page_fault+0x335/0x86e

[ 1127.048879]  [<c0a60555>] _spin_unlock+0x10/0x23

[ 1127.048879]  [<c0870a91>] unmap_vmas+0x498/0x6ab

[ 1127.048879]  [<c087321e>] free_pgtables+0x7d/0x93

[ 1127.048879]  [<c086d42e>] vma_prio_tree_insert+0x17/0x7f

[ 1127.048879]  [<c0874a45>] vma_link+0x51/0x73

[ 1127.048879]  [<c0a60555>] _spin_unlock+0x10/0x23

[ 1127.048879]  [<c0874a5f>] vma_link+0x6b/0x73

[ 1127.048879]  [<c08763b8>] mmap_region+0x475/0x58c

[ 1127.048879]  [<c08767a4>] do_mmap_pgoff+0x2d5/0x326

[ 1127.048879]  [<c08081db>] sys_mmap2+0x62/0x77

[ 1127.048879]  [<c08081e9>] sys_mmap2+0x70/0x77

[ 1127.048879]  [<c081a316>] do_page_fault+0x0/0x86e

[ 1127.048879]  [<c0a60805>] error_code+0x75/0x80

[ 1127.048879] Code: c0 83 c4 14 5b 5e 5f 5d c3 55 89 d5 57 89 c7 56 53
89 d3 c1 e5 07 83 ec 04 8b 74 90 30 8d 85 08 0f 00 00 03 07 8a 10 88 54
24 03 <f6> 86 0d 05 00 00 02 74 12 0f b6 c2 50 56 68 84 5b 08 f8 e8 cd

[ 1127.048879] EIP: [<f808085a>] sky2_mac_intr+0x22/0x9d [sky2] SS:ESP
0068:eb83fb38

[ 1127.470534] Kernel panic - not syncing: Fatal exception in interrupt

[ 1127.478035] Rebooting in 30 seconds..



It seems that the oops occurs when the last network interface using the
sky2 module goes down, although I am not completely certain about this.
I am also fairly sure that the other patches applied to 2.6.28.10 are
not at fault, as the same kernel works perfectly well on different
hardware (which is not using the sky2 NIC module).

Attached are the lspci -v output and the kernel config.

Any hints on what may be wrong would be highly appreciated. I am able to
try patches to sky2 and/or give remote ssh access to the box (although
it will be offline for 5 minutes after triggering the oops...).

best regards,
Rene

[-- Attachment #1.2: lspci.lst.gz --]
[-- Type: application/gzip, Size: 1595 bytes --]

[-- Attachment #1.3: config-2.6.28.10.gz --]
[-- Type: application/gzip, Size: 19547 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply

* [1/4] Remove unused zero-copy code from velocity NIC driver.
From: Dave Jones @ 2009-07-21  3:34 UTC (permalink / raw)
  To: netdev

This code hasn't been enabled in forever.

Signed-off-by: Dave Jones <davej@redhat.com>
---
 drivers/net/via-velocity.c |   77 ++++++-------------------------------------
 1 files changed, 11 insertions(+), 66 deletions(-)

diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 3ba3595..4ebe2ca 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -976,9 +976,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
 	dev->netdev_ops = &velocity_netdev_ops;
 	dev->ethtool_ops = &velocity_ethtool_ops;
 
-#ifdef  VELOCITY_ZERO_COPY_SUPPORT
-	dev->features |= NETIF_F_SG;
-#endif
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
 		NETIF_F_HW_VLAN_RX;
 
@@ -1849,11 +1846,7 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_
 
 		pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
 		for (i = 0; i < tdinfo->nskb_dma; i++) {
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
-			pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], le16_to_cpu(td->tdesc1.len), PCI_DMA_TODEVICE);
-#else
 			pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
-#endif
 			tdinfo->skb_dma[i] = 0;
 		}
 	}
@@ -2095,13 +2088,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	len = cpu_to_le16(pktlen);
 
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
-	if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
-		kfree_skb(skb);
-		return 0;
-	}
-#endif
-
 	spin_lock_irqsave(&vptr->lock, flags);
 
 	index = vptr->tx.curr[qnum];
@@ -2111,59 +2097,18 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
 	td_ptr->tdesc1.TCR = TCR0_TIC;
 	td_ptr->td_buf[0].size &= ~TD_QUEUE;
 
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
-	if (skb_shinfo(skb)->nr_frags > 0) {
-		int nfrags = skb_shinfo(skb)->nr_frags;
-		tdinfo->skb = skb;
-		if (nfrags > 6) {
-			skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
-			tdinfo->skb_dma[0] = tdinfo->buf_dma;
-			td_ptr->tdesc0.len = len;
-			td_ptr->tx.buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
-			td_ptr->tx.buf[0].pa_high = 0;
-			td_ptr->tx.buf[0].size = len;	/* queue is 0 anyway */
-			tdinfo->nskb_dma = 1;
-		} else {
-			int i = 0;
-			tdinfo->nskb_dma = 0;
-			tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data,
-						skb_headlen(skb), PCI_DMA_TODEVICE);
-
-			td_ptr->tdesc0.len = len;
-
-			/* FIXME: support 48bit DMA later */
-			td_ptr->tx.buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma);
-			td_ptr->tx.buf[i].pa_high = 0;
-			td_ptr->tx.buf[i].size = cpu_to_le16(skb_headlen(skb));
-
-			for (i = 0; i < nfrags; i++) {
-				skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-				void *addr = (void *)page_address(frag->page) + frag->page_offset;
-
-				tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE);
-
-				td_ptr->tx.buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
-				td_ptr->tx.buf[i + 1].pa_high = 0;
-				td_ptr->tx.buf[i + 1].size = cpu_to_le16(frag->size);
-			}
-			tdinfo->nskb_dma = i - 1;
-		}
+	/*
+	 *	Map the linear network buffer into PCI space and
+	 *	add it to the transmit ring.
+	 */
+	tdinfo->skb = skb;
+	tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
+	td_ptr->tdesc0.len = len;
+	td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+	td_ptr->td_buf[0].pa_high = 0;
+	td_ptr->td_buf[0].size = len;
+	tdinfo->nskb_dma = 1;
 
-	} else
-#endif
-	{
-		/*
-		 *	Map the linear network buffer into PCI space and
-		 *	add it to the transmit ring.
-		 */
-		tdinfo->skb = skb;
-		tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
-		td_ptr->tdesc0.len = len;
-		td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
-		td_ptr->td_buf[0].pa_high = 0;
-		td_ptr->td_buf[0].size = len;
-		tdinfo->nskb_dma = 1;
-	}
 	td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
 
 	if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
-- 
1.6.2.5


^ permalink raw reply related

* [0/4] trivial cleanups for via-velocity.c
From: Dave Jones @ 2009-07-21  3:34 UTC (permalink / raw)
  To: netdev

I've had these sitting around for a while, they should be safe to apply.
I checked a diff of the disassembly from objdump before/after, and
the only diffs were the placement of the functions & jump offsets changing
due to the reordering in diff 3/4.

	Dave


^ permalink raw reply

* [4/4] Fix typos in comments in via-velocity header.
From: Dave Jones @ 2009-07-21  3:40 UTC (permalink / raw)
  To: netdev

Signed-off-by: Dave Jones <davej@redhat.com>
---
 drivers/net/via-velocity.h |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index 4cd3f6c..2f00c13 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -96,8 +96,8 @@
  * Bits in the CSM register
  */
 
-#define CSM_IPOK            0x40	//IP Checkusm validatiaon ok
-#define CSM_TUPOK           0x20	//TCP/UDP Checkusm validatiaon ok
+#define CSM_IPOK            0x40	//IP Checksum validation ok
+#define CSM_TUPOK           0x20	//TCP/UDP Checksum validation ok
 #define CSM_FRAG            0x10	//Fragment IP datagram
 #define CSM_IPKT            0x04	//Received an IP packet
 #define CSM_TCPKT           0x02	//Received a TCP packet
@@ -819,7 +819,7 @@ enum  velocity_owner {
  *	Bits in the EECSR register
  */
 
-#define EECSR_EMBP          0x40	/* eeprom embeded programming */
+#define EECSR_EMBP          0x40	/* eeprom embedded programming */
 #define EECSR_RELOAD        0x20	/* eeprom content reload */
 #define EECSR_DPM           0x10	/* eeprom direct programming */
 #define EECSR_ECS           0x08	/* eeprom CS pin */
-- 
1.6.2.5


^ permalink raw reply related

* [2/4] Fix up CodingStyle problems in via-velocity.c
From: Dave Jones @ 2009-07-21  3:35 UTC (permalink / raw)
  To: netdev

Signed-off-by: Dave Jones <davej@redhat.com>
---
 drivers/net/via-velocity.c |  175 ++++++++++++++++++++------------------------
 1 files changed, 80 insertions(+), 95 deletions(-)

diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 4ebe2ca..d6a92b7 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -61,9 +61,9 @@
 #include <linux/interrupt.h>
 #include <linux/string.h>
 #include <linux/wait.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/if.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/proc_fs.h>
 #include <linux/inetdevice.h>
 #include <linux/reboot.h>
@@ -81,7 +81,7 @@
 #include "via-velocity.h"
 
 
-static int velocity_nics = 0;
+static int velocity_nics;
 static int msglevel = MSG_LEVEL_INFO;
 
 /**
@@ -93,7 +93,7 @@ static int msglevel = MSG_LEVEL_INFO;
  *	provided mask buffer.
  */
 
-static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
 {
 	int i;
 
@@ -111,7 +111,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
 
 	/* Select mar */
 	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
 }
 
 
@@ -123,7 +122,7 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
  *	Store a new mask into a CAM
  */
 
-static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_set_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
 {
 	int i;
 	/* Select CAM mask */
@@ -131,9 +130,9 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
 
 	writeb(CAMADDR_CAMEN, &regs->CAMADDR);
 
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < 8; i++)
 		writeb(*mask++, &(regs->MARCAM[i]));
-	}
+
 	/* disable CAMEN */
 	writeb(0, &regs->CAMADDR);
 
@@ -141,7 +140,7 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
 	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
 }
 
-static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_set_vlan_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
 {
 	int i;
 	/* Select CAM mask */
@@ -149,9 +148,9 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
 
 	writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
 
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < 8; i++)
 		writeb(*mask++, &(regs->MARCAM[i]));
-	}
+
 	/* disable CAMEN */
 	writeb(0, &regs->CAMADDR);
 
@@ -168,7 +167,7 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
  *	Load an address or vlan tag into a CAM
  */
 
-static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
+static void mac_set_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr)
 {
 	int i;
 
@@ -179,9 +178,9 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
 
 	writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
 
-	for (i = 0; i < 6; i++) {
+	for (i = 0; i < 6; i++)
 		writeb(*addr++, &(regs->MARCAM[i]));
-	}
+
 	BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
 
 	udelay(10);
@@ -192,7 +191,7 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
 	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
 }
 
-static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
+static void mac_set_vlan_cam(struct mac_regs __iomem *regs, int idx,
 			     const u8 *addr)
 {
 
@@ -224,7 +223,7 @@ static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
  *	the rest of the logic from the result of sleep/wakeup
  */
 
-static void mac_wol_reset(struct mac_regs __iomem * regs)
+static void mac_wol_reset(struct mac_regs __iomem *regs)
 {
 
 	/* Turn off SWPTAG right after leaving power mode */
@@ -253,10 +252,10 @@ MODULE_AUTHOR("VIA Networking Technologies, Inc.");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver");
 
-#define VELOCITY_PARAM(N,D) \
-        static int N[MAX_UNITS]=OPTION_DEFAULT;\
+#define VELOCITY_PARAM(N, D) \
+	static int N[MAX_UNITS] = OPTION_DEFAULT;\
 	module_param_array(N, int, NULL, 0); \
-        MODULE_PARM_DESC(N, D);
+	MODULE_PARM_DESC(N, D);
 
 #define RX_DESC_MIN     64
 #define RX_DESC_MAX     255
@@ -336,8 +335,8 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability");
    4: indicate 10Mbps full duplex mode
 
    Note:
-        if EEPROM have been set to the force mode, this option is ignored
-            by driver.
+   if EEPROM have been set to the force mode, this option is ignored
+   by driver.
 */
 VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
 
@@ -391,14 +390,14 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status);
 static u32 velocity_get_link(struct net_device *dev);
 static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
 static void velocity_print_link_status(struct velocity_info *vptr);
-static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs);
+static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs);
 static void velocity_shutdown(struct velocity_info *vptr);
 static void enable_flow_control_ability(struct velocity_info *vptr);
-static void enable_mii_autopoll(struct mac_regs __iomem * regs);
-static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 * pdata);
+static void enable_mii_autopoll(struct mac_regs __iomem *regs);
+static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 *pdata);
 static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data);
-static u32 mii_check_media_mode(struct mac_regs __iomem * regs);
-static u32 check_connection_type(struct mac_regs __iomem * regs);
+static u32 mii_check_media_mode(struct mac_regs __iomem *regs);
+static u32 check_connection_type(struct mac_regs __iomem *regs);
 static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
 
 #ifdef CONFIG_PM
@@ -550,7 +549,7 @@ static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max,
  *	we don't duplicate code for each option.
  */
 
-static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, const char *devname)
+static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag, char *name, const char *devname)
 {
 	(*opt) &= (~flag);
 	if (val == -1)
@@ -604,7 +603,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
 
 static void velocity_init_cam_filter(struct velocity_info *vptr)
 {
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 
 	/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
 	WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -647,19 +646,19 @@ static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
 
-        spin_lock_irq(&vptr->lock);
+	spin_lock_irq(&vptr->lock);
 	velocity_init_cam_filter(vptr);
-        spin_unlock_irq(&vptr->lock);
+	spin_unlock_irq(&vptr->lock);
 }
 
 static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
 
-        spin_lock_irq(&vptr->lock);
+	spin_lock_irq(&vptr->lock);
 	vlan_group_set_device(vptr->vlgrp, vid, NULL);
 	velocity_init_cam_filter(vptr);
-        spin_unlock_irq(&vptr->lock);
+	spin_unlock_irq(&vptr->lock);
 }
 
 static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
@@ -678,7 +677,7 @@ static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
 static void velocity_rx_reset(struct velocity_info *vptr)
 {
 
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	int i;
 
 	velocity_init_rx_ring_indexes(vptr);
@@ -707,7 +706,7 @@ static void velocity_rx_reset(struct velocity_info *vptr)
 static void velocity_init_registers(struct velocity_info *vptr,
 				    enum velocity_init_type type)
 {
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	int i, mii_status;
 
 	mac_wol_reset(regs);
@@ -750,9 +749,9 @@ static void velocity_init_registers(struct velocity_info *vptr,
 		mdelay(5);
 
 		mac_eeprom_reload(regs);
-		for (i = 0; i < 6; i++) {
+		for (i = 0; i < 6; i++)
 			writeb(vptr->dev->dev_addr[i], &(regs->PAR[i]));
-		}
+
 		/*
 		 *	clear Pre_ACPI bit.
 		 */
@@ -829,7 +828,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
 
 static int velocity_soft_reset(struct velocity_info *vptr)
 {
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	int i = 0;
 
 	writel(CR0_SFRST, &regs->CR0Set);
@@ -881,7 +880,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
 	const char *drv_string;
 	const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
 	struct velocity_info *vptr;
-	struct mac_regs __iomem * regs;
+	struct mac_regs __iomem *regs;
 	int ret = -ENOMEM;
 
 	/* FIXME: this driver, like almost all other ethernet drivers,
@@ -1311,7 +1310,7 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
 					    sizeof(struct velocity_td_info),
 					    GFP_KERNEL);
 		if (!vptr->tx.infos[j])	{
-			while(--j >= 0)
+			while (--j >= 0)
 				kfree(vptr->tx.infos[j]);
 			return -ENOMEM;
 		}
@@ -1328,15 +1327,14 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
 static void velocity_free_td_ring_entry(struct velocity_info *vptr,
 							 int q, int n)
 {
-	struct velocity_td_info * td_info = &(vptr->tx.infos[q][n]);
+	struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]);
 	int i;
 
 	if (td_info == NULL)
 		return;
 
 	if (td_info->skb) {
-		for (i = 0; i < td_info->nskb_dma; i++)
-		{
+		for (i = 0; i < td_info->nskb_dma; i++) {
 			if (td_info->skb_dma[i]) {
 				pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
 					td_info->skb->len, PCI_DMA_TODEVICE);
@@ -1363,10 +1361,9 @@ static void velocity_free_td_ring(struct velocity_info *vptr)
 	for (j = 0; j < vptr->tx.numq; j++) {
 		if (vptr->tx.infos[j] == NULL)
 			continue;
-		for (i = 0; i < vptr->options.numtx; i++) {
+		for (i = 0; i < vptr->options.numtx; i++)
 			velocity_free_td_ring_entry(vptr, j, i);
 
-		}
 		kfree(vptr->tx.infos[j]);
 		vptr->tx.infos[j] = NULL;
 	}
@@ -1447,9 +1444,8 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
 		if (rd->rdesc1.CSM & CSM_IPOK) {
 			if ((rd->rdesc1.CSM & CSM_TCPKT) ||
 					(rd->rdesc1.CSM & CSM_UDPKT)) {
-				if (!(rd->rdesc1.CSM & CSM_TUPOK)) {
+				if (!(rd->rdesc1.CSM & CSM_TUPOK))
 					return;
-				}
 			}
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 		}
@@ -1671,9 +1667,8 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
 		}
 		vptr->tx.tail[qnum] = idx;
 
-		if (AVAIL_TD(vptr, qnum) < 1) {
+		if (AVAIL_TD(vptr, qnum) < 1)
 			full = 1;
-		}
 	}
 	/*
 	 *	Look to see if we should kick the transmit network
@@ -1751,7 +1746,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
 {
 
 	if (status & ISR_TXSTLI) {
-		struct mac_regs __iomem * regs = vptr->mac_regs;
+		struct mac_regs __iomem *regs = vptr->mac_regs;
 
 		printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
 		BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
@@ -1763,7 +1758,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
 	}
 
 	if (status & ISR_SRCI) {
-		struct mac_regs __iomem * regs = vptr->mac_regs;
+		struct mac_regs __iomem *regs = vptr->mac_regs;
 		int linked;
 
 		if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
@@ -1783,11 +1778,10 @@ static void velocity_error(struct velocity_info *vptr, int status)
 			/*
 			 *	Only enable CD heart beat counter in 10HD mode
 			 */
-			if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) {
+			if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10))
 				BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
-			} else {
+			else
 				BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
-			}
 		}
 		/*
 		 *	Get link status from PHYSR0
@@ -2023,7 +2017,7 @@ out_0:
 
 static void velocity_shutdown(struct velocity_info *vptr)
 {
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	mac_disable_int(regs);
 	writel(CR0_STOP, &regs->CR0Set);
 	writew(0xFFFF, &regs->TDCSRClr);
@@ -2195,8 +2189,7 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance)
 		if (isr_status & (ISR_PTXI | ISR_PPTXI))
 			max_count += velocity_tx_srv(vptr, isr_status);
 		isr_status = mac_read_isr(vptr->mac_regs);
-		if (max_count > vptr->options.int_works)
-		{
+		if (max_count > vptr->options.int_works) {
 			printk(KERN_WARNING "%s: excessive work at interrupt.\n",
 				dev->name);
 			max_count = 0;
@@ -2221,7 +2214,7 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance)
 static void velocity_set_multi(struct net_device *dev)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	u8 rx_mode;
 	int i;
 	struct dev_mc_list *mclist;
@@ -2270,7 +2263,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev)
 	struct velocity_info *vptr = netdev_priv(dev);
 
 	/* If the hardware is down, don't touch MII */
-	if(!netif_running(dev))
+	if (!netif_running(dev))
 		return &dev->stats;
 
 	spin_lock_irq(&vptr->lock);
@@ -2473,7 +2466,7 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
  *	Turn off the autopoll and wait for it to disable on the chip
  */
 
-static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs)
+static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs)
 {
 	u16 ww;
 
@@ -2494,7 +2487,7 @@ static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs)
  *	hardware. Wait for it to enable.
  */
 
-static void enable_mii_autopoll(struct mac_regs __iomem * regs)
+static void enable_mii_autopoll(struct mac_regs __iomem *regs)
 {
 	int ii;
 
@@ -2644,7 +2637,7 @@ static void mii_set_auto_on(struct velocity_info *vptr)
 
 
 /*
-static void mii_set_auto_off(struct velocity_info * vptr)
+static void mii_set_auto_off(struct velocity_info *vptr)
 {
     MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
 }
@@ -2698,7 +2691,7 @@ static void set_mii_flow_control(struct velocity_info *vptr)
 static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
 {
 	u32 curr_status;
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 
 	vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
 	curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
@@ -2717,9 +2710,8 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
 	   }
 	 */
 
-	if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) {
+	if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
 		MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
-	}
 
 	/*
 	 *	If connection type is AUTO
@@ -2768,11 +2760,11 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
 
 		MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
 
-		if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) {
+		if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10))
 			BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
-		} else {
+		else
 			BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
-		}
+
 		/* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
 		velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
 		ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
@@ -2805,7 +2797,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
  *	accordingly
  */
 
-static u32 mii_check_media_mode(struct mac_regs __iomem * regs)
+static u32 mii_check_media_mode(struct mac_regs __iomem *regs)
 {
 	u32 status = 0;
 	u16 ANAR;
@@ -2841,7 +2833,7 @@ static u32 mii_check_media_mode(struct mac_regs __iomem * regs)
 	return status;
 }
 
-static u32 check_connection_type(struct mac_regs __iomem * regs)
+static u32 check_connection_type(struct mac_regs __iomem *regs)
 {
 	u32 status = 0;
 	u8 PHYSR0;
@@ -2886,7 +2878,7 @@ static u32 check_connection_type(struct mac_regs __iomem * regs)
 static void enable_flow_control_ability(struct velocity_info *vptr)
 {
 
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 
 	switch (vptr->options.flow_cntl) {
 
@@ -2963,7 +2955,7 @@ static void velocity_ethtool_down(struct net_device *dev)
 static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	u32 status;
 	status = check_connection_type(vptr->mac_regs);
 
@@ -3020,7 +3012,7 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
 static u32 velocity_get_link(struct net_device *dev)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
 }
 
@@ -3116,7 +3108,7 @@ static const struct ethtool_ops velocity_ethtool_ops = {
 static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	unsigned long flags;
 	struct mii_ioctl_data *miidata = if_mii(ifr);
 	int err;
@@ -3128,7 +3120,7 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd
 	case SIOCGMIIREG:
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		if(velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
+		if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
 			return -ETIMEDOUT;
 		break;
 	case SIOCSMIIREG:
@@ -3138,7 +3130,7 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd
 		err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
 		spin_unlock_irqrestore(&vptr->lock, flags);
 		check_connection_type(vptr->mac_regs);
-		if(err)
+		if (err)
 			return err;
 		break;
 	default:
@@ -3160,9 +3152,9 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd
  *	power down states
  */
 
-static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context)
+static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context)
 {
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	u16 i;
 	u8 __iomem *ptr = (u8 __iomem *)regs;
 
@@ -3188,13 +3180,12 @@ static void velocity_save_context(struct velocity_info *vptr, struct velocity_co
 
 static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
 {
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	int i;
 	u8 __iomem *ptr = (u8 __iomem *)regs;
 
-	for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) {
+	for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4)
 		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
-	}
 
 	/* Just skip cr0 */
 	for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
@@ -3204,18 +3195,14 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity
 		writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
 	}
 
-	for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) {
+	for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4)
 		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
-	}
 
-	for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) {
+	for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
 		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
-	}
 
-	for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) {
+	for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++)
 		writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
-	}
-
 }
 
 /**
@@ -3227,7 +3214,7 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity
  *	we are interested in.
  */
 
-static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
+static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern)
 {
 	u16 crc = 0xFFFF;
 	u8 mask;
@@ -3266,7 +3253,7 @@ static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
 
 static int velocity_set_wol(struct velocity_info *vptr)
 {
-	struct mac_regs __iomem * regs = vptr->mac_regs;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
 	static u8 buf[256];
 	int i;
 
@@ -3284,9 +3271,8 @@ static int velocity_set_wol(struct velocity_info *vptr)
 	   writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
 	 */
 
-	if (vptr->wol_opts & VELOCITY_WOL_UCAST) {
+	if (vptr->wol_opts & VELOCITY_WOL_UCAST)
 		writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
-	}
 
 	if (vptr->wol_opts & VELOCITY_WOL_ARP) {
 		struct arp_packet *arp = (struct arp_packet *) buf;
@@ -3347,7 +3333,7 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
 	struct velocity_info *vptr = netdev_priv(dev);
 	unsigned long flags;
 
-	if(!netif_running(vptr->dev))
+	if (!netif_running(vptr->dev))
 		return 0;
 
 	netif_device_detach(vptr->dev);
@@ -3382,7 +3368,7 @@ static int velocity_resume(struct pci_dev *pdev)
 	unsigned long flags;
 	int i;
 
-	if(!netif_running(vptr->dev))
+	if (!netif_running(vptr->dev))
 		return 0;
 
 	pci_set_power_state(pdev, PCI_D0);
@@ -3399,9 +3385,8 @@ static int velocity_resume(struct pci_dev *pdev)
 	velocity_tx_srv(vptr, 0);
 
 	for (i = 0; i < vptr->tx.numq; i++) {
-		if (vptr->tx.used[i]) {
+		if (vptr->tx.used[i])
 			mac_tx_queue_wake(vptr->mac_regs, i);
-		}
 	}
 
 	mac_enable_int(vptr->mac_regs);
-- 
1.6.2.5


^ permalink raw reply related

* [3/4] Remove unnecessary forward declarations from velocity NIC driver.
From: Dave Jones @ 2009-07-21  3:35 UTC (permalink / raw)
  To: netdev

By moving functions to before their first call, we eliminate
the need to define forward references.

Signed-off-by: Dave Jones <davej@redhat.com>
---
 drivers/net/via-velocity.c | 3259 +++++++++++++++++++++-----------------------
 1 files changed, 1580 insertions(+), 1679 deletions(-)

diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index d6a92b7..b4bd1d3 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -92,7 +92,6 @@ static int msglevel = MSG_LEVEL_INFO;
  *	Fetch the mask bits of the selected CAM and store them into the
  *	provided mask buffer.
  */
-
 static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
 {
 	int i;
@@ -121,7 +120,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
  *
  *	Store a new mask into a CAM
  */
-
 static void mac_set_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
 {
 	int i;
@@ -166,7 +164,6 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
  *
  *	Load an address or vlan tag into a CAM
  */
-
 static void mac_set_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr)
 {
 	int i;
@@ -222,7 +219,6 @@ static void mac_set_vlan_cam(struct mac_regs __iomem *regs, int idx,
  *	reset the Wake on lan features. This function doesn't restore
  *	the rest of the logic from the result of sleep/wakeup
  */
-
 static void mac_wol_reset(struct mac_regs __iomem *regs)
 {
 
@@ -241,7 +237,6 @@ static void mac_wol_reset(struct mac_regs __iomem *regs)
 	writew(0xFFFF, &regs->WOLSRClr);
 }
 
-static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 static const struct ethtool_ops velocity_ethtool_ops;
 
 /*
@@ -369,76 +364,14 @@ static int rx_copybreak = 200;
 module_param(rx_copybreak, int, 0644);
 MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
 
-static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
-			       const struct velocity_info_tbl *info);
-static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
-static void velocity_print_info(struct velocity_info *vptr);
-static int velocity_open(struct net_device *dev);
-static int velocity_change_mtu(struct net_device *dev, int mtu);
-static int velocity_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t velocity_intr(int irq, void *dev_instance);
-static void velocity_set_multi(struct net_device *dev);
-static struct net_device_stats *velocity_get_stats(struct net_device *dev);
-static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int velocity_close(struct net_device *dev);
-static int velocity_receive_frame(struct velocity_info *, int idx);
-static int velocity_alloc_rx_buf(struct velocity_info *, int idx);
-static void velocity_free_rd_ring(struct velocity_info *vptr);
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
-static int velocity_soft_reset(struct velocity_info *vptr);
-static void mii_init(struct velocity_info *vptr, u32 mii_status);
-static u32 velocity_get_link(struct net_device *dev);
-static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
-static void velocity_print_link_status(struct velocity_info *vptr);
-static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs);
-static void velocity_shutdown(struct velocity_info *vptr);
-static void enable_flow_control_ability(struct velocity_info *vptr);
-static void enable_mii_autopoll(struct mac_regs __iomem *regs);
-static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 *pdata);
-static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data);
-static u32 mii_check_media_mode(struct mac_regs __iomem *regs);
-static u32 check_connection_type(struct mac_regs __iomem *regs);
-static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
-
 #ifdef CONFIG_PM
-
-static int velocity_suspend(struct pci_dev *pdev, pm_message_t state);
-static int velocity_resume(struct pci_dev *pdev);
-
 static DEFINE_SPINLOCK(velocity_dev_list_lock);
 static LIST_HEAD(velocity_dev_list);
-
-#endif
-
-#if defined(CONFIG_PM) && defined(CONFIG_INET)
-
-static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr);
-
-static struct notifier_block velocity_inetaddr_notifier = {
-      .notifier_call	= velocity_netdev_event,
-};
-
-static void velocity_register_notifier(void)
-{
-	register_inetaddr_notifier(&velocity_inetaddr_notifier);
-}
-
-static void velocity_unregister_notifier(void)
-{
-	unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
-}
-
-#else
-
-#define velocity_register_notifier()	do {} while (0)
-#define velocity_unregister_notifier()	do {} while (0)
-
 #endif
 
 /*
  *	Internal board variants. At the moment we have only one
  */
-
 static struct velocity_info_tbl chip_info_table[] = {
 	{CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL},
 	{ }
@@ -448,7 +381,6 @@ static struct velocity_info_tbl chip_info_table[] = {
  *	Describe the PCI device identifiers that we support in this
  *	device driver. Used for hotplug autoloading.
  */
-
 static const struct pci_device_id velocity_id_table[] __devinitdata = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
 	{ }
@@ -463,7 +395,6 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table);
  *	Given a chip identifier return a suitable description. Returns
  *	a pointer a static string valid while the driver is loaded.
  */
-
 static const char __devinit *get_chip_name(enum chip_type chip_id)
 {
 	int i;
@@ -481,7 +412,6 @@ static const char __devinit *get_chip_name(enum chip_type chip_id)
  *	unload for each active device that is present. Disconnects
  *	the device from the network layer and frees all the resources
  */
-
 static void __devexit velocity_remove1(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
@@ -519,7 +449,6 @@ static void __devexit velocity_remove1(struct pci_dev *pdev)
  *	all the verification and checking as well as reporting so that
  *	we don't duplicate code for each option.
  */
-
 static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, const char *devname)
 {
 	if (val == -1)
@@ -548,7 +477,6 @@ static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max,
  *	all the verification and checking as well as reporting so that
  *	we don't duplicate code for each option.
  */
-
 static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag, char *name, const char *devname)
 {
 	(*opt) &= (~flag);
@@ -574,7 +502,6 @@ static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag
  *	Turn the module and command options into a single structure
  *	for the current device
  */
-
 static void __devinit velocity_get_options(struct velocity_opt *opts, int index, const char *devname)
 {
 
@@ -600,7 +527,6 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
  *	Initialize the content addressable memory used for filters. Load
  *	appropriately according to the presence of VLAN
  */
-
 static void velocity_init_cam_filter(struct velocity_info *vptr)
 {
 	struct mac_regs __iomem *regs = vptr->mac_regs;
@@ -673,7 +599,6 @@ static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
  *	Reset the ownership and status for the receive ring side.
  *	Hand all the receive queue to the NIC.
  */
-
 static void velocity_rx_reset(struct velocity_info *vptr)
 {
 
@@ -695,6 +620,647 @@ static void velocity_rx_reset(struct velocity_info *vptr)
 }
 
 /**
+ *	velocity_get_opt_media_mode	-	get media selection
+ *	@vptr: velocity adapter
+ *
+ *	Get the media mode stored in EEPROM or module options and load
+ *	mii_status accordingly. The requested link state information
+ *	is also returned.
+ */
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
+{
+	u32 status = 0;
+
+	switch (vptr->options.spd_dpx) {
+	case SPD_DPX_AUTO:
+		status = VELOCITY_AUTONEG_ENABLE;
+		break;
+	case SPD_DPX_100_FULL:
+		status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
+		break;
+	case SPD_DPX_10_FULL:
+		status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
+		break;
+	case SPD_DPX_100_HALF:
+		status = VELOCITY_SPEED_100;
+		break;
+	case SPD_DPX_10_HALF:
+		status = VELOCITY_SPEED_10;
+		break;
+	}
+	vptr->mii_status = status;
+	return status;
+}
+
+/**
+ *	safe_disable_mii_autopoll	-	autopoll off
+ *	@regs: velocity registers
+ *
+ *	Turn off the autopoll and wait for it to disable on the chip
+ */
+static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs)
+{
+	u16 ww;
+
+	/*  turn off MAUTO */
+	writeb(0, &regs->MIICR);
+	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+		udelay(1);
+		if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+			break;
+	}
+}
+
+/**
+ *	enable_mii_autopoll	-	turn on autopolling
+ *	@regs: velocity registers
+ *
+ *	Enable the MII link status autopoll feature on the Velocity
+ *	hardware. Wait for it to enable.
+ */
+static void enable_mii_autopoll(struct mac_regs __iomem *regs)
+{
+	int ii;
+
+	writeb(0, &(regs->MIICR));
+	writeb(MIIADR_SWMPL, &regs->MIIADR);
+
+	for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+		udelay(1);
+		if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+			break;
+	}
+
+	writeb(MIICR_MAUTO, &regs->MIICR);
+
+	for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+		udelay(1);
+		if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+			break;
+	}
+
+}
+
+/**
+ *	velocity_mii_read	-	read MII data
+ *	@regs: velocity registers
+ *	@index: MII register index
+ *	@data: buffer for received data
+ *
+ *	Perform a single read of an MII 16bit register. Returns zero
+ *	on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
+{
+	u16 ww;
+
+	/*
+	 *	Disable MIICR_MAUTO, so that mii addr can be set normally
+	 */
+	safe_disable_mii_autopoll(regs);
+
+	writeb(index, &regs->MIIADR);
+
+	BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+
+	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+		if (!(readb(&regs->MIICR) & MIICR_RCMD))
+			break;
+	}
+
+	*data = readw(&regs->MIIDATA);
+
+	enable_mii_autopoll(regs);
+	if (ww == W_MAX_TIMEOUT)
+		return -ETIMEDOUT;
+	return 0;
+}
+
+
+/**
+ *	mii_check_media_mode	-	check media state
+ *	@regs: velocity registers
+ *
+ *	Check the current MII status and determine the link status
+ *	accordingly
+ */
+static u32 mii_check_media_mode(struct mac_regs __iomem *regs)
+{
+	u32 status = 0;
+	u16 ANAR;
+
+	if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
+		status |= VELOCITY_LINK_FAIL;
+
+	if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
+		status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+	else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
+		status |= (VELOCITY_SPEED_1000);
+	else {
+		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+		if (ANAR & ANAR_TXFD)
+			status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
+		else if (ANAR & ANAR_TX)
+			status |= VELOCITY_SPEED_100;
+		else if (ANAR & ANAR_10FD)
+			status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
+		else
+			status |= (VELOCITY_SPEED_10);
+	}
+
+	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+		if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+		    == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+			if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+				status |= VELOCITY_AUTONEG_ENABLE;
+		}
+	}
+
+	return status;
+}
+
+/**
+ *	velocity_mii_write	-	write MII data
+ *	@regs: velocity registers
+ *	@index: MII register index
+ *	@data: 16bit data for the MII register
+ *
+ *	Perform a single write to an MII 16bit register. Returns zero
+ *	on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
+{
+	u16 ww;
+
+	/*
+	 *	Disable MIICR_MAUTO, so that mii addr can be set normally
+	 */
+	safe_disable_mii_autopoll(regs);
+
+	/* MII reg offset */
+	writeb(mii_addr, &regs->MIIADR);
+	/* set MII data */
+	writew(data, &regs->MIIDATA);
+
+	/* turn on MIICR_WCMD */
+	BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+
+	/* W_MAX_TIMEOUT is the timeout period */
+	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+		udelay(5);
+		if (!(readb(&regs->MIICR) & MIICR_WCMD))
+			break;
+	}
+	enable_mii_autopoll(regs);
+
+	if (ww == W_MAX_TIMEOUT)
+		return -ETIMEDOUT;
+	return 0;
+}
+
+/**
+ *	set_mii_flow_control	-	flow control setup
+ *	@vptr: velocity interface
+ *
+ *	Set up the flow control on this interface according to
+ *	the supplied user/eeprom options.
+ */
+static void set_mii_flow_control(struct velocity_info *vptr)
+{
+	/*Enable or Disable PAUSE in ANAR */
+	switch (vptr->options.flow_cntl) {
+	case FLOW_CNTL_TX:
+		MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+
+	case FLOW_CNTL_RX:
+		MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+
+	case FLOW_CNTL_TX_RX:
+		MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+
+	case FLOW_CNTL_DISABLE:
+		MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ *	mii_set_auto_on		-	autonegotiate on
+ *	@vptr: velocity
+ *
+ *	Enable autonegotation on this interface
+ */
+static void mii_set_auto_on(struct velocity_info *vptr)
+{
+	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
+		MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+	else
+		MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+
+static u32 check_connection_type(struct mac_regs __iomem *regs)
+{
+	u32 status = 0;
+	u8 PHYSR0;
+	u16 ANAR;
+	PHYSR0 = readb(&regs->PHYSR0);
+
+	/*
+	   if (!(PHYSR0 & PHYSR0_LINKGD))
+	   status|=VELOCITY_LINK_FAIL;
+	 */
+
+	if (PHYSR0 & PHYSR0_FDPX)
+		status |= VELOCITY_DUPLEX_FULL;
+
+	if (PHYSR0 & PHYSR0_SPDG)
+		status |= VELOCITY_SPEED_1000;
+	else if (PHYSR0 & PHYSR0_SPD10)
+		status |= VELOCITY_SPEED_10;
+	else
+		status |= VELOCITY_SPEED_100;
+
+	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+		if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+		    == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+			if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+				status |= VELOCITY_AUTONEG_ENABLE;
+		}
+	}
+
+	return status;
+}
+
+
+
+/**
+ *	velocity_set_media_mode		-	set media mode
+ *	@mii_status: old MII link state
+ *
+ *	Check the media link state and configure the flow control
+ *	PHY and also velocity hardware setup accordingly. In particular
+ *	we need to set up CD polling and frame bursting.
+ */
+static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+{
+	u32 curr_status;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
+
+	vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
+	curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+
+	/* Set mii link status */
+	set_mii_flow_control(vptr);
+
+	/*
+	   Check if new status is consisent with current status
+	   if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
+	   || (mii_status==curr_status)) {
+	   vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
+	   vptr->mii_status=check_connection_type(vptr->mac_regs);
+	   VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
+	   return 0;
+	   }
+	 */
+
+	if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
+		MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+
+	/*
+	 *	If connection type is AUTO
+	 */
+	if (mii_status & VELOCITY_AUTONEG_ENABLE) {
+		VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
+		/* clear force MAC mode bit */
+		BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+		/* set duplex mode of MAC according to duplex mode of MII */
+		MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+		MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
+
+		/* enable AUTO-NEGO mode */
+		mii_set_auto_on(vptr);
+	} else {
+		u16 ANAR;
+		u8 CHIPGCR;
+
+		/*
+		 * 1. if it's 3119, disable frame bursting in halfduplex mode
+		 *    and enable it in fullduplex mode
+		 * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
+		 * 3. only enable CD heart beat counter in 10HD mode
+		 */
+
+		/* set force MAC mode bit */
+		BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+		CHIPGCR = readb(&regs->CHIPGCR);
+		CHIPGCR &= ~CHIPGCR_FCGMII;
+
+		if (mii_status & VELOCITY_DUPLEX_FULL) {
+			CHIPGCR |= CHIPGCR_FCFDX;
+			writeb(CHIPGCR, &regs->CHIPGCR);
+			VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
+			if (vptr->rev_id < REV_ID_VT3216_A0)
+				BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+		} else {
+			CHIPGCR &= ~CHIPGCR_FCFDX;
+			VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
+			writeb(CHIPGCR, &regs->CHIPGCR);
+			if (vptr->rev_id < REV_ID_VT3216_A0)
+				BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+		}
+
+		MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+
+		if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10))
+			BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+		else
+			BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+
+		/* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
+		velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
+		ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
+		if (mii_status & VELOCITY_SPEED_100) {
+			if (mii_status & VELOCITY_DUPLEX_FULL)
+				ANAR |= ANAR_TXFD;
+			else
+				ANAR |= ANAR_TX;
+		} else {
+			if (mii_status & VELOCITY_DUPLEX_FULL)
+				ANAR |= ANAR_10FD;
+			else
+				ANAR |= ANAR_10;
+		}
+		velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
+		/* enable AUTO-NEGO mode */
+		mii_set_auto_on(vptr);
+		/* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+	}
+	/* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
+	/* vptr->mii_status=check_connection_type(vptr->mac_regs); */
+	return VELOCITY_LINK_CHANGE;
+}
+
+/**
+ *	velocity_print_link_status	-	link status reporting
+ *	@vptr: velocity to report on
+ *
+ *	Turn the link status of the velocity card into a kernel log
+ *	description of the new link state, detailing speed and duplex
+ *	status
+ */
+static void velocity_print_link_status(struct velocity_info *vptr)
+{
+
+	if (vptr->mii_status & VELOCITY_LINK_FAIL) {
+		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
+	} else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
+
+		if (vptr->mii_status & VELOCITY_SPEED_1000)
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
+		else if (vptr->mii_status & VELOCITY_SPEED_100)
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
+		else
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+
+		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+			VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
+		else
+			VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
+	} else {
+		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
+		switch (vptr->options.spd_dpx) {
+		case SPD_DPX_100_HALF:
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
+			break;
+		case SPD_DPX_100_FULL:
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
+			break;
+		case SPD_DPX_10_HALF:
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
+			break;
+		case SPD_DPX_10_FULL:
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/**
+ *	enable_flow_control_ability	-	flow control
+ *	@vptr: veloity to configure
+ *
+ *	Set up flow control according to the flow control options
+ *	determined by the eeprom/configuration.
+ */
+static void enable_flow_control_ability(struct velocity_info *vptr)
+{
+
+	struct mac_regs __iomem *regs = vptr->mac_regs;
+
+	switch (vptr->options.flow_cntl) {
+
+	case FLOW_CNTL_DEFAULT:
+		if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
+			writel(CR0_FDXRFCEN, &regs->CR0Set);
+		else
+			writel(CR0_FDXRFCEN, &regs->CR0Clr);
+
+		if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
+			writel(CR0_FDXTFCEN, &regs->CR0Set);
+		else
+			writel(CR0_FDXTFCEN, &regs->CR0Clr);
+		break;
+
+	case FLOW_CNTL_TX:
+		writel(CR0_FDXTFCEN, &regs->CR0Set);
+		writel(CR0_FDXRFCEN, &regs->CR0Clr);
+		break;
+
+	case FLOW_CNTL_RX:
+		writel(CR0_FDXRFCEN, &regs->CR0Set);
+		writel(CR0_FDXTFCEN, &regs->CR0Clr);
+		break;
+
+	case FLOW_CNTL_TX_RX:
+		writel(CR0_FDXTFCEN, &regs->CR0Set);
+		writel(CR0_FDXRFCEN, &regs->CR0Set);
+		break;
+
+	case FLOW_CNTL_DISABLE:
+		writel(CR0_FDXRFCEN, &regs->CR0Clr);
+		writel(CR0_FDXTFCEN, &regs->CR0Clr);
+		break;
+
+	default:
+		break;
+	}
+
+}
+
+/**
+ *	velocity_soft_reset	-	soft reset
+ *	@vptr: velocity to reset
+ *
+ *	Kick off a soft reset of the velocity adapter and then poll
+ *	until the reset sequence has completed before returning.
+ */
+static int velocity_soft_reset(struct velocity_info *vptr)
+{
+	struct mac_regs __iomem *regs = vptr->mac_regs;
+	int i = 0;
+
+	writel(CR0_SFRST, &regs->CR0Set);
+
+	for (i = 0; i < W_MAX_TIMEOUT; i++) {
+		udelay(5);
+		if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
+			break;
+	}
+
+	if (i == W_MAX_TIMEOUT) {
+		writel(CR0_FORSRST, &regs->CR0Set);
+		/* FIXME: PCI POSTING */
+		/* delay 2ms */
+		mdelay(2);
+	}
+	return 0;
+}
+
+/**
+ *	velocity_set_multi	-	filter list change callback
+ *	@dev: network device
+ *
+ *	Called by the network layer when the filter lists need to change
+ *	for a velocity adapter. Reload the CAMs with the new address
+ *	filter ruleset.
+ */
+static void velocity_set_multi(struct net_device *dev)
+{
+	struct velocity_info *vptr = netdev_priv(dev);
+	struct mac_regs __iomem *regs = vptr->mac_regs;
+	u8 rx_mode;
+	int i;
+	struct dev_mc_list *mclist;
+
+	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
+		writel(0xffffffff, &regs->MARCAM[0]);
+		writel(0xffffffff, &regs->MARCAM[4]);
+		rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
+	} else if ((dev->mc_count > vptr->multicast_limit)
+		   || (dev->flags & IFF_ALLMULTI)) {
+		writel(0xffffffff, &regs->MARCAM[0]);
+		writel(0xffffffff, &regs->MARCAM[4]);
+		rx_mode = (RCR_AM | RCR_AB);
+	} else {
+		int offset = MCAM_SIZE - vptr->multicast_limit;
+		mac_get_cam_mask(regs, vptr->mCAMmask);
+
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+			mac_set_cam(regs, i + offset, mclist->dmi_addr);
+			vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
+		}
+
+		mac_set_cam_mask(regs, vptr->mCAMmask);
+		rx_mode = RCR_AM | RCR_AB | RCR_AP;
+	}
+	if (dev->mtu > 1500)
+		rx_mode |= RCR_AL;
+
+	BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+
+}
+
+/*
+ * MII access , media link mode setting functions
+ */
+
+/**
+ *	mii_init	-	set up MII
+ *	@vptr: velocity adapter
+ *	@mii_status:  links tatus
+ *
+ *	Set up the PHY for the current link state.
+ */
+static void mii_init(struct velocity_info *vptr, u32 mii_status)
+{
+	u16 BMCR;
+
+	switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
+	case PHYID_CICADA_CS8201:
+		/*
+		 *	Reset to hardware default
+		 */
+		MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+		/*
+		 *	Turn on ECHODIS bit in NWay-forced full mode and turn it
+		 *	off it in NWay-forced half mode for NWay-forced v.s.
+		 *	legacy-forced issue.
+		 */
+		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+			MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+		else
+			MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+		/*
+		 *	Turn on Link/Activity LED enable bit for CIS8201
+		 */
+		MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
+		break;
+	case PHYID_VT3216_32BIT:
+	case PHYID_VT3216_64BIT:
+		/*
+		 *	Reset to hardware default
+		 */
+		MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+		/*
+		 *	Turn on ECHODIS bit in NWay-forced full mode and turn it
+		 *	off it in NWay-forced half mode for NWay-forced v.s.
+		 *	legacy-forced issue
+		 */
+		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+			MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+		else
+			MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+		break;
+
+	case PHYID_MARVELL_1000:
+	case PHYID_MARVELL_1000S:
+		/*
+		 *	Assert CRS on Transmit
+		 */
+		MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
+		/*
+		 *	Reset to hardware default
+		 */
+		MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+		break;
+	default:
+		;
+	}
+	velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
+	if (BMCR & BMCR_ISO) {
+		BMCR &= ~BMCR_ISO;
+		velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+	}
+}
+
+
+/**
  *	velocity_init_registers	-	initialise MAC registers
  *	@vptr: velocity to init
  *	@type: type of initialisation (hot or cold)
@@ -702,7 +1268,6 @@ static void velocity_rx_reset(struct velocity_info *vptr)
  *	Initialise the MAC on a reset or on first set up on the
  *	hardware.
  */
-
 static void velocity_init_registers(struct velocity_info *vptr,
 				    enum velocity_init_type type)
 {
@@ -818,288 +1383,29 @@ static void velocity_init_registers(struct velocity_info *vptr,
 	}
 }
 
-/**
- *	velocity_soft_reset	-	soft reset
- *	@vptr: velocity to reset
- *
- *	Kick off a soft reset of the velocity adapter and then poll
- *	until the reset sequence has completed before returning.
- */
-
-static int velocity_soft_reset(struct velocity_info *vptr)
+static void velocity_give_many_rx_descs(struct velocity_info *vptr)
 {
 	struct mac_regs __iomem *regs = vptr->mac_regs;
-	int i = 0;
-
-	writel(CR0_SFRST, &regs->CR0Set);
-
-	for (i = 0; i < W_MAX_TIMEOUT; i++) {
-		udelay(5);
-		if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
-			break;
-	}
-
-	if (i == W_MAX_TIMEOUT) {
-		writel(CR0_FORSRST, &regs->CR0Set);
-		/* FIXME: PCI POSTING */
-		/* delay 2ms */
-		mdelay(2);
-	}
-	return 0;
-}
-
-static const struct net_device_ops velocity_netdev_ops = {
-	.ndo_open		= velocity_open,
-	.ndo_stop		= velocity_close,
-	.ndo_start_xmit		= velocity_xmit,
-	.ndo_get_stats		= velocity_get_stats,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_set_multicast_list	= velocity_set_multi,
-	.ndo_change_mtu		= velocity_change_mtu,
-	.ndo_do_ioctl		= velocity_ioctl,
-	.ndo_vlan_rx_add_vid	= velocity_vlan_rx_add_vid,
-	.ndo_vlan_rx_kill_vid	= velocity_vlan_rx_kill_vid,
-	.ndo_vlan_rx_register	= velocity_vlan_rx_register,
-};
-
-/**
- *	velocity_found1		-	set up discovered velocity card
- *	@pdev: PCI device
- *	@ent: PCI device table entry that matched
- *
- *	Configure a discovered adapter from scratch. Return a negative
- *	errno error code on failure paths.
- */
-
-static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	static int first = 1;
-	struct net_device *dev;
-	int i;
-	const char *drv_string;
-	const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
-	struct velocity_info *vptr;
-	struct mac_regs __iomem *regs;
-	int ret = -ENOMEM;
-
-	/* FIXME: this driver, like almost all other ethernet drivers,
-	 * can support more than MAX_UNITS.
-	 */
-	if (velocity_nics >= MAX_UNITS) {
-		dev_notice(&pdev->dev, "already found %d NICs.\n",
-			   velocity_nics);
-		return -ENODEV;
-	}
-
-	dev = alloc_etherdev(sizeof(struct velocity_info));
-	if (!dev) {
-		dev_err(&pdev->dev, "allocate net device failed.\n");
-		goto out;
-	}
-
-	/* Chain it all together */
-
-	SET_NETDEV_DEV(dev, &pdev->dev);
-	vptr = netdev_priv(dev);
-
-
-	if (first) {
-		printk(KERN_INFO "%s Ver. %s\n",
-			VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
-		printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
-		printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
-		first = 0;
-	}
-
-	velocity_init_info(pdev, vptr, info);
-
-	vptr->dev = dev;
-
-	dev->irq = pdev->irq;
-
-	ret = pci_enable_device(pdev);
-	if (ret < 0)
-		goto err_free_dev;
-
-	ret = velocity_get_pci_info(vptr, pdev);
-	if (ret < 0) {
-		/* error message already printed */
-		goto err_disable;
-	}
-
-	ret = pci_request_regions(pdev, VELOCITY_NAME);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "No PCI resources.\n");
-		goto err_disable;
-	}
-
-	regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
-	if (regs == NULL) {
-		ret = -EIO;
-		goto err_release_res;
-	}
-
-	vptr->mac_regs = regs;
-
-	mac_wol_reset(regs);
-
-	dev->base_addr = vptr->ioaddr;
-
-	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = readb(&regs->PAR[i]);
-
-
-	drv_string = dev_driver_string(&pdev->dev);
-
-	velocity_get_options(&vptr->options, velocity_nics, drv_string);
-
-	/*
-	 *	Mask out the options cannot be set to the chip
-	 */
-
-	vptr->options.flags &= info->flags;
+	int avail, dirty, unusable;
 
 	/*
-	 *	Enable the chip specified capbilities
+	 * RD number must be equal to 4X per hardware spec
+	 * (programming guide rev 1.20, p.13)
 	 */
+	if (vptr->rx.filled < 4)
+		return;
 
-	vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
-
-	vptr->wol_opts = vptr->options.wol_opts;
-	vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
-
-	vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
-
-	dev->irq = pdev->irq;
-	dev->netdev_ops = &velocity_netdev_ops;
-	dev->ethtool_ops = &velocity_ethtool_ops;
-
-	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
-		NETIF_F_HW_VLAN_RX;
-
-	if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
-		dev->features |= NETIF_F_IP_CSUM;
-
-	ret = register_netdev(dev);
-	if (ret < 0)
-		goto err_iounmap;
-
-	if (!velocity_get_link(dev)) {
-		netif_carrier_off(dev);
-		vptr->mii_status |= VELOCITY_LINK_FAIL;
-	}
-
-	velocity_print_info(vptr);
-	pci_set_drvdata(pdev, dev);
-
-	/* and leave the chip powered down */
-
-	pci_set_power_state(pdev, PCI_D3hot);
-#ifdef CONFIG_PM
-	{
-		unsigned long flags;
-
-		spin_lock_irqsave(&velocity_dev_list_lock, flags);
-		list_add(&vptr->list, &velocity_dev_list);
-		spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
-	}
-#endif
-	velocity_nics++;
-out:
-	return ret;
-
-err_iounmap:
-	iounmap(regs);
-err_release_res:
-	pci_release_regions(pdev);
-err_disable:
-	pci_disable_device(pdev);
-err_free_dev:
-	free_netdev(dev);
-	goto out;
-}
-
-/**
- *	velocity_print_info	-	per driver data
- *	@vptr: velocity
- *
- *	Print per driver data as the kernel driver finds Velocity
- *	hardware
- */
-
-static void __devinit velocity_print_info(struct velocity_info *vptr)
-{
-	struct net_device *dev = vptr->dev;
-
-	printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
-	printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
-		dev->name,
-		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-}
-
-/**
- *	velocity_init_info	-	init private data
- *	@pdev: PCI device
- *	@vptr: Velocity info
- *	@info: Board type
- *
- *	Set up the initial velocity_info struct for the device that has been
- *	discovered.
- */
-
-static void __devinit velocity_init_info(struct pci_dev *pdev,
-					 struct velocity_info *vptr,
-					 const struct velocity_info_tbl *info)
-{
-	memset(vptr, 0, sizeof(struct velocity_info));
-
-	vptr->pdev = pdev;
-	vptr->chip_id = info->chip_id;
-	vptr->tx.numq = info->txqueue;
-	vptr->multicast_limit = MCAM_SIZE;
-	spin_lock_init(&vptr->lock);
-	INIT_LIST_HEAD(&vptr->list);
-}
-
-/**
- *	velocity_get_pci_info	-	retrieve PCI info for device
- *	@vptr: velocity device
- *	@pdev: PCI device it matches
- *
- *	Retrieve the PCI configuration space data that interests us from
- *	the kernel PCI layer
- */
-
-static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
-{
-	vptr->rev_id = pdev->revision;
-
-	pci_set_master(pdev);
-
-	vptr->ioaddr = pci_resource_start(pdev, 0);
-	vptr->memaddr = pci_resource_start(pdev, 1);
-
-	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
-		dev_err(&pdev->dev,
-			   "region #0 is not an I/O resource, aborting.\n");
-		return -EINVAL;
-	}
-
-	if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
-		dev_err(&pdev->dev,
-			   "region #1 is an I/O resource, aborting.\n");
-		return -EINVAL;
-	}
+	wmb();
 
-	if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
-		dev_err(&pdev->dev, "region #1 is too small.\n");
-		return -EINVAL;
+	unusable = vptr->rx.filled & 0x0003;
+	dirty = vptr->rx.dirty - unusable;
+	for (avail = vptr->rx.filled & 0xfffc; avail; avail--) {
+		dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
+		vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC;
 	}
-	vptr->pdev = pdev;
 
-	return 0;
+	writew(vptr->rx.filled & 0xfffc, &regs->RBRDU);
+	vptr->rx.filled = unusable;
 }
 
 /**
@@ -1109,7 +1415,6 @@ static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pc
  *	Allocate PCI mapped DMA rings for the receive and transmit layer
  *	to use.
  */
-
 static int velocity_init_dma_rings(struct velocity_info *vptr)
 {
 	struct velocity_opt *opt = &vptr->options;
@@ -1150,46 +1455,50 @@ static int velocity_init_dma_rings(struct velocity_info *vptr)
 	return 0;
 }
 
+static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu)
+{
+	vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32;
+}
+
 /**
- *	velocity_free_dma_rings	-	free PCI ring pointers
- *	@vptr: Velocity to free from
+ *	velocity_alloc_rx_buf	-	allocate aligned receive buffer
+ *	@vptr: velocity
+ *	@idx: ring index
  *
- *	Clean up the PCI ring buffers allocated to this velocity.
+ *	Allocate a new full sized buffer for the reception of a frame and
+ *	map it into PCI space for the hardware to use. The hardware
+ *	requires *64* byte alignment of the buffer which makes life
+ *	less fun than would be ideal.
  */
-
-static void velocity_free_dma_rings(struct velocity_info *vptr)
+static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
 {
-	const int size = vptr->options.numrx * sizeof(struct rx_desc) +
-		vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq;
-
-	pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma);
-}
+	struct rx_desc *rd = &(vptr->rx.ring[idx]);
+	struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
 
-static void velocity_give_many_rx_descs(struct velocity_info *vptr)
-{
-	struct mac_regs __iomem *regs = vptr->mac_regs;
-	int avail, dirty, unusable;
+	rd_info->skb = dev_alloc_skb(vptr->rx.buf_sz + 64);
+	if (rd_info->skb == NULL)
+		return -ENOMEM;
 
 	/*
-	 * RD number must be equal to 4X per hardware spec
-	 * (programming guide rev 1.20, p.13)
+	 *	Do the gymnastics to get the buffer head for data at
+	 *	64byte alignment.
 	 */
-	if (vptr->rx.filled < 4)
-		return;
-
-	wmb();
+	skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
+	rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data,
+					vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
 
-	unusable = vptr->rx.filled & 0x0003;
-	dirty = vptr->rx.dirty - unusable;
-	for (avail = vptr->rx.filled & 0xfffc; avail; avail--) {
-		dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
-		vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC;
-	}
+	/*
+	 *	Fill in the descriptor to match
+	 */
 
-	writew(vptr->rx.filled & 0xfffc, &regs->RBRDU);
-	vptr->rx.filled = unusable;
+	*((u32 *) & (rd->rdesc0)) = 0;
+	rd->size = cpu_to_le16(vptr->rx.buf_sz) | RX_INTEN;
+	rd->pa_low = cpu_to_le32(rd_info->skb_dma);
+	rd->pa_high = 0;
+	return 0;
 }
 
+
 static int velocity_rx_refill(struct velocity_info *vptr)
 {
 	int dirty = vptr->rx.dirty, done = 0;
@@ -1217,42 +1526,6 @@ static int velocity_rx_refill(struct velocity_info *vptr)
 	return done;
 }
 
-static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu)
-{
-	vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32;
-}
-
-/**
- *	velocity_init_rd_ring	-	set up receive ring
- *	@vptr: velocity to configure
- *
- *	Allocate and set up the receive buffers for each ring slot and
- *	assign them to the network adapter.
- */
-
-static int velocity_init_rd_ring(struct velocity_info *vptr)
-{
-	int ret = -ENOMEM;
-
-	vptr->rx.info = kcalloc(vptr->options.numrx,
-				sizeof(struct velocity_rd_info), GFP_KERNEL);
-	if (!vptr->rx.info)
-		goto out;
-
-	velocity_init_rx_ring_indexes(vptr);
-
-	if (velocity_rx_refill(vptr) != vptr->options.numrx) {
-		VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
-			"%s: failed to allocate RX buffer.\n", vptr->dev->name);
-		velocity_free_rd_ring(vptr);
-		goto out;
-	}
-
-	ret = 0;
-out:
-	return ret;
-}
-
 /**
  *	velocity_free_rd_ring	-	free receive ring
  *	@vptr: velocity to clean up
@@ -1260,7 +1533,6 @@ out:
  *	Free the receive buffers for each ring slot and any
  *	attached socket buffers that need to go away.
  */
-
 static void velocity_free_rd_ring(struct velocity_info *vptr)
 {
 	int i;
@@ -1288,6 +1560,38 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
 	vptr->rx.info = NULL;
 }
 
+
+
+/**
+ *	velocity_init_rd_ring	-	set up receive ring
+ *	@vptr: velocity to configure
+ *
+ *	Allocate and set up the receive buffers for each ring slot and
+ *	assign them to the network adapter.
+ */
+static int velocity_init_rd_ring(struct velocity_info *vptr)
+{
+	int ret = -ENOMEM;
+
+	vptr->rx.info = kcalloc(vptr->options.numrx,
+				sizeof(struct velocity_rd_info), GFP_KERNEL);
+	if (!vptr->rx.info)
+		goto out;
+
+	velocity_init_rx_ring_indexes(vptr);
+
+	if (velocity_rx_refill(vptr) != vptr->options.numrx) {
+		VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
+			"%s: failed to allocate RX buffer.\n", vptr->dev->name);
+		velocity_free_rd_ring(vptr);
+		goto out;
+	}
+
+	ret = 0;
+out:
+	return ret;
+}
+
 /**
  *	velocity_init_td_ring	-	set up transmit ring
  *	@vptr:	velocity
@@ -1296,7 +1600,6 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
  *	Returns zero on success or a negative posix errno code for
  *	failure.
  */
-
 static int velocity_init_td_ring(struct velocity_info *vptr)
 {
 	dma_addr_t curr;
@@ -1320,10 +1623,81 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
 	return 0;
 }
 
+/**
+ *	velocity_free_dma_rings	-	free PCI ring pointers
+ *	@vptr: Velocity to free from
+ *
+ *	Clean up the PCI ring buffers allocated to this velocity.
+ */
+static void velocity_free_dma_rings(struct velocity_info *vptr)
+{
+	const int size = vptr->options.numrx * sizeof(struct rx_desc) +
+		vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq;
+
+	pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma);
+}
+
+
+static int velocity_init_rings(struct velocity_info *vptr, int mtu)
+{
+	int ret;
+
+	velocity_set_rxbufsize(vptr, mtu);
+
+	ret = velocity_init_dma_rings(vptr);
+	if (ret < 0)
+		goto out;
+
+	ret = velocity_init_rd_ring(vptr);
+	if (ret < 0)
+		goto err_free_dma_rings_0;
+
+	ret = velocity_init_td_ring(vptr);
+	if (ret < 0)
+		goto err_free_rd_ring_1;
+out:
+	return ret;
+
+err_free_rd_ring_1:
+	velocity_free_rd_ring(vptr);
+err_free_dma_rings_0:
+	velocity_free_dma_rings(vptr);
+	goto out;
+}
+
+/**
+ *	velocity_free_tx_buf	-	free transmit buffer
+ *	@vptr: velocity
+ *	@tdinfo: buffer
+ *
+ *	Release an transmit buffer. If the buffer was preallocated then
+ *	recycle it, if not then unmap the buffer.
+ */
+static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
+{
+	struct sk_buff *skb = tdinfo->skb;
+	int i;
+	int pktlen;
+
+	/*
+	 *	Don't unmap the pre-allocated tx_bufs
+	 */
+	if (tdinfo->skb_dma) {
+
+		pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
+		for (i = 0; i < tdinfo->nskb_dma; i++) {
+			pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
+			tdinfo->skb_dma[i] = 0;
+		}
+	}
+	dev_kfree_skb_irq(skb);
+	tdinfo->skb = NULL;
+}
+
+
 /*
  *	FIXME: could we merge this with velocity_free_tx_buf ?
  */
-
 static void velocity_free_td_ring_entry(struct velocity_info *vptr,
 							 int q, int n)
 {
@@ -1353,7 +1727,6 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr,
  *	Free up the transmit ring for this particular velocity adapter.
  *	We free the ring contents but not the ring itself.
  */
-
 static void velocity_free_td_ring(struct velocity_info *vptr)
 {
 	int i, j;
@@ -1369,61 +1742,167 @@ static void velocity_free_td_ring(struct velocity_info *vptr)
 	}
 }
 
+
+static void velocity_free_rings(struct velocity_info *vptr)
+{
+	velocity_free_td_ring(vptr);
+	velocity_free_rd_ring(vptr);
+	velocity_free_dma_rings(vptr);
+}
+
 /**
- *	velocity_rx_srv		-	service RX interrupt
+ *	velocity_error	-	handle error from controller
  *	@vptr: velocity
- *	@status: adapter status (unused)
+ *	@status: card status
+ *
+ *	Process an error report from the hardware and attempt to recover
+ *	the card itself. At the moment we cannot recover from some
+ *	theoretically impossible errors but this could be fixed using
+ *	the pci_device_failed logic to bounce the hardware
  *
- *	Walk the receive ring of the velocity adapter and remove
- *	any received packets from the receive queue. Hand the ring
- *	slots back to the adapter for reuse.
  */
-
-static int velocity_rx_srv(struct velocity_info *vptr, int status)
+static void velocity_error(struct velocity_info *vptr, int status)
 {
-	struct net_device_stats *stats = &vptr->dev->stats;
-	int rd_curr = vptr->rx.curr;
-	int works = 0;
 
-	do {
-		struct rx_desc *rd = vptr->rx.ring + rd_curr;
+	if (status & ISR_TXSTLI) {
+		struct mac_regs __iomem *regs = vptr->mac_regs;
 
-		if (!vptr->rx.info[rd_curr].skb)
-			break;
+		printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
+		BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
+		writew(TRDCSR_RUN, &regs->TDCSRClr);
+		netif_stop_queue(vptr->dev);
 
-		if (rd->rdesc0.len & OWNED_BY_NIC)
-			break;
+		/* FIXME: port over the pci_device_failed code and use it
+		   here */
+	}
 
-		rmb();
+	if (status & ISR_SRCI) {
+		struct mac_regs __iomem *regs = vptr->mac_regs;
+		int linked;
+
+		if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+			vptr->mii_status = check_connection_type(regs);
 
+			/*
+			 *	If it is a 3119, disable frame bursting in
+			 *	halfduplex mode and enable it in fullduplex
+			 *	 mode
+			 */
+			if (vptr->rev_id < REV_ID_VT3216_A0) {
+				if (vptr->mii_status | VELOCITY_DUPLEX_FULL)
+					BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+				else
+					BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+			}
+			/*
+			 *	Only enable CD heart beat counter in 10HD mode
+			 */
+			if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10))
+				BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+			else
+				BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+		}
 		/*
-		 *	Don't drop CE or RL error frame although RXOK is off
+		 *	Get link status from PHYSR0
 		 */
-		if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
-			if (velocity_receive_frame(vptr, rd_curr) < 0)
-				stats->rx_dropped++;
-		} else {
-			if (rd->rdesc0.RSR & RSR_CRC)
-				stats->rx_crc_errors++;
-			if (rd->rdesc0.RSR & RSR_FAE)
-				stats->rx_frame_errors++;
+		linked = readb(&regs->PHYSR0) & PHYSR0_LINKGD;
 
-			stats->rx_dropped++;
+		if (linked) {
+			vptr->mii_status &= ~VELOCITY_LINK_FAIL;
+			netif_carrier_on(vptr->dev);
+		} else {
+			vptr->mii_status |= VELOCITY_LINK_FAIL;
+			netif_carrier_off(vptr->dev);
 		}
 
-		rd->size |= RX_INTEN;
+		velocity_print_link_status(vptr);
+		enable_flow_control_ability(vptr);
 
-		rd_curr++;
-		if (rd_curr >= vptr->options.numrx)
-			rd_curr = 0;
-	} while (++works <= 15);
+		/*
+		 *	Re-enable auto-polling because SRCI will disable
+		 *	auto-polling
+		 */
 
-	vptr->rx.curr = rd_curr;
+		enable_mii_autopoll(regs);
 
-	if ((works > 0) && (velocity_rx_refill(vptr) > 0))
-		velocity_give_many_rx_descs(vptr);
+		if (vptr->mii_status & VELOCITY_LINK_FAIL)
+			netif_stop_queue(vptr->dev);
+		else
+			netif_wake_queue(vptr->dev);
 
-	VAR_USED(stats);
+	};
+	if (status & ISR_MIBFI)
+		velocity_update_hw_mibs(vptr);
+	if (status & ISR_LSTEI)
+		mac_rx_queue_wake(vptr->mac_regs);
+}
+
+/**
+ *	tx_srv		-	transmit interrupt service
+ *	@vptr; Velocity
+ *	@status:
+ *
+ *	Scan the queues looking for transmitted packets that
+ *	we can complete and clean up. Update any statistics as
+ *	necessary/
+ */
+static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+{
+	struct tx_desc *td;
+	int qnum;
+	int full = 0;
+	int idx;
+	int works = 0;
+	struct velocity_td_info *tdinfo;
+	struct net_device_stats *stats = &vptr->dev->stats;
+
+	for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
+		for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
+			idx = (idx + 1) % vptr->options.numtx) {
+
+			/*
+			 *	Get Tx Descriptor
+			 */
+			td = &(vptr->tx.rings[qnum][idx]);
+			tdinfo = &(vptr->tx.infos[qnum][idx]);
+
+			if (td->tdesc0.len & OWNED_BY_NIC)
+				break;
+
+			if ((works++ > 15))
+				break;
+
+			if (td->tdesc0.TSR & TSR0_TERR) {
+				stats->tx_errors++;
+				stats->tx_dropped++;
+				if (td->tdesc0.TSR & TSR0_CDH)
+					stats->tx_heartbeat_errors++;
+				if (td->tdesc0.TSR & TSR0_CRS)
+					stats->tx_carrier_errors++;
+				if (td->tdesc0.TSR & TSR0_ABT)
+					stats->tx_aborted_errors++;
+				if (td->tdesc0.TSR & TSR0_OWC)
+					stats->tx_window_errors++;
+			} else {
+				stats->tx_packets++;
+				stats->tx_bytes += tdinfo->skb->len;
+			}
+			velocity_free_tx_buf(vptr, tdinfo);
+			vptr->tx.used[qnum]--;
+		}
+		vptr->tx.tail[qnum] = idx;
+
+		if (AVAIL_TD(vptr, qnum) < 1)
+			full = 1;
+	}
+	/*
+	 *	Look to see if we should kick the transmit network
+	 *	layer for more work.
+	 */
+	if (netif_queue_stopped(vptr->dev) && (full == 0)
+	    && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
+		netif_wake_queue(vptr->dev);
+	}
 	return works;
 }
 
@@ -1435,7 +1914,6 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
  *	Process the status bits for the received packet and determine
  *	if the checksum was computed and verified by the hardware
  */
-
 static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
 {
 	skb->ip_summed = CHECKSUM_NONE;
@@ -1502,6 +1980,7 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
 	}
 }
 
+
 /**
  *	velocity_receive_frame	-	received packet processor
  *	@vptr: velocity we are handling
@@ -1510,7 +1989,6 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
  *	A packet has arrived. We process the packet and if appropriate
  *	pass the frame up the network stack
  */
-
 static int velocity_receive_frame(struct velocity_info *vptr, int idx)
 {
 	void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
@@ -1572,314 +2050,118 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
 	return 0;
 }
 
+
 /**
- *	velocity_alloc_rx_buf	-	allocate aligned receive buffer
+ *	velocity_rx_srv		-	service RX interrupt
  *	@vptr: velocity
- *	@idx: ring index
+ *	@status: adapter status (unused)
  *
- *	Allocate a new full sized buffer for the reception of a frame and
- *	map it into PCI space for the hardware to use. The hardware
- *	requires *64* byte alignment of the buffer which makes life
- *	less fun than would be ideal.
+ *	Walk the receive ring of the velocity adapter and remove
+ *	any received packets from the receive queue. Hand the ring
+ *	slots back to the adapter for reuse.
  */
-
-static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
+static int velocity_rx_srv(struct velocity_info *vptr, int status)
 {
-	struct rx_desc *rd = &(vptr->rx.ring[idx]);
-	struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
-
-	rd_info->skb = dev_alloc_skb(vptr->rx.buf_sz + 64);
-	if (rd_info->skb == NULL)
-		return -ENOMEM;
+	struct net_device_stats *stats = &vptr->dev->stats;
+	int rd_curr = vptr->rx.curr;
+	int works = 0;
 
-	/*
-	 *	Do the gymnastics to get the buffer head for data at
-	 *	64byte alignment.
-	 */
-	skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
-	rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data,
-					vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
+	do {
+		struct rx_desc *rd = vptr->rx.ring + rd_curr;
 
-	/*
-	 *	Fill in the descriptor to match
-	 */
+		if (!vptr->rx.info[rd_curr].skb)
+			break;
 
-	*((u32 *) & (rd->rdesc0)) = 0;
-	rd->size = cpu_to_le16(vptr->rx.buf_sz) | RX_INTEN;
-	rd->pa_low = cpu_to_le32(rd_info->skb_dma);
-	rd->pa_high = 0;
-	return 0;
-}
+		if (rd->rdesc0.len & OWNED_BY_NIC)
+			break;
 
-/**
- *	tx_srv		-	transmit interrupt service
- *	@vptr; Velocity
- *	@status:
- *
- *	Scan the queues looking for transmitted packets that
- *	we can complete and clean up. Update any statistics as
- *	necessary/
- */
+		rmb();
 
-static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
-{
-	struct tx_desc *td;
-	int qnum;
-	int full = 0;
-	int idx;
-	int works = 0;
-	struct velocity_td_info *tdinfo;
-	struct net_device_stats *stats = &vptr->dev->stats;
+		/*
+		 *	Don't drop CE or RL error frame although RXOK is off
+		 */
+		if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
+			if (velocity_receive_frame(vptr, rd_curr) < 0)
+				stats->rx_dropped++;
+		} else {
+			if (rd->rdesc0.RSR & RSR_CRC)
+				stats->rx_crc_errors++;
+			if (rd->rdesc0.RSR & RSR_FAE)
+				stats->rx_frame_errors++;
 
-	for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
-		for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
-			idx = (idx + 1) % vptr->options.numtx) {
+			stats->rx_dropped++;
+		}
 
-			/*
-			 *	Get Tx Descriptor
-			 */
-			td = &(vptr->tx.rings[qnum][idx]);
-			tdinfo = &(vptr->tx.infos[qnum][idx]);
+		rd->size |= RX_INTEN;
 
-			if (td->tdesc0.len & OWNED_BY_NIC)
-				break;
+		rd_curr++;
+		if (rd_curr >= vptr->options.numrx)
+			rd_curr = 0;
+	} while (++works <= 15);
 
-			if ((works++ > 15))
-				break;
+	vptr->rx.curr = rd_curr;
 
-			if (td->tdesc0.TSR & TSR0_TERR) {
-				stats->tx_errors++;
-				stats->tx_dropped++;
-				if (td->tdesc0.TSR & TSR0_CDH)
-					stats->tx_heartbeat_errors++;
-				if (td->tdesc0.TSR & TSR0_CRS)
-					stats->tx_carrier_errors++;
-				if (td->tdesc0.TSR & TSR0_ABT)
-					stats->tx_aborted_errors++;
-				if (td->tdesc0.TSR & TSR0_OWC)
-					stats->tx_window_errors++;
-			} else {
-				stats->tx_packets++;
-				stats->tx_bytes += tdinfo->skb->len;
-			}
-			velocity_free_tx_buf(vptr, tdinfo);
-			vptr->tx.used[qnum]--;
-		}
-		vptr->tx.tail[qnum] = idx;
+	if ((works > 0) && (velocity_rx_refill(vptr) > 0))
+		velocity_give_many_rx_descs(vptr);
 
-		if (AVAIL_TD(vptr, qnum) < 1)
-			full = 1;
-	}
-	/*
-	 *	Look to see if we should kick the transmit network
-	 *	layer for more work.
-	 */
-	if (netif_queue_stopped(vptr->dev) && (full == 0)
-	    && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
-		netif_wake_queue(vptr->dev);
-	}
+	VAR_USED(stats);
 	return works;
 }
 
-/**
- *	velocity_print_link_status	-	link status reporting
- *	@vptr: velocity to report on
- *
- *	Turn the link status of the velocity card into a kernel log
- *	description of the new link state, detailing speed and duplex
- *	status
- */
-
-static void velocity_print_link_status(struct velocity_info *vptr)
-{
-
-	if (vptr->mii_status & VELOCITY_LINK_FAIL) {
-		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
-	} else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
-		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
-
-		if (vptr->mii_status & VELOCITY_SPEED_1000)
-			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
-		else if (vptr->mii_status & VELOCITY_SPEED_100)
-			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
-		else
-			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
-
-		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
-			VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
-		else
-			VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
-	} else {
-		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
-		switch (vptr->options.spd_dpx) {
-		case SPD_DPX_100_HALF:
-			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
-			break;
-		case SPD_DPX_100_FULL:
-			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
-			break;
-		case SPD_DPX_10_HALF:
-			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
-			break;
-		case SPD_DPX_10_FULL:
-			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
-			break;
-		default:
-			break;
-		}
-	}
-}
 
 /**
- *	velocity_error	-	handle error from controller
- *	@vptr: velocity
- *	@status: card status
- *
- *	Process an error report from the hardware and attempt to recover
- *	the card itself. At the moment we cannot recover from some
- *	theoretically impossible errors but this could be fixed using
- *	the pci_device_failed logic to bounce the hardware
+ *	velocity_intr		-	interrupt callback
+ *	@irq: interrupt number
+ *	@dev_instance: interrupting device
  *
+ *	Called whenever an interrupt is generated by the velocity
+ *	adapter IRQ line. We may not be the source of the interrupt
+ *	and need to identify initially if we are, and if not exit as
+ *	efficiently as possible.
  */
-
-static void velocity_error(struct velocity_info *vptr, int status)
+static irqreturn_t velocity_intr(int irq, void *dev_instance)
 {
+	struct net_device *dev = dev_instance;
+	struct velocity_info *vptr = netdev_priv(dev);
+	u32 isr_status;
+	int max_count = 0;
 
-	if (status & ISR_TXSTLI) {
-		struct mac_regs __iomem *regs = vptr->mac_regs;
 
-		printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
-		BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
-		writew(TRDCSR_RUN, &regs->TDCSRClr);
-		netif_stop_queue(vptr->dev);
+	spin_lock(&vptr->lock);
+	isr_status = mac_read_isr(vptr->mac_regs);
 
-		/* FIXME: port over the pci_device_failed code and use it
-		   here */
+	/* Not us ? */
+	if (isr_status == 0) {
+		spin_unlock(&vptr->lock);
+		return IRQ_NONE;
 	}
 
-	if (status & ISR_SRCI) {
-		struct mac_regs __iomem *regs = vptr->mac_regs;
-		int linked;
-
-		if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
-			vptr->mii_status = check_connection_type(regs);
-
-			/*
-			 *	If it is a 3119, disable frame bursting in
-			 *	halfduplex mode and enable it in fullduplex
-			 *	 mode
-			 */
-			if (vptr->rev_id < REV_ID_VT3216_A0) {
-				if (vptr->mii_status | VELOCITY_DUPLEX_FULL)
-					BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
-				else
-					BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
-			}
-			/*
-			 *	Only enable CD heart beat counter in 10HD mode
-			 */
-			if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10))
-				BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
-			else
-				BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
-		}
-		/*
-		 *	Get link status from PHYSR0
-		 */
-		linked = readb(&regs->PHYSR0) & PHYSR0_LINKGD;
-
-		if (linked) {
-			vptr->mii_status &= ~VELOCITY_LINK_FAIL;
-			netif_carrier_on(vptr->dev);
-		} else {
-			vptr->mii_status |= VELOCITY_LINK_FAIL;
-			netif_carrier_off(vptr->dev);
-		}
-
-		velocity_print_link_status(vptr);
-		enable_flow_control_ability(vptr);
-
-		/*
-		 *	Re-enable auto-polling because SRCI will disable
-		 *	auto-polling
-		 */
-
-		enable_mii_autopoll(regs);
-
-		if (vptr->mii_status & VELOCITY_LINK_FAIL)
-			netif_stop_queue(vptr->dev);
-		else
-			netif_wake_queue(vptr->dev);
-
-	};
-	if (status & ISR_MIBFI)
-		velocity_update_hw_mibs(vptr);
-	if (status & ISR_LSTEI)
-		mac_rx_queue_wake(vptr->mac_regs);
-}
-
-/**
- *	velocity_free_tx_buf	-	free transmit buffer
- *	@vptr: velocity
- *	@tdinfo: buffer
- *
- *	Release an transmit buffer. If the buffer was preallocated then
- *	recycle it, if not then unmap the buffer.
- */
-
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
-{
-	struct sk_buff *skb = tdinfo->skb;
-	int i;
-	int pktlen;
+	mac_disable_int(vptr->mac_regs);
 
 	/*
-	 *	Don't unmap the pre-allocated tx_bufs
+	 *	Keep processing the ISR until we have completed
+	 *	processing and the isr_status becomes zero
 	 */
-	if (tdinfo->skb_dma) {
 
-		pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
-		for (i = 0; i < tdinfo->nskb_dma; i++) {
-			pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
-			tdinfo->skb_dma[i] = 0;
+	while (isr_status != 0) {
+		mac_write_isr(vptr->mac_regs, isr_status);
+		if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
+			velocity_error(vptr, isr_status);
+		if (isr_status & (ISR_PRXI | ISR_PPRXI))
+			max_count += velocity_rx_srv(vptr, isr_status);
+		if (isr_status & (ISR_PTXI | ISR_PPTXI))
+			max_count += velocity_tx_srv(vptr, isr_status);
+		isr_status = mac_read_isr(vptr->mac_regs);
+		if (max_count > vptr->options.int_works) {
+			printk(KERN_WARNING "%s: excessive work at interrupt.\n",
+				dev->name);
+			max_count = 0;
 		}
 	}
-	dev_kfree_skb_irq(skb);
-	tdinfo->skb = NULL;
-}
-
-static int velocity_init_rings(struct velocity_info *vptr, int mtu)
-{
-	int ret;
-
-	velocity_set_rxbufsize(vptr, mtu);
-
-	ret = velocity_init_dma_rings(vptr);
-	if (ret < 0)
-		goto out;
-
-	ret = velocity_init_rd_ring(vptr);
-	if (ret < 0)
-		goto err_free_dma_rings_0;
-
-	ret = velocity_init_td_ring(vptr);
-	if (ret < 0)
-		goto err_free_rd_ring_1;
-out:
-	return ret;
+	spin_unlock(&vptr->lock);
+	mac_enable_int(vptr->mac_regs);
+	return IRQ_HANDLED;
 
-err_free_rd_ring_1:
-	velocity_free_rd_ring(vptr);
-err_free_dma_rings_0:
-	velocity_free_dma_rings(vptr);
-	goto out;
-}
-
-static void velocity_free_rings(struct velocity_info *vptr)
-{
-	velocity_free_td_ring(vptr);
-	velocity_free_rd_ring(vptr);
-	velocity_free_dma_rings(vptr);
 }
 
 /**
@@ -1892,7 +2174,6 @@ static void velocity_free_rings(struct velocity_info *vptr)
  *	All the ring allocation and set up is done on open for this
  *	adapter to minimise memory usage when inactive
  */
-
 static int velocity_open(struct net_device *dev)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
@@ -1926,6 +2207,24 @@ out:
 }
 
 /**
+ *	velocity_shutdown	-	shut down the chip
+ *	@vptr: velocity to deactivate
+ *
+ *	Shuts down the internal operations of the velocity and
+ *	disables interrupts, autopolling, transmit and receive
+ */
+static void velocity_shutdown(struct velocity_info *vptr)
+{
+	struct mac_regs __iomem *regs = vptr->mac_regs;
+	mac_disable_int(regs);
+	writel(CR0_STOP, &regs->CR0Set);
+	writew(0xFFFF, &regs->TDCSRClr);
+	writeb(0xFF, &regs->RDCSRClr);
+	safe_disable_mii_autopoll(regs);
+	mac_clear_isr(regs);
+}
+
+/**
  *	velocity_change_mtu	-	MTU change callback
  *	@dev: network device
  *	@new_mtu: desired MTU
@@ -1934,7 +2233,6 @@ out:
  *	this interface. It gets called on a change by the network layer.
  *	Return zero for success or negative posix error code.
  */
-
 static int velocity_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
@@ -2008,22 +2306,127 @@ out_0:
 }
 
 /**
- *	velocity_shutdown	-	shut down the chip
- *	@vptr: velocity to deactivate
+ *	velocity_mii_ioctl		-	MII ioctl handler
+ *	@dev: network device
+ *	@ifr: the ifreq block for the ioctl
+ *	@cmd: the command
  *
- *	Shuts down the internal operations of the velocity and
- *	disables interrupts, autopolling, transmit and receive
+ *	Process MII requests made via ioctl from the network layer. These
+ *	are used by tools like kudzu to interrogate the link state of the
+ *	hardware
  */
-
-static void velocity_shutdown(struct velocity_info *vptr)
+static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
+	struct velocity_info *vptr = netdev_priv(dev);
 	struct mac_regs __iomem *regs = vptr->mac_regs;
-	mac_disable_int(regs);
-	writel(CR0_STOP, &regs->CR0Set);
-	writew(0xFFFF, &regs->TDCSRClr);
-	writeb(0xFF, &regs->RDCSRClr);
-	safe_disable_mii_autopoll(regs);
-	mac_clear_isr(regs);
+	unsigned long flags;
+	struct mii_ioctl_data *miidata = if_mii(ifr);
+	int err;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
+		break;
+	case SIOCGMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
+			return -ETIMEDOUT;
+		break;
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		spin_lock_irqsave(&vptr->lock, flags);
+		err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
+		spin_unlock_irqrestore(&vptr->lock, flags);
+		check_connection_type(vptr->mac_regs);
+		if (err)
+			return err;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+
+/**
+ *	velocity_ioctl		-	ioctl entry point
+ *	@dev: network device
+ *	@rq: interface request ioctl
+ *	@cmd: command code
+ *
+ *	Called when the user issues an ioctl request to the network
+ *	device in question. The velocity interface supports MII.
+ */
+static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct velocity_info *vptr = netdev_priv(dev);
+	int ret;
+
+	/* If we are asked for information and the device is power
+	   saving then we need to bring the device back up to talk to it */
+
+	if (!netif_running(dev))
+		pci_set_power_state(vptr->pdev, PCI_D0);
+
+	switch (cmd) {
+	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
+	case SIOCGMIIREG:	/* Read MII PHY register. */
+	case SIOCSMIIREG:	/* Write to MII PHY register. */
+		ret = velocity_mii_ioctl(dev, rq, cmd);
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	if (!netif_running(dev))
+		pci_set_power_state(vptr->pdev, PCI_D3hot);
+
+
+	return ret;
+}
+
+/**
+ *	velocity_get_status	-	statistics callback
+ *	@dev: network device
+ *
+ *	Callback from the network layer to allow driver statistics
+ *	to be resynchronized with hardware collected state. In the
+ *	case of the velocity we need to pull the MIB counters from
+ *	the hardware into the counters before letting the network
+ *	layer display them.
+ */
+static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+{
+	struct velocity_info *vptr = netdev_priv(dev);
+
+	/* If the hardware is down, don't touch MII */
+	if (!netif_running(dev))
+		return &dev->stats;
+
+	spin_lock_irq(&vptr->lock);
+	velocity_update_hw_mibs(vptr);
+	spin_unlock_irq(&vptr->lock);
+
+	dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
+	dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
+	dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
+
+//  unsigned long   rx_dropped;     /* no space in linux buffers    */
+	dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
+	/* detailed rx_errors: */
+//  unsigned long   rx_length_errors;
+//  unsigned long   rx_over_errors;     /* receiver ring buff overflow  */
+	dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
+//  unsigned long   rx_frame_errors;    /* recv'd frame alignment error */
+//  unsigned long   rx_fifo_errors;     /* recv'r fifo overrun      */
+//  unsigned long   rx_missed_errors;   /* receiver missed packet   */
+
+	/* detailed tx_errors */
+//  unsigned long   tx_fifo_errors;
+
+	return &dev->stats;
 }
 
 /**
@@ -2033,7 +2436,6 @@ static void velocity_shutdown(struct velocity_info *vptr)
  *	Callback from the network layer when the velocity is being
  *	deactivated by the network layer
  */
-
 static int velocity_close(struct net_device *dev)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
@@ -2063,7 +2465,6 @@ static int velocity_close(struct net_device *dev)
  *	Called by the networ layer to request a packet is queued to
  *	the velocity. Returns zero on success.
  */
-
 static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
@@ -2075,7 +2476,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
 	__le16 len;
 	int index;
 
-
 	if (skb_padto(skb, ETH_ZLEN))
 		goto out;
 	pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
@@ -2145,782 +2545,535 @@ out:
 	return NETDEV_TX_OK;
 }
 
+
+static const struct net_device_ops velocity_netdev_ops = {
+	.ndo_open		= velocity_open,
+	.ndo_stop		= velocity_close,
+	.ndo_start_xmit		= velocity_xmit,
+	.ndo_get_stats		= velocity_get_stats,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address 	= eth_mac_addr,
+	.ndo_set_multicast_list	= velocity_set_multi,
+	.ndo_change_mtu		= velocity_change_mtu,
+	.ndo_do_ioctl		= velocity_ioctl,
+	.ndo_vlan_rx_add_vid	= velocity_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= velocity_vlan_rx_kill_vid,
+	.ndo_vlan_rx_register	= velocity_vlan_rx_register,
+};
+
 /**
- *	velocity_intr		-	interrupt callback
- *	@irq: interrupt number
- *	@dev_instance: interrupting device
+ *	velocity_init_info	-	init private data
+ *	@pdev: PCI device
+ *	@vptr: Velocity info
+ *	@info: Board type
  *
- *	Called whenever an interrupt is generated by the velocity
- *	adapter IRQ line. We may not be the source of the interrupt
- *	and need to identify initially if we are, and if not exit as
- *	efficiently as possible.
+ *	Set up the initial velocity_info struct for the device that has been
+ *	discovered.
  */
-
-static irqreturn_t velocity_intr(int irq, void *dev_instance)
+static void __devinit velocity_init_info(struct pci_dev *pdev,
+					 struct velocity_info *vptr,
+					 const struct velocity_info_tbl *info)
 {
-	struct net_device *dev = dev_instance;
-	struct velocity_info *vptr = netdev_priv(dev);
-	u32 isr_status;
-	int max_count = 0;
-
-
-	spin_lock(&vptr->lock);
-	isr_status = mac_read_isr(vptr->mac_regs);
-
-	/* Not us ? */
-	if (isr_status == 0) {
-		spin_unlock(&vptr->lock);
-		return IRQ_NONE;
-	}
-
-	mac_disable_int(vptr->mac_regs);
-
-	/*
-	 *	Keep processing the ISR until we have completed
-	 *	processing and the isr_status becomes zero
-	 */
-
-	while (isr_status != 0) {
-		mac_write_isr(vptr->mac_regs, isr_status);
-		if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
-			velocity_error(vptr, isr_status);
-		if (isr_status & (ISR_PRXI | ISR_PPRXI))
-			max_count += velocity_rx_srv(vptr, isr_status);
-		if (isr_status & (ISR_PTXI | ISR_PPTXI))
-			max_count += velocity_tx_srv(vptr, isr_status);
-		isr_status = mac_read_isr(vptr->mac_regs);
-		if (max_count > vptr->options.int_works) {
-			printk(KERN_WARNING "%s: excessive work at interrupt.\n",
-				dev->name);
-			max_count = 0;
-		}
-	}
-	spin_unlock(&vptr->lock);
-	mac_enable_int(vptr->mac_regs);
-	return IRQ_HANDLED;
+	memset(vptr, 0, sizeof(struct velocity_info));
 
+	vptr->pdev = pdev;
+	vptr->chip_id = info->chip_id;
+	vptr->tx.numq = info->txqueue;
+	vptr->multicast_limit = MCAM_SIZE;
+	spin_lock_init(&vptr->lock);
+	INIT_LIST_HEAD(&vptr->list);
 }
 
-
 /**
- *	velocity_set_multi	-	filter list change callback
- *	@dev: network device
+ *	velocity_get_pci_info	-	retrieve PCI info for device
+ *	@vptr: velocity device
+ *	@pdev: PCI device it matches
  *
- *	Called by the network layer when the filter lists need to change
- *	for a velocity adapter. Reload the CAMs with the new address
- *	filter ruleset.
+ *	Retrieve the PCI configuration space data that interests us from
+ *	the kernel PCI layer
  */
-
-static void velocity_set_multi(struct net_device *dev)
+static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
 {
-	struct velocity_info *vptr = netdev_priv(dev);
-	struct mac_regs __iomem *regs = vptr->mac_regs;
-	u8 rx_mode;
-	int i;
-	struct dev_mc_list *mclist;
+	vptr->rev_id = pdev->revision;
 
-	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
-		writel(0xffffffff, &regs->MARCAM[0]);
-		writel(0xffffffff, &regs->MARCAM[4]);
-		rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
-	} else if ((dev->mc_count > vptr->multicast_limit)
-		   || (dev->flags & IFF_ALLMULTI)) {
-		writel(0xffffffff, &regs->MARCAM[0]);
-		writel(0xffffffff, &regs->MARCAM[4]);
-		rx_mode = (RCR_AM | RCR_AB);
-	} else {
-		int offset = MCAM_SIZE - vptr->multicast_limit;
-		mac_get_cam_mask(regs, vptr->mCAMmask);
+	pci_set_master(pdev);
 
-		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
-			mac_set_cam(regs, i + offset, mclist->dmi_addr);
-			vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
-		}
+	vptr->ioaddr = pci_resource_start(pdev, 0);
+	vptr->memaddr = pci_resource_start(pdev, 1);
 
-		mac_set_cam_mask(regs, vptr->mCAMmask);
-		rx_mode = RCR_AM | RCR_AB | RCR_AP;
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+		dev_err(&pdev->dev,
+			   "region #0 is not an I/O resource, aborting.\n");
+		return -EINVAL;
 	}
-	if (dev->mtu > 1500)
-		rx_mode |= RCR_AL;
 
-	BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+	if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
+		dev_err(&pdev->dev,
+			   "region #1 is an I/O resource, aborting.\n");
+		return -EINVAL;
+	}
 
+	if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
+		dev_err(&pdev->dev, "region #1 is too small.\n");
+		return -EINVAL;
+	}
+	vptr->pdev = pdev;
+
+	return 0;
 }
 
 /**
- *	velocity_get_status	-	statistics callback
- *	@dev: network device
+ *	velocity_print_info	-	per driver data
+ *	@vptr: velocity
  *
- *	Callback from the network layer to allow driver statistics
- *	to be resynchronized with hardware collected state. In the
- *	case of the velocity we need to pull the MIB counters from
- *	the hardware into the counters before letting the network
- *	layer display them.
+ *	Print per driver data as the kernel driver finds Velocity
+ *	hardware
  */
-
-static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+static void __devinit velocity_print_info(struct velocity_info *vptr)
 {
-	struct velocity_info *vptr = netdev_priv(dev);
-
-	/* If the hardware is down, don't touch MII */
-	if (!netif_running(dev))
-		return &dev->stats;
-
-	spin_lock_irq(&vptr->lock);
-	velocity_update_hw_mibs(vptr);
-	spin_unlock_irq(&vptr->lock);
-
-	dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
-	dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
-	dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
-
-//  unsigned long   rx_dropped;     /* no space in linux buffers    */
-	dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
-	/* detailed rx_errors: */
-//  unsigned long   rx_length_errors;
-//  unsigned long   rx_over_errors;     /* receiver ring buff overflow  */
-	dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
-//  unsigned long   rx_frame_errors;    /* recv'd frame alignment error */
-//  unsigned long   rx_fifo_errors;     /* recv'r fifo overrun      */
-//  unsigned long   rx_missed_errors;   /* receiver missed packet   */
-
-	/* detailed tx_errors */
-//  unsigned long   tx_fifo_errors;
+	struct net_device *dev = vptr->dev;
 
-	return &dev->stats;
+	printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
+	printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+		dev->name,
+		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
 }
 
-
-/**
- *	velocity_ioctl		-	ioctl entry point
- *	@dev: network device
- *	@rq: interface request ioctl
- *	@cmd: command code
- *
- *	Called when the user issues an ioctl request to the network
- *	device in question. The velocity interface supports MII.
- */
-
-static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static u32 velocity_get_link(struct net_device *dev)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
-	int ret;
-
-	/* If we are asked for information and the device is power
-	   saving then we need to bring the device back up to talk to it */
-
-	if (!netif_running(dev))
-		pci_set_power_state(vptr->pdev, PCI_D0);
-
-	switch (cmd) {
-	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
-	case SIOCGMIIREG:	/* Read MII PHY register. */
-	case SIOCSMIIREG:	/* Write to MII PHY register. */
-		ret = velocity_mii_ioctl(dev, rq, cmd);
-		break;
-
-	default:
-		ret = -EOPNOTSUPP;
-	}
-	if (!netif_running(dev))
-		pci_set_power_state(vptr->pdev, PCI_D3hot);
-
-
-	return ret;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
+	return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
 }
 
-/*
- *	Definition for our device driver. The PCI layer interface
- *	uses this to handle all our card discover and plugging
- */
-
-static struct pci_driver velocity_driver = {
-      .name	= VELOCITY_NAME,
-      .id_table	= velocity_id_table,
-      .probe	= velocity_found1,
-      .remove	= __devexit_p(velocity_remove1),
-#ifdef CONFIG_PM
-      .suspend	= velocity_suspend,
-      .resume	= velocity_resume,
-#endif
-};
 
 /**
- *	velocity_init_module	-	load time function
+ *	velocity_found1		-	set up discovered velocity card
+ *	@pdev: PCI device
+ *	@ent: PCI device table entry that matched
  *
- *	Called when the velocity module is loaded. The PCI driver
- *	is registered with the PCI layer, and in turn will call
- *	the probe functions for each velocity adapter installed
- *	in the system.
+ *	Configure a discovered adapter from scratch. Return a negative
+ *	errno error code on failure paths.
  */
-
-static int __init velocity_init_module(void)
+static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	int ret;
+	static int first = 1;
+	struct net_device *dev;
+	int i;
+	const char *drv_string;
+	const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
+	struct velocity_info *vptr;
+	struct mac_regs __iomem *regs;
+	int ret = -ENOMEM;
 
-	velocity_register_notifier();
-	ret = pci_register_driver(&velocity_driver);
-	if (ret < 0)
-		velocity_unregister_notifier();
-	return ret;
-}
+	/* FIXME: this driver, like almost all other ethernet drivers,
+	 * can support more than MAX_UNITS.
+	 */
+	if (velocity_nics >= MAX_UNITS) {
+		dev_notice(&pdev->dev, "already found %d NICs.\n",
+			   velocity_nics);
+		return -ENODEV;
+	}
 
-/**
- *	velocity_cleanup	-	module unload
- *
- *	When the velocity hardware is unloaded this function is called.
- *	It will clean up the notifiers and the unregister the PCI
- *	driver interface for this hardware. This in turn cleans up
- *	all discovered interfaces before returning from the function
- */
+	dev = alloc_etherdev(sizeof(struct velocity_info));
+	if (!dev) {
+		dev_err(&pdev->dev, "allocate net device failed.\n");
+		goto out;
+	}
 
-static void __exit velocity_cleanup_module(void)
-{
-	velocity_unregister_notifier();
-	pci_unregister_driver(&velocity_driver);
-}
+	/* Chain it all together */
 
-module_init(velocity_init_module);
-module_exit(velocity_cleanup_module);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	vptr = netdev_priv(dev);
 
 
-/*
- * MII access , media link mode setting functions
- */
+	if (first) {
+		printk(KERN_INFO "%s Ver. %s\n",
+			VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
+		printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
+		printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
+		first = 0;
+	}
 
+	velocity_init_info(pdev, vptr, info);
 
-/**
- *	mii_init	-	set up MII
- *	@vptr: velocity adapter
- *	@mii_status:  links tatus
- *
- *	Set up the PHY for the current link state.
- */
+	vptr->dev = dev;
 
-static void mii_init(struct velocity_info *vptr, u32 mii_status)
-{
-	u16 BMCR;
+	dev->irq = pdev->irq;
 
-	switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
-	case PHYID_CICADA_CS8201:
-		/*
-		 *	Reset to hardware default
-		 */
-		MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
-		/*
-		 *	Turn on ECHODIS bit in NWay-forced full mode and turn it
-		 *	off it in NWay-forced half mode for NWay-forced v.s.
-		 *	legacy-forced issue.
-		 */
-		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
-			MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
-		else
-			MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
-		/*
-		 *	Turn on Link/Activity LED enable bit for CIS8201
-		 */
-		MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
-		break;
-	case PHYID_VT3216_32BIT:
-	case PHYID_VT3216_64BIT:
-		/*
-		 *	Reset to hardware default
-		 */
-		MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
-		/*
-		 *	Turn on ECHODIS bit in NWay-forced full mode and turn it
-		 *	off it in NWay-forced half mode for NWay-forced v.s.
-		 *	legacy-forced issue
-		 */
-		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
-			MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
-		else
-			MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
-		break;
+	ret = pci_enable_device(pdev);
+	if (ret < 0)
+		goto err_free_dev;
 
-	case PHYID_MARVELL_1000:
-	case PHYID_MARVELL_1000S:
-		/*
-		 *	Assert CRS on Transmit
-		 */
-		MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
-		/*
-		 *	Reset to hardware default
-		 */
-		MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
-		break;
-	default:
-		;
-	}
-	velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
-	if (BMCR & BMCR_ISO) {
-		BMCR &= ~BMCR_ISO;
-		velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+	ret = velocity_get_pci_info(vptr, pdev);
+	if (ret < 0) {
+		/* error message already printed */
+		goto err_disable;
 	}
-}
 
-/**
- *	safe_disable_mii_autopoll	-	autopoll off
- *	@regs: velocity registers
- *
- *	Turn off the autopoll and wait for it to disable on the chip
- */
-
-static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs)
-{
-	u16 ww;
-
-	/*  turn off MAUTO */
-	writeb(0, &regs->MIICR);
-	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
-		udelay(1);
-		if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
-			break;
+	ret = pci_request_regions(pdev, VELOCITY_NAME);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "No PCI resources.\n");
+		goto err_disable;
 	}
-}
 
-/**
- *	enable_mii_autopoll	-	turn on autopolling
- *	@regs: velocity registers
- *
- *	Enable the MII link status autopoll feature on the Velocity
- *	hardware. Wait for it to enable.
- */
-
-static void enable_mii_autopoll(struct mac_regs __iomem *regs)
-{
-	int ii;
+	regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
+	if (regs == NULL) {
+		ret = -EIO;
+		goto err_release_res;
+	}
 
-	writeb(0, &(regs->MIICR));
-	writeb(MIIADR_SWMPL, &regs->MIIADR);
+	vptr->mac_regs = regs;
 
-	for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
-		udelay(1);
-		if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
-			break;
-	}
+	mac_wol_reset(regs);
 
-	writeb(MIICR_MAUTO, &regs->MIICR);
+	dev->base_addr = vptr->ioaddr;
 
-	for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
-		udelay(1);
-		if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
-			break;
-	}
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = readb(&regs->PAR[i]);
 
-}
 
-/**
- *	velocity_mii_read	-	read MII data
- *	@regs: velocity registers
- *	@index: MII register index
- *	@data: buffer for received data
- *
- *	Perform a single read of an MII 16bit register. Returns zero
- *	on success or -ETIMEDOUT if the PHY did not respond.
- */
+	drv_string = dev_driver_string(&pdev->dev);
 
-static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
-{
-	u16 ww;
+	velocity_get_options(&vptr->options, velocity_nics, drv_string);
 
 	/*
-	 *	Disable MIICR_MAUTO, so that mii addr can be set normally
+	 *	Mask out the options cannot be set to the chip
 	 */
-	safe_disable_mii_autopoll(regs);
 
-	writeb(index, &regs->MIIADR);
-
-	BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+	vptr->options.flags &= info->flags;
 
-	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
-		if (!(readb(&regs->MIICR) & MIICR_RCMD))
-			break;
-	}
+	/*
+	 *	Enable the chip specified capbilities
+	 */
 
-	*data = readw(&regs->MIIDATA);
+	vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
 
-	enable_mii_autopoll(regs);
-	if (ww == W_MAX_TIMEOUT)
-		return -ETIMEDOUT;
-	return 0;
-}
+	vptr->wol_opts = vptr->options.wol_opts;
+	vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
 
-/**
- *	velocity_mii_write	-	write MII data
- *	@regs: velocity registers
- *	@index: MII register index
- *	@data: 16bit data for the MII register
- *
- *	Perform a single write to an MII 16bit register. Returns zero
- *	on success or -ETIMEDOUT if the PHY did not respond.
- */
+	vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
 
-static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
-{
-	u16 ww;
+	dev->irq = pdev->irq;
+	dev->netdev_ops = &velocity_netdev_ops;
+	dev->ethtool_ops = &velocity_ethtool_ops;
 
-	/*
-	 *	Disable MIICR_MAUTO, so that mii addr can be set normally
-	 */
-	safe_disable_mii_autopoll(regs);
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
+		NETIF_F_HW_VLAN_RX;
 
-	/* MII reg offset */
-	writeb(mii_addr, &regs->MIIADR);
-	/* set MII data */
-	writew(data, &regs->MIIDATA);
+	if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
+		dev->features |= NETIF_F_IP_CSUM;
 
-	/* turn on MIICR_WCMD */
-	BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+	ret = register_netdev(dev);
+	if (ret < 0)
+		goto err_iounmap;
 
-	/* W_MAX_TIMEOUT is the timeout period */
-	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
-		udelay(5);
-		if (!(readb(&regs->MIICR) & MIICR_WCMD))
-			break;
+	if (!velocity_get_link(dev)) {
+		netif_carrier_off(dev);
+		vptr->mii_status |= VELOCITY_LINK_FAIL;
 	}
-	enable_mii_autopoll(regs);
 
-	if (ww == W_MAX_TIMEOUT)
-		return -ETIMEDOUT;
-	return 0;
-}
+	velocity_print_info(vptr);
+	pci_set_drvdata(pdev, dev);
 
-/**
- *	velocity_get_opt_media_mode	-	get media selection
- *	@vptr: velocity adapter
- *
- *	Get the media mode stored in EEPROM or module options and load
- *	mii_status accordingly. The requested link state information
- *	is also returned.
- */
+	/* and leave the chip powered down */
 
-static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
-{
-	u32 status = 0;
+	pci_set_power_state(pdev, PCI_D3hot);
+#ifdef CONFIG_PM
+	{
+		unsigned long flags;
 
-	switch (vptr->options.spd_dpx) {
-	case SPD_DPX_AUTO:
-		status = VELOCITY_AUTONEG_ENABLE;
-		break;
-	case SPD_DPX_100_FULL:
-		status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
-		break;
-	case SPD_DPX_10_FULL:
-		status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
-		break;
-	case SPD_DPX_100_HALF:
-		status = VELOCITY_SPEED_100;
-		break;
-	case SPD_DPX_10_HALF:
-		status = VELOCITY_SPEED_10;
-		break;
+		spin_lock_irqsave(&velocity_dev_list_lock, flags);
+		list_add(&vptr->list, &velocity_dev_list);
+		spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
 	}
-	vptr->mii_status = status;
-	return status;
-}
-
-/**
- *	mii_set_auto_on		-	autonegotiate on
- *	@vptr: velocity
- *
- *	Enable autonegotation on this interface
- */
+#endif
+	velocity_nics++;
+out:
+	return ret;
 
-static void mii_set_auto_on(struct velocity_info *vptr)
-{
-	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
-		MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
-	else
-		MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+err_iounmap:
+	iounmap(regs);
+err_release_res:
+	pci_release_regions(pdev);
+err_disable:
+	pci_disable_device(pdev);
+err_free_dev:
+	free_netdev(dev);
+	goto out;
 }
 
 
-/*
-static void mii_set_auto_off(struct velocity_info *vptr)
-{
-    MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
-}
-*/
-
 /**
- *	set_mii_flow_control	-	flow control setup
- *	@vptr: velocity interface
+ *	wol_calc_crc		-	WOL CRC
+ *	@pattern: data pattern
+ *	@mask_pattern: mask
  *
- *	Set up the flow control on this interface according to
- *	the supplied user/eeprom options.
+ *	Compute the wake on lan crc hashes for the packet header
+ *	we are interested in.
  */
-
-static void set_mii_flow_control(struct velocity_info *vptr)
+static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern)
 {
-	/*Enable or Disable PAUSE in ANAR */
-	switch (vptr->options.flow_cntl) {
-	case FLOW_CNTL_TX:
-		MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
-		break;
+	u16 crc = 0xFFFF;
+	u8 mask;
+	int i, j;
 
-	case FLOW_CNTL_RX:
-		MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
-		break;
+	for (i = 0; i < size; i++) {
+		mask = mask_pattern[i];
 
-	case FLOW_CNTL_TX_RX:
-		MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
-		break;
+		/* Skip this loop if the mask equals to zero */
+		if (mask == 0x00)
+			continue;
 
-	case FLOW_CNTL_DISABLE:
-		MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-		MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
-		break;
-	default:
-		break;
+		for (j = 0; j < 8; j++) {
+			if ((mask & 0x01) == 0) {
+				mask >>= 1;
+				continue;
+			}
+			mask >>= 1;
+			crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1);
+		}
 	}
+	/*	Finally, invert the result once to get the correct data */
+	crc = ~crc;
+	return bitrev32(crc) >> 16;
 }
 
 /**
- *	velocity_set_media_mode		-	set media mode
- *	@mii_status: old MII link state
+ *	velocity_set_wol	-	set up for wake on lan
+ *	@vptr: velocity to set WOL status on
  *
- *	Check the media link state and configure the flow control
- *	PHY and also velocity hardware setup accordingly. In particular
- *	we need to set up CD polling and frame bursting.
+ *	Set a card up for wake on lan either by unicast or by
+ *	ARP packet.
+ *
+ *	FIXME: check static buffer is safe here
  */
-
-static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+static int velocity_set_wol(struct velocity_info *vptr)
 {
-	u32 curr_status;
 	struct mac_regs __iomem *regs = vptr->mac_regs;
+	static u8 buf[256];
+	int i;
 
-	vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
-	curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+	static u32 mask_pattern[2][4] = {
+		{0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */
+		{0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff}	 /* Magic Packet */
+	};
 
-	/* Set mii link status */
-	set_mii_flow_control(vptr);
+	writew(0xFFFF, &regs->WOLCRClr);
+	writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
+	writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
 
 	/*
-	   Check if new status is consisent with current status
-	   if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
-	   || (mii_status==curr_status)) {
-	   vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
-	   vptr->mii_status=check_connection_type(vptr->mac_regs);
-	   VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
-	   return 0;
-	   }
+	   if (vptr->wol_opts & VELOCITY_WOL_PHY)
+	   writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
 	 */
 
-	if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
-		MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+	if (vptr->wol_opts & VELOCITY_WOL_UCAST)
+		writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
 
-	/*
-	 *	If connection type is AUTO
-	 */
-	if (mii_status & VELOCITY_AUTONEG_ENABLE) {
-		VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
-		/* clear force MAC mode bit */
-		BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
-		/* set duplex mode of MAC according to duplex mode of MII */
-		MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
-		MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
-		MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
+	if (vptr->wol_opts & VELOCITY_WOL_ARP) {
+		struct arp_packet *arp = (struct arp_packet *) buf;
+		u16 crc;
+		memset(buf, 0, sizeof(struct arp_packet) + 7);
 
-		/* enable AUTO-NEGO mode */
-		mii_set_auto_on(vptr);
-	} else {
-		u16 ANAR;
-		u8 CHIPGCR;
+		for (i = 0; i < 4; i++)
+			writel(mask_pattern[0][i], &regs->ByteMask[0][i]);
 
-		/*
-		 * 1. if it's 3119, disable frame bursting in halfduplex mode
-		 *    and enable it in fullduplex mode
-		 * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
-		 * 3. only enable CD heart beat counter in 10HD mode
-		 */
+		arp->type = htons(ETH_P_ARP);
+		arp->ar_op = htons(1);
 
-		/* set force MAC mode bit */
-		BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+		memcpy(arp->ar_tip, vptr->ip_addr, 4);
 
-		CHIPGCR = readb(&regs->CHIPGCR);
-		CHIPGCR &= ~CHIPGCR_FCGMII;
+		crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf,
+				(u8 *) & mask_pattern[0][0]);
 
-		if (mii_status & VELOCITY_DUPLEX_FULL) {
-			CHIPGCR |= CHIPGCR_FCFDX;
-			writeb(CHIPGCR, &regs->CHIPGCR);
-			VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
-			if (vptr->rev_id < REV_ID_VT3216_A0)
-				BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
-		} else {
-			CHIPGCR &= ~CHIPGCR_FCFDX;
-			VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
-			writeb(CHIPGCR, &regs->CHIPGCR);
-			if (vptr->rev_id < REV_ID_VT3216_A0)
-				BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
-		}
+		writew(crc, &regs->PatternCRC[0]);
+		writew(WOLCR_ARP_EN, &regs->WOLCRSet);
+	}
+
+	BYTE_REG_BITS_ON(PWCFG_WOLTYPE, &regs->PWCFGSet);
+	BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, &regs->PWCFGSet);
+
+	writew(0x0FFF, &regs->WOLSRClr);
+
+	if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) {
+		if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
+			MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
 
 		MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+	}
 
-		if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10))
-			BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
-		else
-			BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+	if (vptr->mii_status & VELOCITY_SPEED_1000)
+		MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
 
-		/* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
-		velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
-		ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
-		if (mii_status & VELOCITY_SPEED_100) {
-			if (mii_status & VELOCITY_DUPLEX_FULL)
-				ANAR |= ANAR_TXFD;
-			else
-				ANAR |= ANAR_TX;
-		} else {
-			if (mii_status & VELOCITY_DUPLEX_FULL)
-				ANAR |= ANAR_10FD;
-			else
-				ANAR |= ANAR_10;
-		}
-		velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
-		/* enable AUTO-NEGO mode */
-		mii_set_auto_on(vptr);
-		/* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+	BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+	{
+		u8 GCR;
+		GCR = readb(&regs->CHIPGCR);
+		GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX;
+		writeb(GCR, &regs->CHIPGCR);
 	}
-	/* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
-	/* vptr->mii_status=check_connection_type(vptr->mac_regs); */
-	return VELOCITY_LINK_CHANGE;
+
+	BYTE_REG_BITS_OFF(ISR_PWEI, &regs->ISR);
+	/* Turn on SWPTAG just before entering power mode */
+	BYTE_REG_BITS_ON(STICKHW_SWPTAG, &regs->STICKHW);
+	/* Go to bed ..... */
+	BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+	return 0;
 }
 
 /**
- *	mii_check_media_mode	-	check media state
- *	@regs: velocity registers
+ *	velocity_save_context	-	save registers
+ *	@vptr: velocity
+ *	@context: buffer for stored context
  *
- *	Check the current MII status and determine the link status
- *	accordingly
+ *	Retrieve the current configuration from the velocity hardware
+ *	and stash it in the context structure, for use by the context
+ *	restore functions. This allows us to save things we need across
+ *	power down states
  */
-
-static u32 mii_check_media_mode(struct mac_regs __iomem *regs)
+static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context)
 {
-	u32 status = 0;
-	u16 ANAR;
+	struct mac_regs __iomem *regs = vptr->mac_regs;
+	u16 i;
+	u8 __iomem *ptr = (u8 __iomem *)regs;
 
-	if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
-		status |= VELOCITY_LINK_FAIL;
+	for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
+		*((u32 *) (context->mac_reg + i)) = readl(ptr + i);
 
-	if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
-		status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
-	else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
-		status |= (VELOCITY_SPEED_1000);
-	else {
-		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
-		if (ANAR & ANAR_TXFD)
-			status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
-		else if (ANAR & ANAR_TX)
-			status |= VELOCITY_SPEED_100;
-		else if (ANAR & ANAR_10FD)
-			status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
-		else
-			status |= (VELOCITY_SPEED_10);
-	}
+	for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
+		*((u32 *) (context->mac_reg + i)) = readl(ptr + i);
 
-	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
-		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
-		if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
-		    == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
-			if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
-				status |= VELOCITY_AUTONEG_ENABLE;
-		}
-	}
+	for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+		*((u32 *) (context->mac_reg + i)) = readl(ptr + i);
 
-	return status;
 }
 
-static u32 check_connection_type(struct mac_regs __iomem *regs)
-{
-	u32 status = 0;
-	u8 PHYSR0;
-	u16 ANAR;
-	PHYSR0 = readb(&regs->PHYSR0);
 
-	/*
-	   if (!(PHYSR0 & PHYSR0_LINKGD))
-	   status|=VELOCITY_LINK_FAIL;
-	 */
+static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct velocity_info *vptr = netdev_priv(dev);
+	unsigned long flags;
 
-	if (PHYSR0 & PHYSR0_FDPX)
-		status |= VELOCITY_DUPLEX_FULL;
+	if (!netif_running(vptr->dev))
+		return 0;
 
-	if (PHYSR0 & PHYSR0_SPDG)
-		status |= VELOCITY_SPEED_1000;
-	else if (PHYSR0 & PHYSR0_SPD10)
-		status |= VELOCITY_SPEED_10;
-	else
-		status |= VELOCITY_SPEED_100;
+	netif_device_detach(vptr->dev);
 
-	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
-		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
-		if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
-		    == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
-			if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
-				status |= VELOCITY_AUTONEG_ENABLE;
-		}
+	spin_lock_irqsave(&vptr->lock, flags);
+	pci_save_state(pdev);
+#ifdef ETHTOOL_GWOL
+	if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
+		velocity_get_ip(vptr);
+		velocity_save_context(vptr, &vptr->context);
+		velocity_shutdown(vptr);
+		velocity_set_wol(vptr);
+		pci_enable_wake(pdev, PCI_D3hot, 1);
+		pci_set_power_state(pdev, PCI_D3hot);
+	} else {
+		velocity_save_context(vptr, &vptr->context);
+		velocity_shutdown(vptr);
+		pci_disable_device(pdev);
+		pci_set_power_state(pdev, pci_choose_state(pdev, state));
 	}
-
-	return status;
+#else
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+#endif
+	spin_unlock_irqrestore(&vptr->lock, flags);
+	return 0;
 }
 
 /**
- *	enable_flow_control_ability	-	flow control
- *	@vptr: veloity to configure
+ *	velocity_restore_context	-	restore registers
+ *	@vptr: velocity
+ *	@context: buffer for stored context
  *
- *	Set up flow control according to the flow control options
- *	determined by the eeprom/configuration.
+ *	Reload the register configuration from the velocity context
+ *	created by velocity_save_context.
  */
-
-static void enable_flow_control_ability(struct velocity_info *vptr)
+static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
 {
-
 	struct mac_regs __iomem *regs = vptr->mac_regs;
+	int i;
+	u8 __iomem *ptr = (u8 __iomem *)regs;
 
-	switch (vptr->options.flow_cntl) {
+	for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4)
+		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
 
-	case FLOW_CNTL_DEFAULT:
-		if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
-			writel(CR0_FDXRFCEN, &regs->CR0Set);
-		else
-			writel(CR0_FDXRFCEN, &regs->CR0Clr);
+	/* Just skip cr0 */
+	for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
+		/* Clear */
+		writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
+		/* Set */
+		writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+	}
 
-		if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
-			writel(CR0_FDXTFCEN, &regs->CR0Set);
-		else
-			writel(CR0_FDXTFCEN, &regs->CR0Clr);
-		break;
+	for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4)
+		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
 
-	case FLOW_CNTL_TX:
-		writel(CR0_FDXTFCEN, &regs->CR0Set);
-		writel(CR0_FDXRFCEN, &regs->CR0Clr);
-		break;
+	for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
 
-	case FLOW_CNTL_RX:
-		writel(CR0_FDXRFCEN, &regs->CR0Set);
-		writel(CR0_FDXTFCEN, &regs->CR0Clr);
-		break;
+	for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++)
+		writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+}
 
-	case FLOW_CNTL_TX_RX:
-		writel(CR0_FDXTFCEN, &regs->CR0Set);
-		writel(CR0_FDXRFCEN, &regs->CR0Set);
-		break;
+static int velocity_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct velocity_info *vptr = netdev_priv(dev);
+	unsigned long flags;
+	int i;
 
-	case FLOW_CNTL_DISABLE:
-		writel(CR0_FDXRFCEN, &regs->CR0Clr);
-		writel(CR0_FDXTFCEN, &regs->CR0Clr);
-		break;
+	if (!netif_running(vptr->dev))
+		return 0;
 
-	default:
-		break;
+	pci_set_power_state(pdev, PCI_D0);
+	pci_enable_wake(pdev, 0, 0);
+	pci_restore_state(pdev);
+
+	mac_wol_reset(vptr->mac_regs);
+
+	spin_lock_irqsave(&vptr->lock, flags);
+	velocity_restore_context(vptr, &vptr->context);
+	velocity_init_registers(vptr, VELOCITY_INIT_WOL);
+	mac_disable_int(vptr->mac_regs);
+
+	velocity_tx_srv(vptr, 0);
+
+	for (i = 0; i < vptr->tx.numq; i++) {
+		if (vptr->tx.used[i])
+			mac_tx_queue_wake(vptr->mac_regs, i);
 	}
 
+	mac_enable_int(vptr->mac_regs);
+	spin_unlock_irqrestore(&vptr->lock, flags);
+	netif_device_attach(vptr->dev);
+
+	return 0;
 }
 
 
+/*
+ *	Definition for our device driver. The PCI layer interface
+ *	uses this to handle all our card discover and plugging
+ */
+static struct pci_driver velocity_driver = {
+      .name	= VELOCITY_NAME,
+      .id_table	= velocity_id_table,
+      .probe	= velocity_found1,
+      .remove	= __devexit_p(velocity_remove1),
+#ifdef CONFIG_PM
+      .suspend	= velocity_suspend,
+      .resume	= velocity_resume,
+#endif
+};
+
+
 /**
  *	velocity_ethtool_up	-	pre hook for ethtool
  *	@dev: network device
@@ -2928,7 +3081,6 @@ static void enable_flow_control_ability(struct velocity_info *vptr)
  *	Called before an ethtool operation. We need to make sure the
  *	chip is out of D3 state before we poke at it.
  */
-
 static int velocity_ethtool_up(struct net_device *dev)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
@@ -2944,7 +3096,6 @@ static int velocity_ethtool_up(struct net_device *dev)
  *	Called after an ethtool operation. Restore the chip back to D3
  *	state if it isn't running.
  */
-
 static void velocity_ethtool_down(struct net_device *dev)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
@@ -3009,13 +3160,6 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
 	return ret;
 }
 
-static u32 velocity_get_link(struct net_device *dev)
-{
-	struct velocity_info *vptr = netdev_priv(dev);
-	struct mac_regs __iomem *regs = vptr->mac_regs;
-	return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
-}
-
 static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct velocity_info *vptr = netdev_priv(dev);
@@ -3094,331 +3238,88 @@ static const struct ethtool_ops velocity_ethtool_ops = {
 	.complete	=	velocity_ethtool_down
 };
 
-/**
- *	velocity_mii_ioctl		-	MII ioctl handler
- *	@dev: network device
- *	@ifr: the ifreq block for the ioctl
- *	@cmd: the command
- *
- *	Process MII requests made via ioctl from the network layer. These
- *	are used by tools like kudzu to interrogate the link state of the
- *	hardware
- */
+#ifdef CONFIG_PM
 
-static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+#ifdef CONFIG_INET
+static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
 {
-	struct velocity_info *vptr = netdev_priv(dev);
-	struct mac_regs __iomem *regs = vptr->mac_regs;
+	struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+	struct net_device *dev = ifa->ifa_dev->dev;
+	struct velocity_info *vptr;
 	unsigned long flags;
-	struct mii_ioctl_data *miidata = if_mii(ifr);
-	int err;
 
-	switch (cmd) {
-	case SIOCGMIIPHY:
-		miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
-		break;
-	case SIOCGMIIREG:
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
-			return -ETIMEDOUT;
-		break;
-	case SIOCSMIIREG:
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		spin_lock_irqsave(&vptr->lock, flags);
-		err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
-		spin_unlock_irqrestore(&vptr->lock, flags);
-		check_connection_type(vptr->mac_regs);
-		if (err)
-			return err;
-		break;
-	default:
-		return -EOPNOTSUPP;
+	if (dev_net(dev) != &init_net)
+		return NOTIFY_DONE;
+
+	spin_lock_irqsave(&velocity_dev_list_lock, flags);
+	list_for_each_entry(vptr, &velocity_dev_list, list) {
+		if (vptr->dev == dev) {
+			velocity_get_ip(vptr);
+			break;
+		}
 	}
-	return 0;
-}
+	spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
 
-#ifdef CONFIG_PM
+	return NOTIFY_DONE;
+}
+#endif	/* CONFIG_INET */
 
-/**
- *	velocity_save_context	-	save registers
- *	@vptr: velocity
- *	@context: buffer for stored context
- *
- *	Retrieve the current configuration from the velocity hardware
- *	and stash it in the context structure, for use by the context
- *	restore functions. This allows us to save things we need across
- *	power down states
- */
+#if defined(CONFIG_PM) && defined(CONFIG_INET)
+static struct notifier_block velocity_inetaddr_notifier = {
+      .notifier_call	= velocity_netdev_event,
+};
 
-static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context)
+static void velocity_register_notifier(void)
 {
-	struct mac_regs __iomem *regs = vptr->mac_regs;
-	u16 i;
-	u8 __iomem *ptr = (u8 __iomem *)regs;
-
-	for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
-		*((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
-	for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
-		*((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
-	for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
-		*((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
+	register_inetaddr_notifier(&velocity_inetaddr_notifier);
 }
 
-/**
- *	velocity_restore_context	-	restore registers
- *	@vptr: velocity
- *	@context: buffer for stored context
- *
- *	Reload the register configuration from the velocity context
- *	created by velocity_save_context.
- */
-
-static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
+static void velocity_unregister_notifier(void)
 {
-	struct mac_regs __iomem *regs = vptr->mac_regs;
-	int i;
-	u8 __iomem *ptr = (u8 __iomem *)regs;
-
-	for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4)
-		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+	unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
 
-	/* Just skip cr0 */
-	for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
-		/* Clear */
-		writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
-		/* Set */
-		writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
-	}
+#else
 
-	for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4)
-		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+#define velocity_register_notifier()	do {} while (0)
+#define velocity_unregister_notifier()	do {} while (0)
 
-	for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
-		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+#endif	/* defined(CONFIG_PM) && defined(CONFIG_INET) */
 
-	for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++)
-		writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
-}
+#endif	/* CONFIG_PM */
 
 /**
- *	wol_calc_crc		-	WOL CRC
- *	@pattern: data pattern
- *	@mask_pattern: mask
+ *	velocity_init_module	-	load time function
  *
- *	Compute the wake on lan crc hashes for the packet header
- *	we are interested in.
+ *	Called when the velocity module is loaded. The PCI driver
+ *	is registered with the PCI layer, and in turn will call
+ *	the probe functions for each velocity adapter installed
+ *	in the system.
  */
-
-static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern)
+static int __init velocity_init_module(void)
 {
-	u16 crc = 0xFFFF;
-	u8 mask;
-	int i, j;
-
-	for (i = 0; i < size; i++) {
-		mask = mask_pattern[i];
-
-		/* Skip this loop if the mask equals to zero */
-		if (mask == 0x00)
-			continue;
+	int ret;
 
-		for (j = 0; j < 8; j++) {
-			if ((mask & 0x01) == 0) {
-				mask >>= 1;
-				continue;
-			}
-			mask >>= 1;
-			crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1);
-		}
-	}
-	/*	Finally, invert the result once to get the correct data */
-	crc = ~crc;
-	return bitrev32(crc) >> 16;
+	velocity_register_notifier();
+	ret = pci_register_driver(&velocity_driver);
+	if (ret < 0)
+		velocity_unregister_notifier();
+	return ret;
 }
 
 /**
- *	velocity_set_wol	-	set up for wake on lan
- *	@vptr: velocity to set WOL status on
- *
- *	Set a card up for wake on lan either by unicast or by
- *	ARP packet.
+ *	velocity_cleanup	-	module unload
  *
- *	FIXME: check static buffer is safe here
+ *	When the velocity hardware is unloaded this function is called.
+ *	It will clean up the notifiers and the unregister the PCI
+ *	driver interface for this hardware. This in turn cleans up
+ *	all discovered interfaces before returning from the function
  */
-
-static int velocity_set_wol(struct velocity_info *vptr)
-{
-	struct mac_regs __iomem *regs = vptr->mac_regs;
-	static u8 buf[256];
-	int i;
-
-	static u32 mask_pattern[2][4] = {
-		{0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */
-		{0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff}	 /* Magic Packet */
-	};
-
-	writew(0xFFFF, &regs->WOLCRClr);
-	writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
-	writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
-
-	/*
-	   if (vptr->wol_opts & VELOCITY_WOL_PHY)
-	   writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
-	 */
-
-	if (vptr->wol_opts & VELOCITY_WOL_UCAST)
-		writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
-
-	if (vptr->wol_opts & VELOCITY_WOL_ARP) {
-		struct arp_packet *arp = (struct arp_packet *) buf;
-		u16 crc;
-		memset(buf, 0, sizeof(struct arp_packet) + 7);
-
-		for (i = 0; i < 4; i++)
-			writel(mask_pattern[0][i], &regs->ByteMask[0][i]);
-
-		arp->type = htons(ETH_P_ARP);
-		arp->ar_op = htons(1);
-
-		memcpy(arp->ar_tip, vptr->ip_addr, 4);
-
-		crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf,
-				(u8 *) & mask_pattern[0][0]);
-
-		writew(crc, &regs->PatternCRC[0]);
-		writew(WOLCR_ARP_EN, &regs->WOLCRSet);
-	}
-
-	BYTE_REG_BITS_ON(PWCFG_WOLTYPE, &regs->PWCFGSet);
-	BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, &regs->PWCFGSet);
-
-	writew(0x0FFF, &regs->WOLSRClr);
-
-	if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) {
-		if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
-			MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
-
-		MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
-	}
-
-	if (vptr->mii_status & VELOCITY_SPEED_1000)
-		MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
-
-	BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
-
-	{
-		u8 GCR;
-		GCR = readb(&regs->CHIPGCR);
-		GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX;
-		writeb(GCR, &regs->CHIPGCR);
-	}
-
-	BYTE_REG_BITS_OFF(ISR_PWEI, &regs->ISR);
-	/* Turn on SWPTAG just before entering power mode */
-	BYTE_REG_BITS_ON(STICKHW_SWPTAG, &regs->STICKHW);
-	/* Go to bed ..... */
-	BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
-
-	return 0;
-}
-
-static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct velocity_info *vptr = netdev_priv(dev);
-	unsigned long flags;
-
-	if (!netif_running(vptr->dev))
-		return 0;
-
-	netif_device_detach(vptr->dev);
-
-	spin_lock_irqsave(&vptr->lock, flags);
-	pci_save_state(pdev);
-#ifdef ETHTOOL_GWOL
-	if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
-		velocity_get_ip(vptr);
-		velocity_save_context(vptr, &vptr->context);
-		velocity_shutdown(vptr);
-		velocity_set_wol(vptr);
-		pci_enable_wake(pdev, PCI_D3hot, 1);
-		pci_set_power_state(pdev, PCI_D3hot);
-	} else {
-		velocity_save_context(vptr, &vptr->context);
-		velocity_shutdown(vptr);
-		pci_disable_device(pdev);
-		pci_set_power_state(pdev, pci_choose_state(pdev, state));
-	}
-#else
-	pci_set_power_state(pdev, pci_choose_state(pdev, state));
-#endif
-	spin_unlock_irqrestore(&vptr->lock, flags);
-	return 0;
-}
-
-static int velocity_resume(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct velocity_info *vptr = netdev_priv(dev);
-	unsigned long flags;
-	int i;
-
-	if (!netif_running(vptr->dev))
-		return 0;
-
-	pci_set_power_state(pdev, PCI_D0);
-	pci_enable_wake(pdev, 0, 0);
-	pci_restore_state(pdev);
-
-	mac_wol_reset(vptr->mac_regs);
-
-	spin_lock_irqsave(&vptr->lock, flags);
-	velocity_restore_context(vptr, &vptr->context);
-	velocity_init_registers(vptr, VELOCITY_INIT_WOL);
-	mac_disable_int(vptr->mac_regs);
-
-	velocity_tx_srv(vptr, 0);
-
-	for (i = 0; i < vptr->tx.numq; i++) {
-		if (vptr->tx.used[i])
-			mac_tx_queue_wake(vptr->mac_regs, i);
-	}
-
-	mac_enable_int(vptr->mac_regs);
-	spin_unlock_irqrestore(&vptr->lock, flags);
-	netif_device_attach(vptr->dev);
-
-	return 0;
-}
-
-#ifdef CONFIG_INET
-
-static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
+static void __exit velocity_cleanup_module(void)
 {
-	struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
-	struct net_device *dev = ifa->ifa_dev->dev;
-	struct velocity_info *vptr;
-	unsigned long flags;
-
-	if (dev_net(dev) != &init_net)
-		return NOTIFY_DONE;
-
-	spin_lock_irqsave(&velocity_dev_list_lock, flags);
-	list_for_each_entry(vptr, &velocity_dev_list, list) {
-		if (vptr->dev == dev) {
-			velocity_get_ip(vptr);
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
-
-	return NOTIFY_DONE;
+	velocity_unregister_notifier();
+	pci_unregister_driver(&velocity_driver);
 }
 
-#endif
-#endif
+module_init(velocity_init_module);
+module_exit(velocity_cleanup_module);
-- 
1.6.2.5


^ permalink raw reply related

* Re: Kernel oops on setting sky2 interfaces down
From: Stephen Hemminger @ 2009-07-21 16:58 UTC (permalink / raw)
  To: Rene Mayrhofer; +Cc: netdev, Richard Leitner
In-Reply-To: <4A65EC3F.4050400@gibraltar.at>

On Tue, 21 Jul 2009 18:26:39 +0200
Rene Mayrhofer <rene.mayrhofer@gibraltar.at> wrote:

> Hi everybody,
> 
> [Please CC me in replies, I am not currently subscribed to this list.]
> 
> I have a fully reproducible kernel oops in the sky2 module in kernel
> 2.6.28.10. The kernel is a vanilla 2.6.28.10 (and I can't switch to
> anything newer at this time because of missing squashfs-lzma support),
> patched with PaX, netfilter-layer7, squashfs (with LZMA), and IMQ. The
> base system is a Debian Lenny with some updates from testing/unstable.
> 
> Whenever interfaces using the sky2 module (this box has 8 network
> interfaces in a 19" rack appliance) go down, the oops occurs:

Looks like the device is disappearing from the PCI bus when
brought down.  Can you reproduce it with 2.6.30.2 or 2.6.31-rc3?


> [~]# ifdown -a --exclude=lo
> [ 1535.000069] sky2 0000:01:00.0: error interrupt status=0xffffffff
> [ 1535.006649] sky2 0000:01:00.0: PCI hardware error (0xffff)
> [ 1535.012608] sky2 0000:01:00.0: PCI Express error (0xffffffff)
> [ 1535.018821] sky2 wan: ram data read parity error
> [ 1535.023827] sky2 wan: ram data write parity error
> [ 1535.028913] sky2 wan: MAC parity error
> [ 1535.032992] sky2 wan: RX parity error
> [ 1535.036983] sky2 wan: TCP segmentation error
> [ 1535.041655] general protection fault: 0000 [#1] PREEMPT SMP
> [ 1535.045601] last sysfs file:
> /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
> 
> [ 1535.045601] Modules linked in: xt_multiport cpufreq_userspace xt_DSCP
> xt_length xt_mark xt_dscp xt_MARK xt_CONNMARK xt_comment xt_policy
> ipt_REDIRECT ip6t_LOG xt_tcpudp ip6table_mangle iptable_mangle
> ip6table_filter ip6_tables sit tunnel4 8021q garp stp llc ipt_LOG
> xt_limit xt_state iptable_nat iptable_filter ip_tables x_tables dm_mod
> p4_clockmod speedstep_lib freq_table tun imq nf_nat_ftp nf_nat
> nf_conntrack_ftp nf_conntrack_ipv6 nf_conntrack_ipv4 nf_conntrack
> nf_defrag_ipv4 ipv6 evdev parport_pc parport serio_raw pcspkr i2c_i801
> i2c_core iTCO_wdt rng_core intel_agp agpgart squashfs sqlzma unlzma loop
> aufs exportfs nls_utf8 nls_cp437 ide_generic sd_mod ide_gd_mod
> ata_generic pata_acpi ata_piix piix ide_pci_generic ide_core skge sky2
> thermal_sys
> [ 1535.045601]
> 
> [ 1535.045601] Pid: 9960, comm: mv Not tainted (2.6.28.10 #2)
> 
> [ 1535.045601] EIP: 0060:[<f808085a>] EFLAGS: 00010286 CPU: 0
> 
> [ 1535.045601] EIP is at sky2_mac_intr+0x22/0x9d [sky2]
> 
> [ 1535.045601] EAX: f8090f88 EBX: 00000001 ECX: 00000008 EDX: 000000ff
> 
> [ 1535.045601] ESI: 00000000 EDI: f682cb80 EBP: 00000080 ESP: f5f13ed4
> 
> [ 1535.045601]  DS: 0068 ES: 0068 FS: 00d8 GS: 0033 SS: 0068
> 
> [ 1535.045601] Process mv (pid: 9960, ti=f5f12000 task=f4a961c0
> task.ti=f5f12000)
> 
> [ 1535.045601] Stack:
> 
> [ 1535.045601]  ff08340b f682cb88 ffffffff ffffffff f712b800 f80839d6
> 00000040 f682cb88
> 
> [ 1535.045601]  00000000 00000001 f682cb80 c082111a 00000000 00000000
> 00000003 f7014b80
> [ 1535.045601]  c0a604e8 00000246 f7014b80 c0838f21 00000000 c0a604e8
> 00000101 c1d10124
> [ 1535.045601] Call Trace:
> [ 1535.045601]  [<f80839d6>] sky2_poll+0x1cb/0xbed [sky2]
> [ 1535.045601]  [<c082111a>] __wake_up+0x29/0x39
> [ 1535.045601]  [<c0a604e8>] _spin_unlock_irqrestore+0x22/0x39
> [ 1535.045601]  [<c0838f21>] __queue_work+0x4d/0x5a
> [ 1535.045601]  [<c0a604e8>] _spin_unlock_irqrestore+0x22/0x39
> [ 1535.045601]  [<c09eda45>] net_rx_action+0xb8/0x1f6
> [ 1535.045601]  [<c082f954>] __do_softirq+0x95/0x142
> [ 1535.045601]  [<c082fa49>] do_softirq+0x48/0x57
> [ 1535.045601]  [<c082fbc9>] irq_exit+0x3b/0x78
> [ 1535.045601]  [<c081218f>] smp_apic_timer_interrupt+0x75/0x7f
> [ 1535.045601]  [<c0804f48>] apic_timer_interrupt+0x28/0x30
> [ 1535.045601]  [<c0a60000>] rwsem_down_failed_common+0xa4/0x175
> [ 1535.045601] Code: c0 83 c4 14 5b 5e 5f 5d c3 55 89 d5 57 89 c7 56 53
> 89 d3 c1 e5 07 83 ec 04 8b 74 90 30 8d 85 08 0f 00 00 03 07 8a 10 88 54
> 24 03 <f6> 86 0d 05 00 00 02 74 12 0f b6 c2 50 56 68 84 5b 08 f8 e8 cd
> [ 1535.045601] EIP: [<f808085a>] sky2_mac_intr+0x22/0x9d [sky2] SS:ESP
> 0068:f5f13ed4
> [ 1535.302490] Kernel panic - not syncing: Fatal exception in interrupt
> [ 1535.309412] Rebooting in 30 seconds..
> 
> 
> Or even when doing it more slowly, interface by interface:
> 
> [~]# ifdown tun6to4; cat /proc/net/dev | cut -d: -f1 | grep -v Inter |
> grep -v face | sort -u | while read iface; do echo $iface; ifdown
> $iface; sleep 3s; done
> hb
> 
> lo
> 
> dmz
> 
> lan
> [ 1127.000261] sky2 0000:04:00.0: error interrupt status=0xffffffff
> [ 1127.007348] sky2 0000:04:00.0: PCI hardware error (0xffff)
> [ 1127.013745] sky2 0000:04:00.0: PCI Express error (0xffffffff)
> [ 1127.020468] sky2 lan: ram data read parity error
> [ 1127.025834] sky2 lan: ram data write parity error
> [ 1127.031302] sky2 lan: MAC parity error
> [ 1127.035671] sky2 lan: RX parity error
> [ 1127.039910] sky2 lan: TCP segmentation error
> [ 1127.045079] general protection fault: 0000 [#1] PREEMPT SMP
> [ 1127.048879] last sysfs file:
> /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
> 
> [ 1127.048879] Modules linked in: xt_multiport cpufreq_userspace xt_DSCP
> xt_length xt_mark xt_dscp xt_MARK xt_CONNMARK xt_comment xt_policy
> ipt_REDIRECT ip6t_LOG xt_tcpudp ip6table_mangle iptable_mangle
> ip6table_filter ip6_tables sit tunnel4 8021q garp stp llc ipt_LOG
> xt_limit xt_state iptable_nat iptable_filter ip_tables x_tables dm_mod
> p4_clockmod speedstep_lib freq_table tun imq nf_nat_ftp nf_nat
> nf_conntrack_ftp nf_conntrack_ipv6 nf_conntrack_ipv4 nf_conntrack
> nf_defrag_ipv4 ipv6 evdev parport_pc parport pcspkr serio_raw i2c_i801
> i2c_core iTCO_wdt rng_core intel_agp agpgart squashfs sqlzma unlzma loop
> aufs exportfs nls_utf8 nls_cp437 ide_generic sd_mod ide_gd_mod
> ata_generic pata_acpi ata_piix piix ide_pci_generic ide_core skge sky2
> thermal_sys
> [ 1127.048879]
> 
> [ 1127.048879] Pid: 20150, comm: rndc Not tainted (2.6.28.10 #2)
> 
> [ 1127.048879] EIP: 0060:[<f808085a>] EFLAGS: 00010286 CPU: 0
> 
> [ 1127.048879] EIP is at sky2_mac_intr+0x22/0x9d [sky2]
> 
> [ 1127.048879] EAX: f80d8f88 EBX: 00000001 ECX: 00000008 EDX: 000000ff
> 
> [ 1127.048879] ESI: 00000000 EDI: f68c2a80 EBP: 00000080 ESP: eb83fb38
> 
> [ 1127.048879]  DS: 0068 ES: 0068 FS: 00d8 GS: 0000 SS: 0068
> 
> [ 1127.048879] Process rndc (pid: 20150, ti=eb83e000 task=f695bb00
> task.ti=eb83e000)
> 
> [ 1127.048879] Stack:
> 
> [ 1127.048879]  ff08340b f68c2a88 ffffffff ffffffff f712c000 f80839d6
> 00000040 f68c2a88
> 
> [ 1127.048879]  c0a78d54 f70344e0 f68c2a80 f695bb00 c0a78d54 c0a604e8
> c1d10980 c0a78d54
> 
> [ 1127.048879]  c0827013 00000000 0000000f 00000246 f70344e0 00000102
> c0be5180 c0832dc6
> 
> [ 1127.048879] Call Trace:
> 
> [ 1127.048879]  [<f80839d6>] sky2_poll+0x1cb/0xbed [sky2]
> 
> [ 1127.048879]  [<c0a604e8>] _spin_unlock_irqrestore+0x22/0x39
> 
> [ 1127.048879]  [<c0827013>] try_to_wake_up+0x158/0x162
> 
> [ 1127.048879]  [<c0832dc6>] process_timeout+0x0/0x5
> 
> [ 1127.048879]  [<c09eda45>] net_rx_action+0xb8/0x1f6
> 
> [ 1127.048879]  [<c082f954>] __do_softirq+0x95/0x142
> 
> [ 1127.048879]  [<c082fa49>] do_softirq+0x48/0x57
> 
> [ 1127.048879]  [<c082fbc9>] irq_exit+0x3b/0x78
> 
> [ 1127.048879]  [<c081218f>] smp_apic_timer_interrupt+0x75/0x7f
> 
> [ 1127.048879]  [<c0804f48>] apic_timer_interrupt+0x28/0x30
> 
> [ 1127.048879]  [<c0867764>] get_page_from_freelist+0x2b8/0x3df
> 
> [ 1127.048879]  [<c0867ae0>] __alloc_pages_internal+0x98/0x37f
> 
> [ 1127.048879]  [<c0862ee0>] find_lock_page+0x10/0x43
> 
> [ 1127.048879]  [<c0a60555>] _spin_unlock+0x10/0x23
> 
> [ 1127.048879]  [<c086fb70>] __do_fault+0xaa/0x3bc
> 
> [ 1127.048879]  [<c08718e1>] handle_mm_fault+0x54a/0xbfa
> 
> [ 1127.048879]  [<c0a60555>] _spin_unlock+0x10/0x23
> 
> [ 1127.048879]  [<c089442d>] __d_lookup+0xfa/0x116
> 
> [ 1127.048879]  [<c088cb78>] do_lookup+0x53/0x153
> 
> [ 1127.048879]  [<c0893375>] dput+0x16/0xfc
> 
> [ 1127.048879]  [<c088eb25>] __link_path_walk+0xb01/0xbfb
> 
> [ 1127.048879]  [<c0a60555>] _spin_unlock+0x10/0x23
> 
> [ 1127.048879]  [<c086f05e>] kmap_high+0x17c/0x186
> 
> [ 1127.048879]  [<c0819b76>] default_spin_lock_flags+0x5/0x7
> 
> [ 1127.048879]  [<c081a64b>] do_page_fault+0x335/0x86e
> 
> [ 1127.048879]  [<c0a60555>] _spin_unlock+0x10/0x23
> 
> [ 1127.048879]  [<c0870a91>] unmap_vmas+0x498/0x6ab
> 
> [ 1127.048879]  [<c087321e>] free_pgtables+0x7d/0x93
> 
> [ 1127.048879]  [<c086d42e>] vma_prio_tree_insert+0x17/0x7f
> 
> [ 1127.048879]  [<c0874a45>] vma_link+0x51/0x73
> 
> [ 1127.048879]  [<c0a60555>] _spin_unlock+0x10/0x23
> 
> [ 1127.048879]  [<c0874a5f>] vma_link+0x6b/0x73
> 
> [ 1127.048879]  [<c08763b8>] mmap_region+0x475/0x58c
> 
> [ 1127.048879]  [<c08767a4>] do_mmap_pgoff+0x2d5/0x326
> 
> [ 1127.048879]  [<c08081db>] sys_mmap2+0x62/0x77
> 
> [ 1127.048879]  [<c08081e9>] sys_mmap2+0x70/0x77
> 
> [ 1127.048879]  [<c081a316>] do_page_fault+0x0/0x86e
> 
> [ 1127.048879]  [<c0a60805>] error_code+0x75/0x80
> 
> [ 1127.048879] Code: c0 83 c4 14 5b 5e 5f 5d c3 55 89 d5 57 89 c7 56 53
> 89 d3 c1 e5 07 83 ec 04 8b 74 90 30 8d 85 08 0f 00 00 03 07 8a 10 88 54
> 24 03 <f6> 86 0d 05 00 00 02 74 12 0f b6 c2 50 56 68 84 5b 08 f8 e8 cd
> 
> [ 1127.048879] EIP: [<f808085a>] sky2_mac_intr+0x22/0x9d [sky2] SS:ESP
> 0068:eb83fb38
> 
> [ 1127.470534] Kernel panic - not syncing: Fatal exception in interrupt
> 
> [ 1127.478035] Rebooting in 30 seconds..
> 
> 
> 
> It seems that the oops occurs when the last network interface using the
> sky2 module goes down, although I am not completely certain about this.
> I am also fairly sure that the other patches applied to 2.6.28.10 are
> not at fault, as the same kernel works perfectly well on different
> hardware (which is not using the sky2 NIC module).
> 
> Attached are the lspci -v output and the kernel config.
> 
> Any hints on what may be wrong would be highly appreciated. I am able to
> try patches to sky2 and/or give remote ssh access to the box (although
> it will be offline for 5 minutes after triggering the oops...).

Try later kernels.  


-- 

^ permalink raw reply

* Re: [PATCH v2] net: Rework mdio-ofgpio driver to use of_mdio infrastructure
From: Grant Likely @ 2009-07-21 17:09 UTC (permalink / raw)
  To: Mark Ware; +Cc: netdev, linuxppc-dev, David Miller
In-Reply-To: <4A658F69.7020002@elphinstone.net>

On Tue, Jul 21, 2009 at 3:50 AM, Mark Ware<mware@elphinstone.net> wrote:
> Changes to the fs_enet driver (aa73832c5a80d6c52c69b18af858d88fa595dd3c)
> cause kernel crashes when using the mdio-ofgpio driver.
>
> The following patch replicates similar changes made to the fs_enet
> mii-bitbang drivers.

This looks good to me.  I've not tested it though (no hardware that
uses it).  You should specify the testing you've done in the commit
log.  Your signed-off-by: line is also missing.

Acked-by: Grant Likely <grant.likely@secretlab.ca>

David, once the above issues are solved, this one needs to be merged for 2.6.31.

Cheers,
g.

> ---
>
> This version attempts to address Grant's comments below:
>
> Grant Likely wrote:
>>
>> You should refactor mdio_gpio_bus_init() to not call
>> mdiobus_register() at all, and instead just return a pointer to the
>> unregistered new_bus.  Then mdio_gpio_probe() and mdio_ofgpio_probe()
>> can call the correct register variant directly.  Fewer ugly #ifdefs
>> this way.  It also eliminates the need to cast the void* pointer.
>>
>
>  drivers/net/phy/mdio-gpio.c |   77
> ++++++++++++++++++++-----------------------
>  1 files changed, 36 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
> index 33984b7..22cdd45 100644
> --- a/drivers/net/phy/mdio-gpio.c
> +++ b/drivers/net/phy/mdio-gpio.c
> @@ -30,6 +30,7 @@
>
>  #ifdef CONFIG_OF_GPIO
>  #include <linux/of_gpio.h>
> +#include <linux/of_mdio.h>
>  #include <linux/of_platform.h>
>  #endif
>
> @@ -81,13 +82,12 @@ static struct mdiobb_ops mdio_gpio_ops = {
>        .get_mdio_data = mdio_get,
>  };
>
> -static int __devinit mdio_gpio_bus_init(struct device *dev,
> +static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,
>                                        struct mdio_gpio_platform_data
> *pdata,
>                                        int bus_id)
>  {
>        struct mii_bus *new_bus;
>        struct mdio_gpio_info *bitbang;
> -       int ret = -ENOMEM;
>        int i;
>
>        bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
> @@ -104,8 +104,6 @@ static int __devinit mdio_gpio_bus_init(struct device
> *dev,
>
>        new_bus->name = "GPIO Bitbanged MDIO",
>
> -       ret = -ENODEV;
> -
>        new_bus->phy_mask = pdata->phy_mask;
>        new_bus->irq = pdata->irqs;
>        new_bus->parent = dev;
> @@ -129,15 +127,8 @@ static int __devinit mdio_gpio_bus_init(struct device
> *dev,
>
>        dev_set_drvdata(dev, new_bus);
>
> -       ret = mdiobus_register(new_bus);
> -       if (ret)
> -               goto out_free_all;
> -
> -       return 0;
> +       return new_bus;
>
> -out_free_all:
> -       dev_set_drvdata(dev, NULL);
> -       gpio_free(bitbang->mdio);
>  out_free_mdc:
>        gpio_free(bitbang->mdc);
>  out_free_bus:
> @@ -145,30 +136,47 @@ out_free_bus:
>  out_free_bitbang:
>        kfree(bitbang);
>  out:
> -       return ret;
> +       return NULL;
>  }
>
> -static void __devexit mdio_gpio_bus_destroy(struct device *dev)
> +static void __devinit mdio_gpio_bus_deinit(struct device *dev)
>  {
>        struct mii_bus *bus = dev_get_drvdata(dev);
>        struct mdio_gpio_info *bitbang = bus->priv;
>
> -       mdiobus_unregister(bus);
> -       free_mdio_bitbang(bus);
>        dev_set_drvdata(dev, NULL);
> -       gpio_free(bitbang->mdc);
>        gpio_free(bitbang->mdio);
> +       gpio_free(bitbang->mdc);
> +       free_mdio_bitbang(bus);
>        kfree(bitbang);
>  }
>
> +static void __devexit mdio_gpio_bus_destroy(struct device *dev)
> +{
> +       struct mii_bus *bus = dev_get_drvdata(dev);
> +
> +       mdiobus_unregister(bus);
> +       mdio_gpio_bus_deinit(dev);
> +}
> +
>  static int __devinit mdio_gpio_probe(struct platform_device *pdev)
>  {
>        struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data;
> +       struct mii_bus *new_bus;
> +       int ret;
>
>        if (!pdata)
>                return -ENODEV;
>
> -       return mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
> +       new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
> +       if (!new_bus)
> +               return -ENODEV;
> +
> +       ret = mdiobus_register(new_bus);
> +       if (ret)
> +               mdio_gpio_bus_deinit(&pdev->dev);
> +
> +       return ret;
>  }
>
>  static int __devexit mdio_gpio_remove(struct platform_device *pdev)
> @@ -179,29 +187,12 @@ static int __devexit mdio_gpio_remove(struct
> platform_device *pdev)
>  }
>
>  #ifdef CONFIG_OF_GPIO
> -static void __devinit add_phy(struct mdio_gpio_platform_data *pdata,
> -                             struct device_node *np)
> -{
> -       const u32 *data;
> -       int len, id, irq;
> -
> -       data = of_get_property(np, "reg", &len);
> -       if (!data || len != 4)
> -               return;
> -
> -       id = *data;
> -       pdata->phy_mask &= ~(1 << id);
> -
> -       irq = of_irq_to_resource(np, 0, NULL);
> -       if (irq)
> -               pdata->irqs[id] = irq;
> -}
>
>  static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
>                                         const struct of_device_id *match)
>  {
> -       struct device_node *np = NULL;
>        struct mdio_gpio_platform_data *pdata;
> +       struct mii_bus *new_bus;
>        int ret;
>
>        pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
> @@ -215,14 +206,18 @@ static int __devinit mdio_ofgpio_probe(struct
> of_device *ofdev,
>
>        ret = of_get_gpio(ofdev->node, 1);
>        if (ret < 0)
> -                goto out_free;
> +               goto out_free;
>        pdata->mdio = ret;
>
> -       while ((np = of_get_next_child(ofdev->node, np)))
> -               if (!strcmp(np->type, "ethernet-phy"))
> -                       add_phy(pdata, np);
> +       new_bus = mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
> +       if (!new_bus)
> +               return -ENODEV;
>
> -       return mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
> +       ret = of_mdiobus_register(new_bus, ofdev->node);
> +       if (ret)
> +               mdio_gpio_bus_deinit(&ofdev->dev);
> +
> +       return ret;
>
>  out_free:
>        kfree(pdata);
> --
> 1.5.6.5
>



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [2.6.30.1] Significant latency playing video file from NFS4 share
From: Frans Pop @ 2009-07-21 17:31 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: linux-nfs-u79uwXL29TY76Z2rM5mHXA, Linux Kernel Mailing List,
	netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <200907180131.12586.elendil-EIBgga6/0yRmR6Xm/wNWPw@public.gmane.org>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 8070 bytes --]

Any suggestions based on the data below?

Is the problem maybe that the amount of data transferred each time is so
big that the network speed becomes a bottleneck and causes the latency?
I can reproduce the issue with both a 10MBit wired link and with a 54MBit
wireless link.

Is this a kernel bug or a configuration issue?

Thanks,
FJP

On Saturday 18 July 2009, Frans Pop wrote:
> Thanks for the quick response!
>
> On Saturday 18 July 2009, Trond Myklebust wrote:
> > Have you tried running nfs-iostat from the nfs-utils package to try
> > and figure out what the latency is on each READ request from the
> > client?
> >
> > You need to run something like
> >
> >     nfs-iostat --page 20 10 /src/<mountpoint>
> >
> > while running the vlc app.

$ ../nfs-iostat.py --page 20 10 /srv/fjp/david

Note:
The mount point selection could be improved. I first had a trailing slash
after the mount point and that resulted in all mounts being included in the
output. Removing the slash helped.

elrond:/david mounted on /srv/fjp/david:

   op/s         rpc bklog
   0.65            0.00
read:             ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.406         101.661         250.613        0 (0.0%)         1211.745        1222.640
write:            ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.000           0.000           0.000        0 (0.0%)           0.000           0.000

13 nfs_readpage() calls read 13 pages
1417 nfs_readpages() calls read 971428 pages (685.6 pages per call)

0 nfs_updatepage() calls
0 nfs_writepage() calls wrote 0 pages
18760 nfs_writepages() calls wrote 0 pages (0.0 pages per call)

elrond:/david mounted on /srv/fjp/david:

   op/s         rpc bklog
   0.25            0.00
read:             ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.100           0.426           4.262        0 (0.0%)           6.000           6.000
write:            ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.000           0.000           0.000        0 (0.0%)           0.000           0.000

0 nfs_readpage() calls read 0 pages
2 nfs_readpages() calls read 2 pages (1.0 pages per call)

0 nfs_updatepage() calls
0 nfs_writepage() calls wrote 0 pages
6 nfs_writepages() calls wrote 0 pages (0.0 pages per call)

elrond:/david mounted on /srv/fjp/david:

   op/s         rpc bklog
   0.80            0.00
read:             ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.750         192.196         256.262        0 (0.0%)         1998.933        1999.200
write:            ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.000           0.000           0.000        0 (0.0%)           0.000           0.000

0 nfs_readpage() calls read 0 pages
1 nfs_readpages() calls read 960 pages (960.0 pages per call)

0 nfs_updatepage() calls
0 nfs_writepage() calls wrote 0 pages
6 nfs_writepages() calls wrote 0 pages (0.0 pages per call)

elrond:/david mounted on /srv/fjp/david:

   op/s         rpc bklog
   0.00            0.00
read:             ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.000           0.000           0.000        0 (0.0%)           0.000           0.000
write:            ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.000           0.000           0.000        0 (0.0%)           0.000           0.000

0 nfs_readpage() calls read 0 pages
0 nfs_readpages() calls read 0 pages

0 nfs_updatepage() calls
0 nfs_writepage() calls wrote 0 pages
6 nfs_writepages() calls wrote 0 pages (0.0 pages per call)

elrond:/david mounted on /srv/fjp/david:

   op/s         rpc bklog
   0.85            0.00
read:             ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.750         192.196         256.262        0 (0.0%)         1927.467        1927.467
write:            ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.000           0.000           0.000        0 (0.0%)           0.000           0.000

0 nfs_readpage() calls read 0 pages
1 nfs_readpages() calls read 960 pages (960.0 pages per call)

0 nfs_updatepage() calls
0 nfs_writepage() calls wrote 0 pages
6 nfs_writepages() calls wrote 0 pages (0.0 pages per call)

elrond:/david mounted on /srv/fjp/david:

   op/s         rpc bklog
   0.00            0.00
read:             ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.000           0.000           0.000        0 (0.0%)           0.000           0.000
write:            ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.000           0.000           0.000        0 (0.0%)           0.000           0.000

0 nfs_readpage() calls read 0 pages
0 nfs_readpages() calls read 0 pages

0 nfs_updatepage() calls
0 nfs_writepage() calls wrote 0 pages
6 nfs_writepages() calls wrote 0 pages (0.0 pages per call)

elrond:/david mounted on /srv/fjp/david:

   op/s         rpc bklog
   0.85            0.00
read:             ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.750         192.196         256.262        0 (0.0%)         1930.933        1931.467
write:            ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.000           0.000           0.000        0 (0.0%)           0.000           0.000

0 nfs_readpage() calls read 0 pages
1 nfs_readpages() calls read 960 pages (960.0 pages per call)

0 nfs_updatepage() calls
0 nfs_writepage() calls wrote 0 pages
5 nfs_writepages() calls wrote 0 pages (0.0 pages per call)

elrond:/david mounted on /srv/fjp/david:

   op/s         rpc bklog
   0.15            0.00
read:             ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.100           0.426           4.262        0 (0.0%)           6.000           6.000
write:            ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
                  0.000           0.000           0.000        0 (0.0%)           0.000           0.000

0 nfs_readpage() calls read 0 pages
2 nfs_readpages() calls read 2 pages (1.0 pages per call)

0 nfs_updatepage() calls
0 nfs_writepage() calls wrote 0 pages
6 nfs_writepages() calls wrote 0 pages (0.0 pages per call)
N‹§²æìr¸›yúèšØb²X¬¶Ç§vØ^–)Þº{.nÇ+‰·¥Š{±û"žØ^n‡r¡ö¦zË\x1aëh™¨è­Ú&¢îý»\x05ËÛÔØï¦v¬Îf\x1dp)¹¹br	šê+€Ê+zf£¢·hšˆ§~†­†Ûiÿûàz¹\x1e®w¥¢¸?™¨è­Ú&¢)ߢ^[f

^ permalink raw reply

* Re: [2.6.30.1] Significant latency playing video file from NFS4 share
From: Trond Myklebust @ 2009-07-21 17:58 UTC (permalink / raw)
  To: Frans Pop
  Cc: linux-nfs-u79uwXL29TY76Z2rM5mHXA, Linux Kernel Mailing List,
	netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <200907211931.50015.elendil-EIBgga6/0yRmR6Xm/wNWPw@public.gmane.org>

On Tue, 2009-07-21 at 19:31 +0200, Frans Pop wrote:
> Any suggestions based on the data below?

Yeah. Sorry for the delay.

> Is the problem maybe that the amount of data transferred each time is so
> big that the network speed becomes a bottleneck and causes the latency?
> I can reproduce the issue with both a 10MBit wired link and with a 54MBit
> wireless link.
> 
> Is this a kernel bug or a configuration issue?

<snip>

> elrond:/david mounted on /srv/fjp/david:
> 
>    op/s         rpc bklog
>    0.80            0.00
> read:             ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
>                   0.750         192.196         256.262        0 (0.0%)         1998.933        1999.200
> write:            ops/s            kB/s           kB/op         retrans         avg RTT (ms)    avg exe (ms)
>                   0.000           0.000           0.000        0 (0.0%)           0.000           0.000

This would be where you are losing your performance. 1998.933 ms rtt
means that you are seeing a 2 second delay from the instant the RPC
client pushes the request into the socket to the moment that socket
receives a reply from the server.

Basically, you have either a _very_ slow server, or (more likely) a
networking problem. A tcpdump ought to be able to show what the problem
is: whether it is the packets getting ACKed very slowly, and/or if you
have dropped packet issues or if it is truly a problem with the server
taking a long time to reply.

Cheers
  Trond

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCHv2 1/2] mcastv6: Local variable shadows function argument
From: Gerrit Renker @ 2009-07-21 18:11 UTC (permalink / raw)
  To: David S. Miller, David L Stevens; +Cc: netdev

Hi David,

can you please apply this small one.
Thanks to David L Stevens for clarification.

Gerrit

>>>>>>>>>>>>>>>>>>> Patch <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
mcastv6: Local variable shadows function argument

The local variable 'idev' shadows the function argument 'idev' to
ip6_mc_add_src(). Fixed by removing the local declaration, as pmc->idev
should be identical with 'idev' passed as argument.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: David L Stevens <dlstevens@us.ibm.com>
---
 net/ipv6/mcast.c |    1 -
 1 file changed, 1 deletion(-)

--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2107,7 +2107,6 @@ static int ip6_mc_add_src(struct inet6_d
 		for (j=0; j<i; j++)
 			(void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
 	} else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
-		struct inet6_dev *idev = pmc->idev;
 		struct ip6_sf_list *psf;
 
 		/* filter mode change */

^ permalink raw reply

* Re: [0/4] trivial cleanups for via-velocity.c
From: David Miller @ 2009-07-21 18:12 UTC (permalink / raw)
  To: davej; +Cc: netdev
In-Reply-To: <200907211640.n6LGeG5d011439@gelk.kernelslacker.org>

From: Dave Jones <davej@redhat.com>
Date: Mon, 20 Jul 2009 23:34:56 -0400

> I've had these sitting around for a while, they should be safe to apply.
> I checked a diff of the disassembly from objdump before/after, and
> the only diffs were the placement of the functions & jump offsets changing
> due to the reordering in diff 3/4.

These do not apply to the driver in the current tree, particularly
it doesn't apply at all to net-next-2.6 which is where I would
add this.

Please fix this up and resubmit, thanks.

^ permalink raw reply

* Re: [PATCHv2 1/2] mcastv6: Local variable shadows function argument
From: David Miller @ 2009-07-21 18:13 UTC (permalink / raw)
  To: gerrit; +Cc: dlstevens, netdev
In-Reply-To: <20090721181153.GA5970@gerrit.erg.abdn.ac.uk>

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Tue, 21 Jul 2009 20:11:53 +0200

> mcastv6: Local variable shadows function argument
> 
> The local variable 'idev' shadows the function argument 'idev' to
> ip6_mc_add_src(). Fixed by removing the local declaration, as pmc->idev
> should be identical with 'idev' passed as argument.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: David L Stevens <dlstevens@us.ibm.com>

Applied to net-next-2.6

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox