Commit b55de80e authored by Bruce Allan's avatar Bruce Allan Committed by David S. Miller

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: default avatarBruce Allan <bruce.w.allan@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ed36604b
...@@ -167,7 +167,7 @@ ...@@ -167,7 +167,7 @@
#define DRV_NAME "e100" #define DRV_NAME "e100"
#define DRV_EXT "-NAPI" #define DRV_EXT "-NAPI"
#define DRV_VERSION "3.5.23-k6"DRV_EXT #define DRV_VERSION "3.5.24-k2"DRV_EXT
#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation" #define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation"
#define PFX DRV_NAME ": " #define PFX DRV_NAME ": "
...@@ -240,6 +240,7 @@ static struct pci_device_id e100_id_table[] = { ...@@ -240,6 +240,7 @@ static struct pci_device_id e100_id_table[] = {
INTEL_8255X_ETHERNET_DEVICE(0x1093, 7), INTEL_8255X_ETHERNET_DEVICE(0x1093, 7),
INTEL_8255X_ETHERNET_DEVICE(0x1094, 7), INTEL_8255X_ETHERNET_DEVICE(0x1094, 7),
INTEL_8255X_ETHERNET_DEVICE(0x1095, 7), INTEL_8255X_ETHERNET_DEVICE(0x1095, 7),
INTEL_8255X_ETHERNET_DEVICE(0x10fe, 7),
INTEL_8255X_ETHERNET_DEVICE(0x1209, 0), INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
INTEL_8255X_ETHERNET_DEVICE(0x1229, 0), INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
INTEL_8255X_ETHERNET_DEVICE(0x2449, 2), INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
...@@ -275,6 +276,7 @@ enum phy { ...@@ -275,6 +276,7 @@ enum phy {
phy_82562_em = 0x032002A8, phy_82562_em = 0x032002A8,
phy_82562_ek = 0x031002A8, phy_82562_ek = 0x031002A8,
phy_82562_eh = 0x017002A8, phy_82562_eh = 0x017002A8,
phy_82552_v = 0xd061004d,
phy_unknown = 0xFFFFFFFF, phy_unknown = 0xFFFFFFFF,
}; };
...@@ -943,6 +945,22 @@ static int mdio_read(struct net_device *netdev, int addr, int reg) ...@@ -943,6 +945,22 @@ static int mdio_read(struct net_device *netdev, int addr, int reg)
static void mdio_write(struct net_device *netdev, int addr, int reg, int data) static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
{ {
struct nic *nic = netdev_priv(netdev);
if ((nic->phy == phy_82552_v) && (reg == MII_BMCR) &&
(data & (BMCR_ANRESTART | BMCR_ANENABLE))) {
u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE);
/*
* Workaround Si issue where sometimes the part will not
* autoneg to 100Mbps even when advertised.
*/
if (advert & ADVERTISE_100FULL)
data |= BMCR_SPEED100 | BMCR_FULLDPLX;
else if (advert & ADVERTISE_100HALF)
data |= BMCR_SPEED100;
}
mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data); mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data);
} }
...@@ -1276,16 +1294,12 @@ static int e100_phy_init(struct nic *nic) ...@@ -1276,16 +1294,12 @@ static int e100_phy_init(struct nic *nic)
if (addr == 32) if (addr == 32)
return -EAGAIN; return -EAGAIN;
/* Selected the phy and isolate the rest */ /* Isolate all the PHY ids */
for (addr = 0; addr < 32; addr++) { for (addr = 0; addr < 32; addr++)
if (addr != nic->mii.phy_id) { mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE); /* Select the discovered PHY */
} else { bmcr &= ~BMCR_ISOLATE;
bmcr = mdio_read(netdev, addr, MII_BMCR); mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
mdio_write(netdev, addr, MII_BMCR,
bmcr & ~BMCR_ISOLATE);
}
}
/* Get phy ID */ /* Get phy ID */
id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1); id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1);
...@@ -1303,7 +1317,18 @@ static int e100_phy_init(struct nic *nic) ...@@ -1303,7 +1317,18 @@ static int e100_phy_init(struct nic *nic)
mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong); mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong);
} }
if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && if (nic->phy == phy_82552_v) {
u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE);
/* Workaround Si not advertising flow-control during autoneg */
advert |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
mdio_write(netdev, nic->mii.phy_id, MII_ADVERTISE, advert);
/* Reset for the above changes to take effect */
bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR);
bmcr |= BMCR_RESET;
mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
} else if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
(mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
!(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) { !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
/* enable/disable MDI/MDI-X auto-switching. */ /* enable/disable MDI/MDI-X auto-switching. */
...@@ -2134,6 +2159,9 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) ...@@ -2134,6 +2159,9 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
} }
#define MII_LED_CONTROL 0x1B #define MII_LED_CONTROL 0x1B
#define E100_82552_LED_OVERRIDE 0x19
#define E100_82552_LED_ON 0x000F /* LEDTX and LED_RX both on */
#define E100_82552_LED_OFF 0x000A /* LEDTX and LED_RX both off */
static void e100_blink_led(unsigned long data) static void e100_blink_led(unsigned long data)
{ {
struct nic *nic = (struct nic *)data; struct nic *nic = (struct nic *)data;
...@@ -2143,10 +2171,19 @@ static void e100_blink_led(unsigned long data) ...@@ -2143,10 +2171,19 @@ static void e100_blink_led(unsigned long data)
led_on_559 = 0x05, led_on_559 = 0x05,
led_on_557 = 0x07, led_on_557 = 0x07,
}; };
u16 led_reg = MII_LED_CONTROL;
if (nic->phy == phy_82552_v) {
led_reg = E100_82552_LED_OVERRIDE;
nic->leds = (nic->leds & led_on) ? led_off : nic->leds = (nic->leds == E100_82552_LED_ON) ?
(nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559; E100_82552_LED_OFF : E100_82552_LED_ON;
mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds); } else {
nic->leds = (nic->leds & led_on) ? led_off :
(nic->mac < mac_82559_D101M) ? led_on_557 :
led_on_559;
}
mdio_write(nic->netdev, nic->mii.phy_id, led_reg, nic->leds);
mod_timer(&nic->blink_timer, jiffies + HZ / 4); mod_timer(&nic->blink_timer, jiffies + HZ / 4);
} }
...@@ -2375,13 +2412,15 @@ static void e100_diag_test(struct net_device *netdev, ...@@ -2375,13 +2412,15 @@ static void e100_diag_test(struct net_device *netdev,
static int e100_phys_id(struct net_device *netdev, u32 data) static int e100_phys_id(struct net_device *netdev, u32 data)
{ {
struct nic *nic = netdev_priv(netdev); struct nic *nic = netdev_priv(netdev);
u16 led_reg = (nic->phy == phy_82552_v) ? E100_82552_LED_OVERRIDE :
MII_LED_CONTROL;
if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
mod_timer(&nic->blink_timer, jiffies); mod_timer(&nic->blink_timer, jiffies);
msleep_interruptible(data * 1000); msleep_interruptible(data * 1000);
del_timer_sync(&nic->blink_timer); del_timer_sync(&nic->blink_timer);
mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0); mdio_write(netdev, nic->mii.phy_id, led_reg, 0);
return 0; return 0;
} }
...@@ -2686,6 +2725,9 @@ static void __devexit e100_remove(struct pci_dev *pdev) ...@@ -2686,6 +2725,9 @@ static void __devexit e100_remove(struct pci_dev *pdev)
} }
} }
#define E100_82552_SMARTSPEED 0x14 /* SmartSpeed Ctrl register */
#define E100_82552_REV_ANEG 0x0200 /* Reverse auto-negotiation */
#define E100_82552_ANEG_NOW 0x0400 /* Auto-negotiate now */
static int e100_suspend(struct pci_dev *pdev, pm_message_t state) static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
{ {
struct net_device *netdev = pci_get_drvdata(pdev); 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,6 +2740,15 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
pci_save_state(pdev); pci_save_state(pdev);
if ((nic->flags & wol_magic) | e100_asf(nic)) { if ((nic->flags & wol_magic) | e100_asf(nic)) {
/* enable reverse auto-negotiation */
if (nic->phy == phy_82552_v) {
u16 smartspeed = mdio_read(netdev, nic->mii.phy_id,
E100_82552_SMARTSPEED);
mdio_write(netdev, nic->mii.phy_id,
E100_82552_SMARTSPEED, smartspeed |
E100_82552_REV_ANEG | E100_82552_ANEG_NOW);
}
if (pci_enable_wake(pdev, PCI_D3cold, true)) if (pci_enable_wake(pdev, PCI_D3cold, true))
pci_enable_wake(pdev, PCI_D3hot, true); pci_enable_wake(pdev, PCI_D3hot, true);
} else { } else {
...@@ -2721,6 +2772,16 @@ static int e100_resume(struct pci_dev *pdev) ...@@ -2721,6 +2772,16 @@ static int e100_resume(struct pci_dev *pdev)
/* ack any pending wake events, disable PME */ /* ack any pending wake events, disable PME */
pci_enable_wake(pdev, 0, 0); pci_enable_wake(pdev, 0, 0);
/* disbale reverse auto-negotiation */
if (nic->phy == phy_82552_v) {
u16 smartspeed = mdio_read(netdev, nic->mii.phy_id,
E100_82552_SMARTSPEED);
mdio_write(netdev, nic->mii.phy_id,
E100_82552_SMARTSPEED,
smartspeed & ~(E100_82552_REV_ANEG));
}
netif_device_attach(netdev); netif_device_attach(netdev);
if (netif_running(netdev)) if (netif_running(netdev))
e100_up(nic); e100_up(nic);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment