Commit dfa49c4ad120a784ef1ff0717168aa79f55a483a "USB: xhci - fix math in xhci_get_endpoint_interval()" expands the clamping of the interval value to 0-15, which is only legal for HS/SS endpoints. For FS, it must be 3-11. When testing with FS isochronous endpoints (an audio device), values outside this range caused the following error 0x11 (again) on an NEC xHCI controller: xhci_hcd 0000:01:00.0: ERROR: unexpected command completion code 0x11. usb 1-1: Not enough bandwidth for altsetting 1 This commit makes xhci_parse_exponent_interval() check the EP speed and clamp the interval appropriately. Also, xhci_parse_frame_interval() clamped interval to 3-10; this has been changed to 3-11, as is valid for LS/HS. With this patch, full-speed isoch devices (e.g. audio) work again on xHCI. This should be queued for all stable kernels that contain dfa49c4ad120a784ef1ff0717168aa79f55a483a Signed-off-by: Matt Evans <matt@xxxxxxxxxx> --- A review of the xhci_parse_frame_interval() change (max 10 -> 11) would be appreciated. The value 10 comes from Sarah's original xhci_get_endpoint_interval() implementation; was there a reason for this being 10 rather than (as per the spec) 11? drivers/usb/host/xhci-mem.c | 15 ++++++++++++--- 1 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 26caba4..ba5c40a 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -975,14 +975,22 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud /* * Convert interval expressed as 2^(bInterval - 1) == interval into * straight exponent value 2^n == interval. - * + * Not used for LS. */ static unsigned int xhci_parse_exponent_interval(struct usb_device *udev, struct usb_host_endpoint *ep) { unsigned int interval; - interval = clamp_val(ep->desc.bInterval, 1, 16) - 1; + /* + * xHCI spec 6.2.3 Table 56: "The legal range of values is 3 to 11 for + * Full- or Low-speed Interrupt endpoints and 0 to 15 for all other + * endpoint types". LS doesn't get here, so just check for FS: + */ + if (udev->speed == USB_SPEED_FULL) + interval = clamp_val(ep->desc.bInterval, 4, 12) - 1; + else + interval = clamp_val(ep->desc.bInterval, 1, 16) - 1; if (interval != ep->desc.bInterval - 1) dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n", @@ -995,6 +1003,7 @@ static unsigned int xhci_parse_exponent_interval(struct usb_device *udev, /* * Convert bInterval expressed in frames (in 1-255 range) to exponent of * microframes, rounded down to nearest power of 2. + * Only used for FS/HS. */ static unsigned int xhci_parse_frame_interval(struct usb_device *udev, struct usb_host_endpoint *ep) @@ -1002,7 +1011,7 @@ static unsigned int xhci_parse_frame_interval(struct usb_device *udev, unsigned int interval; interval = fls(8 * ep->desc.bInterval) - 1; - interval = clamp_val(interval, 3, 10); + interval = clamp_val(interval, 3, 11); if ((1 << interval) != 8 * ep->desc.bInterval) dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n", -- 1.7.0.4 -- 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