Skip to content

Commit

Permalink
[PATCH] forcedeth: errata for marvell phys
Browse files Browse the repository at this point in the history
This patch addresses an errata found on certain marvell phys concerning
the reset of the BMCR phy register during phy reset.

Signed-Off-By: Ayaz Abdulla <aabdulla@nvidia.com>

Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Ayaz Abdulla authored and Jeff Garzik committed Sep 6, 2006
1 parent 3784fd7 commit edf7e5e
Showing 1 changed file with 56 additions and 17 deletions.
73 changes: 56 additions & 17 deletions drivers/net/forcedeth.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,9 @@ union ring_type {
#define PHYID1_OUI_SHFT 6
#define PHYID2_OUI_MASK 0xfc00
#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_INIT2 0x0e00
#define PHY_INIT3 0x01000
Expand Down Expand Up @@ -701,6 +704,7 @@ struct fe_priv {
int phyaddr;
int wolenabled;
unsigned int phy_oui;
unsigned int phy_model;
u16 gigabit;
int intr_test;

Expand Down Expand Up @@ -1027,14 +1031,13 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
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);
u32 miicontrol;
unsigned int tries = 0;

miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
miicontrol |= BMCR_RESET;
miicontrol = BMCR_RESET | bmcr_setup;
if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) {
return -1;
}
Expand All @@ -1059,6 +1062,16 @@ static int phy_init(struct net_device *dev)
u8 __iomem *base = get_hwbase(dev);
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 */
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);
Expand Down Expand Up @@ -1089,8 +1102,13 @@ static int phy_init(struct net_device *dev)
else
np->gigabit = 0;

/* reset the phy */
if (phy_reset(dev)) {
mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
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));
return PHY_ERROR;
}
Expand Down Expand Up @@ -3158,9 +3176,18 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (netif_running(dev))
printk(KERN_INFO "%s: link down.\n", dev->name);
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);

if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
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 {
int adv, bmcr;

Expand Down Expand Up @@ -3200,17 +3227,19 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
bmcr |= BMCR_FULLDPLX;
if (np->fixed_mode & (ADVERTISE_100HALF|ADVERTISE_100FULL))
bmcr |= BMCR_SPEED100;
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
if (np->phy_oui == PHY_OUI_MARVELL) {
/* reset the phy */
if (phy_reset(dev)) {
/* reset the phy in order for forced mode settings to stick */
if (phy_reset(dev, bmcr)) {
printk(KERN_INFO "%s: phy reset failed\n", dev->name);
return -EINVAL;
}
} else if (netif_running(dev)) {
/* Wait a bit and then reconfigure the nic. */
udelay(10);
nv_linkchange(dev);
} else {
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
if (netif_running(dev)) {
/* Wait a bit and then reconfigure the nic. */
udelay(10);
nv_linkchange(dev);
}
}
}

Expand Down Expand Up @@ -3267,8 +3296,17 @@ static int nv_nway_reset(struct net_device *dev)
}

bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
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)) {
nv_start_rx(dev);
Expand Down Expand Up @@ -4488,6 +4526,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (id2 < 0 || id2 == 0xffff)
continue;

np->phy_model = id2 & PHYID2_MODEL_MASK;
id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT;
id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT;
dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n",
Expand Down

0 comments on commit edf7e5e

Please sign in to comment.