Re: [RFC 5/7] USB/xHCI: USB 3.0 link PM change bit means port resume.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sigh.  So it turns out the behavior of USB 3.0 external hubs and the
xHCI roothub port link state change bit is different.

The USB 3.0 bus spec, section 10.14.2.6.2 says the port link state
change bit will be set when the port goes from U3 to U0 when the host
initiated the resume, but the bit will *not* be set if the device has
signaled remote wakeup.  But the xHCI spec says that the link state
change bit will be set on a remote wakeup.

I think the idea is that software is supposed to know to resume a device
by looking at the device notification the device sends (and the xHCI
host passes on in an event) when the roothub port finishes resuming.
Only the xHCI host doesn't send device notifications itself, so it uses
the link state change.

The xHCI driver needs a way to tell khubd which device caused the remote
wakeup, because khubd won't be able to tell by looking at the link state
change bits.  It could possibly tell, if it internally kept track of
which link state each USB 3.0 device should be in, and checked which
ports changed link states to U0.

I'll go look at the hub code more closely to see what it currently does,
but I thought I'd pass my finding on to you and see if you have any
thoughts.

Sarah Sharp

On Mon, Jan 09, 2012 at 08:57:16PM -0500, Alan Stern wrote:
> On Mon, 9 Jan 2012, Sarah Sharp wrote:
> 
> > Ok, what about something like this?  I feel like portions of the
> > hub_events really need to get refactored into smaller functions that do
> > one thing (like handle remote wakeup), with the hub_events() function
> > basically keeping track of the future actions it needs to take care of
> > (like handling a connect status change).
> 
> Okay, that's sensible.
> 
> > Sarah Sharp
> > 
> > diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> > index db6b751..cee525c 100644
> > --- a/drivers/usb/core/hub.c
> > +++ b/drivers/usb/core/hub.c
> > @@ -3442,6 +3442,47 @@ done:
> >  		hcd->driver->relinquish_port(hcd, port1);
> >  }
> >  
> > +/* Returns 1 if there was a remote wakeup and a connect status change. */
> > +static int hub_check_remote_wakeup(struct usb_hub *hub, unsigned int port,
> > +		u16 portchange)
> > +{
> > +	struct usb_device *hdev;
> > +	struct usb_device *udev;
> > +	int connect_change = 0;
> > +	int ret;
> > +
> > +	hdev = hub->hdev;
> > +	if (!hub_is_superspeed(hdev) &&
> > +			!(portchange & USB_PORT_STAT_C_SUSPEND))
> > +		return 0;
> > +	if (hub_is_superspeed(hdev) &&
> > +			!(portchange & USB_PORT_STAT_C_LINK_STATE))
> > +		return 0;
> > +
> > +	if (!hub_is_superspeed(hdev))
> > +		clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
> > +	else
> > +		clear_port_feature(hdev, port, USB_PORT_FEAT_C_PORT_LINK_STATE);
> 
> I would have arranged the code to avoid repeated tests:
> 
> 	if (hub_is_superspeed(hdev)) {
> 		if (!(portchange & USB_PORT_STAT_C_LINK_STATE))
> 			return 0;
> 		clear_port_feature(hdev, port, USB_PORT_FEAT_C_LINK_STATE);
> 	} else {
> 		if (!(portchange & USB_PORT_STAT_C_SUSPEND))
> 			return 0;
> 		clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND)
> 	}
> 
> > +	udev = hdev->children[port-1];
> > +	if (udev) {
> > +		/* TRSMRCY = 10 msec */
> > +		msleep(10);
> > +
> > +		usb_lock_device(udev);
> > +		ret = usb_remote_wakeup(hdev->children[port-1]);
> 
> Although this is simply a copy of the existing code, you might as well 
> replace "hdev->children[port-1]" with "udev".  I think the 
> usb_remote_wakeup() call was there first, and when the udev local 
> variable was added, the call's argument didn't get simplified.
> 
> > +		usb_unlock_device(udev);
> > +		if (ret < 0)
> > +			connect_change = 1;
> > +	} else {
> > +		ret = -ENODEV;
> > +		hub_port_disable(hub, port, 1);
> > +	}
> > +	dev_dbg(hub->intfdev, "resume on port %d, status %d\n",
> > +			port, ret);
> > +	return connect_change;
> > +}
> 
> Otherwise fine.
> 
> Alan Stern
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux