[PATCH] pcmcia: default suspend and resume handling
[safe/jmp/linux-2.6] / drivers / net / r8169.c
index 2f9b322..0ad3310 100644 (file)
@@ -92,19 +92,18 @@ VERSION 2.2LK       <2005/01/25>
 #endif /* RTL8169_DEBUG */
 
 #define R8169_MSG_DEFAULT \
-       (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_IFUP | \
-        NETIF_MSG_IFDOWN)
+       (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN)
 
 #define TX_BUFFS_AVAIL(tp) \
        (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1)
 
 #ifdef CONFIG_R8169_NAPI
 #define rtl8169_rx_skb                 netif_receive_skb
-#define rtl8169_rx_hwaccel_skb         vlan_hwaccel_rx
+#define rtl8169_rx_hwaccel_skb         vlan_hwaccel_receive_skb
 #define rtl8169_rx_quota(count, quota) min(count, quota)
 #else
 #define rtl8169_rx_skb                 netif_rx
-#define rtl8169_rx_hwaccel_skb         vlan_hwaccel_receive_skb
+#define rtl8169_rx_hwaccel_skb         vlan_hwaccel_rx
 #define rtl8169_rx_quota(count, quota) count
 #endif
 
@@ -114,11 +113,11 @@ static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
 static int num_media = 0;
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+static const int max_interrupt_work = 20;
 
 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
    The RTL chips use a 64 element hash table based on the Ethernet CRC. */
-static int multicast_filter_limit = 32;
+static const int multicast_filter_limit = 32;
 
 /* MAC address length */
 #define MAC_ADDR_LEN   6
@@ -171,7 +170,7 @@ enum phy_version {
 #define _R(NAME,MAC,MASK) \
        { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
 
-const static struct {
+static const struct {
        const char *name;
        u8 mac_version;
        u32 RxConfigMask;       /* Clears the bits supported by this chip */
@@ -186,8 +185,8 @@ const static struct {
 static struct pci_device_id rtl8169_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8169), },
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK,       0x4300), },
-       { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS,     0x1032), },
        { PCI_DEVICE(0x16ec,                    0x0116), },
+       { PCI_VENDOR_ID_LINKSYS,                0x1032, PCI_ANY_ID, 0x0024, },
        {0,},
 };
 
@@ -288,6 +287,20 @@ enum RTL8169_register_content {
        TxInterFrameGapShift = 24,
        TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
 
+       /* Config1 register p.24 */
+       PMEnable        = (1 << 0),     /* Power Management Enable */
+
+       /* Config3 register p.25 */
+       MagicPacket     = (1 << 5),     /* Wake up when receives a Magic Packet */
+       LinkUp          = (1 << 4),     /* Wake up when the cable connection is re-established */
+
+       /* Config5 register p.27 */
+       BWF             = (1 << 6),     /* Accept Broadcast wakeup frame */
+       MWF             = (1 << 5),     /* Accept Multicast wakeup frame */
+       UWF             = (1 << 4),     /* Accept Unicast wakeup frame */
+       LanWake         = (1 << 1),     /* LanWake enable/disable */
+       PMEStatus       = (1 << 0),     /* PME status can be reset by PCI RST# */
+
        /* TBICSR p.28 */
        TBIReset        = 0x80000000,
        TBILoopback     = 0x40000000,
@@ -434,6 +447,7 @@ struct rtl8169_private {
        unsigned int (*phy_reset_pending)(void __iomem *);
        unsigned int (*link_ok)(void __iomem *);
        struct work_struct task;
+       unsigned wol_enabled : 1;
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -485,13 +499,12 @@ static void mdio_write(void __iomem *ioaddr, int RegAddr, int value)
        int i;
 
        RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
-       udelay(1000);
 
-       for (i = 2000; i > 0; i--) {
+       for (i = 20; i > 0; i--) {
                /* Check if the RTL8169 has completed writing to the specified MII register */
                if (!(RTL_R32(PHYAR) & 0x80000000)) 
                        break;
-               udelay(100);
+               udelay(25);
        }
 }
 
@@ -500,15 +513,14 @@ static int mdio_read(void __iomem *ioaddr, int RegAddr)
        int i, value = -1;
 
        RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
-       udelay(1000);
 
-       for (i = 2000; i > 0; i--) {
+       for (i = 20; i > 0; i--) {
                /* Check if the RTL8169 has completed retrieving data from the specified MII register */
                if (RTL_R32(PHYAR) & 0x80000000) {
                        value = (int) (RTL_R32(PHYAR) & 0xFFFF);
                        break;
                }
-               udelay(100);
+               udelay(25);
        }
        return value;
 }
@@ -610,6 +622,80 @@ static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex)
        *duplex = p->duplex;
 }
 
+static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       u8 options;
+
+       wol->wolopts = 0;
+
+#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
+       wol->supported = WAKE_ANY;
+
+       spin_lock_irq(&tp->lock);
+
+       options = RTL_R8(Config1);
+       if (!(options & PMEnable))
+               goto out_unlock;
+
+       options = RTL_R8(Config3);
+       if (options & LinkUp)
+               wol->wolopts |= WAKE_PHY;
+       if (options & MagicPacket)
+               wol->wolopts |= WAKE_MAGIC;
+
+       options = RTL_R8(Config5);
+       if (options & UWF)
+               wol->wolopts |= WAKE_UCAST;
+       if (options & BWF)
+               wol->wolopts |= WAKE_BCAST;
+       if (options & MWF)
+               wol->wolopts |= WAKE_MCAST;
+
+out_unlock:
+       spin_unlock_irq(&tp->lock);
+}
+
+static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       int i;
+       static struct {
+               u32 opt;
+               u16 reg;
+               u8  mask;
+       } cfg[] = {
+               { WAKE_ANY,   Config1, PMEnable },
+               { WAKE_PHY,   Config3, LinkUp },
+               { WAKE_MAGIC, Config3, MagicPacket },
+               { WAKE_UCAST, Config5, UWF },
+               { WAKE_BCAST, Config5, BWF },
+               { WAKE_MCAST, Config5, MWF },
+               { WAKE_ANY,   Config5, LanWake }
+       };
+
+       spin_lock_irq(&tp->lock);
+
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+       for (i = 0; i < ARRAY_SIZE(cfg); i++) {
+               u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
+               if (wol->wolopts & cfg[i].opt)
+                       options |= cfg[i].mask;
+               RTL_W8(cfg[i].reg, options);
+       }
+
+       RTL_W8(Cfg9346, Cfg9346_Lock);
+
+       tp->wol_enabled = (wol->wolopts) ? 1 : 0;
+
+       spin_unlock_irq(&tp->lock);
+
+       return 0;
+}
+
 static void rtl8169_get_drvinfo(struct net_device *dev,
                                struct ethtool_drvinfo *info)
 {
@@ -678,6 +764,9 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
 
                if (duplex == DUPLEX_HALF)
                        auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full);
+
+               if (duplex == DUPLEX_FULL)
+                       auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_100_Half);
        }
 
        tp->phy_auto_nego_reg = auto_nego;
@@ -1025,9 +1114,12 @@ static struct ethtool_ops rtl8169_ethtool_ops = {
        .get_tso                = ethtool_op_get_tso,
        .set_tso                = ethtool_op_set_tso,
        .get_regs               = rtl8169_get_regs,
+       .get_wol                = rtl8169_get_wol,
+       .set_wol                = rtl8169_set_wol,
        .get_strings            = rtl8169_get_strings,
        .get_stats_count        = rtl8169_get_stats_count,
        .get_ethtool_stats      = rtl8169_get_ethtool_stats,
+       .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
 static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum,
@@ -1346,10 +1438,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
        } else {
                if (netif_msg_probe(tp)) {
                        printk(KERN_ERR PFX
-                              "Cannot find PowerManagement capability. "
-                              "Aborting.\n");
+                              "PowerManagement capability not found.\n");
                }
