aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/e100.c
diff options
context:
space:
mode:
authorBruce Allan <bruce.w.allan@intel.com>2009-03-21 16:25:25 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-21 16:25:25 -0400
commitb55de80e49892002a1878013ab9aee1a30970be6 (patch)
tree77a742d921e9bb0270dea4086c09e6bbc1c41128 /drivers/net/e100.c
parented36604b25023c584fdf93df6073f65dac4b1129 (diff)
e100: add support for 82552 10/100 adapter
This patch enables support for the new Intel 82552 adapter (new PHY paired with the existing MAC in the ICH7 chipset). No new features are added to the driver, however there are minor changes due to updated registers and a few workarounds for hardware errata. Signed-off-by: Bruce Allan <bruce.w.allan@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/e100.c')
-rw-r--r--drivers/net/e100.c93
1 files changed, 77 insertions, 16 deletions
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 861d2eeaa43c..0504db9ad643 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -167,7 +167,7 @@
167 167
168#define DRV_NAME "e100" 168#define DRV_NAME "e100"
169#define DRV_EXT "-NAPI" 169#define DRV_EXT "-NAPI"
170#define DRV_VERSION "3.5.23-k6"DRV_EXT 170#define DRV_VERSION "3.5.24-k2"DRV_EXT
171#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" 171#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver"
172#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation" 172#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation"
173#define PFX DRV_NAME ": " 173#define PFX DRV_NAME ": "
@@ -240,6 +240,7 @@ static struct pci_device_id e100_id_table[] = {
240 INTEL_8255X_ETHERNET_DEVICE(0x1093, 7), 240 INTEL_8255X_ETHERNET_DEVICE(0x1093, 7),
241 INTEL_8255X_ETHERNET_DEVICE(0x1094, 7), 241 INTEL_8255X_ETHERNET_DEVICE(0x1094, 7),
242 INTEL_8255X_ETHERNET_DEVICE(0x1095, 7), 242 INTEL_8255X_ETHERNET_DEVICE(0x1095, 7),
243 INTEL_8255X_ETHERNET_DEVICE(0x10fe, 7),
243 INTEL_8255X_ETHERNET_DEVICE(0x1209, 0), 244 INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
244 INTEL_8255X_ETHERNET_DEVICE(0x1229, 0), 245 INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
245 INTEL_8255X_ETHERNET_DEVICE(0x2449, 2), 246 INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
@@ -275,6 +276,7 @@ enum phy {
275 phy_82562_em = 0x032002A8, 276 phy_82562_em = 0x032002A8,
276 phy_82562_ek = 0x031002A8, 277 phy_82562_ek = 0x031002A8,
277 phy_82562_eh = 0x017002A8, 278 phy_82562_eh = 0x017002A8,
279 phy_82552_v = 0xd061004d,
278 phy_unknown = 0xFFFFFFFF, 280 phy_unknown = 0xFFFFFFFF,
279}; 281};
280 282
@@ -943,6 +945,22 @@ static int mdio_read(struct net_device *netdev, int addr, int reg)
943 945
944static void mdio_write(struct net_device *netdev, int addr, int reg, int data) 946static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
945{ 947{
948 struct nic *nic = netdev_priv(netdev);
949
950 if ((nic->phy == phy_82552_v) && (reg == MII_BMCR) &&
951 (data & (BMCR_ANRESTART | BMCR_ANENABLE))) {
952 u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE);
953
954 /*
955 * Workaround Si issue where sometimes the part will not
956 * autoneg to 100Mbps even when advertised.
957 */
958 if (advert & ADVERTISE_100FULL)
959 data |= BMCR_SPEED100 | BMCR_FULLDPLX;
960 else if (advert & ADVERTISE_100HALF)
961 data |= BMCR_SPEED100;
962 }
963
946 mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data); 964 mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data);
947} 965}
948 966
@@ -1276,16 +1294,12 @@ static int e100_phy_init(struct nic *nic)
1276 if (addr == 32) 1294 if (addr == 32)
1277 return -EAGAIN; 1295 return -EAGAIN;
1278 1296
1279 /* Selected the phy and isolate the rest */ 1297 /* Isolate all the PHY ids */
1280 for (addr = 0; addr < 32; addr++) { 1298 for (addr = 0; addr < 32; addr++)
1281 if (addr != nic->mii.phy_id) { 1299 mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
1282 mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE); 1300 /* Select the discovered PHY */
1283 } else { 1301 bmcr &= ~BMCR_ISOLATE;
1284 bmcr = mdio_read(netdev, addr, MII_BMCR); 1302 mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
1285 mdio_write(netdev, addr, MII_BMCR,
1286 bmcr & ~BMCR_ISOLATE);
1287 }
1288 }
1289 1303
1290 /* Get phy ID */ 1304 /* Get phy ID */
1291 id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1); 1305 id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1);
@@ -1303,7 +1317,18 @@ static int e100_phy_init(struct nic *nic)
1303 mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong); 1317 mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong);
1304 } 1318 }
1305 1319
1306 if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && 1320 if (nic->phy == phy_82552_v) {
1321 u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE);
1322
1323 /* Workaround Si not advertising flow-control during autoneg */
1324 advert |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1325 mdio_write(netdev, nic->mii.phy_id, MII_ADVERTISE, advert);
1326
1327 /* Reset for the above changes to take effect */
1328 bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR);
1329 bmcr |= BMCR_RESET;
1330 mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
1331 } else if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
1307 (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && 1332 (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
1308 !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) { 1333 !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
1309 /* enable/disable MDI/MDI-X auto-switching. */ 1334 /* enable/disable MDI/MDI-X auto-switching. */
@@ -2134,6 +2159,9 @@ err_clean_rx:
2134} 2159}
2135 2160
2136#define MII_LED_CONTROL 0x1B 2161#define MII_LED_CONTROL 0x1B
2162#define E100_82552_LED_OVERRIDE 0x19
2163#define E100_82552_LED_ON 0x000F /* LEDTX and LED_RX both on */
2164#define E100_82552_LED_OFF 0x000A /* LEDTX and LED_RX both off */
2137static void e100_blink_led(unsigned long data) 2165static void e100_blink_led(unsigned long data)
2138{ 2166{
2139 struct nic *nic = (struct nic *)data; 2167 struct nic *nic = (struct nic *)data;
@@ -2143,10 +2171,19 @@ static void e100_blink_led(unsigned long data)
2143 led_on_559 = 0x05, 2171 led_on_559 = 0x05,
2144 led_on_557 = 0x07, 2172 led_on_557 = 0x07,
2145 }; 2173 };
2174 u16 led_reg = MII_LED_CONTROL;
2175
2176 if (nic->phy == phy_82552_v) {
2177 led_reg = E100_82552_LED_OVERRIDE;
2146 2178
2147 nic->leds = (nic->leds & led_on) ? led_off : 2179 nic->leds = (nic->leds == E100_82552_LED_ON) ?
2148 (nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559; 2180 E100_82552_LED_OFF : E100_82552_LED_ON;
2149 mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds); 2181 } else {
2182 nic->leds = (nic->leds & led_on) ? led_off :
2183 (nic->mac < mac_82559_D101M) ? led_on_557 :
2184 led_on_559;
2185 }
2186 mdio_write(nic->netdev, nic->mii.phy_id, led_reg, nic->leds);
2150 mod_timer(&nic->blink_timer, jiffies + HZ / 4); 2187 mod_timer(&nic->blink_timer, jiffies + HZ / 4);
2151} 2188}
2152 2189
@@ -2375,13 +2412,15 @@ static void e100_diag_test(struct net_device *netdev,
2375static int e100_phys_id(struct net_device *netdev, u32 data) 2412static int e100_phys_id(struct net_device *netdev, u32 data)
2376{ 2413{
2377 struct nic *nic = netdev_priv(netdev); 2414 struct nic *nic = netdev_priv(netdev);
2415 u16 led_reg = (nic->phy == phy_82552_v) ? E100_82552_LED_OVERRIDE :
2416 MII_LED_CONTROL;
2378 2417
2379 if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) 2418 if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
2380 data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); 2419 data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
2381 mod_timer(&nic->blink_timer, jiffies); 2420 mod_timer(&nic->blink_timer, jiffies);
2382 msleep_interruptible(data * 1000); 2421 msleep_interruptible(data * 1000);
2383 del_timer_sync(&nic->blink_timer); 2422 del_timer_sync(&nic->blink_timer);
2384 mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0); 2423 mdio_write(netdev, nic->mii.phy_id, led_reg, 0);
2385 2424
2386 return 0; 2425 return 0;
2387} 2426}
@@ -2686,6 +2725,9 @@ static void __devexit e100_remove(struct pci_dev *pdev)
2686 } 2725 }
2687} 2726}
2688 2727
2728#define E100_82552_SMARTSPEED 0x14 /* SmartSpeed Ctrl register */
2729#define E100_82552_REV_ANEG 0x0200 /* Reverse auto-negotiation */
2730#define E100_82552_ANEG_NOW 0x0400 /* Auto-negotiate now */
2689static int e100_suspend(struct pci_dev *pdev, pm_message_t state) 2731static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
2690{ 2732{
2691 struct net_device *netdev = pci_get_drvdata(pdev); 2733 struct net_device *netdev = pci_get_drvdata(pdev);
@@ -2698,6 +2740,15 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
2698 pci_save_state(pdev); 2740 pci_save_state(pdev);
2699 2741
2700 if ((nic->flags & wol_magic) | e100_asf(nic)) { 2742 if ((nic->flags & wol_magic) | e100_asf(nic)) {
2743 /* enable reverse auto-negotiation */
2744 if (nic->phy == phy_82552_v) {
2745 u16 smartspeed = mdio_read(netdev, nic->mii.phy_id,
2746 E100_82552_SMARTSPEED);
2747
2748 mdio_write(netdev, nic->mii.phy_id,
2749 E100_82552_SMARTSPEED, smartspeed |
2750 E100_82552_REV_ANEG | E100_82552_ANEG_NOW);
2751 }
2701 if (pci_enable_wake(pdev, PCI_D3cold, true)) 2752 if (pci_enable_wake(pdev, PCI_D3cold, true))
2702 pci_enable_wake(pdev, PCI_D3hot, true); 2753 pci_enable_wake(pdev, PCI_D3hot, true);
2703 } else { 2754 } else {
@@ -2721,6 +2772,16 @@ static int e100_resume(struct pci_dev *pdev)
2721 /* ack any pending wake events, disable PME */ 2772 /* ack any pending wake events, disable PME */
2722 pci_enable_wake(pdev, 0, 0); 2773 pci_enable_wake(pdev, 0, 0);
2723 2774
2775 /* disbale reverse auto-negotiation */
2776 if (nic->phy == phy_82552_v) {
2777 u16 smartspeed = mdio_read(netdev, nic->mii.phy_id,
2778 E100_82552_SMARTSPEED);
2779
2780 mdio_write(netdev, nic->mii.phy_id,
2781 E100_82552_SMARTSPEED,
2782 smartspeed & ~(E100_82552_REV_ANEG));
2783 }
2784
2724 netif_device_attach(netdev); 2785 netif_device_attach(netdev);
2725 if (netif_running(netdev)) 2786 if (netif_running(netdev))
2726 e100_up(nic); 2787 e100_up(nic);