aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-07 13:14:23 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-07 13:14:23 -0500
commit102ee001912f67a7701f26a56ef2bcf84fc78028 (patch)
treeef1f70c744a734a745c4c8fbd67294bdbbc7df9a /drivers
parent962426e0e2312c5134db13f39d4389a2fa6a13d0 (diff)
parent026630d09ba7b6cd44a43b92ad256c28a9e3ddc2 (diff)
Merge tag 'for-usb-next-2013-01-03' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-next
Sarah writes: usb-next: Further warm reset improvements Hi Greg, Here's some patches for 3.9. They further improve the warm reset error handling, but they're too big to go into stable. There's also a patch to remove an unused variable in the xHCI driver. As I mentioned, you'll need to merge usb-linus into usb-next before applying these patches. Sarah Sharp
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/hub.c207
-rw-r--r--drivers/usb/host/xhci-ring.c2
2 files changed, 107 insertions, 102 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 9641e9c1dec5..ae10862fb041 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2535,77 +2535,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
2535 return ret; 2535 return ret;
2536 2536
2537 /* The port state is unknown until the reset completes. */ 2537 /* The port state is unknown until the reset completes. */
2538 if ((portstatus & USB_PORT_STAT_RESET)) 2538 if (!(portstatus & USB_PORT_STAT_RESET))
2539 goto delay; 2539 break;
2540
2541 /*
2542 * Some buggy devices require a warm reset to be issued even
2543 * when the port appears not to be connected.
2544 */
2545 if (!warm) {
2546 /*
2547 * Some buggy devices can cause an NEC host controller
2548 * to transition to the "Error" state after a hot port
2549 * reset. This will show up as the port state in
2550 * "Inactive", and the port may also report a
2551 * disconnect. Forcing a warm port reset seems to make
2552 * the device work.
2553 *
2554 * See https://bugzilla.kernel.org/show_bug.cgi?id=41752
2555 */
2556 if (hub_port_warm_reset_required(hub, portstatus)) {
2557 int ret;
2558
2559 if ((portchange & USB_PORT_STAT_C_CONNECTION))
2560 clear_port_feature(hub->hdev, port1,
2561 USB_PORT_FEAT_C_CONNECTION);
2562 if (portchange & USB_PORT_STAT_C_LINK_STATE)
2563 clear_port_feature(hub->hdev, port1,
2564 USB_PORT_FEAT_C_PORT_LINK_STATE);
2565 if (portchange & USB_PORT_STAT_C_RESET)
2566 clear_port_feature(hub->hdev, port1,
2567 USB_PORT_FEAT_C_RESET);
2568 dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n",
2569 port1);
2570 ret = hub_port_reset(hub, port1,
2571 udev, HUB_BH_RESET_TIME,
2572 true);
2573 if ((portchange & USB_PORT_STAT_C_CONNECTION))
2574 clear_port_feature(hub->hdev, port1,
2575 USB_PORT_FEAT_C_CONNECTION);
2576 return ret;
2577 }
2578 /* Device went away? */
2579 if (!(portstatus & USB_PORT_STAT_CONNECTION))
2580 return -ENOTCONN;
2581
2582 /* bomb out completely if the connection bounced */
2583 if ((portchange & USB_PORT_STAT_C_CONNECTION))
2584 return -ENOTCONN;
2585
2586 if ((portstatus & USB_PORT_STAT_ENABLE)) {
2587 if (hub_is_wusb(hub))
2588 udev->speed = USB_SPEED_WIRELESS;
2589 else if (hub_is_superspeed(hub->hdev))
2590 udev->speed = USB_SPEED_SUPER;
2591 else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
2592 udev->speed = USB_SPEED_HIGH;
2593 else if (portstatus & USB_PORT_STAT_LOW_SPEED)
2594 udev->speed = USB_SPEED_LOW;
2595 else
2596 udev->speed = USB_SPEED_FULL;
2597 return 0;
2598 }
2599 } else {
2600 if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
2601 hub_port_warm_reset_required(hub,
2602 portstatus))
2603 return -ENOTCONN;
2604
2605 return 0;
2606 }
2607 2540
2608delay:
2609 /* switch to the long delay after two short delay failures */ 2541 /* switch to the long delay after two short delay failures */
2610 if (delay_time >= 2 * HUB_SHORT_RESET_TIME) 2542 if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
2611 delay = HUB_LONG_RESET_TIME; 2543 delay = HUB_LONG_RESET_TIME;
@@ -2615,20 +2547,54 @@ delay:
2615 port1, warm ? "warm " : "", delay); 2547 port1, warm ? "warm " : "", delay);
2616 } 2548 }
2617 2549
2618 return -EBUSY; 2550 if ((portstatus & USB_PORT_STAT_RESET))
2551 return -EBUSY;
2552
2553 if (hub_port_warm_reset_required(hub, portstatus))
2554 return -ENOTCONN;
2555
2556 /* Device went away? */
2557 if (!(portstatus & USB_PORT_STAT_CONNECTION))
2558 return -ENOTCONN;
2559
2560 /* bomb out completely if the connection bounced. A USB 3.0
2561 * connection may bounce if multiple warm resets were issued,
2562 * but the device may have successfully re-connected. Ignore it.
2563 */
2564 if (!hub_is_superspeed(hub->hdev) &&
2565 (portchange & USB_PORT_STAT_C_CONNECTION))
2566 return -ENOTCONN;
2567
2568 if (!(portstatus & USB_PORT_STAT_ENABLE))
2569 return -EBUSY;
2570
2571 if (!udev)
2572 return 0;
2573
2574 if (hub_is_wusb(hub))
2575 udev->speed = USB_SPEED_WIRELESS;
2576 else if (hub_is_superspeed(hub->hdev))
2577 udev->speed = USB_SPEED_SUPER;
2578 else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
2579 udev->speed = USB_SPEED_HIGH;
2580 else if (portstatus & USB_PORT_STAT_LOW_SPEED)
2581 udev->speed = USB_SPEED_LOW;
2582 else
2583 udev->speed = USB_SPEED_FULL;
2584 return 0;
2619} 2585}
2620 2586
2621static void hub_port_finish_reset(struct usb_hub *hub, int port1, 2587static void hub_port_finish_reset(struct usb_hub *hub, int port1,
2622 struct usb_device *udev, int *status, bool warm) 2588 struct usb_device *udev, int *status)
2623{ 2589{
2624 switch (*status) { 2590 switch (*status) {
2625 case 0: 2591 case 0:
2626 if (!warm) { 2592 /* TRSTRCY = 10 ms; plus some extra */
2627 struct usb_hcd *hcd; 2593 msleep(10 + 40);
2628 /* TRSTRCY = 10 ms; plus some extra */ 2594 if (udev) {
2629 msleep(10 + 40); 2595 struct usb_hcd *hcd = bus_to_hcd(udev->bus);
2596
2630 update_devnum(udev, 0); 2597 update_devnum(udev, 0);
2631 hcd = bus_to_hcd(udev->bus);
2632 /* The xHC may think the device is already reset, 2598 /* The xHC may think the device is already reset,
2633 * so ignore the status. 2599 * so ignore the status.
2634 */ 2600 */
@@ -2640,14 +2606,15 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1,
2640 case -ENODEV: 2606 case -ENODEV:
2641 clear_port_feature(hub->hdev, 2607 clear_port_feature(hub->hdev,
2642 port1, USB_PORT_FEAT_C_RESET); 2608 port1, USB_PORT_FEAT_C_RESET);
2643 /* FIXME need disconnect() for NOTATTACHED device */
2644 if (hub_is_superspeed(hub->hdev)) { 2609 if (hub_is_superspeed(hub->hdev)) {
2645 clear_port_feature(hub->hdev, port1, 2610 clear_port_feature(hub->hdev, port1,
2646 USB_PORT_FEAT_C_BH_PORT_RESET); 2611 USB_PORT_FEAT_C_BH_PORT_RESET);
2647 clear_port_feature(hub->hdev, port1, 2612 clear_port_feature(hub->hdev, port1,
2648 USB_PORT_FEAT_C_PORT_LINK_STATE); 2613 USB_PORT_FEAT_C_PORT_LINK_STATE);
2614 clear_port_feature(hub->hdev, port1,
2615 USB_PORT_FEAT_C_CONNECTION);
2649 } 2616 }
2650 if (!warm) 2617 if (udev)
2651 usb_set_device_state(udev, *status 2618 usb_set_device_state(udev, *status
2652 ? USB_STATE_NOTATTACHED 2619 ? USB_STATE_NOTATTACHED
2653 : USB_STATE_DEFAULT); 2620 : USB_STATE_DEFAULT);
@@ -2660,18 +2627,30 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
2660 struct usb_device *udev, unsigned int delay, bool warm) 2627 struct usb_device *udev, unsigned int delay, bool warm)
2661{ 2628{
2662 int i, status; 2629 int i, status;
2630 u16 portchange, portstatus;
2663 2631
2664 if (!warm) { 2632 if (!hub_is_superspeed(hub->hdev)) {
2665 /* Block EHCI CF initialization during the port reset. 2633 if (warm) {
2666 * Some companion controllers don't like it when they mix.
2667 */
2668 down_read(&ehci_cf_port_reset_rwsem);
2669 } else {
2670 if (!hub_is_superspeed(hub->hdev)) {
2671 dev_err(hub->intfdev, "only USB3 hub support " 2634 dev_err(hub->intfdev, "only USB3 hub support "
2672 "warm reset\n"); 2635 "warm reset\n");
2673 return -EINVAL; 2636 return -EINVAL;
2674 } 2637 }
2638 /* Block EHCI CF initialization during the port reset.
2639 * Some companion controllers don't like it when they mix.
2640 */
2641 down_read(&ehci_cf_port_reset_rwsem);
2642 } else if (!warm) {
2643 /*
2644 * If the caller hasn't explicitly requested a warm reset,
2645 * double check and see if one is needed.
2646 */
2647 status = hub_port_status(hub, port1,
2648 &portstatus, &portchange);
2649 if (status < 0)
2650 goto done;
2651
2652 if (hub_port_warm_reset_required(hub, portstatus))
2653 warm = true;
2675 } 2654 }
2676 2655
2677 /* Reset the port */ 2656 /* Reset the port */
@@ -2692,10 +2671,33 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
2692 status); 2671 status);
2693 } 2672 }
2694 2673
2695 /* return on disconnect or reset */ 2674 /* Check for disconnect or reset */
2696 if (status == 0 || status == -ENOTCONN || status == -ENODEV) { 2675 if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
2697 hub_port_finish_reset(hub, port1, udev, &status, warm); 2676 hub_port_finish_reset(hub, port1, udev, &status);
2698 goto done; 2677
2678 if (!hub_is_superspeed(hub->hdev))
2679 goto done;
2680
2681 /*
2682 * If a USB 3.0 device migrates from reset to an error
2683 * state, re-issue the warm reset.
2684 */
2685 if (hub_port_status(hub, port1,
2686 &portstatus, &portchange) < 0)
2687 goto done;
2688
2689 if (!hub_port_warm_reset_required(hub, portstatus))
2690 goto done;
2691
2692 /*
2693 * If the port is in SS.Inactive or Compliance Mode, the
2694 * hot or warm reset failed. Try another warm reset.
2695 */
2696 if (!warm) {
2697 dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n",
2698 port1);
2699 warm = true;
2700 }
2699 } 2701 }
2700 2702
2701 dev_dbg (hub->intfdev, 2703 dev_dbg (hub->intfdev,
@@ -2709,7 +2711,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
2709 port1); 2711 port1);
2710 2712
2711done: 2713done:
2712 if (!warm) 2714 if (!hub_is_superspeed(hub->hdev))
2713 up_read(&ehci_cf_port_reset_rwsem); 2715 up_read(&ehci_cf_port_reset_rwsem);
2714 2716
2715 return status; 2717 return status;
@@ -2945,9 +2947,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
2945 2947
2946 /* see 7.1.7.6 */ 2948 /* see 7.1.7.6 */
2947 if (hub_is_superspeed(hub->hdev)) 2949 if (hub_is_superspeed(hub->hdev))
2948 status = set_port_feature(hub->hdev, 2950 status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
2949 port1 | (USB_SS_PORT_LS_U3 << 3),
2950 USB_PORT_FEAT_LINK_STATE);
2951 else 2951 else
2952 status = set_port_feature(hub->hdev, port1, 2952 status = set_port_feature(hub->hdev, port1,
2953 USB_PORT_FEAT_SUSPEND); 2953 USB_PORT_FEAT_SUSPEND);
@@ -3117,9 +3117,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
3117 3117
3118 /* see 7.1.7.7; affects power usage, but not budgeting */ 3118 /* see 7.1.7.7; affects power usage, but not budgeting */
3119 if (hub_is_superspeed(hub->hdev)) 3119 if (hub_is_superspeed(hub->hdev))
3120 status = set_port_feature(hub->hdev, 3120 status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U0);
3121 port1 | (USB_SS_PORT_LS_U0 << 3),
3122 USB_PORT_FEAT_LINK_STATE);
3123 else 3121 else
3124 status = clear_port_feature(hub->hdev, 3122 status = clear_port_feature(hub->hdev,
3125 port1, USB_PORT_FEAT_SUSPEND); 3123 port1, USB_PORT_FEAT_SUSPEND);
@@ -4700,12 +4698,21 @@ static void hub_events(void)
4700 */ 4698 */
4701 if (hub_port_warm_reset_required(hub, portstatus)) { 4699 if (hub_port_warm_reset_required(hub, portstatus)) {
4702 int status; 4700 int status;
4701 struct usb_device *udev =
4702 hub->ports[i - 1]->child;
4703 4703
4704 dev_dbg(hub_dev, "warm reset port %d\n", i); 4704 dev_dbg(hub_dev, "warm reset port %d\n", i);
4705 status = hub_port_reset(hub, i, NULL, 4705 if (!udev) {
4706 HUB_BH_RESET_TIME, true); 4706 status = hub_port_reset(hub, i,
4707 if (status < 0) 4707 NULL, HUB_BH_RESET_TIME,
4708 hub_port_disable(hub, i, 1); 4708 true);
4709 if (status < 0)
4710 hub_port_disable(hub, i, 1);
4711 } else {
4712 usb_lock_device(udev);
4713 status = usb_reset_device(udev);
4714 usb_unlock_device(udev);
4715 }
4709 connect_change = 0; 4716 connect_change = 0;
4710 } 4717 }
4711 4718
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 59fb5c677dbe..f69720983fc7 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2706,13 +2706,11 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
2706{ 2706{
2707 struct xhci_hcd *xhci = hcd_to_xhci(hcd); 2707 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
2708 u32 status; 2708 u32 status;
2709 union xhci_trb *trb;
2710 u64 temp_64; 2709 u64 temp_64;
2711 union xhci_trb *event_ring_deq; 2710 union xhci_trb *event_ring_deq;
2712 dma_addr_t deq; 2711 dma_addr_t deq;
2713 2712
2714 spin_lock(&xhci->lock); 2713 spin_lock(&xhci->lock);
2715 trb = xhci->event_ring->dequeue;
2716 /* Check if the xHC generated the interrupt, or the irq is shared */ 2714 /* Check if the xHC generated the interrupt, or the irq is shared */
2717 status = xhci_readl(xhci, &xhci->op_regs->status); 2715 status = xhci_readl(xhci, &xhci->op_regs->status);
2718 if (status == 0xffffffff) 2716 if (status == 0xffffffff)