On Wed, 2011-08-17 at 13:10 +0200, Sebastian Andrzej Siewior wrote: > * Andiry Xu | 2011-08-17 18:01:42 [+0800]: > > >This patch tests USB2 software LPM for a USB2 LPM-capable device. > > > >When a lpm-capable device is addressed, if the host also supports software > >LPM, apply a test by putting the device into L1 state and resume it to see > >if the device can do L1 suspend/resume successfully. > > > >If the device fails to enter L1 or resume from L1 state, it may not > >function normally and usbcore may disconnect and re-enumerate it. In this > >case, store the device's Vid and Pid information, make sure the host will > >not test LPM for it twice. > > > >The test result is per device/host. Some devices claim to be lpm-capable, > >but fail to enter L1 or resume. The behavior is also different on different > >IP-vendor hosts: one device passes the test on a host but fails to resume > >on another with different IP vendor. > > The one IPcore that fails on one device, does it also fail on other > devices or does it pass on other devices? So pattern is something like: > > IP Core A B C > device A ok ok fail > device B fail fail ok > device C fail ok fail > I only observe one device shows different behaviors on different IP hosts. Like: IP A B DevA pass pass DevB fail pass DevC fail fail I only have two hosts supporting LPM, so I'm not sure what behavior other IP hosts will have. > i.e. totally random but reproducible mapping between IP core and device? > Do you see any difference with a USB sniffer? > > >diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c > >index 3a0f695..fce413a 100644 > >--- a/drivers/usb/host/xhci.c > >+++ b/drivers/usb/host/xhci.c > >@@ -37,6 +37,10 @@ static int link_quirk; > > module_param(link_quirk, int, S_IRUGO | S_IWUSR); > > MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB"); > > > >+/* BESL to HIRD Encoding array for USB2 LPM */ > >+static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000, > >+ 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000}; > >+ > > /* TODO: copied from ehci-hcd.c - can this be refactored? */ > > /* > > * handshake - spin reading hc until handshake completes or fails > >@@ -2957,6 +2961,166 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) > > return 0; > > } > > > >+/* Calculate HIRD/BESL for USB2 PORTPMSC*/ > >+static int xhci_calculate_hird_besl(int u2del, bool use_besl) > >+{ > >+ int hird; > >+ > >+ if (use_besl) { > >+ for (hird = 0; hird < 16; hird++) { > > ARRAY_SIZE_OF >From the spec, the besl encoding array is fixed with 16 elements. > > >+ if (xhci_besl_encoding[hird] >= u2del) > >+ break; > >+ } > >+ } else { > >+ if (u2del <= 50) > >+ hird = 0; > >+ else > >+ hird = (u2del - 51) / 75 + 1; > >+ > >+ if (hird > 15) > >+ hird = 15; > >+ } > >+ > >+ return hird; > >+} > >+ > >+static int xhci_usb2_software_lpm_test(struct xhci_hcd *xhci, > >+ struct usb_device *udev, unsigned long flags) > >+{ > >+ struct usb_hcd *hcd = xhci_to_hcd(xhci); > >+ struct dev_info *dev_info; > >+ __le32 __iomem **port_array; > >+ __le32 __iomem *addr, *pm_addr; > >+ u32 temp, dev_id; > >+ unsigned int port_num; > >+ int u2del, hird; > >+ int ret; > >+ > >+ if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || > >+ !udev->lpm_capable) > >+ return -EINVAL; > >+ > >+ /* we only support lpm for non-hub device connected to root hub yet */ > >+ if (!udev->parent || udev->parent->parent || > >+ udev->descriptor.bDeviceClass == USB_CLASS_HUB) > >+ return -EINVAL; > >+ > >+ /* Look for devices in lpm_failed_devs list */ > >+ dev_id = le16_to_cpu(udev->descriptor.idVendor) << 16 | > >+ le16_to_cpu(udev->descriptor.idProduct); > >+ list_for_each_entry(dev_info, &xhci->lpm_failed_devs, list) { > >+ if (dev_info->dev_id == dev_id) > >+ return -EINVAL; > >+ } > > I'm still not really convinced about the list for each device. If the > device passes the test you re-test it on the next plug-in. So why not > re-test it in the fail case if your static array is full? > Can you quote some numbers about the time a successfull and a failed > test needs? According to the code would say about 20ms in both cases > (unless it is already in the list). >From my observation, the test result is constant: a device always pass or always fail on the same host. Re-test a passed device does not involve much effort, but re-test a failed device may involve transfer error, disconnection and re-initialization. Actually LPM suspend and resume does not need 20ms, it's designed to suspend/resume very quickly. Here I just use msleep to make sure it enters the right link state. Thanks, Andiry -- 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