On Fri, Oct 12, 2012 at 04:07:43PM -0400, Alan Stern wrote:
> On Thu, 11 Oct 2012, Alan Stern wrote:
> 
> > On Thu, 11 Oct 2012, Sarah Sharp wrote:
> > 
> > > Thinking about this further, USB 2.1 devices need to be brought out of
> > > their low power link state (L1) before they are suspended.  Some xHCI
> > > host controllers have hardware-driven USB 2.1 LPM, so the device could
> > > have been put in L1 before hibernation.  Therefore we need to suspend
> > > USB 2.1 and USB 3.0 devices before we hibernate.
> > 
> > I need to go through the LPM document more carefully before I can 
> > answer fully.  However, what about disabling LPM instead of going all 
> > the way into suspend?  For USB 2.1 devices at least?
> 
> Okay, I have read through the USB-2 LPM documents.  Oddly enough, the
> ECN document consistently talks about USB 2.0 (even using "USB 2.0" as
> part of its title), but it clearly states in section 3 that a device
> cannot indicate support for LPM unless it advertises USB 2.1 -- not 
> USB 2.0.

At least they're consistent! :)

> The kernel support we have now for USB-2 LPM doesn't make any sense.  
> usb_port_suspend() disables LPM before changing the link state out of
> L0, and usb_port_resume() enables LPM after changing the state back to
> L0.
> 
> Thus LPM is disabled precisely at the times when it might be useful!

One thing to understand is that the USB 2.1 LPM code is designed to only
take advantage of host controllers that can do hardware-controlled LPM.
It also only works for devices directly attached to the roothub.  The
code expects that once LPM is enabled, the host controller will
automatically put the idle link into L1 after the port L1 timeout
expires.

We disable LPM before we suspend a device in usb_port_suspend() because
there's no legal transition from L1 to L2/U3/device suspend.  Then when
the device is resumed, we re-enable the host's L1 timeouts, so it can be
automatically placed into L1 by the host.

Basically, if the USB core thinks the device should be suspended, we
make sure it is, because that's the lowest power state.  If the USB core
has to resume the device, we re-enable the L1 timeout.  If the link is
idle in between packets, it's placed into L1.

> In addition to this, I see that ehci-hcd includes some basic support
> for LPM but it doesn't implement the set_usb2_hw_lpm HCD method.  It's
> a sort of do-it-yourself approach (and it includes a bunch of bugs).

Yeah, I think Jacob Pan and another OTC person worked on the USB 2.1 LPM
for an Intel SoC board, but they never found very many USB 2.1 devices,
so they couldn't test it very well.

> One thing I didn't understand; maybe you can explain where to look.  
> The USB 2.0 LPM ECN describes a specific kind of control transfer used 
> for enabling LPM transitions for devices attached to hubs.  Section 
> 4.10.3 says that bRequest should be set to SET_AND_TEST -- but the 
> document doesn't define SET_AND_TEST anywhere.  Do you know where it is 
> defined?

Did you look for errrata associated with the USB 2.0 ECN?  Since the
xHCI host provides registers for placing the device into L1, I never
really had to look the bus-level mechanism to do so.

> P.S.: Going back to an earlier topic of conversation...
> 
> There is a good reason for treating the FREEZE and QUIESCE (or PRETHAW)  
> events differently from the others, although I may have forgotten to
> mention it.  The other events involve changing power levels, but these
> two don't.  They require only that devices be quiescent: not generating
> IRQs or doing DMA.  Since USB devices (as opposed to host controller)
> can't do either, FREEZE and QUIESCE are no-ops for them.
> 
> With OHCI and UHCI, there's no way to stop the controller from doing
> DMA while still sending SOF packets over the USB bus.  Therefore
> quiescing the root hub amounts to the same thing as doing a bus
> suspend, and we haven't tried to distinguish the two operations.  They
> both end up calling hcd_bus_suspend().
> 
> EHCI hardware _is_ capable of turning off IRQs and DMA while keeping
> the bus alive.  But ehci-hcd doesn't make use of this capability --
> indeed, it has no way of doing so because both events go through the
> same ehci_bus_suspend() routine.
> 
> I don't know about xHCI; can it also be quiesced while keeping the USB 
> bus alive?  If so, we should think about adding a pair of new HCD 
> methods for FREEZE/QUIESCE and THAW/RECOVER.

We could stop all endpoints, and halt the host controller, and I think
that should stop all DMA.  The host controller developers *should* know
that the OS or BIOS could move structures around and rewrite registers
after the host is halted, but since there's no "you *shall* not DMA
after you are halted" sentence in the spec, who knows what hosts
actually do.  Especially the ones that use scratchpad pages for internal
storage keeping.

I think it's probably safer to just rely on the bus suspend methods we
already have to quiesce the host controller.  That triggers the xHCI
save registers code.  Host controllers expect to be powered down after
the registers are saved, so they shouldn't be doing any DMA after that
command completes.

Sarah Sharp
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to