diff options
-rw-r--r-- | drivers/net/r8169.c | 152 |
1 files changed, 125 insertions, 27 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 9d3ebf3e975e..964305c7f9f1 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> |
@@ -504,6 +505,7 @@ struct rtl8169_private { | |||
504 | 505 | ||
505 | struct mii_if_info mii; | 506 | struct mii_if_info mii; |
506 | struct rtl8169_counters counters; | 507 | struct rtl8169_counters counters; |
508 | u32 saved_wolopts; | ||
507 | }; | 509 | }; |
508 | 510 | ||
509 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); | 511 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); |
@@ -744,53 +746,61 @@ static void rtl8169_check_link_status(struct net_device *dev, | |||
744 | 746 | ||
745 | spin_lock_irqsave(&tp->lock, flags); | 747 | spin_lock_irqsave(&tp->lock, flags); |
746 | if (tp->link_ok(ioaddr)) { | 748 | if (tp->link_ok(ioaddr)) { |
749 | /* This is to cancel a scheduled suspend if there's one. */ | ||
750 | pm_request_resume(&tp->pci_dev->dev); | ||
747 | netif_carrier_on(dev); | 751 | netif_carrier_on(dev); |
748 | netif_info(tp, ifup, dev, "link up\n"); | 752 | netif_info(tp, ifup, dev, "link up\n"); |
749 | } else { | 753 | } else { |
750 | netif_carrier_off(dev); | 754 | netif_carrier_off(dev); |
751 | netif_info(tp, ifdown, dev, "link down\n"); | 755 | netif_info(tp, ifdown, dev, "link down\n"); |
756 | pm_schedule_suspend(&tp->pci_dev->dev, 100); | ||
752 | } | 757 | } |
753 | spin_unlock_irqrestore(&tp->lock, flags); | 758 | spin_unlock_irqrestore(&tp->lock, flags); |
754 | } | 759 | } |
755 | 760 | ||
756 | static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | 761 | #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) |
762 | |||
763 | static u32 __rtl8169_get_wol(struct rtl8169_private *tp) | ||
757 | { | 764 | { |
758 | struct rtl8169_private *tp = netdev_priv(dev); | ||
759 | void __iomem *ioaddr = tp->mmio_addr; | 765 | void __iomem *ioaddr = tp->mmio_addr; |
760 | u8 options; | 766 | u8 options; |
761 | 767 | u32 wolopts = 0; | |
762 | wol->wolopts = 0; | ||
763 | |||
764 | #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) | ||
765 | wol->supported = WAKE_ANY; | ||
766 | |||
767 | spin_lock_irq(&tp->lock); | ||
768 | 768 | ||
769 | options = RTL_R8(Config1); | 769 | options = RTL_R8(Config1); |
770 | if (!(options & PMEnable)) | 770 | if (!(options & PMEnable)) |
771 | goto out_unlock; | 771 | return 0; |
772 | 772 | ||
773 | options = RTL_R8(Config3); | 773 | options = RTL_R8(Config3); |
774 | if (options & LinkUp) | 774 | if (options & LinkUp) |
775 | wol->wolopts |= WAKE_PHY; | 775 | wolopts |= WAKE_PHY; |
776 | if (options & MagicPacket) | 776 | if (options & MagicPacket) |
777 | wol->wolopts |= WAKE_MAGIC; | 777 | wolopts |= WAKE_MAGIC; |
778 | 778 | ||
779 | options = RTL_R8(Config5); | 779 | options = RTL_R8(Config5); |
780 | if (options & UWF) | 780 | if (options & UWF) |
781 | wol->wolopts |= WAKE_UCAST; | 781 | wolopts |= WAKE_UCAST; |
782 | if (options & BWF) | 782 | if (options & BWF) |
783 | wol->wolopts |= WAKE_BCAST; | 783 | wolopts |= WAKE_BCAST; |
784 | if (options & MWF) | 784 | if (options & MWF) |
785 | wol->wolopts |= WAKE_MCAST; | 785 | wolopts |= WAKE_MCAST; |
786 | 786 | ||
787 | out_unlock: | 787 | return wolopts; |
788 | spin_unlock_irq(&tp->lock); | ||
789 | } | 788 | } |
790 | 789 | ||
791 | static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | 790 | static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
792 | { | 791 | { |
793 | struct rtl8169_private *tp = netdev_priv(dev); | 792 | struct rtl8169_private *tp = netdev_priv(dev); |
793 | |||
794 | spin_lock_irq(&tp->lock); | ||
795 | |||
796 | wol->supported = WAKE_ANY; | ||
797 | wol->wolopts = __rtl8169_get_wol(tp); | ||
798 | |||
799 | spin_unlock_irq(&tp->lock); | ||
800 | } | ||
801 | |||
802 | static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) | ||
803 | { | ||
794 | void __iomem *ioaddr = tp->mmio_addr; | 804 | void __iomem *ioaddr = tp->mmio_addr; |
795 | unsigned int i; | 805 | unsigned int i; |
796 | static const struct { | 806 | static const struct { |
@@ -807,23 +817,29 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |||
807 | { WAKE_ANY, Config5, LanWake } | 817 | { WAKE_ANY, Config5, LanWake } |
808 | }; | 818 | }; |
809 | 819 | ||
810 | spin_lock_irq(&tp->lock); | ||
811 | |||
812 | RTL_W8(Cfg9346, Cfg9346_Unlock); | 820 | RTL_W8(Cfg9346, Cfg9346_Unlock); |
813 | 821 | ||
814 | for (i = 0; i < ARRAY_SIZE(cfg); i++) { | 822 | for (i = 0; i < ARRAY_SIZE(cfg); i++) { |
815 | u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask; | 823 | u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask; |
816 | if (wol->wolopts & cfg[i].opt) | 824 | if (wolopts & cfg[i].opt) |
817 | options |= cfg[i].mask; | 825 | options |= cfg[i].mask; |
818 | RTL_W8(cfg[i].reg, options); | 826 | RTL_W8(cfg[i].reg, options); |
819 | } | 827 | } |
820 | 828 | ||
821 | RTL_W8(Cfg9346, Cfg9346_Lock); | 829 | RTL_W8(Cfg9346, Cfg9346_Lock); |
830 | } | ||
831 | |||
832 | static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
833 | { | ||
834 | struct rtl8169_private *tp = netdev_priv(dev); | ||
835 | |||
836 | spin_lock_irq(&tp->lock); | ||
822 | 837 | ||
823 | if (wol->wolopts) | 838 | if (wol->wolopts) |
824 | tp->features |= RTL_FEATURE_WOL; | 839 | tp->features |= RTL_FEATURE_WOL; |
825 | else | 840 | else |
826 | tp->features &= ~RTL_FEATURE_WOL; | 841 | tp->features &= ~RTL_FEATURE_WOL; |
842 | __rtl8169_set_wol(tp, wol->wolopts); | ||
827 | device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts); | 843 | device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts); |
828 | 844 | ||
829 | spin_unlock_irq(&tp->lock); | 845 | spin_unlock_irq(&tp->lock); |
@@ -3189,6 +3205,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3189 | 3205 | ||
3190 | device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL); | 3206 | device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL); |
3191 | 3207 | ||
3208 | if (pci_dev_run_wake(pdev)) { | ||
3209 | pm_runtime_set_active(&pdev->dev); | ||
3210 | pm_runtime_enable(&pdev->dev); | ||
3211 | } | ||
3212 | pm_runtime_idle(&pdev->dev); | ||
3213 | |||
3192 | out: | 3214 | out: |
3193 | return rc; | 3215 | return rc; |
3194 | 3216 | ||
@@ -3211,10 +3233,18 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) | |||
3211 | struct net_device *dev = pci_get_drvdata(pdev); | 3233 | struct net_device *dev = pci_get_drvdata(pdev); |
3212 | struct rtl8169_private *tp = netdev_priv(dev); | 3234 | struct rtl8169_private *tp = netdev_priv(dev); |
3213 | 3235 | ||
3236 | pm_runtime_get_sync(&pdev->dev); | ||
3237 | |||
3214 | flush_scheduled_work(); | 3238 | flush_scheduled_work(); |
3215 | 3239 | ||
3216 | unregister_netdev(dev); | 3240 | unregister_netdev(dev); |
3217 | 3241 | ||
3242 | if (pci_dev_run_wake(pdev)) { | ||
3243 | pm_runtime_disable(&pdev->dev); | ||
3244 | pm_runtime_set_suspended(&pdev->dev); | ||
3245 | } | ||
3246 | pm_runtime_put_noidle(&pdev->dev); | ||
3247 | |||
3218 | /* restore original MAC address */ | 3248 | /* restore original MAC address */ |
3219 | rtl_rar_set(tp, dev->perm_addr); | 3249 | rtl_rar_set(tp, dev->perm_addr); |
3220 | 3250 | ||
@@ -3237,6 +3267,7 @@ static int rtl8169_open(struct net_device *dev) | |||
3237 | struct pci_dev *pdev = tp->pci_dev; | 3267 | struct pci_dev *pdev = tp->pci_dev; |
3238 | int retval = -ENOMEM; | 3268 | int retval = -ENOMEM; |
3239 | 3269 | ||
3270 | pm_runtime_get_sync(&pdev->dev); | ||
3240 | 3271 | ||
3241 | rtl8169_set_rxbufsize(tp, dev); | 3272 | rtl8169_set_rxbufsize(tp, dev); |
3242 | 3273 | ||
@@ -3247,7 +3278,7 @@ static int rtl8169_open(struct net_device *dev) | |||
3247 | tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, | 3278 | tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, |
3248 | &tp->TxPhyAddr); | 3279 | &tp->TxPhyAddr); |
3249 | if (!tp->TxDescArray) | 3280 | if (!tp->TxDescArray) |
3250 | goto out; | 3281 | goto err_pm_runtime_put; |
3251 | 3282 | ||
3252 | tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, | 3283 | tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, |
3253 | &tp->RxPhyAddr); | 3284 | &tp->RxPhyAddr); |
@@ -3274,6 +3305,9 @@ static int rtl8169_open(struct net_device *dev) | |||
3274 | 3305 | ||
3275 | rtl8169_request_timer(dev); | 3306 | rtl8169_request_timer(dev); |
3276 | 3307 | ||
3308 | tp->saved_wolopts = 0; | ||
3309 | pm_runtime_put_noidle(&pdev->dev); | ||
3310 | |||
3277 | rtl8169_check_link_status(dev, tp, tp->mmio_addr); | 3311 | rtl8169_check_link_status(dev, tp, tp->mmio_addr); |
3278 | out: | 3312 | out: |
3279 | return retval; | 3313 | return retval; |
@@ -3283,9 +3317,13 @@ err_release_ring_2: | |||
3283 | err_free_rx_1: | 3317 | err_free_rx_1: |
3284 | pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, | 3318 | pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, |
3285 | tp->RxPhyAddr); | 3319 | tp->RxPhyAddr); |
3320 | tp->RxDescArray = NULL; | ||
3286 | err_free_tx_0: | 3321 | err_free_tx_0: |
3287 | pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, | 3322 | pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, |
3288 | tp->TxPhyAddr); | 3323 | tp->TxPhyAddr); |
3324 | tp->TxDescArray = NULL; | ||
3325 | err_pm_runtime_put: | ||
3326 | pm_runtime_put_noidle(&pdev->dev); | ||
3289 | goto out; | 3327 | goto out; |
3290 | } | 3328 | } |
3291 | 3329 | ||
@@ -4692,6 +4730,8 @@ static int rtl8169_close(struct net_device *dev) | |||
4692 | struct rtl8169_private *tp = netdev_priv(dev); | 4730 | struct rtl8169_private *tp = netdev_priv(dev); |
4693 | struct pci_dev *pdev = tp->pci_dev; | 4731 | struct pci_dev *pdev = tp->pci_dev; |
4694 | 4732 | ||
4733 | pm_runtime_get_sync(&pdev->dev); | ||
4734 | |||
4695 | /* update counters before going down */ | 4735 | /* update counters before going down */ |
4696 | rtl8169_update_counters(dev); | 4736 | rtl8169_update_counters(dev); |
4697 | 4737 | ||
@@ -4706,6 +4746,8 @@ static int rtl8169_close(struct net_device *dev) | |||
4706 | tp->TxDescArray = NULL; | 4746 | tp->TxDescArray = NULL; |
4707 | tp->RxDescArray = NULL; | 4747 | tp->RxDescArray = NULL; |
4708 | 4748 | ||
4749 | pm_runtime_put_sync(&pdev->dev); | ||
4750 | |||
4709 | return 0; | 4751 | return 0; |
4710 | } | 4752 | } |
4711 | 4753 | ||
@@ -4804,21 +4846,74 @@ static int rtl8169_suspend(struct device *device) | |||
4804 | return 0; | 4846 | return 0; |
4805 | } | 4847 | } |
4806 | 4848 | ||
4849 | static void __rtl8169_resume(struct net_device *dev) | ||
4850 | { | ||
4851 | netif_device_attach(dev); | ||
4852 | rtl8169_schedule_work(dev, rtl8169_reset_task); | ||
4853 | } | ||
4854 | |||
4807 | static int rtl8169_resume(struct device *device) | 4855 | static int rtl8169_resume(struct device *device) |
4808 | { | 4856 | { |
4809 | struct pci_dev *pdev = to_pci_dev(device); | 4857 | struct pci_dev *pdev = to_pci_dev(device); |
4810 | struct net_device *dev = pci_get_drvdata(pdev); | 4858 | struct net_device *dev = pci_get_drvdata(pdev); |
4811 | 4859 | ||
4812 | if (!netif_running(dev)) | 4860 | if (netif_running(dev)) |
4813 | goto out; | 4861 | __rtl8169_resume(dev); |
4814 | 4862 | ||
4815 | netif_device_attach(dev); | 4863 | return 0; |
4864 | } | ||
4865 | |||
4866 | static int rtl8169_runtime_suspend(struct device *device) | ||
4867 | { | ||
4868 | struct pci_dev *pdev = to_pci_dev(device); | ||
4869 | struct net_device *dev = pci_get_drvdata(pdev); | ||
4870 | struct rtl8169_private *tp = netdev_priv(dev); | ||
4871 | |||
4872 | if (!tp->TxDescArray) | ||
4873 | return 0; | ||
4874 | |||
4875 | spin_lock_irq(&tp->lock); | ||
4876 | tp->saved_wolopts = __rtl8169_get_wol(tp); | ||
4877 | __rtl8169_set_wol(tp, WAKE_ANY); | ||
4878 | spin_unlock_irq(&tp->lock); | ||
4879 | |||
4880 | rtl8169_net_suspend(dev); | ||
4881 | |||
4882 | return 0; | ||
4883 | } | ||
4884 | |||
4885 | static int rtl8169_runtime_resume(struct device *device) | ||
4886 | { | ||
4887 | struct pci_dev *pdev = to_pci_dev(device); | ||
4888 | struct net_device *dev = pci_get_drvdata(pdev); | ||
4889 | struct rtl8169_private *tp = netdev_priv(dev); | ||
4890 | |||
4891 | if (!tp->TxDescArray) | ||
4892 | return 0; | ||
4893 | |||
4894 | spin_lock_irq(&tp->lock); | ||
4895 | __rtl8169_set_wol(tp, tp->saved_wolopts); | ||
4896 | tp->saved_wolopts = 0; | ||
4897 | spin_unlock_irq(&tp->lock); | ||
4898 | |||
4899 | __rtl8169_resume(dev); | ||
4816 | 4900 | ||
4817 | rtl8169_schedule_work(dev, rtl8169_reset_task); | ||
4818 | out: | ||
4819 | return 0; | 4901 | return 0; |
4820 | } | 4902 | } |
4821 | 4903 | ||
4904 | static int rtl8169_runtime_idle(struct device *device) | ||
4905 | { | ||
4906 | struct pci_dev *pdev = to_pci_dev(device); | ||
4907 | struct net_device *dev = pci_get_drvdata(pdev); | ||
4908 | struct rtl8169_private *tp = netdev_priv(dev); | ||
4909 | |||
4910 | if (!tp->TxDescArray) | ||
4911 | return 0; | ||
4912 | |||
4913 | rtl8169_check_link_status(dev, tp, tp->mmio_addr); | ||
4914 | return -EBUSY; | ||
4915 | } | ||
4916 | |||
4822 | static const struct dev_pm_ops rtl8169_pm_ops = { | 4917 | static const struct dev_pm_ops rtl8169_pm_ops = { |
4823 | .suspend = rtl8169_suspend, | 4918 | .suspend = rtl8169_suspend, |
4824 | .resume = rtl8169_resume, | 4919 | .resume = rtl8169_resume, |
@@ -4826,6 +4921,9 @@ static const struct dev_pm_ops rtl8169_pm_ops = { | |||
4826 | .thaw = rtl8169_resume, | 4921 | .thaw = rtl8169_resume, |
4827 | .poweroff = rtl8169_suspend, | 4922 | .poweroff = rtl8169_suspend, |
4828 | .restore = rtl8169_resume, | 4923 | .restore = rtl8169_resume, |
4924 | .runtime_suspend = rtl8169_runtime_suspend, | ||
4925 | .runtime_resume = rtl8169_runtime_resume, | ||
4926 | .runtime_idle = rtl8169_runtime_idle, | ||
4829 | }; | 4927 | }; |
4830 | 4928 | ||
4831 | #define RTL8169_PM_OPS (&rtl8169_pm_ops) | 4929 | #define RTL8169_PM_OPS (&rtl8169_pm_ops) |