Re: xHCI USB2 link state change issue

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

 



On Thu, Nov 03, 2011 at 10:09:51AM +0800, Andiry Xu wrote:
> On 11/03/2011 07:17 AM, Sarah Sharp wrote:
> >Hi Andiry,
> >
> >I've been running into an issue with an xHCI host that's very strict
> >about the rule in the xHCI spec that a port status change event is not
> >generated if a change bit hasn't been cleared by software.  What I think
> >are bugs in the xHCI driver are causing future port status changes to be
> >lost.
> >
> >I'm having issues after the resume of a USB 2.0 hub, and I thought I'd
> >ping you on them, since you wrote the device suspend/resume code.
> >
> >The USB 2.0 roothub port state diagram in Figure 34 in the xHCI spec
> >shows that PLC (port link state change) is set on the transition from U3
> >to resume.  The port status change event handler even checks for that
> >bit being set for both USB 2.0 and USB 3.0 devices:
> >
> >static void handle_port_status(struct xhci_hcd *xhci,
> >                 union xhci_trb *event)
> >...
> >         if ((temp&  PORT_PLC)&&  (temp&  PORT_PLS_MASK) == XDEV_RESUME) {
> >                 xhci_dbg(xhci, "port resume event for port %d\n", port_id);
> >
> >However, before your USB 2.0 LPM changes were merged for 3.2, there was
> >no where in the code where the PLC bit was cleared for USB 2.0 devices,
> >AFAICT.
> >
> 
> Oh. It's supposed to be cleared in GetPortStatus in
> xhci_hub_control(), after driver writes U0 to PORTSC.
> Maybe I missed it because my platform does not show this issue...

Ok, I doubled checked, and I see that PLC does get cleared in bus_resume
for USB 2.0 devices, but no where else.  I think you did miss clearing
it in the GetPortStatus request...

> >In any case, can you look over the original device suspend/resume
> >patches and let me know if there's a reason why you didn't clear PLC?
> >If it's just a bug, I'll send off these commits to the stable tree:
> >
> >6fd4562 xHCI: Clear PLC for USB2 root hub ports
> >d2f52c9 xHCI: test and clear RWC bit
> >
> >
> 
> Yes, we must clear PLC directly for all USB2 root hub ports since
> usbcore does not handle it.
> Please send the two patches to stable tree.

Ok, will do.

> However, I'm wondering if driver need to clear PLC when device
> transition from Resume to U0. From the figure 34 it seems PLC is set
> to 1 during the transition. If this does not cause a port status
> change event, driver may need to clear PLC in GetPortStatus in
> xhci_hub_control(), after writes U0 to PORTSC and PLC is reported.
> Please also check on this.

I think I get what you're saying.  Would a patch like this fix it?

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 18432cc..1de2b1c 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -462,30 +462,32 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        if ((temp & PORT_PLS_MASK) == XDEV_U3
                                        && (temp & PORT_POWER))
                                status |= USB_PORT_STAT_SUSPEND;
                }
                if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
                        if ((temp & PORT_RESET) || !(temp & PORT_PE))
                                goto error;
                        if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies,
                                                bus_state->resume_done[wIndex])) {
                                xhci_dbg(xhci, "Resume USB2 port %d\n",
                                        wIndex + 1);
                                bus_state->resume_done[wIndex] = 0;
                                temp1 = xhci_port_state_to_neutral(temp);
                                temp1 &= ~PORT_PLS_MASK;
                                temp1 |= PORT_LINK_STROBE | XDEV_U0;
+                               if ((temp1 & PORT_PLC))
+                                       temp1 |= PORT_PLC;
                                xhci_writel(xhci, temp1, port_array[wIndex]);
 
                                xhci_dbg(xhci, "set port %d resume\n",
                                        wIndex + 1);
                                slot_id = xhci_find_slot_id_by_port(hcd, xhci,
                                                                 wIndex + 1);
                                if (!slot_id) {
                                        xhci_dbg(xhci, "slot_id is zero\n");
                                        goto error;
                                }
                                xhci_ring_device(xhci, slot_id);
                                bus_state->port_c_suspend |= 1 << wIndex;
                                bus_state->suspended_ports &= ~(1 << wIndex);
                        }
                }

I also think there's a potential race condition because the PLC bit can
race with another port status change bit to cause a port status event,
and it will take some time for the USB core to react to it.  I can
envision the following scenario (although I think it's pretty unlikely
to be hit by anyone):

1. USB 2.0 device on port 1 has hardware LPM enabled, and it's currently
   in U2.

2. A second device on port 2 shares a ganged power switch with port 1,
   and it starts to draw too much current.

3. The xHC sets the overcurrent change bit for ports 1 and 2, and
   generates a port status change event.

4. The event is handled and khubd is kicked.  However, before it can
   clear the OCC bit, the device on port 1 comes out of U2, and the PLC
   bit is set.

Since OCC is set, the xHC won't generate a port status change event for
the PLC bit, and it will never have the chance to be cleared in the port
status change event handler.  I think what we need to do is check if the
PLC bit is set for a USB 2.0 device in the function that clears any
other port status change bit, and make sure to clear PLC there.

Does that sound like it would work?  Are there any other race conditions
with the PLC bit that I've missed?

Sarah Sharp
--
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