aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-05-04 11:52:20 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:29:47 -0400
commit0458d5b4c9cc4ca0f62625d0144ddc4b4bc97a3c (patch)
tree8b1fcb4f063ef4aa6f2e3cd41a60d986a1e432d4 /drivers/usb
parentce7cd137fced114d49178b73d468b82096a107fb (diff)
USB: add USB-Persist facility
This patch (as886) adds the controversial USB-persist facility, allowing USB devices to persist across a power loss during system suspend. The facility is controlled by a new Kconfig option (with appropriate warnings about the potential dangers); when the option is off the behavior will remain the same as it is now. But when the option is on, people will be able to use suspend-to-disk and keep their USB filesystems intact -- something particularly valuable for small machines where the root filesystem is on a USB device! Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/Kconfig22
-rw-r--r--drivers/usb/core/driver.c39
-rw-r--r--drivers/usb/core/generic.c5
-rw-r--r--drivers/usb/core/hub.c196
-rw-r--r--drivers/usb/core/usb.h1
-rw-r--r--drivers/usb/storage/usb.c8
6 files changed, 197 insertions, 74 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 346fc030c929..5113ef4cb7f6 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -86,6 +86,28 @@ config USB_SUSPEND
86 86
87 If you are unsure about this, say N here. 87 If you are unsure about this, say N here.
88 88
89config USB_PERSIST
90 bool "USB device persistence during system suspend (DANGEROUS)"
91 depends on USB && PM && EXPERIMENTAL
92 default n
93 help
94 If you say Y here, USB device data structures will remain
95 persistent across system suspend, even if the USB bus loses
96 power. (This includes software-suspend, also known as swsusp,
97 or suspend-to-disk.) The devices will reappear as if by magic
98 when the system wakes up, with no need to unmount USB filesystems,
99 rmmod host-controller drivers, or do anything else.
100
101 WARNING: This option can be dangerous!
102
103 If a USB device is replaced by another of the same type while
104 the system is asleep, there's a good chance the kernel won't
105 detect the change. Likewise if the media in a USB storage
106 device is replaced. When this happens it's almost certain to
107 cause data corruption and maybe even crash your system.
108
109 If you are unsure, say N here.
110
89config USB_OTG 111config USB_OTG
90 bool 112 bool
91 depends on USB && EXPERIMENTAL 113 depends on USB && EXPERIMENTAL
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index e8b447e06c54..12dd986bdffd 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -824,8 +824,9 @@ static int usb_resume_device(struct usb_device *udev)
824 struct usb_device_driver *udriver; 824 struct usb_device_driver *udriver;
825 int status = 0; 825 int status = 0;
826 826
827 if (udev->state == USB_STATE_NOTATTACHED || 827 if (udev->state == USB_STATE_NOTATTACHED)
828 udev->state != USB_STATE_SUSPENDED) 828 goto done;
829 if (udev->state != USB_STATE_SUSPENDED && !udev->reset_resume)
829 goto done; 830 goto done;
830 831
831 /* Can't resume it if it doesn't have a driver. */ 832 /* Can't resume it if it doesn't have a driver. */
@@ -882,7 +883,7 @@ done:
882} 883}
883 884
884/* Caller has locked intf's usb_device's pm_mutex */ 885/* Caller has locked intf's usb_device's pm_mutex */
885static int usb_resume_interface(struct usb_interface *intf) 886static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
886{ 887{
887 struct usb_driver *driver; 888 struct usb_driver *driver;
888 int status = 0; 889 int status = 0;
@@ -902,21 +903,21 @@ static int usb_resume_interface(struct usb_interface *intf)
902 } 903 }
903 driver = to_usb_driver(intf->dev.driver); 904 driver = to_usb_driver(intf->dev.driver);
904 905
905 if (driver->resume) { 906 if (reset_resume && driver->post_reset)
907 driver->post_reset(intf, reset_resume);
908 else if (driver->resume) {
906 status = driver->resume(intf); 909 status = driver->resume(intf);
907 if (status) 910 if (status)
908 dev_err(&intf->dev, "%s error %d\n", 911 dev_err(&intf->dev, "%s error %d\n",
909 "resume", status); 912 "resume", status);
910 else 913 } else
911 mark_active(intf);
912 } else {
913 dev_warn(&intf->dev, "no resume for driver %s?\n", 914 dev_warn(&intf->dev, "no resume for driver %s?\n",
914 driver->name); 915 driver->name);
915 mark_active(intf);
916 }
917 916
918done: 917done:
919 // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); 918 // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
919 if (status == 0)
920 mark_active(intf);
920 return status; 921 return status;
921} 922}
922 923
@@ -1063,7 +1064,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
1063 if (status != 0) { 1064 if (status != 0) {
1064 while (--i >= 0) { 1065 while (--i >= 0) {
1065 intf = udev->actconfig->interface[i]; 1066 intf = udev->actconfig->interface[i];
1066 usb_resume_interface(intf); 1067 usb_resume_interface(intf, 0);
1067 } 1068 }
1068 1069
1069 /* Try another autosuspend when the interfaces aren't busy */ 1070 /* Try another autosuspend when the interfaces aren't busy */
@@ -1162,20 +1163,21 @@ static int usb_resume_both(struct usb_device *udev)
1162 } 1163 }
1163 } else { 1164 } else {
1164 1165
1165 /* Needed only for setting udev->dev.power.power_state.event 1166 /* Needed for setting udev->dev.power.power_state.event,
1166 * and for possible debugging message. */ 1167 * for possible debugging message, and for reset_resume. */
1167 status = usb_resume_device(udev); 1168 status = usb_resume_device(udev);
1168 } 1169 }
1169 1170
1170 if (status == 0 && udev->actconfig) { 1171 if (status == 0 && udev->actconfig) {
1171 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { 1172 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
1172 intf = udev->actconfig->interface[i]; 1173 intf = udev->actconfig->interface[i];
1173 usb_resume_interface(intf); 1174 usb_resume_interface(intf, udev->reset_resume);
1174 } 1175 }
1175 } 1176 }
1176 1177
1177 done: 1178 done:
1178 // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); 1179 // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
1180 udev->reset_resume = 0;
1179 return status; 1181 return status;
1180} 1182}
1181 1183
@@ -1510,8 +1512,15 @@ static int usb_resume(struct device *dev)
1510 if (!is_usb_device(dev)) /* Ignore PM for interfaces */ 1512 if (!is_usb_device(dev)) /* Ignore PM for interfaces */
1511 return 0; 1513 return 0;
1512 udev = to_usb_device(dev); 1514 udev = to_usb_device(dev);
1513 if (udev->autoresume_disabled) 1515
1514 return -EPERM; 1516 /* If autoresume is disabled then we also want to prevent resume
1517 * during system wakeup. However, a "persistent-device" reset-resume
1518 * after power loss counts as a wakeup event. So allow a
1519 * reset-resume to occur if remote wakeup is enabled. */
1520 if (udev->autoresume_disabled) {
1521 if (!(udev->reset_resume && udev->do_remote_wakeup))
1522 return -EPERM;
1523 }
1515 return usb_external_resume_device(udev); 1524 return usb_external_resume_device(udev);
1516} 1525}
1517 1526
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 7cbf992adccd..d363b0ea7345 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -217,7 +217,10 @@ static int generic_resume(struct usb_device *udev)
217{ 217{
218 int rc; 218 int rc;
219 219
220 rc = usb_port_resume(udev); 220 if (udev->reset_resume)
221 rc = usb_reset_suspended_device(udev);
222 else
223 rc = usb_port_resume(udev);
221 224
222 /* Root hubs don't have upstream ports to resume or reset, 225 /* Root hubs don't have upstream ports to resume or reset,
223 * so the line above won't do much for them. We have to 226 * so the line above won't do much for them. We have to
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 77a6627b18d2..51d2d304568b 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -553,45 +553,121 @@ static int hub_hub_status(struct usb_hub *hub,
553static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) 553static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
554{ 554{
555 struct usb_device *hdev = hub->hdev; 555 struct usb_device *hdev = hub->hdev;
556 int ret; 556 int ret = 0;
557 557
558 if (hdev->children[port1-1] && set_state) { 558 if (hdev->children[port1-1] && set_state)
559 usb_set_device_state(hdev->children[port1-1], 559 usb_set_device_state(hdev->children[port1-1],
560 USB_STATE_NOTATTACHED); 560 USB_STATE_NOTATTACHED);
561 } 561 if (!hub->error)
562 ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); 562 ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
563 if (ret) 563 if (ret)
564 dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", 564 dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
565 port1, ret); 565 port1, ret);
566
567 return ret; 566 return ret;
568} 567}
569 568
569/*
570 * Disable a port and mark a logical connnect-change event, so that some
571 * time later khubd will disconnect() any existing usb_device on the port
572 * and will re-enumerate if there actually is a device attached.
573 */
574static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
575{
576 dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
577 hub_port_disable(hub, port1, 1);
570 578
571/* caller has locked the hub device */ 579 /* FIXME let caller ask to power down the port:
572static void hub_pre_reset(struct usb_interface *intf) 580 * - some devices won't enumerate without a VBUS power cycle
581 * - SRP saves power that way
582 * - ... new call, TBD ...
583 * That's easy if this hub can switch power per-port, and
584 * khubd reactivates the port later (timer, SRP, etc).
585 * Powerdown must be optional, because of reset/DFU.
586 */
587
588 set_bit(port1, hub->change_bits);
589 kick_khubd(hub);
590}
591
592static void disconnect_all_children(struct usb_hub *hub, int logical)
573{ 593{
574 struct usb_hub *hub = usb_get_intfdata(intf);
575 struct usb_device *hdev = hub->hdev; 594 struct usb_device *hdev = hub->hdev;
576 int port1; 595 int port1;
577 596
578 for (port1 = 1; port1 <= hdev->maxchild; ++port1) { 597 for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
579 if (hdev->children[port1 - 1]) { 598 if (hdev->children[port1-1]) {
580 usb_disconnect(&hdev->children[port1 - 1]); 599 if (logical)
581 if (hub->error == 0) 600 hub_port_logical_disconnect(hub, port1);
582 hub_port_disable(hub, port1, 0); 601 else
602 usb_disconnect(&hdev->children[port1-1]);
603 }
604 }
605}
606
607#ifdef CONFIG_USB_PERSIST
608
609#define USB_PERSIST 1
610
611/* For "persistent-device" resets we must mark the child devices for reset
612 * and turn off a possible connect-change status (so khubd won't disconnect
613 * them later).
614 */
615static void mark_children_for_reset_resume(struct usb_hub *hub)
616{
617 struct usb_device *hdev = hub->hdev;
618 int port1;
619
620 for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
621 struct usb_device *child = hdev->children[port1-1];
622
623 if (child) {
624 child->reset_resume = 1;
625 clear_port_feature(hdev, port1,
626 USB_PORT_FEAT_C_CONNECTION);
583 } 627 }
584 } 628 }
629}
630
631#else
632
633#define USB_PERSIST 0
634
635static inline void mark_children_for_reset_resume(struct usb_hub *hub)
636{ }
637
638#endif /* CONFIG_USB_PERSIST */
639
640/* caller has locked the hub device */
641static void hub_pre_reset(struct usb_interface *intf)
642{
643 struct usb_hub *hub = usb_get_intfdata(intf);
644
645 /* This routine doesn't run as part of a reset-resume, so it's safe
646 * to disconnect all the drivers below the hub.
647 */
648 disconnect_all_children(hub, 0);
585 hub_quiesce(hub); 649 hub_quiesce(hub);
586} 650}
587 651
588/* caller has locked the hub device */ 652/* caller has locked the hub device */
589static void hub_post_reset(struct usb_interface *intf) 653static void hub_post_reset(struct usb_interface *intf, int reset_resume)
590{ 654{
591 struct usb_hub *hub = usb_get_intfdata(intf); 655 struct usb_hub *hub = usb_get_intfdata(intf);
592 656
593 hub_activate(hub);
594 hub_power_on(hub); 657 hub_power_on(hub);
658 if (reset_resume) {
659 if (USB_PERSIST)
660 mark_children_for_reset_resume(hub);
661 else {
662 /* Reset-resume doesn't call pre_reset, so we have to
663 * disconnect the children here. But we may not lock
664 * the child devices, so we have to do a "logical"
665 * disconnect.
666 */
667 disconnect_all_children(hub, 1);
668 }
669 }
670 hub_activate(hub);
595} 671}
596 672
597 673
@@ -1054,32 +1130,63 @@ void usb_set_device_state(struct usb_device *udev,
1054#ifdef CONFIG_PM 1130#ifdef CONFIG_PM
1055 1131
1056/** 1132/**
1133 * usb_reset_suspended_device - reset a suspended device instead of resuming it
1134 * @udev: device to be reset instead of resumed
1135 *
1136 * If a host controller doesn't maintain VBUS suspend current during a
1137 * system sleep or is reset when the system wakes up, all the USB
1138 * power sessions below it will be broken. This is especially troublesome
1139 * for mass-storage devices containing mounted filesystems, since the
1140 * device will appear to have disconnected and all the memory mappings
1141 * to it will be lost.
1142 *
1143 * As an alternative, this routine attempts to recover power sessions for
1144 * devices that are still present by resetting them instead of resuming
1145 * them. If all goes well, the devices will appear to persist across the
1146 * the interruption of the power sessions.
1147 *
1148 * This facility is inherently dangerous. Although usb_reset_device()
1149 * makes every effort to insure that the same device is present after the
1150 * reset as before, it cannot provide a 100% guarantee. Furthermore it's
1151 * quite possible for a device to remain unaltered but its media to be
1152 * changed. If the user replaces a flash memory card while the system is
1153 * asleep, he will have only himself to blame when the filesystem on the
1154 * new card is corrupted and the system crashes.
1155 */
1156int usb_reset_suspended_device(struct usb_device *udev)
1157{
1158 int rc = 0;
1159
1160 dev_dbg(&udev->dev, "usb %sresume\n", "reset-");
1161
1162 /* After we're done the device won't be suspended any more.
1163 * In addition, the reset won't work if udev->state is SUSPENDED.
1164 */
1165 usb_set_device_state(udev, udev->actconfig
1166 ? USB_STATE_CONFIGURED
1167 : USB_STATE_ADDRESS);
1168
1169 /* Root hubs don't need to be (and can't be) reset */
1170 if (udev->parent)
1171 rc = usb_reset_device(udev);
1172 return rc;
1173}
1174
1175/**
1057 * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power 1176 * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
1058 * @rhdev: struct usb_device for the root hub 1177 * @rhdev: struct usb_device for the root hub
1059 * 1178 *
1060 * The USB host controller driver calls this function when its root hub 1179 * The USB host controller driver calls this function when its root hub
1061 * is resumed and Vbus power has been interrupted or the controller 1180 * is resumed and Vbus power has been interrupted or the controller
1062 * has been reset. The routine marks all the children of the root hub 1181 * has been reset. The routine marks @rhdev as having lost power. When
1063 * as NOTATTACHED and marks logical connect-change events on their ports. 1182 * the hub driver is resumed it will take notice; if CONFIG_USB_PERSIST
1183 * is enabled then it will carry out power-session recovery, otherwise
1184 * it will disconnect all the child devices.
1064 */ 1185 */
1065void usb_root_hub_lost_power(struct usb_device *rhdev) 1186void usb_root_hub_lost_power(struct usb_device *rhdev)
1066{ 1187{
1067 struct usb_hub *hub;
1068 int port1;
1069 unsigned long flags;
1070
1071 dev_warn(&rhdev->dev, "root hub lost power or was reset\n"); 1188 dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
1072 1189 rhdev->reset_resume = 1;
1073 spin_lock_irqsave(&device_state_lock, flags);
1074 hub = hdev_to_hub(rhdev);
1075 for (port1 = 1; port1 <= rhdev->maxchild; ++port1) {
1076 if (rhdev->children[port1 - 1]) {
1077 recursively_mark_NOTATTACHED(
1078 rhdev->children[port1 - 1]);
1079 set_bit(port1, hub->change_bits);
1080 }
1081 }
1082 spin_unlock_irqrestore(&device_state_lock, flags);
1083} 1190}
1084EXPORT_SYMBOL_GPL(usb_root_hub_lost_power); 1191EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
1085 1192
@@ -1513,29 +1620,6 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
1513 return status; 1620 return status;
1514} 1621}
1515 1622
1516/*
1517 * Disable a port and mark a logical connnect-change event, so that some
1518 * time later khubd will disconnect() any existing usb_device on the port
1519 * and will re-enumerate if there actually is a device attached.
1520 */
1521static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
1522{
1523 dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
1524 hub_port_disable(hub, port1, 1);
1525
1526 /* FIXME let caller ask to power down the port:
1527 * - some devices won't enumerate without a VBUS power cycle
1528 * - SRP saves power that way
1529 * - ... new call, TBD ...
1530 * That's easy if this hub can switch power per-port, and
1531 * khubd reactivates the port later (timer, SRP, etc).
1532 * Powerdown must be optional, because of reset/DFU.
1533 */
1534
1535 set_bit(port1, hub->change_bits);
1536 kick_khubd(hub);
1537}
1538
1539#ifdef CONFIG_PM 1623#ifdef CONFIG_PM
1540 1624
1541#ifdef CONFIG_USB_SUSPEND 1625#ifdef CONFIG_USB_SUSPEND
@@ -3018,7 +3102,7 @@ int usb_reset_composite_device(struct usb_device *udev,
3018 cintf->dev.driver) { 3102 cintf->dev.driver) {
3019 drv = to_usb_driver(cintf->dev.driver); 3103 drv = to_usb_driver(cintf->dev.driver);
3020 if (drv->post_reset) 3104 if (drv->post_reset)
3021 (drv->post_reset)(cintf); 3105 (drv->post_reset)(cintf, 0);
3022 } 3106 }
3023 if (cintf != iface) 3107 if (cintf != iface)
3024 up(&cintf->dev.sem); 3108 up(&cintf->dev.sem);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 6f361df374fc..1a4862886733 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -36,6 +36,7 @@ extern void usb_host_cleanup(void);
36extern void usb_autosuspend_work(struct work_struct *work); 36extern void usb_autosuspend_work(struct work_struct *work);
37extern int usb_port_suspend(struct usb_device *dev); 37extern int usb_port_suspend(struct usb_device *dev);
38extern int usb_port_resume(struct usb_device *dev); 38extern int usb_port_resume(struct usb_device *dev);
39extern int usb_reset_suspended_device(struct usb_device *udev);
39extern int usb_external_suspend_device(struct usb_device *udev, 40extern int usb_external_suspend_device(struct usb_device *udev,
40 pm_message_t msg); 41 pm_message_t msg);
41extern int usb_external_resume_device(struct usb_device *udev); 42extern int usb_external_resume_device(struct usb_device *udev);
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index df5dc186aef5..be4cd8fe4ce6 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -236,7 +236,7 @@ static void storage_pre_reset(struct usb_interface *iface)
236 mutex_lock(&us->dev_mutex); 236 mutex_lock(&us->dev_mutex);
237} 237}
238 238
239static void storage_post_reset(struct usb_interface *iface) 239static void storage_post_reset(struct usb_interface *iface, int reset_resume)
240{ 240{
241 struct us_data *us = usb_get_intfdata(iface); 241 struct us_data *us = usb_get_intfdata(iface);
242 242
@@ -249,7 +249,11 @@ static void storage_post_reset(struct usb_interface *iface)
249 249
250 /* FIXME: Notify the subdrivers that they need to reinitialize 250 /* FIXME: Notify the subdrivers that they need to reinitialize
251 * the device */ 251 * the device */
252 mutex_unlock(&us->dev_mutex); 252
253 /* If this is a reset-resume then the pre_reset routine wasn't
254 * called, so we don't need to unlock the mutex. */
255 if (!reset_resume)
256 mutex_unlock(&us->dev_mutex);
253} 257}
254 258
255/* 259/*