Re: [PATCH 8/9 v2] xHCI: test USB2 software LPM

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

 



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


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

  Powered by Linux