diff options
author | Sarah Sharp <saharabeara@gmail.com> | 2007-12-21 19:54:15 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-01 17:35:00 -0500 |
commit | 1512300689426cb98bfd7e567ee9fdfaaf61b7c7 (patch) | |
tree | a275493675fe7bc6b666d1c6a8179e103c7a199c /drivers | |
parent | 228426edac844a2c9270528e9cd7ab6260ef7628 (diff) |
USB: Export suspend statistics
This patch exports two statistics to userspace:
/sys/bus/usb/device/.../power/connected_duration
/sys/bus/usb/device/.../power/active_duration
connected_duration is the total time (in msec) that the device has
been connected. active_duration is the total time the device has not
been suspended. With these two statistics, tools like PowerTOP can
calculate the percentage time that a device is active, i.e. not
suspended or auto-suspended.
Users can also use the active_duration to check if a device is actually
autosuspended. Currently, they can set power/level to auto and
power/autosuspend to a positive timeout, but there's no way to know from
userspace if a device was actually autosuspended without looking at the
dmesg output. These statistics will be useful in creating an automated
userspace script to test autosuspend for USB devices.
Signed-off-by: Sarah Sharp <sarah.a.sharp@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/core/hub.c | 10 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 49 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 2 |
3 files changed, 60 insertions, 1 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index cc93aa9336fe..53fe049b40f5 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1034,8 +1034,10 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev) | |||
1034 | if (udev->children[i]) | 1034 | if (udev->children[i]) |
1035 | recursively_mark_NOTATTACHED(udev->children[i]); | 1035 | recursively_mark_NOTATTACHED(udev->children[i]); |
1036 | } | 1036 | } |
1037 | if (udev->state == USB_STATE_SUSPENDED) | 1037 | if (udev->state == USB_STATE_SUSPENDED) { |
1038 | udev->discon_suspended = 1; | 1038 | udev->discon_suspended = 1; |
1039 | udev->active_duration -= jiffies; | ||
1040 | } | ||
1039 | udev->state = USB_STATE_NOTATTACHED; | 1041 | udev->state = USB_STATE_NOTATTACHED; |
1040 | } | 1042 | } |
1041 | 1043 | ||
@@ -1084,6 +1086,12 @@ void usb_set_device_state(struct usb_device *udev, | |||
1084 | else | 1086 | else |
1085 | device_init_wakeup(&udev->dev, 0); | 1087 | device_init_wakeup(&udev->dev, 0); |
1086 | } | 1088 | } |
1089 | if (udev->state == USB_STATE_SUSPENDED && | ||
1090 | new_state != USB_STATE_SUSPENDED) | ||
1091 | udev->active_duration -= jiffies; | ||
1092 | else if (new_state == USB_STATE_SUSPENDED && | ||
1093 | udev->state != USB_STATE_SUSPENDED) | ||
1094 | udev->active_duration += jiffies; | ||
1087 | udev->state = new_state; | 1095 | udev->state = new_state; |
1088 | } else | 1096 | } else |
1089 | recursively_mark_NOTATTACHED(udev); | 1097 | recursively_mark_NOTATTACHED(udev); |
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 32bd130b1eed..021b1d37462c 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c | |||
@@ -249,6 +249,41 @@ static void remove_persist_attributes(struct device *dev) | |||
249 | #ifdef CONFIG_USB_SUSPEND | 249 | #ifdef CONFIG_USB_SUSPEND |
250 | 250 | ||
251 | static ssize_t | 251 | static ssize_t |
252 | show_connected_duration(struct device *dev, struct device_attribute *attr, | ||
253 | char *buf) | ||
254 | { | ||
255 | struct usb_device *udev = to_usb_device(dev); | ||
256 | |||
257 | return sprintf(buf, "%u\n", | ||
258 | jiffies_to_msecs(jiffies - udev->connect_time)); | ||
259 | } | ||
260 | |||
261 | static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL); | ||
262 | |||
263 | /* | ||
264 | * If the device is resumed, the last time the device was suspended has | ||
265 | * been pre-subtracted from active_duration. We add the current time to | ||
266 | * get the duration that the device was actually active. | ||
267 | * | ||
268 | * If the device is suspended, the active_duration is up-to-date. | ||
269 | */ | ||
270 | static ssize_t | ||
271 | show_active_duration(struct device *dev, struct device_attribute *attr, | ||
272 | char *buf) | ||
273 | { | ||
274 | struct usb_device *udev = to_usb_device(dev); | ||
275 | int duration; | ||
276 | |||
277 | if (udev->state != USB_STATE_SUSPENDED) | ||
278 | duration = jiffies_to_msecs(jiffies + udev->active_duration); | ||
279 | else | ||
280 | duration = jiffies_to_msecs(udev->active_duration); | ||
281 | return sprintf(buf, "%u\n", duration); | ||
282 | } | ||
283 | |||
284 | static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL); | ||
285 | |||
286 | static ssize_t | ||
252 | show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) | 287 | show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) |
253 | { | 288 | { |
254 | struct usb_device *udev = to_usb_device(dev); | 289 | struct usb_device *udev = to_usb_device(dev); |
@@ -365,6 +400,14 @@ static int add_power_attributes(struct device *dev) | |||
365 | rc = sysfs_add_file_to_group(&dev->kobj, | 400 | rc = sysfs_add_file_to_group(&dev->kobj, |
366 | &dev_attr_level.attr, | 401 | &dev_attr_level.attr, |
367 | power_group); | 402 | power_group); |
403 | if (rc == 0) | ||
404 | rc = sysfs_add_file_to_group(&dev->kobj, | ||
405 | &dev_attr_connected_duration.attr, | ||
406 | power_group); | ||
407 | if (rc == 0) | ||
408 | rc = sysfs_add_file_to_group(&dev->kobj, | ||
409 | &dev_attr_active_duration.attr, | ||
410 | power_group); | ||
368 | } | 411 | } |
369 | return rc; | 412 | return rc; |
370 | } | 413 | } |
@@ -372,6 +415,12 @@ static int add_power_attributes(struct device *dev) | |||
372 | static void remove_power_attributes(struct device *dev) | 415 | static void remove_power_attributes(struct device *dev) |
373 | { | 416 | { |
374 | sysfs_remove_file_from_group(&dev->kobj, | 417 | sysfs_remove_file_from_group(&dev->kobj, |
418 | &dev_attr_active_duration.attr, | ||
419 | power_group); | ||
420 | sysfs_remove_file_from_group(&dev->kobj, | ||
421 | &dev_attr_connected_duration.attr, | ||
422 | power_group); | ||
423 | sysfs_remove_file_from_group(&dev->kobj, | ||
375 | &dev_attr_level.attr, | 424 | &dev_attr_level.attr, |
376 | power_group); | 425 | power_group); |
377 | sysfs_remove_file_from_group(&dev->kobj, | 426 | sysfs_remove_file_from_group(&dev->kobj, |
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index bc5edacb0c34..fdb444d81271 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c | |||
@@ -339,6 +339,8 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) | |||
339 | mutex_init(&dev->pm_mutex); | 339 | mutex_init(&dev->pm_mutex); |
340 | INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); | 340 | INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); |
341 | dev->autosuspend_delay = usb_autosuspend_delay * HZ; | 341 | dev->autosuspend_delay = usb_autosuspend_delay * HZ; |
342 | dev->connect_time = jiffies; | ||
343 | dev->active_duration = -jiffies; | ||
342 | #endif | 344 | #endif |
343 | if (root_hub) /* Root hub always ok [and always wired] */ | 345 | if (root_hub) /* Root hub always ok [and always wired] */ |
344 | dev->authorized = 1; | 346 | dev->authorized = 1; |