Merge branch 'linus' into core/futexes
[pandora-kernel.git] / drivers / net / e100.c
index 86bb876..0504db9 100644 (file)
 
 #define DRV_NAME               "e100"
 #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_COPYRIGHT          "Copyright(c) 1999-2006 Intel Corporation"
 #define PFX                    DRV_NAME ": "
@@ -240,6 +240,7 @@ static struct pci_device_id e100_id_table[] = {
        INTEL_8255X_ETHERNET_DEVICE(0x1093, 7),
        INTEL_8255X_ETHERNET_DEVICE(0x1094, 7),
        INTEL_8255X_ETHERNET_DEVICE(0x1095, 7),
+       INTEL_8255X_ETHERNET_DEVICE(0x10fe, 7),
        INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
@@ -275,6 +276,7 @@ enum phy {
        phy_82562_em = 0x032002A8,
        phy_82562_ek = 0x031002A8,
        phy_82562_eh = 0x017002A8,
+       phy_82552_v  = 0xd061004d,
        phy_unknown  = 0xFFFFFFFF,
 };
 
@@ -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)
 {
+       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);
 }
 
@@ -1276,16 +1294,12 @@ static int e100_phy_init(struct nic *nic)
        if (addr == 32)
                return -EAGAIN;
 
-       /* Selected the phy and isolate the rest */
-       for (addr = 0; addr < 32; addr++) {
-               if (addr != nic->mii.phy_id) {
-                       mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
-               } else {
-                       bmcr = mdio_read(netdev, addr, MII_BMCR);
-                       mdio_write(netdev, addr, MII_BMCR,
-                               bmcr & ~BMCR_ISOLATE);
-               }
-       }
+       /* Isolate all the PHY ids */
+       for (addr = 0; addr < 32; addr++)
+               mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
+       /* Select the discovered PHY */
+       bmcr &= ~BMCR_ISOLATE;
+       mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
 
        /* Get phy ID */
        id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1);
@@ -1303,7 +1317,18 @@ static int e100_phy_init(struct nic *nic)
                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) &&
                !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
                /* enable/disable MDI/MDI-X auto-switching. */
@@ -1944,9 +1969,9 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
        if (stat_ack & stat_ack_rnr)
                nic->ru_running = RU_SUSPENDED;
 
-       if (likely(netif_rx_schedule_prep(&nic->napi))) {
+       if (likely(napi_schedule_prep(&nic->napi))) {
                e100_disable_irq(nic);
-               __netif_rx_schedule(&nic->napi);
+               __napi_schedule(&nic->napi);
        }
 
        return IRQ_HANDLED;
@@ -1962,7 +1987,7 @@ static int e100_poll(struct napi_struct *napi, int budget)
 
        /* If budget not fully consumed, exit the polling mode */
        if (work_done < budget) {
-               netif_rx_complete(napi);
+               napi_complete(napi);
                e100_enable_irq(nic);
        }
 
@@ -2134,6 +2159,9 @@ err_clean_rx:
 }
 
 #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)
 {
        struct nic *nic = (struct nic *)data;
@@ -2143,10 +2171,19 @@ static void e100_blink_led(unsigned long data)
                led_on_559 = 0x05,
                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->mac < mac_82559_D101M) ? led_on_557 : led_on_559;
-       mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds);
+               nic->leds = (nic->leds == E100_82552_LED_ON) ?
+                           E100_82552_LED_OFF : E100_82552_LED_ON;
+       } 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);
 }
 
@@ -2375,13 +2412,15 @@ static void e100_diag_test(struct net_device *netdev,
 static int e100_phys_id(struct net_device *netdev, u32 data)
 {
        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))
                data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
        mod_timer(&nic->blink_timer, jiffies);
        msleep_interruptible(data * 1000);
        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;
 }
@@ -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)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
@@ -2698,6 +2740,15 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
        pci_save_state(pdev);
 
        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))
                        pci_enable_wake(pdev, PCI_D3hot, true);
        } else {
@@ -2721,6 +2772,16 @@ static int e100_resume(struct pci_dev *pdev)
        /* ack any pending wake events, disable PME */
        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);
        if (netif_running(netdev))
                e100_up(nic);