diff options
author | Francois Romieu <romieu@fr.zoreil.com> | 2006-02-22 18:55:25 -0500 |
---|---|---|
committer | Francois Romieu <romieu@fr.zoreil.com> | 2006-02-23 17:06:48 -0500 |
commit | 61a4dcc2f9b5c6861e7198b80dd73dd6e9247b7b (patch) | |
tree | af9a8e4c32af8dc92bf443361337a0b8e58ff4c6 | |
parent | 5d06a99f543e734ceb53bbc9e550537be97f0c49 (diff) |
r8169: enable wake on lan
Similar to 8139cp code but more inspired/lucky.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
-rw-r--r-- | drivers/net/r8169.c | 87 |
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 | ||
444 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); | 453 | MODULE_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 | ||
625 | static 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 | |||
656 | out_unlock: | ||
657 | spin_unlock_irq(&tp->lock); | ||
658 | } | ||
659 | |||
660 | static 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 | |||
616 | static void rtl8169_get_drvinfo(struct net_device *dev, | 699 | static 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)); |
2696 | out: | 2782 | out: |
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); |
2713 | out: | 2800 | out: |