All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [patch 0/3] driver model wakeup flags
@ 2005-09-13  2:23 David Brownell
  2005-09-13  2:39 ` [patch 1/3] " David Brownell
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: David Brownell @ 2005-09-13  2:23 UTC (permalink / raw
  To: linux-pm

[-- Attachment #1: Type: text/plain, Size: 1914 bytes --]

This is a refresh of the patch to add wakeup infrastructure to the
driver model, in three parts.  Comments?  Merge?

	pm-wake.patch ... adds the flags, and sysfs support
	pm-usb.patch ... usb devices use it
	pm-pci.patch ... pci devices use it

The default gives the current behavior:  wakeup is enabled on all
devices that support it.  (Assuming ACPI etc don't get in the way...)

This goes back to having the sysfs "wakeup" file be tristate.
Wakeup can be "enabled" or "disabled", and toggled from userspace.
Or it can be unavailable, value "", if the hardware doesn't support
wakeup or if no software has marked the device as supporting wakeup.

I attach a simple script I wrote to show what devices are capable
of wakeup events.  On one system, it reports wakeup allowed for
several builtin devices and a USB keyboard/hub:

  lan        on  pci0000:00/0000:00:0a.0/0000:02:01.0
  modem      on  pci0000:00/0000:00:06.1
  hub        on  pci0000:00/0000:00:02.2/usb1
  usb_host   on  pci0000:00/0000:00:02.2
  input      on  pci0000:00/0000:00:02.1/usb3/3-1/3-1.1
  hub        on  pci0000:00/0000:00:02.1/usb3/3-1
  hub        on  pci0000:00/0000:00:02.1/usb3
  usb_host   on  pci0000:00/0000:00:02.1
  hub        on  pci0000:00/0000:00:02.0/usb2
  usb_host   on  pci0000:00/0000:00:02.0
  i2c        on  pci0000:00/0000:00:01.1

On this system /proc/acpi/wakeup says

  Device  Sleep state     Status
  USB0       3            disabled
  USB1       3            disabled
  USB2       3            disabled
  MAC0       3            disabled

I'm guessing those are the 00:02.* and 02:01.0 nodes.  The hubs and
input device (USB keyboard) use USB-internal wakeups and kick the
usb_host nodes ... ACPI wouldn't know about them.  (I understand
that firewire could do the same sort of thing too.)  The I2C device
is actually SMBUS, waking up from D3hot or D3cold; I suspect that's
handled by ACPI somehow.

- Dave


[-- Attachment #2: pm-wake --]
[-- Type: application/x-shellscript, Size: 1345 bytes --]

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [patch 1/3] driver model wakeup flags
  2005-09-13  2:23 [patch 0/3] driver model wakeup flags David Brownell
@ 2005-09-13  2:39 ` David Brownell
  2005-09-13  2:39 ` [patch 2/3] usb device " David Brownell
  2005-09-13  2:48 ` [patch 3/3] pci " David Brownell
  2 siblings, 0 replies; 4+ messages in thread
