RE: [PATCH 1/1] usb: chipidea: host: add .bus_suspend quirk

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

 



Alan, Sorry for late 

> 
> There may be a problem, because the wakeup signal will cause the port to
> switch automatically from suspend to active status.  This means it will use the
> high-speed terminations.  But the device will go back into suspend when it
> doesn't get any SoF packets within 3 ms, so it will be using the full-speed
> terminations.  Then when the host controller does start sending out SoF
> packets, the mismatched terminations will show up as a disconnect.
> 
> (I really think this is a mistake in the USB spec.  Allowing only 3 ms for a host
> system to turn itself on is not reasonable.)
> 

USB spec should be ok, the host system software can control when to
end resume signal (for ehci fully-compatible controller), so the resume
signal can be ended after software set RS bit. The controller internal
logic should meet this 3ms requirement to send SoF.

> We could try putting the port back into suspend before turning on the
> Run/Stop bit.  That might work -- but if we don't do it carefully, we will lose
> track of the fact that the device sent a wakeup signal.  Can you try testing this
> approach to see if it will work?
> 

Unfortunately, it can't work, the chipidea controller will clear PORT_SUSPEND
and PORT_RESUME after resume signal has ended automatically.

I have traced three cases: 
Case 1: with my patch
Case 2: without my patch
Case 3: without my patch, and add PORT_SUSPEND before sending the resume

Case1:
=========================================dmesg==============================
[  272.439524] PM: early resume of devices complete after 6.741 msecs
[  272.447920] imx_usb 2184000.usb: at imx_controller_resume
[  272.448029] imx_usb 2184200.usb: at imx_controller_resume
[  272.448072] wakeup int at ci_hdrc.1
[  272.457089] fec 2188000.ethernet eth0: rcv is not +last
[  272.462493] fec 2188000.ethernet eth0: rcv is not +last
[  272.467801] fec 2188000.ethernet eth0: rcv is not +last
[  272.473144] fec 2188000.ethernet eth0: rcv is not +last
[  272.478443] fec 2188000.ethernet eth0: rcv is not +last
[  272.484428] ci_hdrc ci_hdrc.0: at ci_controller_resume
[  272.487720] ci_hdrc ci_hdrc.1: at ci_controller_resume
[  272.490974] ci_hdrc ci_hdrc.1: port 1 remote wakeup
[  272.491142] usb usb1: usb resume
[  272.491180] ci_hdrc ci_hdrc.1: resume root hub
[  272.491213] ci_hdrc ci_hdrc.1: Port status(0x18601205) is wrong
[  272.502577] hub 1-0:1.0: hub_resume
[  272.502687] ci_hdrc ci_hdrc.1: GetStatus port:1 status 18001205 12  ACK POWER sig=se0 LPM PE CONNECT
[  272.503908] usb usb1-port1: status 0503 change 0004
[  272.504375] ci_hdrc ci_hdrc.1: GetStatus port:1 status 18001205 12  ACK POWER sig=se0 LPM PE CONNECT
[  272.504795] usb 1-1: finish resume
[  272.558811] PM: resume of devices complete after 112.954 msecs
[  272.573011] PM: resume devices took 0.130 seconds
[  272.577739] PM: Finishing wakeup.
================================================================================
Bus analyzer screenshot: with_rs_in_suspend.png

Case2:
 =========================================dmesg==============================
[ 5400.407854] PM: early resume of devices complete after 6.965 msecs
[ 5400.416317] imx_usb 2184000.usb: at imx_controller_resume
[ 5400.416423] imx_usb 2184200.usb: at imx_controller_resume
[ 5400.416471] wakeup int at ci_hdrc.1
[ 5400.426821] fec 2188000.ethernet eth0: rcv is not +last
[ 5400.433550] ci_hdrc ci_hdrc.0: at ci_controller_resume
[ 5400.436843] ci_hdrc ci_hdrc.1: at ci_controller_resume
[ 5400.440091] ci_hdrc ci_hdrc.1: port 1 remote wakeup
[ 5400.440265] usb usb1: usb resume
[ 5400.440304] ci_hdrc ci_hdrc.1: resume root hub
[ 5400.440335] ci_hdrc ci_hdrc.1: Port status(0x18601205) is wrong
[ 5400.451585] hub 1-0:1.0: hub_resume
[ 5400.451690] ci_hdrc ci_hdrc.1: GetStatus port:1 status 1000180b 8  ACK POWER sig=j PEC CSC CONNECT
[ 5400.452945] usb usb1-port1: status 0101 change 0003
[ 5400.562200] usb 1-1: finish reset-resume
[ 5400.621568] ci_hdrc ci_hdrc.1: Failed to enable port 1 on root hub TT
[ 5400.621622] ci_hdrc ci_hdrc.1: GetStatus port:1 status 1000180b 8  ACK POWER sig=j PEC CSC CONNECT
[ 5400.623930] usb usb1-port1: logical disconnect
[ 5400.624161] usb 1-1: gone after usb resume? status -19
[ 5400.624198] usb 1-1: can't resume, status -19
[ 5400.624221] usb usb1-port1: logical disconnect
[ 5400.624776] PM: resume of devices complete after 210.596 msecs
[ 5400.638801] PM: resume devices took 0.220 seconds
================================================================================
Bus analyzer screenshot: without_rs_in_suspend.png

