aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorAyaz Abdulla <aabdulla@nvidia.com>2008-04-23 14:37:30 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-04-25 02:08:57 -0400
commit9f3f7910c67adfb520bbae3d8b16985439a97198 (patch)
treee9f18409bc92f9342b9602bd8e259f044a3d8f72 /drivers/net
parentcca87c18ce3357e52facf6519f4ab0fbedd1279f (diff)
forcedeth: realtek phy crossover detection
This patch fixes an issue seen with the realtek 8201 phy. This phy has a problem with crossover detection and it needs to be disabled. The problem only arises on certain switches. Therefore, a module parameter has been added to allow enabling crossover detection if needed. The default will be set to disabled. Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/forcedeth.c220
1 files changed, 178 insertions, 42 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 73d85b31fbdc..35f66d4a4595 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -483,16 +483,22 @@ union ring_type {
483#define DESC_VER_3 3 483#define DESC_VER_3 3
484 484
485/* PHY defines */ 485/* PHY defines */
486#define PHY_OUI_MARVELL 0x5043 486#define PHY_OUI_MARVELL 0x5043
487#define PHY_OUI_CICADA 0x03f1 487#define PHY_OUI_CICADA 0x03f1
488#define PHY_OUI_VITESSE 0x01c1 488#define PHY_OUI_VITESSE 0x01c1
489#define PHY_OUI_REALTEK 0x0732 489#define PHY_OUI_REALTEK 0x0732
490#define PHY_OUI_REALTEK2 0x0020
490#define PHYID1_OUI_MASK 0x03ff 491#define PHYID1_OUI_MASK 0x03ff
491#define PHYID1_OUI_SHFT 6 492#define PHYID1_OUI_SHFT 6
492#define PHYID2_OUI_MASK 0xfc00 493#define PHYID2_OUI_MASK 0xfc00
493#define PHYID2_OUI_SHFT 10 494#define PHYID2_OUI_SHFT 10
494#define PHYID2_MODEL_MASK 0x03f0 495#define PHYID2_MODEL_MASK 0x03f0
495#define PHY_MODEL_MARVELL_E3016 0x220 496#define PHY_MODEL_REALTEK_8211 0x0110
497#define PHY_REV_MASK 0x0001
498#define PHY_REV_REALTEK_8211B 0x0000
499#define PHY_REV_REALTEK_8211C 0x0001
500#define PHY_MODEL_REALTEK_8201 0x0200
501#define PHY_MODEL_MARVELL_E3016 0x0220
496#define PHY_MARVELL_E3016_INITMASK 0x0300 502#define PHY_MARVELL_E3016_INITMASK 0x0300
497#define PHY_CICADA_INIT1 0x0f000 503#define PHY_CICADA_INIT1 0x0f000
498#define PHY_CICADA_INIT2 0x0e00 504#define PHY_CICADA_INIT2 0x0e00
@@ -519,10 +525,18 @@ union ring_type {
519#define PHY_REALTEK_INIT_REG1 0x1f 525#define PHY_REALTEK_INIT_REG1 0x1f
520#define PHY_REALTEK_INIT_REG2 0x19 526#define PHY_REALTEK_INIT_REG2 0x19
521#define PHY_REALTEK_INIT_REG3 0x13 527#define PHY_REALTEK_INIT_REG3 0x13
528#define PHY_REALTEK_INIT_REG4 0x14
529#define PHY_REALTEK_INIT_REG5 0x18
530#define PHY_REALTEK_INIT_REG6 0x11
522#define PHY_REALTEK_INIT1 0x0000 531#define PHY_REALTEK_INIT1 0x0000
523#define PHY_REALTEK_INIT2 0x8e00 532#define PHY_REALTEK_INIT2 0x8e00
524#define PHY_REALTEK_INIT3 0x0001 533#define PHY_REALTEK_INIT3 0x0001
525#define PHY_REALTEK_INIT4 0xad17 534#define PHY_REALTEK_INIT4 0xad17
535#define PHY_REALTEK_INIT5 0xfb54
536#define PHY_REALTEK_INIT6 0xf5c7
537#define PHY_REALTEK_INIT7 0x1000
538#define PHY_REALTEK_INIT8 0x0003
539#define PHY_REALTEK_INIT_MSK1 0x0003
526 540
527#define PHY_GIGABIT 0x0100 541#define PHY_GIGABIT 0x0100
528 542
@@ -701,6 +715,7 @@ struct fe_priv {
701 int wolenabled; 715 int wolenabled;
702 unsigned int phy_oui; 716 unsigned int phy_oui;
703 unsigned int phy_model; 717 unsigned int phy_model;
718 unsigned int phy_rev;
704 u16 gigabit; 719 u16 gigabit;
705 int intr_test; 720 int intr_test;
706 int recover_error; 721 int recover_error;
@@ -714,6 +729,7 @@ struct fe_priv {
714 u32 txrxctl_bits; 729 u32 txrxctl_bits;
715 u32 vlanctl_bits; 730 u32 vlanctl_bits;
716 u32 driver_data; 731 u32 driver_data;
732 u32 device_id;
717 u32 register_size; 733 u32 register_size;
718 int rx_csum; 734 int rx_csum;
719 u32 mac_in_use; 735 u32 mac_in_use;
@@ -824,6 +840,16 @@ enum {
824}; 840};
825static int dma_64bit = NV_DMA_64BIT_ENABLED; 841static int dma_64bit = NV_DMA_64BIT_ENABLED;
826 842
843/*
844 * Crossover Detection
845 * Realtek 8201 phy + some OEM boards do not work properly.
846 */
847enum {
848 NV_CROSSOVER_DETECTION_DISABLED,
849 NV_CROSSOVER_DETECTION_ENABLED
850};
851static int phy_cross = NV_CROSSOVER_DETECTION_DISABLED;
852
827static inline struct fe_priv *get_nvpriv(struct net_device *dev) 853static inline struct fe_priv *get_nvpriv(struct net_device *dev)
828{ 854{
829 return netdev_priv(dev); 855 return netdev_priv(dev);
@@ -1088,25 +1114,53 @@ static int phy_init(struct net_device *dev)
1088 } 1114 }
1089 } 1115 }
1090 if (np->phy_oui == PHY_OUI_REALTEK) { 1116 if (np->phy_oui == PHY_OUI_REALTEK) {
1091 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { 1117 if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
1092 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); 1118 np->phy_rev == PHY_REV_REALTEK_8211B) {
1093 return PHY_ERROR; 1119 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
1094 } 1120 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1095 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) { 1121 return PHY_ERROR;
1096 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); 1122 }
1097 return PHY_ERROR; 1123 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
1098 } 1124 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1099 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) { 1125 return PHY_ERROR;
1100 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); 1126 }
1101 return PHY_ERROR; 1127 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
1102 } 1128 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1103 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) { 1129 return PHY_ERROR;
1104 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); 1130 }
1105 return PHY_ERROR; 1131 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
1132 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1133 return PHY_ERROR;
1134 }
1135 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5)) {
1136 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1137 return PHY_ERROR;
1138 }
1139 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6)) {
1140 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1141 return PHY_ERROR;
1142 }
1143 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
1144 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1145 return PHY_ERROR;
1146 }
1106 } 1147 }
1107 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { 1148 if (np->phy_model == PHY_MODEL_REALTEK_8201) {
1108 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); 1149 if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 ||
1109 return PHY_ERROR; 1150 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 ||
1151 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 ||
1152 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 ||
1153 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 ||
1154 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 ||
1155 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 ||
1156 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) {
1157 phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
1158 phy_reserved |= PHY_REALTEK_INIT7;
1159 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) {
1160 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1161 return PHY_ERROR;
1162 }
1163 }
1110 } 1164 }
1111 } 1165 }
1112 1166
@@ -1246,26 +1300,71 @@ static int phy_init(struct net_device *dev)
1246 } 1300 }
1247 } 1301 }
1248 if (np->phy_oui == PHY_OUI_REALTEK) { 1302 if (np->phy_oui == PHY_OUI_REALTEK) {
1249 /* reset could have cleared these out, set them back */ 1303 if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
1250 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { 1304 np->phy_rev == PHY_REV_REALTEK_8211B) {
1251 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); 1305 /* reset could have cleared these out, set them back */
1252 return PHY_ERROR; 1306 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
1253 } 1307 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1254 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) { 1308 return PHY_ERROR;
1255 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); 1309 }
1256 return PHY_ERROR; 1310 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
1257 } 1311 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1258 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) { 1312 return PHY_ERROR;
1259 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); 1313 }
1260 return PHY_ERROR; 1314 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
1261 } 1315 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1262 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) { 1316 return PHY_ERROR;
1263 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); 1317 }
1264 return PHY_ERROR; 1318 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
1319 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1320 return PHY_ERROR;
1321 }
1322 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5)) {
1323 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1324 return PHY_ERROR;
1325 }
1326 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6)) {
1327 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1328 return PHY_ERROR;
1329 }
1330 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
1331 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1332 return PHY_ERROR;
1333 }
1265 } 1334 }
1266 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { 1335 if (np->phy_model == PHY_MODEL_REALTEK_8201) {
1267 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); 1336 if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 ||
1268 return PHY_ERROR; 1337 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 ||
1338 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 ||
1339 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 ||
1340 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 ||
1341 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 ||
1342 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 ||
1343 np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) {
1344 phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
1345 phy_reserved |= PHY_REALTEK_INIT7;
1346 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) {
1347 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1348 return PHY_ERROR;
1349 }
1350 }
1351 if (phy_cross == NV_CROSSOVER_DETECTION_DISABLED) {
1352 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
1353 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1354 return PHY_ERROR;
1355 }
1356 phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, MII_READ);
1357 phy_reserved &= ~PHY_REALTEK_INIT_MSK1;
1358 phy_reserved |= PHY_REALTEK_INIT3;
1359 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, phy_reserved)) {
1360 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1361 return PHY_ERROR;
1362 }
1363 if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
1364 printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
1365 return PHY_ERROR;
1366 }
1367 }
1269 } 1368 }
1270 } 1369 }
1271 1370
@@ -5254,6 +5353,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
5254 5353
5255 /* copy of driver data */ 5354 /* copy of driver data */
5256 np->driver_data = id->driver_data; 5355 np->driver_data = id->driver_data;
5356 /* copy of device id */
5357 np->device_id = id->device;
5257 5358
5258 /* handle different descriptor versions */ 5359 /* handle different descriptor versions */
5259 if (id->driver_data & DEV_HAS_HIGH_DMA) { 5360 if (id->driver_data & DEV_HAS_HIGH_DMA) {
@@ -5543,6 +5644,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
5543 pci_name(pci_dev), id1, id2, phyaddr); 5644 pci_name(pci_dev), id1, id2, phyaddr);
5544 np->phyaddr = phyaddr; 5645 np->phyaddr = phyaddr;
5545 np->phy_oui = id1 | id2; 5646 np->phy_oui = id1 | id2;
5647
5648 /* Realtek hardcoded phy id1 to all zero's on certain phys */
5649 if (np->phy_oui == PHY_OUI_REALTEK2)
5650 np->phy_oui = PHY_OUI_REALTEK;
5651 /* Setup phy revision for Realtek */
5652 if (np->phy_oui == PHY_OUI_REALTEK && np->phy_model == PHY_MODEL_REALTEK_8211)
5653 np->phy_rev = mii_rw(dev, phyaddr, MII_RESV1, MII_READ) & PHY_REV_MASK;
5654
5546 break; 5655 break;
5547 } 5656 }
5548 if (i == 33) { 5657 if (i == 33) {
@@ -5621,6 +5730,28 @@ out:
5621 return err; 5730 return err;
5622} 5731}
5623 5732
5733static void nv_restore_phy(struct net_device *dev)
5734{
5735 struct fe_priv *np = netdev_priv(dev);
5736 u16 phy_reserved, mii_control;
5737
5738 if (np->phy_oui == PHY_OUI_REALTEK &&
5739 np->phy_model == PHY_MODEL_REALTEK_8201 &&
5740 phy_cross == NV_CROSSOVER_DETECTION_DISABLED) {
5741 mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3);
5742 phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, MII_READ);
5743 phy_reserved &= ~PHY_REALTEK_INIT_MSK1;
5744 phy_reserved |= PHY_REALTEK_INIT8;
5745 mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, phy_reserved);
5746 mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1);
5747
5748 /* restart auto negotiation */
5749 mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
5750 mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE);
5751 mii_rw(dev, np->phyaddr, MII_BMCR, mii_control);
5752 }
5753}
5754
5624static void __devexit nv_remove(struct pci_dev *pci_dev) 5755static void __devexit nv_remove(struct pci_dev *pci_dev)
5625{ 5756{
5626 struct net_device *dev = pci_get_drvdata(pci_dev); 5757 struct net_device *dev = pci_get_drvdata(pci_dev);
@@ -5637,6 +5768,9 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
5637 writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV, 5768 writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV,
5638 base + NvRegTransmitPoll); 5769 base + NvRegTransmitPoll);
5639 5770
5771 /* restore any phy related changes */
5772 nv_restore_phy(dev);
5773
5640 /* free all structures */ 5774 /* free all structures */
5641 free_rings(dev); 5775 free_rings(dev);
5642 iounmap(get_hwbase(dev)); 5776 iounmap(get_hwbase(dev));
@@ -5888,6 +6022,8 @@ module_param(msix, int, 0);
5888MODULE_PARM_DESC(msix, "MSIX interrupts are enabled by setting to 1 and disabled by setting to 0."); 6022MODULE_PARM_DESC(msix, "MSIX interrupts are enabled by setting to 1 and disabled by setting to 0.");
5889module_param(dma_64bit, int, 0); 6023module_param(dma_64bit, int, 0);
5890MODULE_PARM_DESC(dma_64bit, "High DMA is enabled by setting to 1 and disabled by setting to 0."); 6024MODULE_PARM_DESC(dma_64bit, "High DMA is enabled by setting to 1 and disabled by setting to 0.");
6025module_param(phy_cross, int, 0);
6026MODULE_PARM_DESC(phy_cross, "Phy crossover detection for Realtek 8201 phy is enabled by setting to 1 and disabled by setting to 0.");
5891 6027
5892MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>"); 6028MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
5893MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); 6029MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");