From: David Brownell @ 2005-09-13  2:39 UTC (permalink / raw
  To: linux-pm

[-- Attachment #1: Type: text/plain, Size: 530 bytes --]

I think we need "wakeup" infrastructure in the driver model core,
so there's consistent support for userspace being able to

  (a) tell if the device can be a wakeup source;
  (b) change the default wakeup policy for any device.

For example, I have a USB mouse that lies about being able to
issue wakeup events, so if Linux is ever going to suspend mice
(for that save-2-Watts-with-usb-mouse-on-laptop scenario), it's
got to prevent that from happening with this one.

So this is a fairly minimal patch doing just that.

- Dave


[-- Attachment #2: pm-wake.patch --]
[-- Type: text/x-diff, Size: 5392 bytes --]

This is a refresh of an earlier patch to add "wakeup" support to the
PM core model.  This provides per-device bus-neutral control of the
use of wakeup events.

  * "struct device_pm_info" has two bits that are initialized as
    part of setting up the enclosing struct device:
      - "can_wakeup", reflecting hardware capabilities
      - "may_wakeup", the policy setting (when CONFIG_PM)

  * There's a writeable sysfs "wakeup" file, with one of two values:
      - "enabled", when the policy is to allow wakeup 
      - "disabled", when the policy is not to allow it
      - "" if the device can't currently issue wakeups

By default, wakeup is enabled on all devices that support it.  If its
driver doesn't support it ... treat it as a bug.  :)

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

--- g26.orig/include/linux/pm.h	2005-09-11 16:12:54.000000000 -0700
+++ g26/include/linux/pm.h	2005-09-12 11:45:52.000000000 -0700
@@ -219,7 +219,9 @@ typedef struct pm_message {
 
 struct dev_pm_info {
 	pm_message_t		power_state;
+	unsigned		can_wakeup:1;
 #ifdef	CONFIG_PM
+	unsigned		should_wakeup:1;
 	pm_message_t		prev_state;
 	void			* saved_state;
 	atomic_t		pm_users;
@@ -236,13 +238,35 @@ extern void device_resume(void);
 
 #ifdef CONFIG_PM
 extern int device_suspend(pm_message_t state);
-#else
+
+#define device_set_wakeup_enable(dev,val) \
+	((dev)->power.should_wakeup = !!(val))
+#define device_may_wakeup(dev) \
+	(device_can_wakeup(dev) && (dev)->power.should_wakeup)
+
+#else /* !CONFIG_PM */
+
 static inline int device_suspend(pm_message_t state)
 {
 	return 0;
 }
+
+#define device_set_wakeup_enable(dev,val)	do{}while(0)
+#define device_may_wakeup(dev)			(0)
+
 #endif
 
+/* changes to device_may_wakeup take effect on the next pm state change.
+ * by default, devices should wakeup if they can.
+ */
+#define device_can_wakeup(dev) \
+	((dev)->power.can_wakeup)
+#define device_init_wakeup(dev,val) \
+	do { \
+		device_can_wakeup(dev) = !!(val); \
+		device_set_wakeup_enable(dev,val); \
+	} while(0)
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_PM_H */
--- g26.orig/drivers/base/core.c	2005-09-11 16:12:54.000000000 -0700
+++ g26/drivers/base/core.c	2005-09-11 16:13:06.000000000 -0700
@@ -225,6 +225,7 @@ void device_initialize(struct device *de
 		   klist_children_put);
 	INIT_LIST_HEAD(&dev->dma_pools);
 	init_MUTEX(&dev->sem);
+	device_init_wakeup(dev, 0);
 }
 
 /**
--- g26.orig/drivers/base/power/sysfs.c	2005-09-11 16:12:54.000000000 -0700
+++ g26/drivers/base/power/sysfs.c	2005-09-11 16:13:06.000000000 -0700
@@ -48,8 +48,81 @@ static ssize_t state_store(struct device
 static DEVICE_ATTR(state, 0644, state_show, state_store);
 
 
+/*
+ *	wakeup - Report/change current wakeup option for device
+ *
+ *	Some devices support "wakeup" events, which are hardware signals
+ *	used to activate devices from suspended or low power states.  Such
+ *	devices have one of three values for the sysfs power/wakeup file:
+ *
+ *	 + "enabled\n" to issue the events;
+ *	 + "disabled\n" not to do so; or
+ *	 + "\n" for temporary or permanent inability to issue wakeup.
+ *
+ *	(For example, unconfigured USB devices can't issue wakeups.)
+ *
+ *	Familiar examples of devices that can issue wakeup events include
+ *	keyboards and mice (both PS2 and USB styles), power buttons, modems,
+ *	"Wake-On-LAN" Ethernet links, GPIO lines, and more.  Some events
+ *	will wake the entire system from a suspend state; others may just
+ *	wake up the device (if the system as a whole is already active).
+ *	Some wakeup events use normal IRQ lines; other use special out
+ *	of band signaling.
+ *
+ *	It is the responsibility of device drivers to enable (or disable)
+ *	wakeup signaling as part of changing device power states, respecting
+ *	the policy choices provided through the driver model.
+ *
+ *	Devices may not be able to generate wakeup events from all power
+ *	states.  Also, the events may be ignored in some configurations;
+ *	for example, they might need help from other devices that aren't
+ *	active, or which may have wakeup disabled.  Some drivers rely on
+ *	wakeup events internally (unless they are disabled), keeping
+ *	their hardware in low power modes whenever they're unused.  This
+ *	saves runtime power, without requiring system-wide sleep states.
+ */
+
+static const char enabled[] = "enabled";
+static const char disabled[] = "disabled";
+
+static ssize_t
+wake_show(struct device * dev, struct device_attribute *attr, char * buf)
+{
+	return sprintf(buf, "%s\n", device_can_wakeup(dev)
+		? (device_may_wakeup(dev) ? enabled : disabled)
+		: "");
+}
+
+static ssize_t
+wake_store(struct device * dev, struct device_attribute *attr,
+	const char * buf, size_t n)
+{
+	char *cp;
+	int len = n;
+
+	if (!device_can_wakeup(dev))
+		return -EINVAL;
+
+	cp = memchr(buf, '\n', n);
+	if (cp)
+		len = cp - buf;
+	if (len == sizeof enabled - 1
+			&& strncmp(buf, enabled, sizeof enabled - 1) == 0)
+		device_set_wakeup_enable(dev, 1);
+	else if (len == sizeof disabled - 1
+			&& strncmp(buf, disabled, sizeof disabled - 1) == 0)
+		device_set_wakeup_enable(dev, 0);
+	else
+		return -EINVAL;
+	return n;
+}
+
+static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
+
+
 static struct attribute * power_attrs[] = {
 	&dev_attr_state.attr,
+	&dev_attr_wakeup.attr,
 	NULL,
 };
 static struct attribute_group pm_attr_group = {

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [patch 2/3] usb device wakeup flags
  2005-09-13  2:23 [patch 0/3] driver model wakeup flags David Brownell
  2005-09-13  2:39 ` [patch 1/3] " David Brownell
@ 2005-09-13  2:39 ` David Brownell
  2005-09-13  2:48 ` [patch 3/3] pci " David Brownell
  2 siblings, 0 replies; 4+ messages in thread
From: David Brownell @ 2005-09-13  2:39 UTC (permalink / raw
  To: linux-pm

[-- Attachment #1: Type: text/plain, Size: 430 bytes --]

Here's a patch showing how USB can detect wakeup-capable devices,
such as hubs, keyboards, mice, and Ethernet adapters ... and use
the policy setting to enable remote wakeup only when appropriate.

There's another USB patch on the way, switching the HCDs over to
use the new driver model bits rather than the USB-only bits that
do the same thing.  I'm holding back on that till more of the
HCD level PM updates get made.

- Dave


[-- Attachment #2: pm-wake-usb.patch --]
[-- Type: text/x-diff, Size: 1901 bytes --]

This patch teaches "usb_device" about the new driver model wakeup support:

 - It updates device wakeup capabilities when entering a configuration
   with the WAKEUP attribute;

 - During suspend processing it consults the policy bit to see
   whether it should enable wakeup for that device.  (This resolves
   a FIXME to not assume the answer is always "yes"; some devices
   lie about supporting remote wakeup.)

Support for root hubs and the HCDs is separate (and more complex).

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

--- g26.orig/drivers/usb/core/hub.c	2005-09-11 18:24:17.000000000 -0700
+++ g26/drivers/usb/core/hub.c	2005-09-12 11:43:16.000000000 -0700
@@ -1020,9 +1020,15 @@ void usb_set_device_state(struct usb_dev
 	spin_lock_irqsave(&device_state_lock, flags);
 	if (udev->state == USB_STATE_NOTATTACHED)
 		;	/* do nothing */
-	else if (new_state != USB_STATE_NOTATTACHED)
+	else if (new_state != USB_STATE_NOTATTACHED) {
 		udev->state = new_state;
-	else
+		if (new_state == USB_STATE_CONFIGURED)
+			device_init_wakeup(&udev->dev,
+				(udev->actconfig->desc.bmAttributes
+				 & USB_CONFIG_ATT_WAKEUP));
+		else if (new_state != USB_STATE_SUSPENDED)
+			device_init_wakeup(&udev->dev, 0);
+	} else
 		recursively_mark_NOTATTACHED(udev);
 	spin_unlock_irqrestore(&device_state_lock, flags);
 }
@@ -1546,11 +1552,7 @@ static int hub_port_suspend(struct usb_h
 	 * NOTE:  OTG devices may issue remote wakeup (or SRP) even when
 	 * we don't explicitly enable it here.
 	 */
-	if (udev->actconfig
-			// && FIXME (remote wakeup enabled on this bus)
-			// ... currently assuming it's always appropriate
-			&& (udev->actconfig->desc.bmAttributes
-				& USB_CONFIG_ATT_WAKEUP) != 0) {
+	if (device_may_wakeup(&udev->dev)) {
 		status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 				USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
 				USB_DEVICE_REMOTE_WAKEUP, 0,

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [patch 3/3] pci device wakeup flags
  2005-09-13  2:23 [patch 0/3] driver model wakeup flags David Brownell
  2005-09-13  2:39 ` [patch 1/3] " David Brownell
  2005-09-13  2:39 ` [patch 2/3] usb device " David Brownell
@ 2005-09-13  2:48 ` David Brownell
  2 siblings, 0 replies; 4+ messages in thread
From: David Brownell @ 2005-09-13  2:48 UTC (permalink / raw
  To: linux-pm

[-- Attachment #1: Type: text/plain, Size: 533 bytes --]

And here's the PCI support, as driven by PCI PM capabilities.  On systems
using ACPI, most of these will be reported through ACPI.  (But there will
often also be PS/2 mouse and keyboard devices ...)

Two minor notes here.  One, the PCI spec says we should init some PM
stuff that we don't; that'll matter for wakeup from D3cold (but not now).
Two, some oddness in the PCI device init sequence.  Evidently some PPC
patches are on the way, but nothing in the current tree will care about
reverting that part of a recent patch.

- Dave

[-- Attachment #2: pm-wake-pci.patch --]
[-- Type: text/x-diff, Size: 2912 bytes --]

This patch teaches "pci_dev" about the new driver model wakeup support:

 - It marks devices as supporting wakeup when "can issue PME#" is
   listed in its PCI PM capability.

 - pci_enable_wake() refuses to enable wake if that's been disabled
   (e.g. through sysfs).

NOTE that a recent patch changed PCI probing, and this reverts part
of that change ... so that driver model initialization is again done
before the PCI setup.

(One issue is that the driver model "init + add == register" pattern isn't
being used inside PCI ...  and that probe change worsened the problem by
making "add" do some "init" too.  Maybe PCI should match the driver model
more closely, and just grow a new "pci_dev_init" function.)

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

--- g26.orig/drivers/pci/probe.c	2005-09-11 18:24:11.000000000 -0700
+++ g26/drivers/pci/probe.c	2005-09-12 11:38:01.000000000 -0700
@@ -571,6 +571,7 @@ static void pci_read_irq(struct pci_dev 
 static int pci_setup_device(struct pci_dev * dev)
 {
 	u32 class;
+	u16 pm;
 
 	sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
 		dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
@@ -598,6 +599,19 @@ static int pci_setup_device(struct pci_d
 		pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
 		pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
 		pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
+
+		/* PCI PM capable devices may be able to issue PME# (wakeup) */
+		pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+		if (pm) {
+			pci_read_config_word(dev, pm + PCI_PM_PMC, &pm);
+			if (pm & PCI_PM_CAP_PME_MASK)
+				device_init_wakeup(&dev->dev, 1);
+
+			/* REVISIT: if (pm & PCI_PM_CAP_PME_D3cold) then
+			 * pci pm spec 1.2, section 3.2.4 says we should
+			 * init PCI_PM_CTRL_PME_{STATUS,ENABLE} ...
+			 */
+		}
 		break;
 
 	case PCI_HEADER_TYPE_BRIDGE:		    /* bridge header */
@@ -737,6 +751,7 @@ pci_scan_device(struct pci_bus *bus, int
 	memset(dev, 0, sizeof(struct pci_dev));
 	dev->bus = bus;
 	dev->sysdata = bus->sysdata;
+	device_initialize(&dev->dev);
 	dev->dev.parent = bus->bridge;
 	dev->dev.bus = &pci_bus_type;
 	dev->devfn = devfn;
@@ -759,7 +774,6 @@ pci_scan_device(struct pci_bus *bus, int
 
 void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
 {
-	device_initialize(&dev->dev);
 	dev->dev.release = pci_release_dev;
 	pci_dev_get(dev);
 
--- g26.orig/drivers/pci/pci.c	2005-09-11 18:24:11.000000000 -0700
+++ g26/drivers/pci/pci.c	2005-09-11 18:25:12.000000000 -0700
@@ -531,6 +531,10 @@ int pci_enable_wake(struct pci_dev *dev,
 	if (!pm) 
 		return enable ? -EIO : 0; 
 
+	/* don't enable unless policy set through driver core allows it */
+	if (!device_may_wakeup(&dev->dev) && enable)
+		return -EROFS;
+
 	/* Check device's ability to generate PME# */
 	pci_read_config_word(dev,pm+PCI_PM_PMC,&value);
 

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-09-13  2:48 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-13  2:23 [patch 0/3] driver model wakeup flags David Brownell
2005-09-13  2:39 ` [patch 1/3] " David Brownell
2005-09-13  2:39 ` [patch 2/3] usb device " David Brownell
2005-09-13  2:48 ` [patch 3/3] pci " David Brownell

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.