diff mbox series

[v1,2/2] usb: core: enable remote wakeup function for usb controller

Message ID 1638956391-20149-2-git-send-email-zhuyinbo@loongson.cn
State New
Headers show
Series None | expand

Commit Message

Yinbo Zhu Dec. 8, 2021, 9:39 a.m. UTC
The remote wake up function is a regular function on usb device and
I think keeping it enabled by default will make the usb application
more convenient and usb device remote wake up function keep enabled
that ask usb controller remote wake up was enabled at first.

This patch only enable wake up on usb root hub device, among which,
usb3.0 root hub doesn't be set wakeup node property but use command
USB_INTRF_FUNC_SUSPEND to enable remote wake up function.

Signed-off-by: Yinbo Zhu <zhuyinbo@loongson.cn>
---
 drivers/usb/core/hub.c | 20 ++++++++++++++++++--
 include/linux/usb.h    |  4 +++-
 2 files changed, 21 insertions(+), 3 deletions(-)

Comments

Alan Stern Dec. 8, 2021, 10:04 p.m. UTC | #1
On Wed, Dec 08, 2021 at 05:39:51PM +0800, Yinbo Zhu wrote:
> The remote wake up function is a regular function on usb device and
> I think keeping it enabled by default will make the usb application
> more convenient and usb device remote wake up function keep enabled
> that ask usb controller remote wake up was enabled at first.
> 
> This patch only enable wake up on usb root hub device, among which,

You say the patch only affects root hub devices, but this doesn't appear 
to be true.

