diff options
author | Ayaz Abdulla <aabdulla@nvidia.com> | 2008-07-25 15:31:29 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-07-29 17:48:22 -0400 |
commit | 22ae03a190011fa2241e68a6c51369d78039348e (patch) | |
tree | b1224c29bdf78d27c69cd1a0a52d54ca9ea6cff1 | |
parent | 281c7413ed914623d3245299a4761b6b27ab9fdb (diff) |
forcedeth bug fix: realtek phy 8211c errata
This patch adds support for the realtek 8211c phy. The driver must
perform a hardware reset of the phy due to an errata where the phy could
not detect the link.
Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r-- | drivers/net/forcedeth.c | 64 |
1 files changed, 58 insertions, 6 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 4ed89fa9ae46..01b38b092c76 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -333,6 +333,7 @@ enum { | |||
333 | NvRegPowerState2 = 0x600, | 333 | NvRegPowerState2 = 0x600, |
334 | #define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11 | 334 | #define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11 |
335 | #define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001 | 335 | #define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001 |
336 | #define NVREG_POWERSTATE2_PHY_RESET 0x0004 | ||
336 | }; | 337 | }; |
337 | 338 | ||
338 | /* Big endian: should work, but is untested */ | 339 | /* Big endian: should work, but is untested */ |
@@ -529,6 +530,7 @@ union ring_type { | |||
529 | #define PHY_REALTEK_INIT_REG4 0x14 | 530 | #define PHY_REALTEK_INIT_REG4 0x14 |
530 | #define PHY_REALTEK_INIT_REG5 0x18 | 531 | #define PHY_REALTEK_INIT_REG5 0x18 |
531 | #define PHY_REALTEK_INIT_REG6 0x11 | 532 | #define PHY_REALTEK_INIT_REG6 0x11 |
533 | #define PHY_REALTEK_INIT_REG7 0x01 | ||
532 | #define PHY_REALTEK_INIT1 0x0000 | 534 | #define PHY_REALTEK_INIT1 0x0000 |
533 | #define PHY_REALTEK_INIT2 0x8e00 | 535 | #define PHY_REALTEK_INIT2 0x8e00 |
534 | #define PHY_REALTEK_INIT3 0x0001 | 536 | #define PHY_REALTEK_INIT3 0x0001 |
@@ -537,6 +539,9 @@ union ring_type { | |||
537 | #define PHY_REALTEK_INIT6 0xf5c7 | 539 | #define PHY_REALTEK_INIT6 0xf5c7 |
538 | #define PHY_REALTEK_INIT7 0x1000 | 540 | #define PHY_REALTEK_INIT7 0x1000 |
539 | #define PHY_REALTEK_INIT8 0x0003 | 541 | #define PHY_REALTEK_INIT8 0x0003 |
542 | #define PHY_REALTEK_INIT9 0x0008 | ||
543 | #define PHY_REALTEK_INIT10 0x0005 | ||
544 | #define PHY_REALTEK_INIT11 0x0200 | ||
540 | #define PHY_REALTEK_INIT_MSK1 0x0003 | 545 | #define PHY_REALTEK_INIT_MSK1 0x0003 |
541 | 546 | ||
542 | #define PHY_GIGABIT 0x0100 | 547 | #define PHY_GIGABIT 0x0100 |
@@ -1149,6 +1154,42 @@ static int phy_init(struct net_device *dev) | |||
1149 | return PHY_ERROR; | 1154 | return PHY_ERROR; |
1150 | } | 1155 | } |
1151 | } | 1156 | } |
1157 | if (np->phy_model == PHY_MODEL_REALTEK_8211 && | ||
1158 | np->phy_rev == PHY_REV_REALTEK_8211C) { | ||
1159 | u32 powerstate = readl(base + NvRegPowerState2); | ||
1160 | |||
1161 | /* need to perform hw phy reset */ | ||
1162 | powerstate |= NVREG_POWERSTATE2_PHY_RESET; | ||
1163 | writel(powerstate, base + NvRegPowerState2); | ||
1164 | msleep(25); | ||
1165 | |||
1166 | powerstate &= ~NVREG_POWERSTATE2_PHY_RESET; | ||
1167 | writel(powerstate, base + NvRegPowerState2); | ||
1168 | msleep(25); | ||
1169 | |||
1170 | reg = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ); | ||
1171 | reg |= PHY_REALTEK_INIT9; | ||
1172 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, reg)) { | ||
1173 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1174 | return PHY_ERROR; | ||
1175 | } | ||
1176 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT10)) { | ||
1177 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1178 | return PHY_ERROR; | ||
1179 | } | ||
1180 | reg = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG7, MII_READ); | ||
1181 | if (!(reg & PHY_REALTEK_INIT11)) { | ||
1182 | reg |= PHY_REALTEK_INIT11; | ||
1183 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG7, reg)) { | ||
1184 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1185 | return PHY_ERROR; | ||
1186 | } | ||
1187 | } | ||
1188 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { | ||
1189 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1190 | return PHY_ERROR; | ||
1191 | } | ||
1192 | } | ||
1152 | if (np->phy_model == PHY_MODEL_REALTEK_8201) { | 1193 | if (np->phy_model == PHY_MODEL_REALTEK_8201) { |
1153 | if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || | 1194 | if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || |
1154 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || | 1195 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || |
@@ -1201,12 +1242,23 @@ static int phy_init(struct net_device *dev) | |||
1201 | mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | 1242 | mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); |
1202 | mii_control |= BMCR_ANENABLE; | 1243 | mii_control |= BMCR_ANENABLE; |
1203 | 1244 | ||
1204 | /* reset the phy | 1245 | if (np->phy_oui == PHY_OUI_REALTEK && |
1205 | * (certain phys need bmcr to be setup with reset) | 1246 | np->phy_model == PHY_MODEL_REALTEK_8211 && |
1206 | */ | 1247 | np->phy_rev == PHY_REV_REALTEK_8211C) { |
1207 | if (phy_reset(dev, mii_control)) { | 1248 | /* start autoneg since we already performed hw reset above */ |
1208 | printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev)); | 1249 | mii_control |= BMCR_ANRESTART; |
1209 | return PHY_ERROR; | 1250 | if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) { |
1251 | printk(KERN_INFO "%s: phy init failed\n", pci_name(np->pci_dev)); | ||
1252 | return PHY_ERROR; | ||
1253 | } | ||
1254 | } else { | ||
1255 | /* reset the phy | ||
1256 | * (certain phys need bmcr to be setup with reset) | ||
1257 | */ | ||
1258 | if (phy_reset(dev, mii_control)) { | ||
1259 | printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev)); | ||
1260 | return PHY_ERROR; | ||
1261 | } | ||
1210 | } | 1262 | } |
1211 | 1263 | ||
1212 | /* phy vendor specific configuration */ | 1264 | /* phy vendor specific configuration */ |