diff options
author | Ayaz Abdulla <aabdulla@nvidia.com> | 2006-08-24 15:43:42 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-09-06 10:57:37 -0400 |
commit | edf7e5ec99c2e24cea3951f7961958fc7edbfdd1 (patch) | |
tree | 1862fb28066e7f8728f7bc325349e1efc5885ab6 | |
parent | 3784fd7316d336f2ba79b6c7c8168d08eff8a714 (diff) |
[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: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/net/forcedeth.c | 73 |
1 files changed, 56 insertions, 17 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 8c8f7cf0e952..74ed8bb266ec 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -543,6 +543,9 @@ union ring_type { | |||
543 | #define PHYID1_OUI_SHFT 6 | 543 | #define PHYID1_OUI_SHFT 6 |
544 | #define PHYID2_OUI_MASK 0xfc00 | 544 | #define PHYID2_OUI_MASK 0xfc00 |
545 | #define PHYID2_OUI_SHFT 10 | 545 | #define PHYID2_OUI_SHFT 10 |
546 | #define PHYID2_MODEL_MASK 0x03f0 | ||
547 | #define PHY_MODEL_MARVELL_E3016 0x220 | ||
548 | #define PHY_MARVELL_E3016_INITMASK 0x0300 | ||
546 | #define PHY_INIT1 0x0f000 | 549 | #define PHY_INIT1 0x0f000 |
547 | #define PHY_INIT2 0x0e00 | 550 | #define PHY_INIT2 0x0e00 |
548 | #define PHY_INIT3 0x01000 | 551 | #define PHY_INIT3 0x01000 |
@@ -701,6 +704,7 @@ struct fe_priv { | |||
701 | int phyaddr; | 704 | int phyaddr; |
702 | int wolenabled; | 705 | int wolenabled; |
703 | unsigned int phy_oui; | 706 | unsigned int phy_oui; |
707 | unsigned int phy_model; | ||
704 | u16 gigabit; | 708 | u16 gigabit; |
705 | int intr_test; | 709 | int intr_test; |
706 | 710 | ||
@@ -1027,14 +1031,13 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value) | |||
1027 | return retval; | 1031 | return retval; |
1028 | } | 1032 | } |
1029 | 1033 | ||
1030 | static int phy_reset(struct net_device *dev) | 1034 | static int phy_reset(struct net_device *dev, u32 bmcr_setup) |
1031 | { | 1035 | { |
1032 | struct fe_priv *np = netdev_priv(dev); | 1036 | struct fe_priv *np = netdev_priv(dev); |
1033 | u32 miicontrol; | 1037 | u32 miicontrol; |
1034 | unsigned int tries = 0; | 1038 | unsigned int tries = 0; |
1035 | 1039 | ||
1036 | miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | 1040 | miicontrol = BMCR_RESET | bmcr_setup; |
1037 | miicontrol |= BMCR_RESET; | ||
1038 | if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) { | 1041 | if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) { |
1039 | return -1; | 1042 | return -1; |
1040 | } | 1043 | } |
@@ -1059,6 +1062,16 @@ static int phy_init(struct net_device *dev) | |||
1059 | u8 __iomem *base = get_hwbase(dev); | 1062 | u8 __iomem *base = get_hwbase(dev); |
1060 | u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg; | 1063 | u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg; |
1061 | 1064 | ||
1065 | /* phy errata for E3016 phy */ | ||
1066 | if (np->phy_model == PHY_MODEL_MARVELL_E3016) { | ||
1067 | reg = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ); | ||
1068 | reg &= ~PHY_MARVELL_E3016_INITMASK; | ||
1069 | if (mii_rw(dev, np->phyaddr, MII_NCONFIG, reg)) { | ||
1070 | printk(KERN_INFO "%s: phy write to errata reg failed.\n", pci_name(np->pci_dev)); | ||
1071 | return PHY_ERROR; | ||
1072 | } | ||
1073 | } | ||
1074 | |||
1062 | /* set advertise register */ | 1075 | /* set advertise register */ |
1063 | reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); | 1076 | reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); |
1064 | reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|ADVERTISE_PAUSE_ASYM|ADVERTISE_PAUSE_CAP); | 1077 | 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 | else | 1102 | else |
1090 | np->gigabit = 0; | 1103 | np->gigabit = 0; |
1091 | 1104 | ||
1092 | /* reset the phy */ | 1105 | mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); |
1093 | if (phy_reset(dev)) { | 1106 | mii_control |= BMCR_ANENABLE; |
1107 | |||
1108 | /* reset the phy | ||
1109 | * (certain phys need bmcr to be setup with reset) | ||
1110 | */ | ||
1111 | if (phy_reset(dev, mii_control)) { | ||
1094 | printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev)); | 1112 | printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev)); |
1095 | return PHY_ERROR; | 1113 | return PHY_ERROR; |
1096 | } | 1114 | } |
@@ -3158,9 +3176,18 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
3158 | if (netif_running(dev)) | 3176 | if (netif_running(dev)) |
3159 | printk(KERN_INFO "%s: link down.\n", dev->name); | 3177 | printk(KERN_INFO "%s: link down.\n", dev->name); |
3160 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | 3178 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); |
3161 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); | 3179 | if (np->phy_model == PHY_MODEL_MARVELL_E3016) { |
3162 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); | 3180 | bmcr |= BMCR_ANENABLE; |
3163 | 3181 | /* reset the phy in order for settings to stick, | |
3182 | * and cause autoneg to start */ | ||
3183 | if (phy_reset(dev, bmcr)) { | ||
3184 | printk(KERN_INFO "%s: phy reset failed\n", dev->name); | ||
3185 | return -EINVAL; | ||
3186 | } | ||
3187 | } else { | ||
3188 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); | ||
3189 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); | ||
3190 | } | ||
3164 | } else { | 3191 | } else { |
3165 | int adv, bmcr; | 3192 | int adv, bmcr; |
3166 | 3193 | ||
@@ -3200,17 +3227,19 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
3200 | bmcr |= BMCR_FULLDPLX; | 3227 | bmcr |= BMCR_FULLDPLX; |
3201 | if (np->fixed_mode & (ADVERTISE_100HALF|ADVERTISE_100FULL)) | 3228 | if (np->fixed_mode & (ADVERTISE_100HALF|ADVERTISE_100FULL)) |
3202 | bmcr |= BMCR_SPEED100; | 3229 | bmcr |= BMCR_SPEED100; |
3203 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); | ||
3204 | if (np->phy_oui == PHY_OUI_MARVELL) { | 3230 | if (np->phy_oui == PHY_OUI_MARVELL) { |
3205 | /* reset the phy */ | 3231 | /* reset the phy in order for forced mode settings to stick */ |
3206 | if (phy_reset(dev)) { | 3232 | if (phy_reset(dev, bmcr)) { |
3207 | printk(KERN_INFO "%s: phy reset failed\n", dev->name); | 3233 | printk(KERN_INFO "%s: phy reset failed\n", dev->name); |
3208 | return -EINVAL; | 3234 | return -EINVAL; |
3209 | } | 3235 | } |
3210 | } else if (netif_running(dev)) { | 3236 | } else { |
3211 | /* Wait a bit and then reconfigure the nic. */ | 3237 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); |
3212 | udelay(10); | 3238 | if (netif_running(dev)) { |
3213 | nv_linkchange(dev); | 3239 | /* Wait a bit and then reconfigure the nic. */ |
3240 | udelay(10); | ||
3241 | nv_linkchange(dev); | ||
3242 | } | ||
3214 | } | 3243 | } |
3215 | } | 3244 | } |
3216 | 3245 | ||
@@ -3267,8 +3296,17 @@ static int nv_nway_reset(struct net_device *dev) | |||
3267 | } | 3296 | } |
3268 | 3297 | ||
3269 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | 3298 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); |
3270 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); | 3299 | if (np->phy_model == PHY_MODEL_MARVELL_E3016) { |
3271 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); | 3300 | bmcr |= BMCR_ANENABLE; |
3301 | /* reset the phy in order for settings to stick*/ | ||
3302 | if (phy_reset(dev, bmcr)) { | ||
3303 | printk(KERN_INFO "%s: phy reset failed\n", dev->name); | ||
3304 | return -EINVAL; | ||
3305 | } | ||
3306 | } else { | ||
3307 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); | ||
3308 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); | ||
3309 | } | ||
3272 | 3310 | ||
3273 | if (netif_running(dev)) { | 3311 | if (netif_running(dev)) { |
3274 | nv_start_rx(dev); | 3312 | nv_start_rx(dev); |
@@ -4488,6 +4526,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
4488 | if (id2 < 0 || id2 == 0xffff) | 4526 | if (id2 < 0 || id2 == 0xffff) |
4489 | continue; | 4527 | continue; |
4490 | 4528 | ||
4529 | np->phy_model = id2 & PHYID2_MODEL_MASK; | ||
4491 | id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT; | 4530 | id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT; |
4492 | id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT; | 4531 | id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT; |
4493 | dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n", | 4532 | dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n", |