> usb3.0 root hub doesn't be set wakeup node property but use command
> USB_INTRF_FUNC_SUSPEND to enable remote wake up function.
> 
> Signed-off-by: Yinbo Zhu <zhuyinbo@loongson.cn>
> ---
>  drivers/usb/core/hub.c | 20 ++++++++++++++++++--
>  include/linux/usb.h    |  4 +++-
>  2 files changed, 21 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 86658a8..cb4b956 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -2509,6 +2509,8 @@ static void set_usb_port_removable(struct usb_device *udev)
>   */
>  int usb_new_device(struct usb_device *udev)
>  {
> +	struct usb_host_config *config;
> +	int ncfg;
>  	int err;
>  
>  	if (udev->parent) {
> @@ -2540,6 +2542,18 @@ int usb_new_device(struct usb_device *udev)
>  	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
>  			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
>  
> +	for (ncfg = 0; ncfg < udev->descriptor.bNumConfigurations; ncfg++) {
> +		config = &udev->config[ncfg];
> +		if ((config->desc.bmAttributes & (1 << 5)) == 0)
> +			break;
> +		if (ncfg + 1 == udev->descriptor.bNumConfigurations) {
> +			err = usb_enable_remote_wakeup(udev);
> +			if (err)
> +				dev_dbg(&udev->dev,
> +				      "won't remote wakeup, err %d\n", err);
> +		}
> +	}

I don't see anything in there which treats root hubs differently from 
other devices.

Besides, enabling wakeup for root hubs is generally a bad idea.  Suppose 
you closed a laptop's lid and then unplugged a USB device -- with wakeup 
enabled, the unplug would cause the laptop to wake up again without your 
knowledge.

Alan Stern
Alan Stern Dec. 10, 2021, 4:35 p.m. UTC | #2
On Fri, Dec 10, 2021 at 05:27:30PM +0800, zhuyinbo wrote:
> 
> 
> 在 2021/12/9 上午6:04, Alan Stern 写道:
> > On Wed, Dec 08, 2021 at 05:39:51PM +0800, Yinbo Zhu wrote:
> > > The remote wake up function is a regular function on usb device and
> > > I think keeping it enabled by default will make the usb application
> > > more convenient and usb device remote wake up function keep enabled
> > > that ask usb controller remote wake up was enabled at first.
> > > 
> > > This patch only enable wake up on usb root hub device, among which,
> > 
> > You say the patch only affects root hub devices, but this doesn't appear
> > to be true.
> > 
> > > usb3.0 root hub doesn't be set wakeup node property but use command
> > > USB_INTRF_FUNC_SUSPEND to enable remote wake up function.
> > > 
> > > Signed-off-by: Yinbo Zhu <zhuyinbo@loongson.cn>
> > > ---
> > >   drivers/usb/core/hub.c | 20 ++++++++++++++++++--
> > >   include/linux/usb.h    |  4 +++-
> > >   2 files changed, 21 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> > > index 86658a8..cb4b956 100644
> > > --- a/drivers/usb/core/hub.c
> > > +++ b/drivers/usb/core/hub.c
> > > @@ -2509,6 +2509,8 @@ static void set_usb_port_removable(struct usb_device *udev)
> > >    */
> > >   int usb_new_device(struct usb_device *udev)
> > >   {
> > > +	struct usb_host_config *config;
> > > +	int ncfg;
> > >   	int err;
> > >   	if (udev->parent) {
> > > @@ -2540,6 +2542,18 @@ int usb_new_device(struct usb_device *udev)
> > >   	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
> > >   			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
> > > +	for (ncfg = 0; ncfg < udev->descriptor.bNumConfigurations; ncfg++) {
> > > +		config = &udev->config[ncfg];
> > > +		if ((config->desc.bmAttributes & (1 << 5)) == 0)
> > > +			break;
> > > +		if (ncfg + 1 == udev->descriptor.bNumConfigurations) {
> > > +			err = usb_enable_remote_wakeup(udev);
> > > +			if (err)
> > > +				dev_dbg(&udev->dev,
> > > +				      "won't remote wakeup, err %d\n", err);
> > > +		}
> > > +	}
> > 
> > I don't see anything in there which treats root hubs differently from
> > other devices.
> > 
> Hi Alan Stern,
> 
> You can find following code, non-root-hub had removed Wakeup sysfs
> attributes and disabled wakeup and root-hub had added wakeup sysfs attibutes
> before call usb_new_device, so this patch was only enabled
> remote wakeup for root-hub device.
> int usb_new_device(struct usb_device *udev)
> {
>         if (udev->parent) {
>                 /* Initialize non-root-hub device wakeup to disabled;
>                  * device (un)configuration controls wakeup capable
>                  * sysfs power/wakeup controls wakeup enabled/disabled
>                  */
>                 device_init_wakeup(&udev->dev, 0);
>         }

Okay.  But in any case, you're doing this in the wrong place.  Remote 
wakeup capability depends on the configuration, so you must not enable 
in usb_new_device() before the configuration has been chosen.

Furthermore, remote wakeup gets turned on only at the time when the 
device is suspended.  We don't leave it on all the time.

> > Besides, enabling wakeup for root hubs is generally a bad idea.  Suppose
> > you closed a laptop's lid and then unplugged a USB device -- with wakeup
> > enabled, the unplug would cause the laptop to wake up again without your
> > knowledge.
> > 
> > Alan Stern
> when closed laptop's lid and then unplugged a non-hid usb device it doesn't
> cause laptop to wakeup. and if that usb device is hid type and cause laptop
> into wakeup state then system will continue into suspend state becuase
> system ask that need accepted a acpi lid open event.

Not all laptops have ACPI.

> and for laptop usb wakeup that as general ask bios to enable usb wakeup then
> if need do more things to enable usb wakeup I think this usb wakeup function
> isn't friendly and inconveient, so enable it by default.
> after add this patch, if want to use usb wakeup function it only need enable
> bios configure it think it is appropriate.

The decision about whether or not to enable remote wakeup for a USB 
device is a matter of policy.  It has to be decided by the user, not by 
the kernel.

This is why there are userspace tools, like Powertop, that 
automatically enable remote wakeup when devices are detected and that 
allow the user to control which devices get enabled.  Using these tools 
is easy and convenient -- that's why they exist -- so the kernel's 
interface does not need to be friendly.

Alan Stern
diff mbox series

Patch

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 86658a8..cb4b956 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2509,6 +2509,8 @@  static void set_usb_port_removable(struct usb_device *udev)
  */
 int usb_new_device(struct usb_device *udev)
 {
+	struct usb_host_config *config;
+	int ncfg;
 	int err;
 
 	if (udev->parent) {
@@ -2540,6 +2542,18 @@  int usb_new_device(struct usb_device *udev)
 	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
 			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
 
+	for (ncfg = 0; ncfg < udev->descriptor.bNumConfigurations; ncfg++) {
+		config = &udev->config[ncfg];
+		if ((config->desc.bmAttributes & (1 << 5)) == 0)
+			break;
+		if (ncfg + 1 == udev->descriptor.bNumConfigurations) {
+			err = usb_enable_remote_wakeup(udev);
+			if (err)
+				dev_dbg(&udev->dev,
+				      "won't remote wakeup, err %d\n", err);
+		}
+	}
+
 	/* Tell the world! */
 	announce_device(udev);
 
@@ -3234,7 +3248,7 @@  void usb_enable_ltm(struct usb_device *udev)
  * enable remote wake for the first interface.  FIXME if the interface
  * association descriptor shows there's more than one function.
  */
-static int usb_enable_remote_wakeup(struct usb_device *udev)
+int usb_enable_remote_wakeup(struct usb_device *udev)
 {
 	if (udev->speed < USB_SPEED_SUPER)
 		return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
@@ -3249,6 +3263,7 @@  static int usb_enable_remote_wakeup(struct usb_device *udev)
 					USB_INTRF_FUNC_SUSPEND_LP,
 				NULL, 0, USB_CTRL_SET_TIMEOUT);
 }
+EXPORT_SYMBOL_GPL(usb_enable_remote_wakeup);
 
 /*
  * usb_disable_remote_wakeup - disable remote wakeup for a device
@@ -3260,7 +3275,7 @@  static int usb_enable_remote_wakeup(struct usb_device *udev)
  * disable remote wake for the first interface.  FIXME if the interface
  * association descriptor shows there's more than one function.
  */
-static int usb_disable_remote_wakeup(struct usb_device *udev)
+int usb_disable_remote_wakeup(struct usb_device *udev)
 {
 	if (udev->speed < USB_SPEED_SUPER)
 		return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
@@ -3273,6 +3288,7 @@  static int usb_disable_remote_wakeup(struct usb_device *udev)
 				USB_INTRF_FUNC_SUSPEND,	0, NULL, 0,
 				USB_CTRL_SET_TIMEOUT);
 }
+EXPORT_SYMBOL_GPL(usb_disable_remote_wakeup);
 
 /* Count of wakeup-enabled devices at or below udev */
 unsigned usb_wakeup_enabled_descendants(struct usb_device *udev)
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 7ccaa76..8097eee 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -754,8 +754,10 @@  static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
 	{ return true; }
 #endif
 
-/* USB autosuspend and autoresume */
 #ifdef CONFIG_PM
+extern int usb_enable_remote_wakeup(struct usb_device *udev);
+extern int usb_disable_remote_wakeup(struct usb_device *udev);
+
 extern void usb_enable_autosuspend(struct usb_device *udev);
 extern void usb_disable_autosuspend(struct usb_device *udev);