USB: xhci - fix math in xhci_get_endpoint_interval()
When parsing exponent-expressed intervals we subtract 1 from the value and then expect it to match with original + 1, which is highly unlikely, and we end with frequent spew: usb 3-4: ep 0x83 - rounding interval to 512 microframes Also, parsing interval for fullspeed isochronous endpoints was incorrect - according to USB spec they use exponent-based intervals (but xHCI spec claims frame-based intervals). I trust USB spec more, especially since USB core agrees with it. This should be queued for stable kernels back to 2.6.31. Reviewed-by: Micah Elizabeth Scott <micah@vmware.com> Signed-off-by: Dmitry Torokhov <dtor@vmware.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: stable@kernel.org
This commit is contained in:
parent
926008c938
commit
dfa49c4ad1
@ -974,6 +974,47 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert interval expressed as 2^(bInterval - 1) == interval into
|
||||||
|
* straight exponent value 2^n == interval.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
if (interval != ep->desc.bInterval - 1)
|
||||||
|
dev_warn(&udev->dev,
|
||||||
|
"ep %#x - rounding interval to %d microframes\n",
|
||||||
|
ep->desc.bEndpointAddress,
|
||||||
|
1 << interval);
|
||||||
|
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert bInterval expressed in frames (in 1-255 range) to exponent of
|
||||||
|
* microframes, rounded down to nearest power of 2.
|
||||||
|
*/
|
||||||
|
static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
|
||||||
|
struct usb_host_endpoint *ep)
|
||||||
|
{
|
||||||
|
unsigned int interval;
|
||||||
|
|
||||||
|
interval = fls(8 * ep->desc.bInterval) - 1;
|
||||||
|
interval = clamp_val(interval, 3, 10);
|
||||||
|
if ((1 << interval) != 8 * ep->desc.bInterval)
|
||||||
|
dev_warn(&udev->dev,
|
||||||
|
"ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n",
|
||||||
|
ep->desc.bEndpointAddress,
|
||||||
|
1 << interval,
|
||||||
|
8 * ep->desc.bInterval);
|
||||||
|
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the polling or NAK interval.
|
/* Return the polling or NAK interval.
|
||||||
*
|
*
|
||||||
* The polling interval is expressed in "microframes". If xHCI's Interval field
|
* The polling interval is expressed in "microframes". If xHCI's Interval field
|
||||||
@ -991,45 +1032,38 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
|
|||||||
case USB_SPEED_HIGH:
|
case USB_SPEED_HIGH:
|
||||||
/* Max NAK rate */
|
/* Max NAK rate */
|
||||||
if (usb_endpoint_xfer_control(&ep->desc) ||
|
if (usb_endpoint_xfer_control(&ep->desc) ||
|
||||||
usb_endpoint_xfer_bulk(&ep->desc))
|
usb_endpoint_xfer_bulk(&ep->desc)) {
|
||||||
interval = ep->desc.bInterval;
|
interval = ep->desc.bInterval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
/* Fall through - SS and HS isoc/int have same decoding */
|
/* Fall through - SS and HS isoc/int have same decoding */
|
||||||
|
|
||||||
case USB_SPEED_SUPER:
|
case USB_SPEED_SUPER:
|
||||||
if (usb_endpoint_xfer_int(&ep->desc) ||
|
if (usb_endpoint_xfer_int(&ep->desc) ||
|
||||||
usb_endpoint_xfer_isoc(&ep->desc)) {
|
usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||||
if (ep->desc.bInterval == 0)
|
interval = xhci_parse_exponent_interval(udev, ep);
|
||||||
interval = 0;
|
|
||||||
else
|
|
||||||
interval = ep->desc.bInterval - 1;
|
|
||||||
if (interval > 15)
|
|
||||||
interval = 15;
|
|
||||||
if (interval != ep->desc.bInterval + 1)
|
|
||||||
dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n",
|
|
||||||
ep->desc.bEndpointAddress, 1 << interval);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/* Convert bInterval (in 1-255 frames) to microframes and round down to
|
|
||||||
* nearest power of 2.
|
|
||||||
*/
|
|
||||||
case USB_SPEED_FULL:
|
case USB_SPEED_FULL:
|
||||||
|
if (usb_endpoint_xfer_int(&ep->desc)) {
|
||||||
|
interval = xhci_parse_exponent_interval(udev, ep);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Fall through for isochronous endpoint interval decoding
|
||||||
|
* since it uses the same rules as low speed interrupt
|
||||||
|
* endpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
case USB_SPEED_LOW:
|
case USB_SPEED_LOW:
|
||||||
if (usb_endpoint_xfer_int(&ep->desc) ||
|
if (usb_endpoint_xfer_int(&ep->desc) ||
|
||||||
usb_endpoint_xfer_isoc(&ep->desc)) {
|
usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||||
interval = fls(8*ep->desc.bInterval) - 1;
|
|
||||||
if (interval > 10)
|
interval = xhci_parse_frame_interval(udev, ep);
|
||||||
interval = 10;
|
|
||||||
if (interval < 3)
|
|
||||||
interval = 3;
|
|
||||||
if ((1 << interval) != 8*ep->desc.bInterval)
|
|
||||||
dev_warn(&udev->dev,
|
|
||||||
"ep %#x - rounding interval"
|
|
||||||
" to %d microframes, "
|
|
||||||
"ep desc says %d microframes\n",
|
|
||||||
ep->desc.bEndpointAddress,
|
|
||||||
1 << interval,
|
|
||||||
8*ep->desc.bInterval);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user