Case 3:
====================================diff==========================================
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -412,11 +412,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
        ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
        ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
 
-       /* restore CMD_RUN, framelist size, and irq threshold */
-       ehci->command |= CMD_RUN;
-       ehci_writel(ehci, ehci->command, &ehci->regs->command);
-       ehci->rh_state = EHCI_RH_RUNNING;
-
        /*
         * According to Bugzilla #8190, the port status for some controllers
         * will be wrong without a delay. At their wrong status, the port
@@ -428,6 +423,8 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
                if ((temp & PORT_PE) &&
                                !(temp & (PORT_SUSPEND | PORT_RESUME))) {
                        ehci_dbg(ehci, "Port status(0x%x) is wrong\n", temp);
+                       temp |= PORT_SUSPEND;
+                       ehci_writel(ehci, temp, &ehci->regs->port_status[i]);
                        spin_unlock_irq(&ehci->lock);
                        msleep(8);
                        spin_lock_irq(&ehci->lock);
@@ -435,6 +432,11 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
                }
        }
 
+       /* restore CMD_RUN, framelist size, and irq threshold */
+       ehci->command |= CMD_RUN;
+       ehci->command |= CMD_RUN;
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
+       ehci->rh_state = EHCI_RH_RUNNING;
+
        if (ehci->shutdown)
                goto shutdown;
===========================================================================

=========================================dmesg==============================
[   48.756582] PM: early resume of devices complete after 7.979 msecs
[   48.765353] imx_usb 2184000.usb: at imx_controller_resume
[   48.765416] wakeup int at ci_hdrc.0
[   48.765491] imx_usb 2184200.usb: at imx_controller_resume
[   48.783110] ci_hdrc ci_hdrc.0: at ci_controller_resume
[   48.788459] ci_hdrc ci_hdrc.0: port 1 remote wakeup
[   48.788711] usb usb1: usb resume
[   48.788751] ci_hdrc ci_hdrc.0: resume root hub
[   48.788784] ci_hdrc ci_hdrc.0: Port status(0x18601205) is wrong
[   48.789783] ci_hdrc ci_hdrc.1: at ci_controller_resume
[   48.793081] usb usb2: usb resume
[   48.793124] ci_hdrc ci_hdrc.1: resume root hub
[   48.793227] hub 2-0:1.0: hub_resume
[   48.803033] hub 1-0:1.0: hub_resume
[   48.804401] usb usb1-port1: status 0507 change 0000
[   48.806378] usb 1-1: usb resume
[   48.842979] ci_hdrc ci_hdrc.0: GetStatus port:1 status 1000180b 8  ACK POWER sig=j PEC CSC CONNECT
[   48.863324] usb 1-1: finish reset-resume
[   48.923082] ci_hdrc ci_hdrc.0: Failed to enable port 1 on root hub TT
[   48.923142] ci_hdrc ci_hdrc.0: GetStatus port:1 status 1000180b 8  ACK POWER sig=j PEC CSC CONNECT
[   48.927003] usb usb1-port1: logical disconnect
[   48.927249] usb 1-1: gone after usb resume? status -19
[   48.927287] usb 1-1: can't resume, status -19
[   48.927312] usb usb1-port1: logical disconnect
[   48.929383] PM: resume of devices complete after 166.473 msecs
================================================================================
Bus analyzer screenshot: without_rs_in_suspend_with_port_suspend_in_resume.png

Let's see why case 3 can't work:
- At packet 31187, it is resume signal for remote wakeup, after the resume (K) ends, the bus state is
high speed idle (SE0), when the device sees high speed idle no less than 3.0 ms and no more than 3.125 ms
 (TWTREV), it will reverse to full speed by disconnecting its termination resistors and reconnecting its 
D+ pull-up resistor. If device sees full speed J, it will consider it is suspend process, If device sees it is
still SE0, it will consider it is reset process. (In spec: 7.1.7.6 Suspending & 7.1.7.5 Reset Signaling)
- At packet 31188-31191, the device consider it is reset process, so it starts high speed negotiation with
ChirpK. Unfortunately, the host is not in reset state, so the that negotiation will be failed, then the
device goes to full speed state, but the host is still at high speed.
- At packet 31192, we put port in suspend mode, so the bus is in suspend state.
- At packet 31193:  due to the port is at suspend mode, it will set PORT_RESUME, and then we see resume
signal at the bus, after resume has ended. The mismatch should occur due to the host is high speed,
but the device is full speed.
- When the host sends SoF send, it will detect the disconnection.

Since the port will switch to high speed idle automatically after resume ends, we had to set RS before that, in that way, it can
 send SoF in time, the device will not reverse to full speed state.

Peter

Attachment: with_rs_in_suspend.png
Description: with_rs_in_suspend.png

Attachment: without_rs_in_suspend.png
Description: without_rs_in_suspend.png

Attachment: without_rs_in_suspend_with_port_suspend_in_resume.png
Description: without_rs_in_suspend_with_port_suspend_in_resume.png


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

  Powered by Linux