diff options
Diffstat (limited to 'drivers/net/sis190.c')
-rw-r--r-- | drivers/net/sis190.c | 131 |
1 files changed, 86 insertions, 45 deletions
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index bf3440aa6c24..92f75529eff8 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c | |||
@@ -179,14 +179,6 @@ enum sis190_register_content { | |||
179 | TxInterFrameGapShift = 24, | 179 | TxInterFrameGapShift = 24, |
180 | TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ | 180 | TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ |
181 | 181 | ||
182 | /* StationControl */ | ||
183 | _1000bpsF = 0x1c00, | ||
184 | _1000bpsH = 0x0c00, | ||
185 | _100bpsF = 0x1800, | ||
186 | _100bpsH = 0x0800, | ||
187 | _10bpsF = 0x1400, | ||
188 | _10bpsH = 0x0400, | ||
189 | |||
190 | LinkStatus = 0x02, // unused | 182 | LinkStatus = 0x02, // unused |
191 | FullDup = 0x01, // unused | 183 | FullDup = 0x01, // unused |
192 | 184 | ||
@@ -279,6 +271,12 @@ enum sis190_eeprom_address { | |||
279 | EEPROMMACAddr = 0x03 | 271 | EEPROMMACAddr = 0x03 |
280 | }; | 272 | }; |
281 | 273 | ||
274 | enum sis190_feature { | ||
275 | F_HAS_RGMII = 1, | ||
276 | F_PHY_88E1111 = 2, | ||
277 | F_PHY_BCM5461 = 4 | ||
278 | }; | ||
279 | |||
282 | struct sis190_private { | 280 | struct sis190_private { |
283 | void __iomem *mmio_addr; | 281 | void __iomem *mmio_addr; |
284 | struct pci_dev *pci_dev; | 282 | struct pci_dev *pci_dev; |
@@ -300,6 +298,7 @@ struct sis190_private { | |||
300 | u32 msg_enable; | 298 | u32 msg_enable; |
301 | struct mii_if_info mii_if; | 299 | struct mii_if_info mii_if; |
302 | struct list_head first_phy; | 300 | struct list_head first_phy; |
301 | u32 features; | ||
303 | }; | 302 | }; |
304 | 303 | ||
305 | struct sis190_phy { | 304 | struct sis190_phy { |
@@ -321,24 +320,25 @@ static struct mii_chip_info { | |||
321 | const char *name; | 320 | const char *name; |
322 | u16 id[2]; | 321 | u16 id[2]; |
323 | unsigned int type; | 322 | unsigned int type; |
323 | u32 feature; | ||
324 | } mii_chip_table[] = { | 324 | } mii_chip_table[] = { |
325 | { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN }, | 325 | { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 }, |
326 | { "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN }, | 326 | { "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN, 0 }, |
327 | { "Marvell PHY 88E1111", { 0x0141, 0x0cc0 }, LAN }, | 327 | { "Marvell PHY 88E1111", { 0x0141, 0x0cc0 }, LAN, F_PHY_88E1111 }, |
328 | { "Realtek PHY RTL8201", { 0x0000, 0x8200 }, LAN }, | 328 | { "Realtek PHY RTL8201", { 0x0000, 0x8200 }, LAN, 0 }, |
329 | { NULL, } | 329 | { NULL, } |
330 | }; | 330 | }; |
331 | 331 | ||
332 | const static struct { | 332 | const static struct { |
333 | const char *name; | 333 | const char *name; |
334 | u8 version; /* depend on docs */ | ||
335 | u32 RxConfigMask; /* clear the bits supported by this chip */ | ||
336 | } sis_chip_info[] = { | 334 | } sis_chip_info[] = { |
337 | { DRV_NAME, 0x00, 0xff7e1880, }, | 335 | { "SiS 190 PCI Fast Ethernet adapter" }, |
336 | { "SiS 191 PCI Gigabit Ethernet adapter" }, | ||
338 | }; | 337 | }; |
339 | 338 | ||
340 | static struct pci_device_id sis190_pci_tbl[] __devinitdata = { | 339 | static struct pci_device_id sis190_pci_tbl[] __devinitdata = { |
341 | { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 }, | 340 | { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 }, |
341 | { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 }, | ||
342 | { 0, }, | 342 | { 0, }, |
343 | }; | 343 | }; |
344 | 344 | ||
@@ -360,7 +360,7 @@ MODULE_VERSION(DRV_VERSION); | |||
360 | MODULE_LICENSE("GPL"); | 360 | MODULE_LICENSE("GPL"); |
361 | 361 | ||
362 | static const u32 sis190_intr_mask = | 362 | static const u32 sis190_intr_mask = |
363 | RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt; | 363 | RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt | LinkChange; |
364 | 364 | ||
365 | /* | 365 | /* |
366 | * Maximum number of multicast addresses to filter (vs. Rx-all-multicast). | 366 | * Maximum number of multicast addresses to filter (vs. Rx-all-multicast). |
@@ -879,11 +879,6 @@ static void sis190_hw_start(struct net_device *dev) | |||
879 | 879 | ||
880 | SIS_W32(IntrStatus, 0xffffffff); | 880 | SIS_W32(IntrStatus, 0xffffffff); |
881 | SIS_W32(IntrMask, 0x0); | 881 | SIS_W32(IntrMask, 0x0); |
882 | /* | ||
883 | * Default is 100Mbps. | ||
884 | * A bit strange: 100Mbps is 0x1801 elsewhere -- FR 2005/06/09 | ||
885 | */ | ||
886 | SIS_W16(StationControl, 0x1901); | ||
887 | SIS_W32(GMIIControl, 0x0); | 882 | SIS_W32(GMIIControl, 0x0); |
888 | SIS_W32(TxMacControl, 0x60); | 883 | SIS_W32(TxMacControl, 0x60); |
889 | SIS_W16(RxMacControl, 0x02); | 884 | SIS_W16(RxMacControl, 0x02); |
@@ -923,35 +918,30 @@ static void sis190_phy_task(void * data) | |||
923 | BMSR_ANEGCOMPLETE)) { | 918 | BMSR_ANEGCOMPLETE)) { |
924 | net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n", | 919 | net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n", |
925 | dev->name); | 920 | dev->name); |
921 | netif_carrier_off(dev); | ||
926 | mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET); | 922 | mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET); |
927 | mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT); | 923 | mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT); |
928 | } else { | 924 | } else { |
929 | /* Rejoice ! */ | 925 | /* Rejoice ! */ |
930 | struct { | 926 | struct { |
931 | int val; | 927 | int val; |
928 | u32 ctl; | ||
932 | const char *msg; | 929 | const char *msg; |
933 | u16 ctl; | ||
934 | } reg31[] = { | 930 | } reg31[] = { |
935 | { LPA_1000XFULL | LPA_SLCT, | 931 | { LPA_1000XFULL | LPA_SLCT, 0x07000c00 | 0x00001000, |
936 | "1000 Mbps Full Duplex", | 932 | "1000 Mbps Full Duplex" }, |
937 | 0x01 | _1000bpsF }, | 933 | { LPA_1000XHALF | LPA_SLCT, 0x07000c00, |
938 | { LPA_1000XHALF | LPA_SLCT, | 934 | "1000 Mbps Half Duplex" }, |
939 | "1000 Mbps Half Duplex", | 935 | { LPA_100FULL, 0x04000800 | 0x00001000, |
940 | 0x01 | _1000bpsH }, | 936 | "100 Mbps Full Duplex" }, |
941 | { LPA_100FULL, | 937 | { LPA_100HALF, 0x04000800, |
942 | "100 Mbps Full Duplex", | 938 | "100 Mbps Half Duplex" }, |
943 | 0x01 | _100bpsF }, | 939 | { LPA_10FULL, 0x04000400 | 0x00001000, |
944 | { LPA_100HALF, | 940 | "10 Mbps Full Duplex" }, |
945 | "100 Mbps Half Duplex", | 941 | { LPA_10HALF, 0x04000400, |
946 | 0x01 | _100bpsH }, | 942 | "10 Mbps Half Duplex" }, |
947 | { LPA_10FULL, | 943 | { 0, 0x04000400, "unknown" } |
948 | "10 Mbps Full Duplex", | 944 | }, *p; |
949 | 0x01 | _10bpsF }, | ||
950 | { LPA_10HALF, | ||
951 | "10 Mbps Half Duplex", | ||
952 | 0x01 | _10bpsH }, | ||
953 | { 0, "unknown", 0x0000 } | ||
954 | }, *p; | ||
955 | u16 adv; | 945 | u16 adv; |
956 | 946 | ||
957 | val = mdio_read(ioaddr, phy_id, 0x1f); | 947 | val = mdio_read(ioaddr, phy_id, 0x1f); |
@@ -964,12 +954,29 @@ static void sis190_phy_task(void * data) | |||
964 | 954 | ||
965 | val &= adv; | 955 | val &= adv; |
966 | 956 | ||
967 | for (p = reg31; p->ctl; p++) { | 957 | for (p = reg31; p->val; p++) { |
968 | if ((val & p->val) == p->val) | 958 | if ((val & p->val) == p->val) |
969 | break; | 959 | break; |
970 | } | 960 | } |
971 | if (p->ctl) | 961 | |
972 | SIS_W16(StationControl, p->ctl); | 962 | p->ctl |= SIS_R32(StationControl) & ~0x0f001c00; |
963 | |||
964 | if ((tp->features & F_HAS_RGMII) && | ||
965 | (tp->features & F_PHY_BCM5461)) { | ||
966 | // Set Tx Delay in RGMII mode. | ||
967 | mdio_write(ioaddr, phy_id, 0x18, 0xf1c7); | ||
968 | udelay(200); | ||
969 | mdio_write(ioaddr, phy_id, 0x1c, 0x8c00); | ||
970 | p->ctl |= 0x03000000; | ||
971 | } | ||
972 | |||
973 | SIS_W32(StationControl, p->ctl); | ||
974 | |||
975 | if (tp->features & F_HAS_RGMII) { | ||
976 | SIS_W32(RGDelay, 0x0441); | ||
977 | SIS_W32(RGDelay, 0x0440); | ||
978 | } | ||
979 | |||
973 | net_link(tp, KERN_INFO "%s: link on %s mode.\n", dev->name, | 980 | net_link(tp, KERN_INFO "%s: link on %s mode.\n", dev->name, |
974 | p->msg); | 981 | p->msg); |
975 | netif_carrier_on(dev); | 982 | netif_carrier_on(dev); |
@@ -1308,6 +1315,7 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp, | |||
1308 | phy->type = (p->type == MIX) ? | 1315 | phy->type = (p->type == MIX) ? |
1309 | ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ? | 1316 | ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ? |
1310 | LAN : HOME) : p->type; | 1317 | LAN : HOME) : p->type; |
1318 | tp->features |= p->feature; | ||
1311 | } else | 1319 | } else |
1312 | phy->type = UNKNOWN; | 1320 | phy->type = UNKNOWN; |
1313 | 1321 | ||
@@ -1316,6 +1324,25 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp, | |||
1316 | (phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id); | 1324 | (phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id); |
1317 | } | 1325 | } |
1318 | 1326 | ||
1327 | static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp) | ||
1328 | { | ||
1329 | if (tp->features & F_PHY_88E1111) { | ||
1330 | void __iomem *ioaddr = tp->mmio_addr; | ||
1331 | int phy_id = tp->mii_if.phy_id; | ||
1332 | u16 reg[2][2] = { | ||
1333 | { 0x808b, 0x0ce1 }, | ||
1334 | { 0x808f, 0x0c60 } | ||
1335 | }, *p; | ||
1336 | |||
1337 | p = (tp->features & F_HAS_RGMII) ? reg[0] : reg[1]; | ||
1338 | |||
1339 | mdio_write(ioaddr, phy_id, 0x1b, p[0]); | ||
1340 | udelay(200); | ||
1341 | mdio_write(ioaddr, phy_id, 0x14, p[1]); | ||
1342 | udelay(200); | ||
1343 | } | ||
1344 | } | ||
1345 | |||
1319 | /** | 1346 | /** |
1320 | * sis190_mii_probe - Probe MII PHY for sis190 | 1347 | * sis190_mii_probe - Probe MII PHY for sis190 |
1321 | * @dev: the net device to probe for | 1348 | * @dev: the net device to probe for |
@@ -1366,6 +1393,8 @@ static int __devinit sis190_mii_probe(struct net_device *dev) | |||
1366 | /* Select default PHY for mac */ | 1393 | /* Select default PHY for mac */ |
1367 | sis190_default_phy(dev); | 1394 | sis190_default_phy(dev); |
1368 | 1395 | ||
1396 | sis190_mii_probe_88e1111_fixup(tp); | ||
1397 | |||
1369 | mii_if->dev = dev; | 1398 | mii_if->dev = dev; |
1370 | mii_if->mdio_read = __mdio_read; | 1399 | mii_if->mdio_read = __mdio_read; |
1371 | mii_if->mdio_write = __mdio_write; | 1400 | mii_if->mdio_write = __mdio_write; |
@@ -1505,6 +1534,11 @@ static void sis190_tx_timeout(struct net_device *dev) | |||
1505 | netif_wake_queue(dev); | 1534 | netif_wake_queue(dev); |
1506 | } | 1535 | } |
1507 | 1536 | ||
1537 | static void sis190_set_rgmii(struct sis190_private *tp, u8 reg) | ||
1538 | { | ||
1539 | tp->features |= (reg & 0x80) ? F_HAS_RGMII : 0; | ||
1540 | } | ||
1541 | |||
1508 | static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, | 1542 | static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, |
1509 | struct net_device *dev) | 1543 | struct net_device *dev) |
1510 | { | 1544 | { |
@@ -1532,6 +1566,8 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, | |||
1532 | ((u16 *)dev->dev_addr)[0] = le16_to_cpu(w); | 1566 | ((u16 *)dev->dev_addr)[0] = le16_to_cpu(w); |
1533 | } | 1567 | } |
1534 | 1568 | ||
1569 | sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo)); | ||
1570 | |||
1535 | return 0; | 1571 | return 0; |
1536 | } | 1572 | } |
1537 | 1573 | ||
@@ -1577,6 +1613,8 @@ static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev, | |||
1577 | outb(0x12, 0x78); | 1613 | outb(0x12, 0x78); |
1578 | reg = inb(0x79); | 1614 | reg = inb(0x79); |
1579 | 1615 | ||
1616 | sis190_set_rgmii(tp, reg); | ||
1617 | |||
1580 | /* Restore the value to ISA Bridge */ | 1618 | /* Restore the value to ISA Bridge */ |
1581 | pci_write_config_byte(isa_bridge, 0x48, tmp8); | 1619 | pci_write_config_byte(isa_bridge, 0x48, tmp8); |
1582 | pci_dev_put(isa_bridge); | 1620 | pci_dev_put(isa_bridge); |
@@ -1799,6 +1837,9 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, | |||
1799 | dev->dev_addr[2], dev->dev_addr[3], | 1837 | dev->dev_addr[2], dev->dev_addr[3], |
1800 | dev->dev_addr[4], dev->dev_addr[5]); | 1838 | dev->dev_addr[4], dev->dev_addr[5]); |
1801 | 1839 | ||
1840 | net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name, | ||
1841 | (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII"); | ||
1842 | |||
1802 | netif_carrier_off(dev); | 1843 | netif_carrier_off(dev); |
1803 | 1844 | ||
1804 | sis190_set_speed_auto(dev); | 1845 | sis190_set_speed_auto(dev); |