Re: [RFC v3] xhci-hub: Roothub USB2.0 descriptor for BESL DBESL

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

 



On Sat, Aug 10, 2013 at 04:04:02AM +0000, Paul Zimmerman wrote:
> > From: linux-usb-owner@xxxxxxxxxxxxxxx [mailto:linux-usb-owner@xxxxxxxxxxxxxxx] On Behalf Of Alexandra Yates
> > Sent: Friday, August 09, 2013 12:21 PM
> 
> Hi Alexandra,
> 
> <snip>
> 
> > 
> > +/* USB 2.0 BOS descriptor and a capability descriptor, combined */
> > +static u8 usb2_bos_descriptor[] = {
> > +	USB_DT_BOS_SIZE,                /*  __u8 bLength, 5 bytes */
> > +	USB_DT_BOS,                     /*  __u8 bDescriptorType */
> > +	0x0c, 0x00,                     /*  __le16 wTotalLength, 15 bytes */
> > +	0x1,                            /*  __u8 bNumDeviceCaps */
> > +					/* First device capability */
> > +	USB_DT_USB_EXT_CAP_SIZE,        /*  7 bits USB2 ext */
> > +	USB_DT_DEVICE_CAPABILITY,       /* Device Capability */
> > +	USB_CAP_TYPE_EXT,               /* DevCapability Type, USB2.0 ext */
> > +	0x1e,                           /* bmAttributes first byte: bit1:LPM
> > +					   Supported, bit2: BESL supported,
> > +					   bit3:valid  baseline BESL, bit4:
> > +					   valid Deep BESL, bits5-7 */
> 
> Here you hard-code the first byte of bmAttributes, so LPM Supported, BESL
> Supported etc. are already set...

Yes, Paul is right, you need to set this value to 0x00 in the initial
structure.

> > +	0xff,                           /* bmAttributes - second byte:
> > +					   8-11bit:BESL and 12-16bit:DBESL*/

You also need to set this to 0x00.

> > +	0x00,                           /* bmAttribute - third byte: reserved,
> > +					   must be zero */
> > +	0x00,                           /* bmAttribute - fourth byte: reserved,
> > +					   must be zero */
> > +};
> > +
> > 
> >  static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
> >  		struct usb_hub_descriptor *desc, int ports)
> > @@ -577,12 +599,33 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
> >  		if ((wValue & 0xff00) != (USB_DT_BOS << 8))
> >  			goto error;
> > 
> > -		if (hcd->speed != HCD_USB3)
> > +		if (hcd->speed == HCD_USB3) {
> > +			/* Set the U1 and U2 exit latencies. */
> > +			memcpy(buf, &usb3_bos_descriptor,
> > +				USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE);
> > +		} else if (hcd ->speed == HCD_USB2) {
> > +			memcpy(buf, &usb2_bos_descriptor,
> > +				USB_DT_BOS_SIZE + USB_DT_USB_EXT_CAP_SIZE);
> > +
> > +                        /* Set first byte of bmAttributes in the
> > +                         * usb2_bos_descriptor */
> > +			if (xhci->hw_lpm_support)
> > +				buf[8] |= USB_LPM_SUPPORT;
> 
> ...so these two lines have no effect, the bit is already set.

Then OR'ing in the USB_LPM_SUPPORT bit will work here.

Further, we want to tell lsusb that the USB 2.0 roothub has Link PM
support if the host controller supports either software-controlled Link
PM, or hardware-controlled link PM.  The USB core only works with
hardware-controlled Link PM, but we could add software controlled link
PM in the future.

In xhci-mem.c:xhci_add_in_port(), xhci->sw_lpm_support is set if the
host supports USB 2.0 link PM.  If the host supports hardware-controlled
Link PM, xhci->hw_lpm_support is additionally set.

Your code currently only works for hosts that support
hardware-controlled Link PM.  You should change this line:

+			if (xhci->hw_lpm_support)
+				buf[8] |= USB_LPM_SUPPORT;

To

+			if (xhci->sw_lpm_support)
+				buf[8] |= USB_LPM_SUPPORT;


> > +                       /* Set the BESL support bit in bmAttributes first
> > +                        * byte */
> > +                       if (XHCI_BLC)
> > +                               buf[8] |= USB_BESL_SUPPORT;
> > +                       if (xhci->dbesl) {
> > +                               buf[8] = USB_BESL_DEEP_VALID;
> > +                               buf[9] = xhci->dbesl;
> > +                       }
> > +                       if (xhci->dbesld) {
> > +                               buf[8] = USB_BESL_DEEP_VALID;
> > +                               buf[9] = xhci->dbesl << 4;
> > +                       }

The math here is off, and your initialization of the structure hid those
issues.  You should have used USB_BESL_BASELINE_VALID in the second if
block instead of using USB_BESL_DEEP_VALID twice.  In the third if
statement block, I think you meant to use xhci->dbesld not xhci->dbesl.

Finally, you overwrote the contents of buf[8] and buf[9] in the two if
statements, which means USB_LPM_SUPPORT and USB_BESL_SUPPORT would never
be set in buf[8], and if xhci->dbesl and xhci->dbesld were both set,
buf[9] would only contain the deep BESL value.  You probably meant to
use |= instead of = for all the assignments in those last two if
blocks.

> > diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> > index c338741..90edeed 100644
> > --- a/drivers/usb/host/xhci.h
> > +++ b/drivers/usb/host/xhci.h
> > @@ -1564,6 +1564,9 @@ struct xhci_hcd {
> >        /* Compliance Mode Recovery Data */
> >        struct timer_list       comp_mode_recovery_timer;
> >        u32                     port_status_u0;
> > +       /* LPM DBESL and BESL USB 2.0 Errata support */
> > +       u32                     dbesl;
> > +       u32                     dbesld;
> > /* Compliance Mode Timer Triggered every 2 seconds */
> > #define COMP_MODE_RCVRY_MSECS 2000
> > };

You defined these new values, but you don't set them any where in the
code.  I think this was one of the areas where you were stuck, when we
discussed this last.  Sorry for not getting back to you on this sooner.
Here's what I would like you to do.

First, the xHCI driver ignores any BESL deep values from the device, and
only uses the BESL values.  Therefore, we shouldn't report the deep BESL
value in the USB 2.0 BOS descriptor, and we shouldn't set
USB_BESL_DEEP_VALID.  We should only report the BESL value if the host
supports BESL for any of the roothub ports.

So, how do we know if the host supports the BESL encoding for the
roothub ports?  To do that, we need to look at the port's extended
capabilities register.  The code in xhci_add_in_port() caches those
capabilities in xhci->ext_caps:

        /* cache usb2 port capabilities */
        if (major_revision < 0x03 && xhci->num_ext_caps < max_caps)
                xhci->ext_caps[xhci->num_ext_caps++] = temp;

Code in xhci_update_device() later checks the extended capabilities for
the port to see if it supports the BESL encoding:

                        if (xhci_check_usb2_port_capability(xhci, portnum,
                                                            XHCI_BLC))

That function checks the xhci->ext_caps for that port to see if the bit
(XHCI_BLC) is set:

/* check if a usb2 port supports a given extened capability protocol
 * only USB2 ports extended protocol capability values are cached.
 * Return 1 if capability is supported
 */
static int xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int port,
                                           unsigned capability)
{
        u32 port_offset, port_count;
        int i;

        for (i = 0; i < xhci->num_ext_caps; i++) {
                if (xhci->ext_caps[i] & capability) {
                        /* port offsets starts at 1 */
                        port_offset = XHCI_EXT_PORT_OFF(xhci->ext_caps[i]) - 1;
                        port_count = XHCI_EXT_PORT_COUNT(xhci->ext_caps[i]);
                        if (port >= port_offset &&
                            port < port_offset + port_count)
                                return 1;
                }
        }
        return 0;
}

Basically, if any of the USB 2.0 ports support the BESL encoding, some
array entry in xhci->ext_caps will have XHCI_BLC set.  If that bit is
set for any of the USB 2.0 registers, the roothub descriptor should have
USB_BESL_BASELINE_VALID set.

Now, what do we set the value of the baseline BESL to be in the hub
descriptor?

The xHCI BESL and DSBESL values are actually in the PCI configuration
registers.  However, the xHCI driver doesn't actually use those values
from the PCI registers.  Instead, it ignores the deep BESL values, and
uses a default BESL value of XHCI_DEFAULT_BESL.  XHCI_DEFAULT_BESL is
defined as 4, which means a BESL value of 400 microseconds (see the
Table X-X1. BESL & HIRD Encodings).

We only use the XHCI_DEFAULT_BESL if the USB 2.0 port register in the
extended capabilities section has BLC set.

So here's what you should do:

1. Delete xhci->dbesld from your patch.

2. Change the name from xhci->dbesl to just xhci->besl.  The USB spec
refers to it as baseline BESL, even though the PCI spec refers to it as
default BESL.  It's confusing, so let's stick with the USB version,
since this is a USB driver.

2. In xhci_add_in_port(), if any port capability has the XHCI_BLC set,
set xhci->besl to XHCI_DEFAULT_BESL, i.e.:

                if (xhci->ext_caps[i] & XHCI_BLC)
			xhci->besl = XHCI_DEFAULT_BESL;

3. Where XHCI_DEFAULT_BESL is used in xhci_update_device() in xhci.c,
change it to use xhci->besl instead.

4. Zero the USB 2.0 BOS descriptors as I mentioned above.

5. Change your math in the BOS descriptor to be:

+                       /* Set the BESL support bit in bmAttributes */
+                       if (xhci->besl) {
+                               buf[8] |= USB_BESL_SUPPORT;
+                               buf[8] |= USB_BESL_BASELINE_VALID;
+                               buf[9] = xhci->besl;
+                       }

Does that make sense?  If you have any questions, you can get me on IRC.
I may not be in the office tomorrow, but I will definitely be in the
office on Thursday.

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