All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Rafael J. Wysocki" <rjw@sisk.pl>
To: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Matthew Garrett <mjg@redhat.com>, Len Brown <lenb@kernel.org>,
	LKML <linux-kernel@vger.kernel.org>,
	pm list <linux-pm@lists.linux-foundation.org>,
	Alan Stern <stern@rowland.harvard.edu>,
	ACPI Devel Maling List <linux-acpi@vger.kernel.org>,
	Linux PCI <linux-pci@vger.kernel.org>,
	Oliver Neukum <oliver@neukum.org>,
	Bjorn Helgaas <bjorn.helgaas@hp.com>,
	Shaohua Li <shaohua.li@intel.com>,
	Francois Romieu <romieu@fr.zoreil.com>
Subject: [PATCH 12/12] PM / r8169: Add simplified run-time PM support
Date: Sun, 27 Dec 2009 21:11:41 +0100	[thread overview]
Message-ID: <200912272111.41728.rjw@sisk.pl> (raw)
In-Reply-To: <200912272057.10443.rjw@sisk.pl>

From: Rafael J. Wysocki <rjw@sisk.pl>

Use the PCI run-time power management framework to add simplified
run-time PM support to the r8169 driver.  Namely, make the driver
suspend the device when the link is off and set it up for generating
wake-up event after the link has been detected again.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
The patch is still missing an important part, which is that the driver should
turn the power management on as soon as it's probed, not only after someone
calls open() on it.  Nevertheless, the patch is fully functional in this form.

Rafael
---
 drivers/net/r8169.c |  135 +++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 108 insertions(+), 27 deletions(-)

Index: linux-2.6/drivers/net/r8169.c
===================================================================
--- linux-2.6.orig/drivers/net/r8169.c
+++ linux-2.6/drivers/net/r8169.c
@@ -23,6 +23,7 @@
 #include <linux/tcp.h>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -504,6 +505,8 @@ struct rtl8169_private {
 
 	struct mii_if_info mii;
 	struct rtl8169_counters counters;
