Skip to content

Commit

Permalink
Merge tag 'for-usb-next-2012-05-03' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/kernel/git/sarah/xhci into usb-next

xhci: isoc, Intel xHCI, and suspend races.

Hi Greg,

Here's some xHCI fixes that should be queued for 3.5.

The first patch builds on Alan Stern's 3.4 patch to close the suspend and port
event race conditions.  It's marked for 3.4 stable, since that's where Alan's
patch landed.  The second patch fixes an incorrect error code that the xHCI
driver would return when an isochronous transfer error occurred.

The third and fourth patches fix issues seen on Intel xHCI host controllers.
The third patch fixes a dead port issue that was seen on the Panther Point
EHCI/xHCI host when CONFIG_USB_XHCI_HCD was turned off.  The ports were being
switched over to xHCI, even though the xHCI driver was never even built.  The
fourth patch adds support for the EHCI to xHCI port switchover for the upcoming
Intel Lynx Point chipset.

As I said, there's nothing here that's terribly urgent, and these patches can
wait a couple weeks for the 3.5 merge window.

Thanks,
Sarah Sharp
  • Loading branch information
Greg Kroah-Hartman committed May 3, 2012
2 parents 3244560 + 1c12443 commit cbad67e
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 14 deletions.
4 changes: 3 additions & 1 deletion drivers/usb/host/ehci-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,9 @@ static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
{
return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == 0x1E26;
(pdev->device == 0x1E26 ||
pdev->device == 0x8C2D ||
pdev->device == 0x8C26);
}

static void ehci_enable_xhci_companion(void)
Expand Down
32 changes: 31 additions & 1 deletion drivers/usb/host/pci-quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

#include <linux/types.h>
#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
Expand Down Expand Up @@ -712,12 +713,28 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
return -ETIMEDOUT;
}

bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31

bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev)
{
return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
}

/* The Intel Lynx Point chipset also has switchable ports. */
bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev)
{
return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI;
}

bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
{
return usb_is_intel_ppt_switchable_xhci(pdev) ||
usb_is_intel_lpt_switchable_xhci(pdev);
}
EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);

/*
Expand All @@ -742,6 +759,19 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
{
u32 ports_available;

/* Don't switchover the ports if the user hasn't compiled the xHCI
* driver. Otherwise they will see "dead" USB ports that don't power
* the devices.
*/
if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) {
dev_warn(&xhci_pdev->dev,
"CONFIG_USB_XHCI_HCD is turned off, "
"defaulting to EHCI.\n");
dev_warn(&xhci_pdev->dev,
"USB 3.0 devices will work at USB 2.0 speeds.\n");
return;
}

ports_available = 0xffffffff;
/* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable
* Register, to turn on SuperSpeed terminations for all
Expand Down
22 changes: 12 additions & 10 deletions drivers/usb/host/xhci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_dbg(xhci, "Resume USB2 port %d\n",
wIndex + 1);
bus_state->resume_done[wIndex] = 0;
clear_bit(wIndex, &bus_state->resuming_ports);
xhci_set_link_state(xhci, port_array, wIndex,
XDEV_U0);
xhci_dbg(xhci, "set port %d resume\n",
Expand Down Expand Up @@ -845,7 +846,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
/* Initial status is no changes */
retval = (max_ports + 8) / 8;
memset(buf, 0, retval);
status = 0;

/*
* Inform the usbcore about resume-in-progress by returning
* a non-zero value even if there are no status changes.
*/
status = bus_state->resuming_ports;

mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;

Expand Down Expand Up @@ -885,15 +891,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
spin_lock_irqsave(&xhci->lock, flags);

if (hcd->self.root_hub->do_remote_wakeup) {
port_index = max_ports;
while (port_index--) {
if (bus_state->resume_done[port_index] != 0) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "suspend failed because "
"port %d is resuming\n",
port_index + 1);
return -EBUSY;
}
if (bus_state->resuming_ports) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "suspend failed because "
"a port is resuming\n");
return -EBUSY;
}
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/host/xhci-ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
xhci_dbg(xhci, "resume HS port %d\n", port_id);
bus_state->resume_done[faked_port_index] = jiffies +
msecs_to_jiffies(20);
set_bit(faked_port_index, &bus_state->resuming_ports);
mod_timer(&hcd->rh_timer,
bus_state->resume_done[faked_port_index]);
/* Do the rest in GetPortStatus */
Expand Down Expand Up @@ -1803,6 +1804,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
break;
case COMP_DEV_ERR:
case COMP_STALL:
case COMP_TX_ERR:
frame->status = -EPROTO;
skip_td = true;
break;
Expand Down
12 changes: 10 additions & 2 deletions drivers/usb/host/xhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ int xhci_reset(struct xhci_hcd *xhci)
{
u32 command;
u32 state;
int ret;
int ret, i;

state = xhci_readl(xhci, &xhci->op_regs->status);
if ((state & STS_HALT) == 0) {
Expand All @@ -175,7 +175,15 @@ int xhci_reset(struct xhci_hcd *xhci)
* xHCI cannot write to any doorbells or operational registers other
* than status until the "Controller Not Ready" flag is cleared.
*/
return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);

for (i = 0; i < 2; ++i) {
xhci->bus_state[i].port_c_suspend = 0;
xhci->bus_state[i].suspended_ports = 0;
xhci->bus_state[i].resuming_ports = 0;
}

return ret;
}

#ifdef CONFIG_PCI
Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/host/xhci.h
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,8 @@ struct xhci_bus_state {
u32 suspended_ports;
u32 port_remote_wakeup;
unsigned long resume_done[USB_MAXCHILDREN];
/* which ports have started to resume */
unsigned long resuming_ports;
};

static inline unsigned int hcd_index(struct usb_hcd *hcd)
Expand Down

0 comments on commit cbad67e

Please sign in to comment.