Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: add usb_hcd_{start,end}_port_resume

This patch (as1649) adds a mechanism for host controller drivers to
inform usbcore when they have begun or ended resume signalling on a
particular root-hub port. The core will then make sure that the root
hub does not get runtime-suspended while the port resume is going on.

Since commit 596d789a211d134dc5f94d1e5957248c204ef850 (USB: set hub's
default autosuspend delay as 0), the system tries to suspend hubs
whenever they aren't in use. While a root-hub port is being resumed,
the root hub does not appear to be in use. Attempted runtime suspends
fail because of the ongoing port resume, but the PM core just keeps on
trying over and over again. We want to prevent this wasteful effort.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Tested-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
da0aa716 6e0c3339

+49
+44
drivers/usb/core/hcd.c
··· 39 39 #include <asm/unaligned.h> 40 40 #include <linux/platform_device.h> 41 41 #include <linux/workqueue.h> 42 + #include <linux/pm_runtime.h> 42 43 43 44 #include <linux/usb.h> 44 45 #include <linux/usb/hcd.h> ··· 1026 1025 return retval; 1027 1026 } 1028 1027 1028 + /* 1029 + * usb_hcd_start_port_resume - a root-hub port is sending a resume signal 1030 + * @bus: the bus which the root hub belongs to 1031 + * @portnum: the port which is being resumed 1032 + * 1033 + * HCDs should call this function when they know that a resume signal is 1034 + * being sent to a root-hub port. The root hub will be prevented from 1035 + * going into autosuspend until usb_hcd_end_port_resume() is called. 1036 + * 1037 + * The bus's private lock must be held by the caller. 1038 + */ 1039 + void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum) 1040 + { 1041 + unsigned bit = 1 << portnum; 1042 + 1043 + if (!(bus->resuming_ports & bit)) { 1044 + bus->resuming_ports |= bit; 1045 + pm_runtime_get_noresume(&bus->root_hub->dev); 1046 + } 1047 + } 1048 + EXPORT_SYMBOL_GPL(usb_hcd_start_port_resume); 1049 + 1050 + /* 1051 + * usb_hcd_end_port_resume - a root-hub port has stopped sending a resume signal 1052 + * @bus: the bus which the root hub belongs to 1053 + * @portnum: the port which is being resumed 1054 + * 1055 + * HCDs should call this function when they know that a resume signal has 1056 + * stopped being sent to a root-hub port. The root hub will be allowed to 1057 + * autosuspend again. 1058 + * 1059 + * The bus's private lock must be held by the caller. 1060 + */ 1061 + void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum) 1062 + { 1063 + unsigned bit = 1 << portnum; 1064 + 1065 + if (bus->resuming_ports & bit) { 1066 + bus->resuming_ports &= ~bit; 1067 + pm_runtime_put_noidle(&bus->root_hub->dev); 1068 + } 1069 + } 1070 + EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume); 1029 1071 1030 1072 /*-------------------------------------------------------------------------*/ 1031 1073
+2
include/linux/usb.h
··· 357 357 int bandwidth_int_reqs; /* number of Interrupt requests */ 358 358 int bandwidth_isoc_reqs; /* number of Isoc. requests */ 359 359 360 + unsigned resuming_ports; /* bit array: resuming root-hub ports */ 361 + 360 362 #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) 361 363 struct mon_bus *mon_bus; /* non-null when associated */ 362 364 int monitored; /* non-zero when monitored */
+3
include/linux/usb/hcd.h
··· 430 430 extern void usb_wakeup_notification(struct usb_device *hdev, 431 431 unsigned int portnum); 432 432 433 + extern void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum); 434 + extern void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum); 435 + 433 436 /* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ 434 437 #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) 435 438 #define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep)))