Skip to contentSkip to conversation

PATCH/RFC: driver model/pmcore wakeup hooks (1/4)

PATCH David Brownell 4 participants 10 messages Oct 4, 2004 – Oct 20, 2004

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

This lets drivers standardize how they present their ability to issue wakeups, and how they manage whether that ability should be used.

This adds basic driver model and sysfs support for device wakeup capabilities.

- adds two driver model pmcore wakeup bits:
* can_wakeup, initialized using device_init_wakeup() in bus or device driver code
* should_wakeup, tested by device_may_wakeup() during device power state transitions

- make that new state observable and manageable by letting sysfs change the should_wakeup policy by writing the "wakeup" attribute

This patch doesn't add callers or change existing wakeup code like:

- USB (these bits replace two existing usb-internal bits)
- PCI (can_wakeup coming from PCI PM capability)
- ACPI (this should probably replace the new /proc/acpi/wakeup)
- Ethtool should just set WOL policies
- ... probably there are others.

Patches for the USB and PCI exist already.

[ against 2.6.9-rc3 ]

drivers/base/power/sysfs.c +63 -0
@@ -48,8 +48,71 @@
 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 in suspended or low power states.  Such
+ *	devices have one of two wakeup options:  "enabled" to issue the
+ *	events, otherwise "disabled".  The value is effective at the next
+ *	state change.  (Other devices have no value for this option.)
+ *
+ *	Familiar examples of devices that can issue wakeup events include
+ *	keyboards and mice (both PS2 and USB styles), power buttons, clocks,
+ *	"Wake-On-LAN" Ethernet links, modems, and more.  Sometimes these
+ *	events will wake the system from a suspend state, but often they
+ *	just wake up a single device that's been selectively suspended.
+ *
+ *	It is the responsibility of device drivers to enable (or disable)
+ *	wakeup signaling as part of changing device suspend or power states,
+ *	respecting the policy choice 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.  Some drivers
+ *	use wakeup events internally, keeping their hardware in a low power
+ *	mode most of the time (even without a system-wide suspend state),
+ *	unless wakeup is disabled.
+ */
+
+static const char enabled[] = "enabled";
+static const char disabled[] = "disabled";
+
+static ssize_t wake_show(struct device * dev, 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, 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 = {
include/linux/pm.h +19 -0
@@ -237,6 +237,8 @@
 	atomic_t		pm_users;
 	struct device		* pm_parent;
 	struct list_head	entry;
+	unsigned		can_wakeup:1;
+	unsigned		should_wakeup:1;
 #endif
 };
 
@@ -247,6 +249,23 @@
 extern void device_power_up(void);
 extern void device_resume(void);
 
+/* wakeup changes take effect on device's next pm state change */
+#ifdef CONFIG_PM
+#define device_init_wakeup(dev,val) \
+	((dev)->power.can_wakeup = ((dev)->power.should_wakeup = !!(val)))
+#define device_set_wakeup_enable(dev,val) \
+	((dev)->power.should_wakeup = (dev)->power.can_wakeup ? !!(val) : 0)
+#define device_can_wakeup(dev) \
+	((dev)->power.can_wakeup)
+#define device_may_wakeup(dev) \
+	(device_can_wakeup(dev) && (dev)->power.should_wakeup)
+
+#else /* !CONFIG_PM */
+#define device_init_wakeup(dev,val)		do()while(0)
+#define device_set_wakeup_enable(dev,val)	do()while(0)
+#define device_can_wakeup(dev)			(0)
+#define device_may_wakeup(dev)			(0)
+#endif
 
 #endif /* __KERNEL__ */
 
#1 lore raw

Hi!

Quoted 2 lines

This lets drivers standardize how they present their ability to issue wakeups, and how they manage whether that ability should be used.

Why do you assign "enabled" to variable instead of using it directly? And perhaps you should print "not supported" instead of empty string...

Pavel

Signature · 1 line
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms         
#2 lore raw
Quoted 6 lines · Pavel Machek

Hi!

Quoted 2 lines

This lets drivers standardize how they present their ability to issue wakeups, and how they manage whether that ability should be used.

Why do you assign "enabled" to variable instead of using it directly?

So there's exactly one copy of that string in use, agreeing with itself. Also, so strncmp() can be used. It won't matter if the sysadmin goes

echo -n enabled > wakeup
echo enabled > wakeup

I'd personally rather use "on" and "off", but there seems to be a convention in /proc/acpi/wakeup in favor of polysyllabicism.

Quoted 1 line

And perhaps you should print "not supported" instead of empty string...

Except that's two words, not one, which will make shell script bugs happen more readily. I thought about "(none)" which has the same issue, and "-". But I figured that if it were very important, a good solution would appear ... ;)

- Dave

#3 lore raw

Hi!

Quoted 10 lines
Quoted 4 lines
Quoted 2 lines

This lets drivers standardize how they present their ability to issue wakeups, and how they manage whether that ability should be used.

Why do you assign "enabled" to variable instead of using it directly?

So there's exactly one copy of that string in use, agreeing with itself. Also, so strncmp() can be used. It won't matter if the sysadmin goes

echo -n enabled > wakeup
echo enabled > wakeup

Well, you could make that 0,1. That would be more sysfs-style...

Quoted 10 lines

I'd personally rather use "on" and "off", but there seems to be a convention in /proc/acpi/wakeup in favor of polysyllabicism.

Quoted 1 line

And perhaps you should print "not supported" instead of empty string...

Except that's two words, not one, which will make shell script bugs happen more readily. I thought about "(none)" which has the same issue, and "-". But I figured that if it were very important, a good solution would appear ... ;)

On the second thought, perhaps file simply should not be there if wakeup is not supported.
Pavel

Signature · 2 lines
People were complaining that M$ turns users into beta-testers...
...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
#4 lore raw
Quoted 6 lines · Pavel Machek
Quoted 4 lines

Also, so strncmp() can be used. It won't matter if the sysadmin goes

echo -n enabled > wakeup
echo enabled > wakeup

Well, you could make that 0,1. That would be more sysfs-style...

Only for things like detach_state and power_state, which shouldn't be numbers in the first place ... :)

The /sys/module/*/OPTION strings use Y/N for booleans, and maybe sysfs should actually have generic code to read/write such boolean values.

Quoted 2 lines

On the second thought, perhaps file simply should not be there if wakeup is not supported.

That doesn't work too well for things like USB, where one config may support wakeup but another doesn't ... and unconfigured devices never support it. The "can_support" value changes over time.

- Dave

#5 lore raw
In reply to David Brownell
Quoted 1 line

- ACPI (this should probably replace the new /proc/acpi/wakeup)

Agreed. That file is a temporary solution.
The right solution is for the devices to appear in the right place in the device tree and to hang the wakeup capabilities off of them there.

thanks,
-Len

-------------------------------------------------------
This SF.net email is sponsored by: IT Product Guide on ITManagersJournal Use IT products in your business? Tell us what you think of them. Give us Your Opinions, Get Free ThinkGeek Gift Certificates! Click to find out more
http://productguide.itmanagersjournal.com/guidepromo.tmpl

#6 lore raw
Quoted 6 lines · Len Brown
Quoted 1 line

- ACPI (this should probably replace the new /proc/acpi/wakeup)

Agreed. That file is a temporary solution.
The right solution is for the devices to appear in the right place in the device tree and to hang the wakeup capabilities off of them there.

So what would that patch need before ACPI could convert to use it?

I didn't notice any obvious associations between the strings in the acpi/wakeup file and anything in sysfs. Which of USB1..USB4 was which of the three controllers shown by "lspci" (and which one was "extra"!), as one head-scratcher.

For PCI, I'd kind of expect pci_enable_wake() to trigger the additional ACPI-specific work to make sure the device can
actually wake that system. Seems like dev->platform_data
might need to combine with some platform-specific API hook.

- Dave

#7 lore raw
Quoted 7 lines · David Brownell

So what would that patch need before ACPI could convert to use it?

I didn't notice any obvious associations between the strings in the acpi/wakeup file and anything in sysfs. Which of USB1..USB4 was which of the three controllers shown by "lspci" (and which one was "extra"!), as one head-scratcher.

Quoted 6 lines

For PCI, I'd kind of expect pci_enable_wake() to trigger the additional ACPI-specific work to make sure the device can
actually wake that system. Seems like dev->platform_data
might need to combine with some platform-specific API hook.

- Dave

Does anoyone give me a link to the original RFC?
I cannot find the original mail as a newbie associated with this list.

Hiro.

-------------------------------------------------------
This SF.net email is sponsored by: IT Product Guide on ITManagersJournal Use IT products in your business? Tell us what you think of them. Give us Your Opinions, Get Free ThinkGeek Gift Certificates! Click to find out more
http://productguide.itmanagersjournal.com/guidepromo.tmpl

#8 lore raw
Quoted 4 lines · On Monday 18 October 2004 9:55 pm, Hiroshi 2 Itoh wrote:
Quoted 1 line

So what would that patch need before ACPI could convert to use it?

Does anoyone give me a link to the original RFC?
I cannot find the original mail as a newbie associated with this list.

Messages 0-4 are:

http://marc.theaimsgroup.com/?l=linux-kernel&m=109692668310738&w=2
http://marc.theaimsgroup.com/?l=linux-kernel&m=109692668228442&w=2
http://marc.theaimsgroup.com/?l=linux-kernel&m=109692610403412&w=2
http://marc.theaimsgroup.com/?l=linux-kernel&m=109692915107429&w=2
http://marc.theaimsgroup.com/?l=linux-kernel&m=109692881326178&w=2

Click on the second one ... :)

- Dave

#9 lore raw
In reply to David Brownell
Quoted 8 lines · David Brownell
Quoted 6 lines · Len Brown
Quoted 1 line

- ACPI (this should probably replace the new /proc/acpi/wakeup)

Agreed. That file is a temporary solution.
The right solution is for the devices to appear in the right place in the device tree and to hang the wakeup capabilities off of them there.

Quoted 6 lines

So what would that patch need before ACPI could convert to use it?

I didn't notice any obvious associations between the strings in the acpi/wakeup file and anything in sysfs. Which of USB1..USB4 was which of the three controllers shown by "lspci" (and which one was "extra"!), as one head-scratcher.

The strings "USB1" etc. are completely arbitrary, which is one reason that /proc/acpi/wakeup is only marginally useful.

Quoted 4 lines

For PCI, I'd kind of expect pci_enable_wake() to trigger the additional ACPI-specific work to make sure the device can
actually wake that system. Seems like dev->platform_data
might need to combine with some platform-specific API hook.

In the ACPI DSDT...
Devices are explicitly identified as PCI busses by their PNP-id. These PCI busses are enumerated by their _BBN or _CRS.
The devices under the PCI busses all contain an _ADR which encodes the PCI device/function number.

Ie. ACPI tells us the PCI bus/dev/func for each PCI device in the DSDT, and with this information it needs to be able to find devices in the Linux device tree and associate some ACPI capabilities with it.

-Len

-------------------------------------------------------
This SF.net email is sponsored by: IT Product Guide on ITManagersJournal Use IT products in your business? Tell us what you think of them. Give us Your Opinions, Get Free ThinkGeek Gift Certificates! Click to find out more
http://productguide.itmanagersjournal.com/guidepromo.tmpl