+	u32 saved_wolopts;
+	bool exiting;
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -743,6 +746,8 @@ static void rtl8169_check_link_status(st
 
 	spin_lock_irqsave(&tp->lock, flags);
 	if (tp->link_ok(ioaddr)) {
+		/* This is to cancel a scheduled suspend if there's one. */
+		pm_request_resume(&tp->pci_dev->dev);
 		netif_carrier_on(dev);
 		if (netif_msg_ifup(tp))
 			printk(KERN_INFO PFX "%s: link up\n", dev->name);
@@ -750,48 +755,54 @@ static void rtl8169_check_link_status(st
 		if (netif_msg_ifdown(tp))
 			printk(KERN_INFO PFX "%s: link down\n", dev->name);
 		netif_carrier_off(dev);
+		pm_schedule_suspend(&tp->pci_dev->dev, 100);
 	}
 	spin_unlock_irqrestore(&tp->lock, flags);
 }
 
-static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
+
+static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
 {
-	struct rtl8169_private *tp = netdev_priv(dev);
 	void __iomem *ioaddr = tp->mmio_addr;
 	u8 options;
-
-	wol->wolopts = 0;
-
-#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
-	wol->supported = WAKE_ANY;
-
-	spin_lock_irq(&tp->lock);
+	u32 wolopts = 0;
 
 	options = RTL_R8(Config1);
 	if (!(options & PMEnable))
-		goto out_unlock;
+		return 0;
 
 	options = RTL_R8(Config3);
 	if (options & LinkUp)
-		wol->wolopts |= WAKE_PHY;
+		wolopts |= WAKE_PHY;
 	if (options & MagicPacket)
-		wol->wolopts |= WAKE_MAGIC;
+		wolopts |= WAKE_MAGIC;
 
 	options = RTL_R8(Config5);
 	if (options & UWF)
-		wol->wolopts |= WAKE_UCAST;
+		wolopts |= WAKE_UCAST;
 	if (options & BWF)
-		wol->wolopts |= WAKE_BCAST;
+		wolopts |= WAKE_BCAST;
 	if (options & MWF)
-		wol->wolopts |= WAKE_MCAST;
+		wolopts |= WAKE_MCAST;
 
-out_unlock:
-	spin_unlock_irq(&tp->lock);
+	return wolopts;
 }
 
-static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
+
+	spin_lock_irq(&tp->lock);
+
+	wol->supported = WAKE_ANY;
+	wol->wolopts = __rtl8169_get_wol(tp);
+
+	spin_unlock_irq(&tp->lock);
+}
+
+static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
+{
 	void __iomem *ioaddr = tp->mmio_addr;
 	unsigned int i;
 	static const struct {
@@ -808,23 +819,29 @@ static int rtl8169_set_wol(struct net_de
 		{ WAKE_ANY,   Config5, LanWake }
 	};
 
-	spin_lock_irq(&tp->lock);
-
 	RTL_W8(Cfg9346, Cfg9346_Unlock);
 
 	for (i = 0; i < ARRAY_SIZE(cfg); i++) {
 		u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
-		if (wol->wolopts & cfg[i].opt)
+		if (wolopts & cfg[i].opt)
 			options |= cfg[i].mask;
 		RTL_W8(cfg[i].reg, options);
 	}
 
 	RTL_W8(Cfg9346, Cfg9346_Lock);
+}
+
+static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+
+	spin_lock_irq(&tp->lock);
 
 	if (wol->wolopts)
 		tp->features |= RTL_FEATURE_WOL;
 	else
 		tp->features &= ~RTL_FEATURE_WOL;
+	__rtl8169_set_wol(tp, wol->wolopts);
 	device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
 
 	spin_unlock_irq(&tp->lock);
@@ -3000,6 +3017,7 @@ rtl8169_init_one(struct pci_dev *pdev, c
 	tp->dev = dev;
 	tp->pci_dev = pdev;
 	tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
+	tp->exiting = false;
 
 	mii = &tp->mii;
 	mii->dev = dev;
@@ -3232,6 +3250,8 @@ static void __devexit rtl8169_remove_one
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct rtl8169_private *tp = netdev_priv(dev);
 
+	tp->exiting = true;
+
 	flush_scheduled_work();
 
 	unregister_netdev(dev);
@@ -3258,7 +3278,6 @@ static int rtl8169_open(struct net_devic
 	struct pci_dev *pdev = tp->pci_dev;
 	int retval = -ENOMEM;
 
-
 	rtl8169_set_rxbufsize(tp, dev);
 
 	/*
@@ -3295,6 +3314,13 @@ static int rtl8169_open(struct net_devic
 
 	rtl8169_request_timer(dev);
 
+	tp->saved_wolopts = 0;
+
+	if (pci_dev_run_wake(pdev)) {
+		pm_runtime_set_active(&pdev->dev);
+		pm_runtime_enable(&pdev->dev);
+	}
+
 	rtl8169_check_link_status(dev, tp, tp->mmio_addr);
 out:
 	return retval;
@@ -4727,6 +4753,14 @@ static int rtl8169_close(struct net_devi
 	struct rtl8169_private *tp = netdev_priv(dev);
 	struct pci_dev *pdev = tp->pci_dev;
 
+	if (pci_dev_run_wake(pdev)) {
+		pm_runtime_get_noresume(&pdev->dev);
+		pm_runtime_resume(&pdev->dev);
+		pm_runtime_disable(&pdev->dev);
+		pm_runtime_set_suspended(&pdev->dev);
+		pm_runtime_put_noidle(&pdev->dev);
+	}
+
 	/* update counters before going down */
 	rtl8169_update_counters(dev);
 
@@ -4844,21 +4878,65 @@ static int rtl8169_suspend(struct device
 	return 0;
 }
 
+static void __rtl8169_resume(struct net_device *dev)
+{
+	netif_device_attach(dev);
+	rtl8169_schedule_work(dev, rtl8169_reset_task);
+}
+
 static int rtl8169_resume(struct device *device)
 {
 	struct pci_dev *pdev = to_pci_dev(device);
 	struct net_device *dev = pci_get_drvdata(pdev);
 
-	if (!netif_running(dev))
-		goto out;
+	if (netif_running(dev))
+		__rtl8169_resume(dev);
 
-	netif_device_attach(dev);
+	return 0;
+}
+
+static int rtl8169_runtime_suspend(struct device *device)
+{
+	struct pci_dev *pdev = to_pci_dev(device);
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct rtl8169_private *tp = netdev_priv(dev);
+
+	dev_dbg(&pdev->dev, "suspending\n");
+
+	spin_lock_irq(&tp->lock);
+	tp->saved_wolopts = __rtl8169_get_wol(tp);
+	__rtl8169_set_wol(tp, WAKE_ANY);
+	spin_unlock_irq(&tp->lock);
+
+	rtl8169_net_suspend(dev);
+
+	return 0;
+}
+
+static int rtl8169_runtime_resume(struct device *device)
+{
+	struct pci_dev *pdev = to_pci_dev(device);
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct rtl8169_private *tp = netdev_priv(dev);
+
+	dev_dbg(&pdev->dev, "resuming\n");
+
+	spin_lock_irq(&tp->lock);
+	__rtl8169_set_wol(tp, tp->saved_wolopts);
+	tp->saved_wolopts = 0;
+	spin_unlock_irq(&tp->lock);
+
+	if (!tp->exiting)
+		__rtl8169_resume(dev);
 
-	rtl8169_schedule_work(dev, rtl8169_reset_task);
-out:
 	return 0;
 }
 
+static int rtl8169_runtime_idle(struct device *device)
+{
+	return -EBUSY;
+}
+
 static const struct dev_pm_ops rtl8169_pm_ops = {
 	.suspend = rtl8169_suspend,
 	.resume = rtl8169_resume,
@@ -4866,6 +4944,9 @@ static const struct dev_pm_ops rtl8169_p
 	.thaw = rtl8169_resume,
 	.poweroff = rtl8169_suspend,
 	.restore = rtl8169_resume,
+	.runtime_suspend = rtl8169_runtime_suspend,
+	.runtime_resume = rtl8169_runtime_resume,
+	.runtime_idle = rtl8169_runtime_idle,
 };
 
 #define RTL8169_PM_OPS	(&rtl8169_pm_ops)

  parent reply	other threads:[~2009-12-27 20:11 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-12-27 19:57 [PATCH 0/12] PCI run-time PM support (rev. 2) Rafael J. Wysocki
2009-12-27 19:59 ` [PATCH 1/12] PCI PM: Add function for checking PME status of devices Rafael J. Wysocki
2009-12-27 19:59   ` Rafael J. Wysocki
2010-01-06 21:46   ` Jesse Barnes
2010-01-06 21:46   ` Jesse Barnes
2009-12-27 20:00 ` [PATCH 2/12] PCI / PM: Propagate wake-up enable for PCIe devices too Rafael J. Wysocki
2010-01-04 23:40   ` Jesse Barnes
2010-01-05 21:27     ` Rafael J. Wysocki
2010-01-05 21:27     ` Rafael J. Wysocki
2010-01-04 23:40   ` Jesse Barnes
2009-12-27 20:00 ` Rafael J. Wysocki
2009-12-27 20:01 ` [PATCH 3/12] PCI PM: PCIe PME root port service driver (rev. 5) Rafael J. Wysocki
2009-12-27 20:01 ` Rafael J. Wysocki
2010-01-06 21:53   ` Jesse Barnes
2010-01-06 21:53   ` Jesse Barnes
2009-12-27 20:02 ` [PATCH 4/12] PCI PM: Make it possible to force using INTx for PCIe PME signaling Rafael J. Wysocki
2009-12-27 20:02   ` Rafael J. Wysocki
2010-01-06 21:56   ` Jesse Barnes
2010-01-06 21:56   ` Jesse Barnes
2010-01-06 22:02     ` Matthew Garrett
2010-01-06 23:00       ` Rafael J. Wysocki
2010-01-06 23:00       ` Rafael J. Wysocki
2010-01-08 20:08         ` Len Brown
2010-01-08 20:25           ` Greg KH
2010-01-08 20:25           ` Greg KH
2010-01-08 20:08         ` Len Brown
2010-01-06 22:02     ` Matthew Garrett
2009-12-27 20:03 ` [PATCH 5/12] ACPI: Add infrastructure for refcounting GPE consumers Rafael J. Wysocki
2009-12-27 20:03 ` Rafael J. Wysocki
2009-12-27 20:03 ` [PATCH 6/12] ACPI: Add support for new refcounted GPE API to drivers Rafael J. Wysocki
2009-12-27 20:03   ` Rafael J. Wysocki
2009-12-27 20:04 ` [PATCH 7/12] ACPI: Remove old GPE API and transition code entirely to new one Rafael J. Wysocki
2009-12-27 20:04 ` Rafael J. Wysocki
2009-12-27 20:05 ` [PATCH 8/12] ACPI / PM: Add more run-time wake-up fields Rafael J. Wysocki
2010-01-08 20:39   ` Len Brown
2010-01-08 23:27     ` Rafael J. Wysocki
2010-01-08 23:27     ` Rafael J. Wysocki
2010-01-08 20:39   ` Len Brown
2009-12-27 20:05 ` Rafael J. Wysocki
2009-12-27 20:06 ` [PATCH 9/12] ACPI / PM: Introduce acpi_pm_wakeup_power() Rafael J. Wysocki
2010-01-06 22:00   ` Jesse Barnes
2010-01-06 23:11     ` Rafael J. Wysocki
2010-01-06 23:11     ` Rafael J. Wysocki
2010-01-07 21:11       ` Rafael J. Wysocki
2010-01-07 21:11       ` Rafael J. Wysocki
2010-01-06 22:00   ` Jesse Barnes
2009-12-27 20:06 ` Rafael J. Wysocki
2009-12-27 20:07 ` [PATCH 10/12] PCI / ACPI / PM: Platform support for PCI PME wake-up (rev. 6) Rafael J. Wysocki
2010-01-06 22:04   ` Jesse Barnes
2010-01-07 21:18     ` Rafael J. Wysocki
2010-01-07 21:18     ` Rafael J. Wysocki
2010-01-06 22:04   ` Jesse Barnes
2009-12-27 20:07 ` Rafael J. Wysocki
2009-12-27 20:08 ` [PATCH 11/12] PCI PM: Run-time callbacks for PCI bus type (rev. 2) Rafael J. Wysocki
2009-12-27 20:08 ` Rafael J. Wysocki
2010-01-06 22:06   ` Jesse Barnes
2010-01-06 22:06   ` Jesse Barnes
2009-12-27 20:11 ` [PATCH 12/12] PM / r8169: Add simplified run-time PM support Rafael J. Wysocki
2009-12-27 20:11 ` Rafael J. Wysocki [this message]
2010-01-01 19:06   ` [PATCH 12/12] PM / r8169: Add simplified run-time PM support (rev. 2) Rafael J. Wysocki
2010-01-01 19:06   ` Rafael J. Wysocki
2010-01-01  1:29 ` [PATCH][RFC] e1000e: Add basic runtime PM support (was: [PATCH 0/12] PCI run-time PM support (rev. 2)) Rafael J. Wysocki
2010-01-01  1:29 ` Rafael J. Wysocki
2010-01-01  1:29   ` Rafael J. Wysocki
2010-01-01 19:03   ` [PATCH][RFC] e1000e: Add basic runtime PM support (rev. 2) " Rafael J. Wysocki
2010-01-01 21:51     ` [PATCH][RFC] e1000e: Add basic runtime PM support (rev. 3) " Rafael J. Wysocki
2010-01-01 21:51     ` Rafael J. Wysocki
2010-01-01 19:03   ` [PATCH][RFC] e1000e: Add basic runtime PM support (rev. 2) " Rafael J. Wysocki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200912272111.41728.rjw@sisk.pl \
    --to=rjw@sisk.pl \
    --cc=bjorn.helgaas@hp.com \
    --cc=jbarnes@virtuousgeek.org \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-pm@lists.linux-foundation.org \
    --cc=mjg@redhat.com \
    --cc=oliver@neukum.org \
    --cc=romieu@fr.zoreil.com \
    --cc=shaohua.li@intel.com \
    --cc=stern@rowland.harvard.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.