aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAyaz Abdulla <aabdulla@nvidia.com>2008-07-25 15:31:29 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-07-29 17:48:22 -0400
commit22ae03a190011fa2241e68a6c51369d78039348e (patch)
treeb1224c29bdf78d27c69cd1a0a52d54ca9ea6cff1 /drivers
parent281c7413ed914623d3245299a4761b6b27ab9fdb (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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/forcedeth.c64
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 */