aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/r8169.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-03-14 10:33:51 -0400
committerDavid S. Miller <davem@davemloft.net>2010-03-17 00:23:34 -0400
commite175944115db6762d3e98520c709e5a87f933c61 (patch)
treeb02c9f6128847c46a22504ee38357b4009022fc0 /drivers/net/r8169.c
parentff6e2163f28a1094fb5ca5950fe2b43c3cf6bc7a (diff)
r8169 / PCI / PM: Add simplified runtime PM support (rev. 3)
Use the PCI runtime power management framework to add basic PCI runtime PM support to the r8169 driver. Namely, make the driver suspend the device when the link is not present and set it up for generating a wakeup event after the link has been detected again. [This feature is disabled until the user space enables it with the help of the /sys/devices/.../power/contol device attribute.] Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/r8169.c')
-rw-r--r--drivers/net/r8169.c152
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
509MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); 511MODULE_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
756static 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
763static 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
787out_unlock: 787 return wolopts;
788 spin_unlock_irq(&tp->lock);
789} 788}
790 789
791static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 790static 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
802static 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
832static 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
3192out: 3214out:
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);
3278out: 3312out:
3279 return retval; 3313 return retval;
@@ -3283,9 +3317,13 @@ err_release_ring_2:
3283err_free_rx_1: 3317err_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;
3286err_free_tx_0: 3321err_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;
3325err_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
4849static void __rtl8169_resume(struct net_device *dev)
4850{
4851 netif_device_attach(dev);
4852 rtl8169_schedule_work(dev, rtl8169_reset_task);
4853}
4854
4807static int rtl8169_resume(struct device *device) 4855static 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
4866static 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
4885static 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);
4818out:
4819 return 0; 4901 return 0;
4820} 4902}
4821 4903
4904static 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
4822static const struct dev_pm_ops rtl8169_pm_ops = { 4917static 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)