Commit 9a9a71b7 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'for-usb-linus-2012-02-21' of...

Merge tag 'for-usb-linus-2012-02-21' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-linus

Hi Greg,

Here's three bug fixes that should be queued for 3.3.

The first fixes an issue we saw with an Intel Panther Point xHCI host,
where a certain OSV's custom BIOS would disable the PCI device during
boot.  It changes the generic PCI quirks handler for all USB host
controllers, but in a way both Jesse Barnes and Oliver Neukum have
agreed is safe.

The second patch is Elric Fu's first kernel patch!  Congrats!  It fixes
a bug in the USB 3.0 hub reset handling.

The last patch fixes a bug in the xHCI driver that feeds invalid input
to the xHC host.  Only the VIA host controller seems to have issues with
it.  Thanks to Felipe Contreras for testing this patch on his VIA host,
and Andiry Xu for suggesting the fix.

All three patches are marked for stable.

Sarah Sharp
parents b9e44fe5 340a3504
...@@ -705,10 +705,26 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) ...@@ -705,10 +705,26 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
if (type == HUB_INIT3) if (type == HUB_INIT3)
goto init3; goto init3;
/* After a resume, port power should still be on. /* The superspeed hub except for root hub has to use Hub Depth
* value as an offset into the route string to locate the bits
* it uses to determine the downstream port number. So hub driver
* should send a set hub depth request to superspeed hub after
* the superspeed hub is set configuration in initialization or
* reset procedure.
*
* After a resume, port power should still be on.
* For any other type of activation, turn it on. * For any other type of activation, turn it on.
*/ */
if (type != HUB_RESUME) { if (type != HUB_RESUME) {
if (hdev->parent && hub_is_superspeed(hdev)) {
ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
HUB_SET_DEPTH, USB_RT_HUB,
hdev->level - 1, 0, NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (ret < 0)
dev_err(hub->intfdev,
"set hub depth failed\n");
}
/* Speed up system boot by using a delayed_work for the /* Speed up system boot by using a delayed_work for the
* hub's initial power-up delays. This is pretty awkward * hub's initial power-up delays. This is pretty awkward
...@@ -987,18 +1003,6 @@ static int hub_configure(struct usb_hub *hub, ...@@ -987,18 +1003,6 @@ static int hub_configure(struct usb_hub *hub,
goto fail; goto fail;
} }
if (hub_is_superspeed(hdev) && (hdev->parent != NULL)) {
ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
HUB_SET_DEPTH, USB_RT_HUB,
hdev->level - 1, 0, NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (ret < 0) {
message = "can't set hub depth";
goto fail;
}
}
/* Request the entire hub descriptor. /* Request the entire hub descriptor.
* hub->descriptor can handle USB_MAXCHILDREN ports, * hub->descriptor can handle USB_MAXCHILDREN ports,
* but the hub can/will return fewer bytes here. * but the hub can/will return fewer bytes here.
......
...@@ -872,7 +872,17 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) ...@@ -872,7 +872,17 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
*/ */
if (pdev->vendor == 0x184e) /* vendor Netlogic */ if (pdev->vendor == 0x184e) /* vendor Netlogic */
return; return;
if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI &&
pdev->class != PCI_CLASS_SERIAL_USB_OHCI &&
pdev->class != PCI_CLASS_SERIAL_USB_EHCI &&
pdev->class != PCI_CLASS_SERIAL_USB_XHCI)
return;
if (pci_enable_device(pdev) < 0) {
dev_warn(&pdev->dev, "Can't enable PCI device, "
"BIOS handoff failed.\n");
return;
}
if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI) if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI)
quirk_usb_handoff_uhci(pdev); quirk_usb_handoff_uhci(pdev);
else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI) else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI)
...@@ -881,5 +891,6 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) ...@@ -881,5 +891,6 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
quirk_usb_disable_ehci(pdev); quirk_usb_disable_ehci(pdev);
else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI) else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
quirk_usb_handoff_xhci(pdev); quirk_usb_handoff_xhci(pdev);
pci_disable_device(pdev);
} }
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
...@@ -1126,26 +1126,42 @@ static unsigned int xhci_parse_exponent_interval(struct usb_device *udev, ...@@ -1126,26 +1126,42 @@ static unsigned int xhci_parse_exponent_interval(struct usb_device *udev,
} }
/* /*
* Convert bInterval expressed in frames (in 1-255 range) to exponent of * Convert bInterval expressed in microframes (in 1-255 range) to exponent of
* microframes, rounded down to nearest power of 2. * microframes, rounded down to nearest power of 2.
*/ */
static unsigned int xhci_parse_frame_interval(struct usb_device *udev, static unsigned int xhci_microframes_to_exponent(struct usb_device *udev,
struct usb_host_endpoint *ep) struct usb_host_endpoint *ep, unsigned int desc_interval,
unsigned int min_exponent, unsigned int max_exponent)
{ {
unsigned int interval; unsigned int interval;
interval = fls(8 * ep->desc.bInterval) - 1; interval = fls(desc_interval) - 1;
interval = clamp_val(interval, 3, 10); interval = clamp_val(interval, min_exponent, max_exponent);
if ((1 << interval) != 8 * ep->desc.bInterval) if ((1 << interval) != desc_interval)
dev_warn(&udev->dev, dev_warn(&udev->dev,
"ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n", "ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n",
ep->desc.bEndpointAddress, ep->desc.bEndpointAddress,
1 << interval, 1 << interval,
8 * ep->desc.bInterval); desc_interval);
return interval; return interval;
} }
static unsigned int xhci_parse_microframe_interval(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
return xhci_microframes_to_exponent(udev, ep,
ep->desc.bInterval, 0, 15);
}
static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
return xhci_microframes_to_exponent(udev, ep,
ep->desc.bInterval * 8, 3, 10);
}
/* 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
...@@ -1164,7 +1180,7 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev, ...@@ -1164,7 +1180,7 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
/* 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 = xhci_parse_microframe_interval(udev, ep);
break; break;
} }
/* Fall through - SS and HS isoc/int have same decoding */ /* Fall through - SS and HS isoc/int have same decoding */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment