Commit edf7e5ec authored by Ayaz Abdulla's avatar Ayaz Abdulla Committed by Jeff Garzik

[PATCH] forcedeth: errata for marvell phys

This patch addresses an errata found on certain marvell phys concerning
the reset of the BMCR phy register during phy reset.
Signed-Off-By: default avatarAyaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 3784fd73
...@@ -543,6 +543,9 @@ union ring_type { ...@@ -543,6 +543,9 @@ union ring_type {
#define PHYID1_OUI_SHFT 6 #define PHYID1_OUI_SHFT 6
#define PHYID2_OUI_MASK 0xfc00 #define PHYID2_OUI_MASK 0xfc00
#define PHYID2_OUI_SHFT 10 #define PHYID2_OUI_SHFT 10
#define PHYID2_MODEL_MASK 0x03f0
#define PHY_MODEL_MARVELL_E3016 0x220
#define PHY_MARVELL_E3016_INITMASK 0x0300
#define PHY_INIT1 0x0f000 #define PHY_INIT1 0x0f000
#define PHY_INIT2 0x0e00 #define PHY_INIT2 0x0e00
#define PHY_INIT3 0x01000 #define PHY_INIT3 0x01000
...@@ -701,6 +704,7 @@ struct fe_priv { ...@@ -701,6 +704,7 @@ struct fe_priv {
int phyaddr; int phyaddr;
int wolenabled; int wolenabled;
unsigned int phy_oui; unsigned int phy_oui;
unsigned int phy_model;
u16 gigabit; u16 gigabit;
int intr_test; int intr_test;
...@@ -1027,14 +1031,13 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value) ...@@ -1027,14 +1031,13 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
return retval; return retval;
} }
static int phy_reset(struct net_device *dev) static int phy_reset(struct net_device *dev, u32 bmcr_setup)
{ {
struct fe_priv *np = netdev_priv(dev); struct fe_priv *np = netdev_priv(dev);
u32 miicontrol; u32 miicontrol;
unsigned int tries = 0; unsigned int tries = 0;
miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); miicontrol = BMCR_RESET | bmcr_setup;
miicontrol |= BMCR_RESET;
if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) { if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) {
return -1; return -1;
} }
...@@ -1059,6 +1062,16 @@ static int phy_init(struct net_device *dev) ...@@ -1059,6 +1062,16 @@ static int phy_init(struct net_device *dev)
u8 __iomem *base = get_hwbase(dev); u8 __iomem *base = get_hwbase(dev);
u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg; u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg;
/* phy errata for E3016 phy */
if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
reg = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
reg &= ~PHY_MARVELL_E3016_INITMASK;
if (mii_rw(dev, np->phyaddr, MII_NCONFIG, reg)) {
printk(KERN_INFO "%s: phy write to errata reg failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
}
/* set advertise register */ /* set advertise register */
reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|ADVERTISE_PAUSE_ASYM|ADVERTISE_PAUSE_CAP); reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|ADVERTISE_PAUSE_ASYM|ADVERTISE_PAUSE_CAP);
...@@ -1089,8 +1102,13 @@ static int phy_init(struct net_device *dev) ...@@ -1089,8 +1102,13 @@ static int phy_init(struct net_device *dev)
else else
np->gigabit = 0; np->gigabit = 0;
/* reset the phy */ mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
if (phy_reset(dev)) { mii_control |= BMCR_ANENABLE;
/* reset the phy
* (certain phys need bmcr to be setup with reset)
*/
if (phy_reset(dev, mii_control)) {
printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev)); printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev));
return PHY_ERROR; return PHY_ERROR;
} }
...@@ -3158,9 +3176,18 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ...@@ -3158,9 +3176,18 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (netif_running(dev)) if (netif_running(dev))
printk(KERN_INFO "%s: link down.\n", dev->name); printk(KERN_INFO "%s: link down.\n", dev->name);
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); bmcr |= BMCR_ANENABLE;
/* reset the phy in order for settings to stick,
* and cause autoneg to start */
if (phy_reset(dev, bmcr)) {
printk(KERN_INFO "%s: phy reset failed\n", dev->name);
return -EINVAL;
}
} else {
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
}
} else { } else {
int adv, bmcr; int adv, bmcr;
...@@ -3200,17 +3227,19 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ...@@ -3200,17 +3227,19 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
bmcr |= BMCR_FULLDPLX; bmcr |= BMCR_FULLDPLX;
if (np->fixed_mode & (ADVERTISE_100HALF|ADVERTISE_100FULL)) if (np->fixed_mode & (ADVERTISE_100HALF|ADVERTISE_100FULL))
bmcr |= BMCR_SPEED100; bmcr |= BMCR_SPEED100;
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
if (np->phy_oui == PHY_OUI_MARVELL) { if (np->phy_oui == PHY_OUI_MARVELL) {
/* reset the phy */ /* reset the phy in order for forced mode settings to stick */
if (phy_reset(dev)) { if (phy_reset(dev, bmcr)) {
printk(KERN_INFO "%s: phy reset failed\n", dev->name); printk(KERN_INFO "%s: phy reset failed\n", dev->name);
return -EINVAL; return -EINVAL;
} }
} else if (netif_running(dev)) { } else {
/* Wait a bit and then reconfigure the nic. */ mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
udelay(10); if (netif_running(dev)) {
nv_linkchange(dev); /* Wait a bit and then reconfigure the nic. */
udelay(10);
nv_linkchange(dev);
}
} }
} }
...@@ -3267,8 +3296,17 @@ static int nv_nway_reset(struct net_device *dev) ...@@ -3267,8 +3296,17 @@ static int nv_nway_reset(struct net_device *dev)
} }
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); bmcr |= BMCR_ANENABLE;
/* reset the phy in order for settings to stick*/
if (phy_reset(dev, bmcr)) {
printk(KERN_INFO "%s: phy reset failed\n", dev->name);
return -EINVAL;
}
} else {
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
}
if (netif_running(dev)) { if (netif_running(dev)) {
nv_start_rx(dev); nv_start_rx(dev);
...@@ -4488,6 +4526,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i ...@@ -4488,6 +4526,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (id2 < 0 || id2 == 0xffff) if (id2 < 0 || id2 == 0xffff)
continue; continue;
np->phy_model = id2 & PHYID2_MODEL_MASK;
id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT; id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT;
id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT; id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT;
dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n", dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment