aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/r8169.c
diff options
context:
space:
mode:
authorFrancois Romieu <romieu@fr.zoreil.com>2006-02-22 18:55:25 -0500
committerFrancois Romieu <romieu@fr.zoreil.com>2006-02-23 17:06:48 -0500
commit61a4dcc2f9b5c6861e7198b80dd73dd6e9247b7b (patch)
treeaf9a8e4c32af8dc92bf443361337a0b8e58ff4c6 /drivers/net/r8169.c
parent5d06a99f543e734ceb53bbc9e550537be97f0c49 (diff)
r8169: enable wake on lan
Similar to 8139cp code but more inspired/lucky. Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Diffstat (limited to 'drivers/net/r8169.c')
-rw-r--r--drivers/net/r8169.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 999fd6cef77e..8cc0d0bbdf50 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -290,7 +290,15 @@ enum RTL8169_register_content {
290 /* Config1 register p.24 */ 290 /* Config1 register p.24 */
291 PMEnable = (1 << 0), /* Power Management Enable */ 291 PMEnable = (1 << 0), /* Power Management Enable */
292 292
293 /* Config3 register p.25 */
294 MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */
295 LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */
296
293 /* Config5 register p.27 */ 297 /* Config5 register p.27 */
298 BWF = (1 << 6), /* Accept Broadcast wakeup frame */
299 MWF = (1 << 5), /* Accept Multicast wakeup frame */
300 UWF = (1 << 4), /* Accept Unicast wakeup frame */
301 LanWake = (1 << 1), /* LanWake enable/disable */
294 PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ 302 PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
295 303
296 /* TBICSR p.28 */ 304 /* TBICSR p.28 */
@@ -439,6 +447,7 @@ struct rtl8169_private {
439 unsigned int (*phy_reset_pending)(void __iomem *); 447 unsigned int (*phy_reset_pending)(void __iomem *);
440 unsigned int (*link_ok)(void __iomem *); 448 unsigned int (*link_ok)(void __iomem *);
441 struct work_struct task; 449 struct work_struct task;
450 unsigned wol_enabled : 1;
442}; 451};
443 452
444MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); 453MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -613,6 +622,80 @@ static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex)
613 *duplex = p->duplex; 622 *duplex = p->duplex;
614} 623}
615 624
625static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
626{
627 struct rtl8169_private *tp = netdev_priv(dev);
628 void __iomem *ioaddr = tp->mmio_addr;
629 u8 options;
630
631 wol->wolopts = 0;
632
633#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
634 wol->supported = WAKE_ANY;
635
636 spin_lock_irq(&tp->lock);
637
638 options = RTL_R8(Config1);
639 if (!(options & PMEnable))
640 goto out_unlock;
641
642 options = RTL_R8(Config3);
643 if (options & LinkUp)
644 wol->wolopts |= WAKE_PHY;
645 if (options & MagicPacket)
646 wol->wolopts |= WAKE_MAGIC;
647
648 options = RTL_R8(Config5);
649 if (options & UWF)
650 wol->wolopts |= WAKE_UCAST;
651 if (options & BWF)
652 wol->wolopts |= WAKE_BCAST;
653 if (options & MWF)
654 wol->wolopts |= WAKE_MCAST;
655
656out_unlock:
657 spin_unlock_irq(&tp->lock);
658}
659
660static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
661{
662 struct rtl8169_private *tp = netdev_priv(dev);
663 void __iomem *ioaddr = tp->mmio_addr;
664 int i;
665 static struct {
666 u32 opt;
667 u16 reg;
668 u8 mask;
669 } cfg[] = {
670 { WAKE_ANY, Config1, PMEnable },
671 { WAKE_PHY, Config3, LinkUp },
672 { WAKE_MAGIC, Config3, MagicPacket },
673 { WAKE_UCAST, Config5, UWF },
674 { WAKE_BCAST, Config5, BWF },
675 { WAKE_MCAST, Config5, MWF },
676 { WAKE_ANY, Config5, LanWake }
677 };
678
679 spin_lock_irq(&tp->lock);
680
681 RTL_W8(Cfg9346, Cfg9346_Unlock);
682
683 for (i = 0; i < ARRAY_SIZE(cfg); i++) {
684 u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
685 if (wol->wolopts & cfg[i].opt)
686 options |= cfg[i].mask;
687 RTL_W8(cfg[i].reg, options);
688 }
689
690 RTL_W8(Cfg9346, Cfg9346_Lock);
691
692 tp->wol_enabled = (wol->wolopts) ? 1 : 0;
693
694 spin_unlock_irq(&tp->lock);
695
696 return 0;
697}
698
616static void rtl8169_get_drvinfo(struct net_device *dev, 699static void rtl8169_get_drvinfo(struct net_device *dev,
617 struct ethtool_drvinfo *info) 700 struct ethtool_drvinfo *info)
618{ 701{
@@ -1031,6 +1114,8 @@ static struct ethtool_ops rtl8169_ethtool_ops = {
1031 .get_tso = ethtool_op_get_tso, 1114 .get_tso = ethtool_op_get_tso,
1032 .set_tso = ethtool_op_set_tso, 1115 .set_tso = ethtool_op_set_tso,
1033 .get_regs = rtl8169_get_regs, 1116 .get_regs = rtl8169_get_regs,
1117 .get_wol = rtl8169_get_wol,
1118 .set_wol = rtl8169_set_wol,
1034 .get_strings = rtl8169_get_strings, 1119 .get_strings = rtl8169_get_strings,
1035 .get_stats_count = rtl8169_get_stats_count, 1120 .get_stats_count = rtl8169_get_stats_count,
1036 .get_ethtool_stats = rtl8169_get_ethtool_stats, 1121 .get_ethtool_stats = rtl8169_get_ethtool_stats,
@@ -2692,6 +2777,7 @@ static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state)
2692 spin_unlock_irq(&tp->lock); 2777 spin_unlock_irq(&tp->lock);
2693 2778
2694 pci_save_state(pdev); 2779 pci_save_state(pdev);
2780 pci_enable_wake(pdev, pci_choose_state(pdev, state), tp->wol_enabled);
2695 pci_set_power_state(pdev, pci_choose_state(pdev, state)); 2781 pci_set_power_state(pdev, pci_choose_state(pdev, state));
2696out: 2782out:
2697 return 0; 2783 return 0;
@@ -2708,6 +2794,7 @@ static int rtl8169_resume(struct pci_dev *pdev)
2708 2794
2709 pci_set_power_state(pdev, PCI_D0); 2795 pci_set_power_state(pdev, PCI_D0);
2710 pci_restore_state(pdev); 2796 pci_restore_state(pdev);
2797 pci_enable_wake(pdev, PCI_D0, 0);
2711 2798
2712 rtl8169_schedule_work(dev, rtl8169_reset_task); 2799 rtl8169_schedule_work(dev, rtl8169_reset_task);
2713out: 2800out: