diff options
Diffstat (limited to 'drivers/net/r8169.c')
-rw-r--r-- | drivers/net/r8169.c | 158 |
1 files changed, 128 insertions, 30 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index dd8106ff35aa..217e709bda3e 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/tcp.h> | 23 | #include <linux/tcp.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/dma-mapping.h> | 25 | #include <linux/dma-mapping.h> |
26 | #include <linux/pm_runtime.h> | ||
26 | 27 | ||
27 | #include <asm/system.h> | 28 | #include <asm/system.h> |
28 | #include <asm/io.h> | 29 | #include <asm/io.h> |
@@ -509,6 +510,7 @@ struct rtl8169_private { | |||
509 | 510 | ||
510 | struct mii_if_info mii; | 511 | struct mii_if_info mii; |
511 | struct rtl8169_counters counters; | 512 | struct rtl8169_counters counters; |
513 | u32 saved_wolopts; | ||
512 | }; | 514 | }; |
513 | 515 | ||
514 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); | 516 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); |
@@ -748,53 +750,61 @@ static void rtl8169_check_link_status(struct net_device *dev, | |||
748 | 750 | ||
749 | spin_lock_irqsave(&tp->lock, flags); | 751 | spin_lock_irqsave(&tp->lock, flags); |
750 | if (tp->link_ok(ioaddr)) { | 752 | if (tp->link_ok(ioaddr)) { |
753 | /* This is to cancel a scheduled suspend if there's one. */ | ||
754 | pm_request_resume(&tp->pci_dev->dev); | ||
751 | netif_carrier_on(dev); | 755 | netif_carrier_on(dev); |
752 | netif_info(tp, ifup, dev, "link up\n"); | 756 | netif_info(tp, ifup, dev, "link up\n"); |
753 | } else { | 757 | } else { |
754 | netif_carrier_off(dev); | 758 | netif_carrier_off(dev); |
755 | netif_info(tp, ifdown, dev, "link down\n"); | 759 | netif_info(tp, ifdown, dev, "link down\n"); |
760 | pm_schedule_suspend(&tp->pci_dev->dev, 100); | ||
756 | } | 761 | } |
757 | spin_unlock_irqrestore(&tp->lock, flags); | 762 | spin_unlock_irqrestore(&tp->lock, flags); |
758 | } | 763 | } |
759 | 764 | ||
760 | static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | 765 | #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) |
766 | |||
767 | static u32 __rtl8169_get_wol(struct rtl8169_private *tp) | ||
761 | { | 768 | { |
762 | struct rtl8169_private *tp = netdev_priv(dev); | ||
763 | void __iomem *ioaddr = tp->mmio_addr; | 769 | void __iomem *ioaddr = tp->mmio_addr; |
764 | u8 options; | 770 | u8 options; |
765 | 771 | u32 wolopts = 0; | |
766 | wol->wolopts = 0; | ||
767 | |||
768 | #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) | ||
769 | wol->supported = WAKE_ANY; | ||
770 | |||
771 | spin_lock_irq(&tp->lock); | ||
772 | 772 | ||
773 | options = RTL_R8(Config1); | 773 | options = RTL_R8(Config1); |
774 | if (!(options & PMEnable)) | 774 | if (!(options & PMEnable)) |
775 | goto out_unlock; | 775 | return 0; |
776 | 776 | ||
777 | options = RTL_R8(Config3); | 777 | options = RTL_R8(Config3); |
778 | if (options & LinkUp) | 778 | if (options & LinkUp) |
779 | wol->wolopts |= WAKE_PHY; | 779 | wolopts |= WAKE_PHY; |
780 | if (options & MagicPacket) | 780 | if (options & MagicPacket) |
781 | wol->wolopts |= WAKE_MAGIC; | 781 | wolopts |= WAKE_MAGIC; |
782 | 782 | ||
783 | options = RTL_R8(Config5); | 783 | options = RTL_R8(Config5); |
784 | if (options & UWF) | 784 | if (options & UWF) |
785 | wol->wolopts |= WAKE_UCAST; | 785 | wolopts |= WAKE_UCAST; |
786 | if (options & BWF) | 786 | if (options & BWF) |
787 | wol->wolopts |= WAKE_BCAST; | 787 | wolopts |= WAKE_BCAST; |
788 | if (options & MWF) | 788 | if (options & MWF) |
789 | wol->wolopts |= WAKE_MCAST; | 789 | wolopts |= WAKE_MCAST; |
790 | 790 | ||
791 | out_unlock: | 791 | return wolopts; |
792 | spin_unlock_irq(&tp->lock); | ||
793 | } | 792 | } |
794 | 793 | ||
795 | static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | 794 | static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
796 | { | 795 | { |
797 | struct rtl8169_private *tp = netdev_priv(dev); | 796 | struct rtl8169_private *tp = netdev_priv(dev); |
797 | |||
798 | spin_lock_irq(&tp->lock); | ||
799 | |||
800 | wol->supported = WAKE_ANY; | ||
801 | wol->wolopts = __rtl8169_get_wol(tp); | ||
802 | |||
803 | spin_unlock_irq(&tp->lock); | ||
804 | } | ||
805 | |||
806 | static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) | ||
807 | { | ||
798 | void __iomem *ioaddr = tp->mmio_addr; | 808 | void __iomem *ioaddr = tp->mmio_addr; |
799 | unsigned int i; | 809 | unsigned int i; |
800 | static const struct { | 810 | static const struct { |
@@ -811,23 +821,29 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |||
811 | { WAKE_ANY, Config5, LanWake } | 821 | { WAKE_ANY, Config5, LanWake } |
812 | }; | 822 | }; |
813 | 823 | ||
814 | spin_lock_irq(&tp->lock); | ||
815 | |||
816 | RTL_W8(Cfg9346, Cfg9346_Unlock); | 824 | RTL_W8(Cfg9346, Cfg9346_Unlock); |
817 | 825 | ||
818 | for (i = 0; i < ARRAY_SIZE(cfg); i++) { | 826 | for (i = 0; i < ARRAY_SIZE(cfg); i++) { |
819 | u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask; | 827 | u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask; |
820 | if (wol->wolopts & cfg[i].opt) | 828 | if (wolopts & cfg[i].opt) |
821 | options |= cfg[i].mask; | 829 | options |= cfg[i].mask; |
822 | RTL_W8(cfg[i].reg, options); | 830 | RTL_W8(cfg[i].reg, options); |
823 | } | 831 | } |
824 | 832 | ||
825 | RTL_W8(Cfg9346, Cfg9346_Lock); | 833 | RTL_W8(Cfg9346, Cfg9346_Lock); |
834 | } | ||
835 | |||
836 | static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
837 | { | ||
838 | struct rtl8169_private *tp = netdev_priv(dev); | ||
839 | |||
840 | spin_lock_irq(&tp->lock); | ||
826 | 841 | ||
827 | if (wol->wolopts) | 842 | if (wol->wolopts) |
828 | tp->features |= RTL_FEATURE_WOL; | 843 | tp->features |= RTL_FEATURE_WOL; |
829 | else | 844 | else |
830 | tp->features &= ~RTL_FEATURE_WOL; | 845 | tp->features &= ~RTL_FEATURE_WOL; |
846 | __rtl8169_set_wol(tp, wol->wolopts); | ||
831 | device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts); | 847 | device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts); |
832 | 848 | ||
833 | spin_unlock_irq(&tp->lock); | 849 | spin_unlock_irq(&tp->lock); |
@@ -3192,6 +3208,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3192 | 3208 | ||
3193 | device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL); | 3209 | device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL); |
3194 | 3210 | ||
3211 | if (pci_dev_run_wake(pdev)) { | ||
3212 | pm_runtime_set_active(&pdev->dev); | ||
3213 | pm_runtime_enable(&pdev->dev); | ||
3214 | } | ||
3215 | pm_runtime_idle(&pdev->dev); | ||
3216 | |||
3195 | out: | 3217 | out: |
3196 | return rc; | 3218 | return rc; |
3197 | 3219 | ||
@@ -3213,10 +3235,18 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) | |||
3213 | struct net_device *dev = pci_get_drvdata(pdev); | 3235 | struct net_device *dev = pci_get_drvdata(pdev); |
3214 | struct rtl8169_private *tp = netdev_priv(dev); | 3236 | struct rtl8169_private *tp = netdev_priv(dev); |
3215 | 3237 | ||
3238 | pm_runtime_get_sync(&pdev->dev); | ||
3239 | |||
3216 | flush_scheduled_work(); | 3240 | flush_scheduled_work(); |
3217 | 3241 | ||
3218 | unregister_netdev(dev); | 3242 | unregister_netdev(dev); |
3219 | 3243 | ||
3244 | if (pci_dev_run_wake(pdev)) { | ||
3245 | pm_runtime_disable(&pdev->dev); | ||
3246 | pm_runtime_set_suspended(&pdev->dev); | ||
3247 | } | ||
3248 | pm_runtime_put_noidle(&pdev->dev); | ||
3249 | |||
3220 | /* restore original MAC address */ | 3250 | /* restore original MAC address */ |
3221 | rtl_rar_set(tp, dev->perm_addr); | 3251 | rtl_rar_set(tp, dev->perm_addr); |
3222 | 3252 | ||
@@ -3243,6 +3273,7 @@ static int rtl8169_open(struct net_device *dev) | |||
3243 | struct pci_dev *pdev = tp->pci_dev; | 3273 | struct pci_dev *pdev = tp->pci_dev; |
3244 | int retval = -ENOMEM; | 3274 | int retval = -ENOMEM; |
3245 | 3275 | ||
3276 | pm_runtime_get_sync(&pdev->dev); | ||
3246 | 3277 | ||
3247 | /* | 3278 | /* |
3248 | * Note that we use a magic value here, its wierd I know | 3279 | * Note that we use a magic value here, its wierd I know |
@@ -3263,7 +3294,7 @@ static int rtl8169_open(struct net_device *dev) | |||
3263 | tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, | 3294 | tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, |
3264 | &tp->TxPhyAddr); | 3295 | &tp->TxPhyAddr); |
3265 | if (!tp->TxDescArray) | 3296 | if (!tp->TxDescArray) |
3266 | goto out; | 3297 | goto err_pm_runtime_put; |
3267 | 3298 | ||
3268 | tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, | 3299 | tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, |
3269 | &tp->RxPhyAddr); | 3300 | &tp->RxPhyAddr); |
@@ -3290,6 +3321,9 @@ static int rtl8169_open(struct net_device *dev) | |||
3290 | 3321 | ||
3291 | rtl8169_request_timer(dev); | 3322 | rtl8169_request_timer(dev); |
3292 | 3323 | ||
3324 | tp->saved_wolopts = 0; | ||
3325 | pm_runtime_put_noidle(&pdev->dev); | ||
3326 | |||
3293 | rtl8169_check_link_status(dev, tp, tp->mmio_addr); | 3327 | rtl8169_check_link_status(dev, tp, tp->mmio_addr); |
3294 | out: | 3328 | out: |
3295 | return retval; | 3329 | return retval; |
@@ -3299,9 +3333,13 @@ err_release_ring_2: | |||
3299 | err_free_rx_1: | 3333 | err_free_rx_1: |
3300 | pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, | 3334 | pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, |
3301 | tp->RxPhyAddr); | 3335 | tp->RxPhyAddr); |
3336 | tp->RxDescArray = NULL; | ||
3302 | err_free_tx_0: | 3337 | err_free_tx_0: |
3303 | pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, | 3338 | pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, |
3304 | tp->TxPhyAddr); | 3339 | tp->TxPhyAddr); |
3340 | tp->TxDescArray = NULL; | ||
3341 | err_pm_runtime_put: | ||
3342 | pm_runtime_put_noidle(&pdev->dev); | ||
3305 | goto out; | 3343 | goto out; |
3306 | } | 3344 | } |
3307 | 3345 | ||
@@ -4720,6 +4758,8 @@ static int rtl8169_close(struct net_device *dev) | |||
4720 | struct rtl8169_private *tp = netdev_priv(dev); | 4758 | struct rtl8169_private *tp = netdev_priv(dev); |
4721 | struct pci_dev *pdev = tp->pci_dev; | 4759 | struct pci_dev *pdev = tp->pci_dev; |
4722 | 4760 | ||
4761 | pm_runtime_get_sync(&pdev->dev); | ||
4762 | |||
4723 | /* update counters before going down */ | 4763 | /* update counters before going down */ |
4724 | rtl8169_update_counters(dev); | 4764 | rtl8169_update_counters(dev); |
4725 | 4765 | ||
@@ -4734,6 +4774,8 @@ static int rtl8169_close(struct net_device *dev) | |||
4734 | tp->TxDescArray = NULL; | 4774 | tp->TxDescArray = NULL; |
4735 | tp->RxDescArray = NULL; | 4775 | tp->RxDescArray = NULL; |
4736 | 4776 | ||
4777 | pm_runtime_put_sync(&pdev->dev); | ||
4778 | |||
4737 | return 0; | 4779 | return 0; |
4738 | } | 4780 | } |
4739 | 4781 | ||
@@ -4759,12 +4801,12 @@ static void rtl_set_rx_mode(struct net_device *dev) | |||
4759 | rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; | 4801 | rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; |
4760 | mc_filter[1] = mc_filter[0] = 0xffffffff; | 4802 | mc_filter[1] = mc_filter[0] = 0xffffffff; |
4761 | } else { | 4803 | } else { |
4762 | struct dev_mc_list *mclist; | 4804 | struct netdev_hw_addr *ha; |
4763 | 4805 | ||
4764 | rx_mode = AcceptBroadcast | AcceptMyPhys; | 4806 | rx_mode = AcceptBroadcast | AcceptMyPhys; |
4765 | mc_filter[1] = mc_filter[0] = 0; | 4807 | mc_filter[1] = mc_filter[0] = 0; |
4766 | netdev_for_each_mc_addr(mclist, dev) { | 4808 | netdev_for_each_mc_addr(ha, dev) { |
4767 | int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; | 4809 | int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; |
4768 | mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); | 4810 | mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); |
4769 | rx_mode |= AcceptMulticast; | 4811 | rx_mode |= AcceptMulticast; |
4770 | } | 4812 | } |
@@ -4832,21 +4874,74 @@ static int rtl8169_suspend(struct device *device) | |||
4832 | return 0; | 4874 | return 0; |
4833 | } | 4875 | } |
4834 | 4876 | ||
4877 | static void __rtl8169_resume(struct net_device *dev) | ||
4878 | { | ||
4879 | netif_device_attach(dev); | ||
4880 | rtl8169_schedule_work(dev, rtl8169_reset_task); | ||
4881 | } | ||
4882 | |||
4835 | static int rtl8169_resume(struct device *device) | 4883 | static int rtl8169_resume(struct device *device) |
4836 | { | 4884 | { |
4837 | struct pci_dev *pdev = to_pci_dev(device); | 4885 | struct pci_dev *pdev = to_pci_dev(device); |
4838 | struct net_device *dev = pci_get_drvdata(pdev); | 4886 | struct net_device *dev = pci_get_drvdata(pdev); |
4839 | 4887 | ||
4840 | if (!netif_running(dev)) | 4888 | if (netif_running(dev)) |
4841 | goto out; | 4889 | __rtl8169_resume(dev); |
4842 | 4890 | ||
4843 | netif_device_attach(dev); | 4891 | return 0; |
4892 | } | ||
4893 | |||
4894 | static int rtl8169_runtime_suspend(struct device *device) | ||
4895 | { | ||
4896 | struct pci_dev *pdev = to_pci_dev(device); | ||
4897 | struct net_device *dev = pci_get_drvdata(pdev); | ||
4898 | struct rtl8169_private *tp = netdev_priv(dev); | ||
4899 | |||
4900 | if (!tp->TxDescArray) | ||
4901 | return 0; | ||
4902 | |||
4903 | spin_lock_irq(&tp->lock); | ||
4904 | tp->saved_wolopts = __rtl8169_get_wol(tp); | ||
4905 | __rtl8169_set_wol(tp, WAKE_ANY); | ||
4906 | spin_unlock_irq(&tp->lock); | ||
4907 | |||
4908 | rtl8169_net_suspend(dev); | ||
4909 | |||
4910 | return 0; | ||
4911 | } | ||
4912 | |||
4913 | static int rtl8169_runtime_resume(struct device *device) | ||
4914 | { | ||
4915 | struct pci_dev *pdev = to_pci_dev(device); | ||
4916 | struct net_device *dev = pci_get_drvdata(pdev); | ||
4917 | struct rtl8169_private *tp = netdev_priv(dev); | ||
4918 | |||
4919 | if (!tp->TxDescArray) | ||
4920 | return 0; | ||
4921 | |||
4922 | spin_lock_irq(&tp->lock); | ||
4923 | __rtl8169_set_wol(tp, tp->saved_wolopts); | ||
4924 | tp->saved_wolopts = 0; | ||
4925 | spin_unlock_irq(&tp->lock); | ||
4926 | |||
4927 | __rtl8169_resume(dev); | ||
4844 | 4928 | ||
4845 | rtl8169_schedule_work(dev, rtl8169_reset_task); | ||
4846 | out: | ||
4847 | return 0; | 4929 | return 0; |
4848 | } | 4930 | } |
4849 | 4931 | ||
4932 | static int rtl8169_runtime_idle(struct device *device) | ||
4933 | { | ||
4934 | struct pci_dev *pdev = to_pci_dev(device); | ||
4935 | struct net_device *dev = pci_get_drvdata(pdev); | ||
4936 | struct rtl8169_private *tp = netdev_priv(dev); | ||
4937 | |||
4938 | if (!tp->TxDescArray) | ||
4939 | return 0; | ||
4940 | |||
4941 | rtl8169_check_link_status(dev, tp, tp->mmio_addr); | ||
4942 | return -EBUSY; | ||
4943 | } | ||
4944 | |||
4850 | static const struct dev_pm_ops rtl8169_pm_ops = { | 4945 | static const struct dev_pm_ops rtl8169_pm_ops = { |
4851 | .suspend = rtl8169_suspend, | 4946 | .suspend = rtl8169_suspend, |
4852 | .resume = rtl8169_resume, | 4947 | .resume = rtl8169_resume, |
@@ -4854,6 +4949,9 @@ static const struct dev_pm_ops rtl8169_pm_ops = { | |||
4854 | .thaw = rtl8169_resume, | 4949 | .thaw = rtl8169_resume, |
4855 | .poweroff = rtl8169_suspend, | 4950 | .poweroff = rtl8169_suspend, |
4856 | .restore = rtl8169_resume, | 4951 | .restore = rtl8169_resume, |
4952 | .runtime_suspend = rtl8169_runtime_suspend, | ||
4953 | .runtime_resume = rtl8169_runtime_resume, | ||
4954 | .runtime_idle = rtl8169_runtime_idle, | ||
4857 | }; | 4955 | }; |
4858 | 4956 | ||
4859 | #define RTL8169_PM_OPS (&rtl8169_pm_ops) | 4957 | #define RTL8169_PM_OPS (&rtl8169_pm_ops) |