-               goto err_out_mwi;
        }
 
        /* make sure PCI base addr 1 is MMIO */
@@ -1443,6 +1533,11 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
        }
        tp->chipset = i;
 
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
+       RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
+       RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
+       RTL_W8(Cfg9346, Cfg9346_Lock);
+
        *ioaddr_out = ioaddr;
        *dev_out = dev;
 out:
@@ -1512,6 +1607,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Get MAC address.  FIXME: read EEPROM */
        for (i = 0; i < MAC_ADDR_LEN; i++)
                dev->dev_addr[i] = RTL_R8(MAC0 + i);
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        dev->open = rtl8169_open;
        dev->hard_start_xmit = rtl8169_start_xmit;
@@ -1612,49 +1708,6 @@ rtl8169_remove_one(struct pci_dev *pdev)
        pci_set_drvdata(pdev, NULL);
 }
 
-#ifdef CONFIG_PM
-
-static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct rtl8169_private *tp = netdev_priv(dev);
-       void __iomem *ioaddr = tp->mmio_addr;
-       unsigned long flags;
-
-       if (!netif_running(dev))
-               return 0;
-       
-       netif_device_detach(dev);
-       netif_stop_queue(dev);
-       spin_lock_irqsave(&tp->lock, flags);
-
-       /* Disable interrupts, stop Rx and Tx */
-       RTL_W16(IntrMask, 0);
-       RTL_W8(ChipCmd, 0);
-               
-       /* Update the error counts. */
-       tp->stats.rx_missed_errors += RTL_R32(RxMissed);
-       RTL_W32(RxMissed, 0);
-       spin_unlock_irqrestore(&tp->lock, flags);
-       
-       return 0;
-}
-
-static int rtl8169_resume(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-
-       if (!netif_running(dev))
-           return 0;
-
-       netif_device_attach(dev);
-       rtl8169_hw_start(dev);
-
-       return 0;
-}
-                                                                                
-#endif /* CONFIG_PM */
-
 static void rtl8169_set_rxbufsize(struct rtl8169_private *tp,
                                  struct net_device *dev)
 {
@@ -2515,7 +2568,7 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
        } while (boguscnt > 0);
 
        if (boguscnt <= 0) {
-               if (net_ratelimit() && netif_msg_intr(tp)) {
+               if (netif_msg_intr(tp) && net_ratelimit() ) {
                        printk(KERN_WARNING
                               "%s: Too much work at interrupt!\n", dev->name);
                }
@@ -2700,6 +2753,56 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
        return &tp->stats;
 }
 
+#ifdef CONFIG_PM
+
+static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       if (!netif_running(dev))
+               goto out;
+
+       netif_device_detach(dev);
+       netif_stop_queue(dev);
+
+       spin_lock_irq(&tp->lock);
+
+       rtl8169_asic_down(ioaddr);
+
+       tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+       RTL_W32(RxMissed, 0);
+
+       spin_unlock_irq(&tp->lock);
+
+       pci_save_state(pdev);
+       pci_enable_wake(pdev, pci_choose_state(pdev, state), tp->wol_enabled);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+out:
+       return 0;
+}
+
+static int rtl8169_resume(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       if (!netif_running(dev))
+               goto out;
+
+       netif_device_attach(dev);
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       pci_enable_wake(pdev, PCI_D0, 0);
+
+       rtl8169_schedule_work(dev, rtl8169_reset_task);
+out:
+       return 0;
+}
+
+#endif /* CONFIG_PM */
+
 static struct pci_driver rtl8169_pci_driver = {
        .name           = MODULENAME,
        .id_table       = rtl8169_pci_tbl,