diff options
| -rw-r--r-- | drivers/usb/core/hub.c | 110 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 38 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-mem.c | 2 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 9 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.c | 10 |
5 files changed, 145 insertions, 24 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a815fd2cc5e..9641e9c1dec 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
| @@ -877,6 +877,60 @@ static int hub_hub_status(struct usb_hub *hub, | |||
| 877 | return ret; | 877 | return ret; |
| 878 | } | 878 | } |
| 879 | 879 | ||
| 880 | static int hub_set_port_link_state(struct usb_hub *hub, int port1, | ||
| 881 | unsigned int link_status) | ||
| 882 | { | ||
| 883 | return set_port_feature(hub->hdev, | ||
| 884 | port1 | (link_status << 3), | ||
| 885 | USB_PORT_FEAT_LINK_STATE); | ||
| 886 | } | ||
| 887 | |||
| 888 | /* | ||
| 889 | * If USB 3.0 ports are placed into the Disabled state, they will no longer | ||
| 890 | * detect any device connects or disconnects. This is generally not what the | ||
| 891 | * USB core wants, since it expects a disabled port to produce a port status | ||
| 892 | * change event when a new device connects. | ||
| 893 | * | ||
| 894 | * Instead, set the link state to Disabled, wait for the link to settle into | ||
| 895 | * that state, clear any change bits, and then put the port into the RxDetect | ||
| 896 | * state. | ||
| 897 | */ | ||
| 898 | static int hub_usb3_port_disable(struct usb_hub *hub, int port1) | ||
| 899 | { | ||
| 900 | int ret; | ||
| 901 | int total_time; | ||
| 902 | u16 portchange, portstatus; | ||
| 903 | |||
| 904 | if (!hub_is_superspeed(hub->hdev)) | ||
| 905 | return -EINVAL; | ||
| 906 | |||
| 907 | ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED); | ||
| 908 | if (ret) { | ||
| 909 | dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", | ||
| 910 | port1, ret); | ||
| 911 | return ret; | ||
| 912 | } | ||
| 913 | |||
| 914 | /* Wait for the link to enter the disabled state. */ | ||
| 915 | for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { | ||
| 916 | ret = hub_port_status(hub, port1, &portstatus, &portchange); | ||
| 917 | if (ret < 0) | ||
| 918 | return ret; | ||
| 919 | |||
| 920 | if ((portstatus & USB_PORT_STAT_LINK_STATE) == | ||
| 921 | USB_SS_PORT_LS_SS_DISABLED) | ||
| 922 | break; | ||
| 923 | if (total_time >= HUB_DEBOUNCE_TIMEOUT) | ||
| 924 | break; | ||
| 925 | msleep(HUB_DEBOUNCE_STEP); | ||
| 926 | } | ||
| 927 | if (total_time >= HUB_DEBOUNCE_TIMEOUT) | ||
| 928 | dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n", | ||
| 929 | port1, total_time); | ||
| 930 | |||
| 931 | return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT); | ||
| 932 | } | ||
| 933 | |||
| 880 | static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) | 934 | static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) |
| 881 | { | 935 | { |
| 882 | struct usb_device *hdev = hub->hdev; | 936 | struct usb_device *hdev = hub->hdev; |
| @@ -885,8 +939,13 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) | |||
| 885 | if (hub->ports[port1 - 1]->child && set_state) | 939 | if (hub->ports[port1 - 1]->child && set_state) |
| 886 | usb_set_device_state(hub->ports[port1 - 1]->child, | 940 | usb_set_device_state(hub->ports[port1 - 1]->child, |
| 887 | USB_STATE_NOTATTACHED); | 941 | USB_STATE_NOTATTACHED); |
| 888 | if (!hub->error && !hub_is_superspeed(hub->hdev)) | 942 | if (!hub->error) { |
| 889 | ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); | 943 | if (hub_is_superspeed(hub->hdev)) |
| 944 | ret = hub_usb3_port_disable(hub, port1); | ||
| 945 | else | ||
| 946 | ret = clear_port_feature(hdev, port1, | ||
| 947 | USB_PORT_FEAT_ENABLE); | ||
| 948 | } | ||
| 890 | if (ret) | 949 | if (ret) |
| 891 | dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", | 950 | dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", |
| 892 | port1, ret); | 951 | port1, ret); |
| @@ -2440,7 +2499,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) | |||
| 2440 | #define HUB_SHORT_RESET_TIME 10 | 2499 | #define HUB_SHORT_RESET_TIME 10 |
| 2441 | #define HUB_BH_RESET_TIME 50 | 2500 | #define HUB_BH_RESET_TIME 50 |
| 2442 | #define HUB_LONG_RESET_TIME 200 | 2501 | #define HUB_LONG_RESET_TIME 200 |
| 2443 | #define HUB_RESET_TIMEOUT 500 | 2502 | #define HUB_RESET_TIMEOUT 800 |
| 2444 | 2503 | ||
| 2445 | static int hub_port_reset(struct usb_hub *hub, int port1, | 2504 | static int hub_port_reset(struct usb_hub *hub, int port1, |
| 2446 | struct usb_device *udev, unsigned int delay, bool warm); | 2505 | struct usb_device *udev, unsigned int delay, bool warm); |
| @@ -2475,6 +2534,10 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, | |||
| 2475 | if (ret < 0) | 2534 | if (ret < 0) |
| 2476 | return ret; | 2535 | return ret; |
| 2477 | 2536 | ||
| 2537 | /* The port state is unknown until the reset completes. */ | ||
| 2538 | if ((portstatus & USB_PORT_STAT_RESET)) | ||
| 2539 | goto delay; | ||
| 2540 | |||
| 2478 | /* | 2541 | /* |
| 2479 | * Some buggy devices require a warm reset to be issued even | 2542 | * Some buggy devices require a warm reset to be issued even |
| 2480 | * when the port appears not to be connected. | 2543 | * when the port appears not to be connected. |
| @@ -2520,11 +2583,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, | |||
| 2520 | if ((portchange & USB_PORT_STAT_C_CONNECTION)) | 2583 | if ((portchange & USB_PORT_STAT_C_CONNECTION)) |
| 2521 | return -ENOTCONN; | 2584 | return -ENOTCONN; |
| 2522 | 2585 | ||
| 2523 | /* if we`ve finished resetting, then break out of | 2586 | if ((portstatus & USB_PORT_STAT_ENABLE)) { |
| 2524 | * the loop | ||
| 2525 | */ | ||
| 2526 | if (!(portstatus & USB_PORT_STAT_RESET) && | ||
| 2527 | (portstatus & USB_PORT_STAT_ENABLE)) { | ||
| 2528 | if (hub_is_wusb(hub)) | 2587 | if (hub_is_wusb(hub)) |
| 2529 | udev->speed = USB_SPEED_WIRELESS; | 2588 | udev->speed = USB_SPEED_WIRELESS; |
| 2530 | else if (hub_is_superspeed(hub->hdev)) | 2589 | else if (hub_is_superspeed(hub->hdev)) |
| @@ -2538,10 +2597,15 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, | |||
| 2538 | return 0; | 2597 | return 0; |
| 2539 | } | 2598 | } |
| 2540 | } else { | 2599 | } else { |
| 2541 | if (portchange & USB_PORT_STAT_C_BH_RESET) | 2600 | if (!(portstatus & USB_PORT_STAT_CONNECTION) || |
| 2542 | return 0; | 2601 | hub_port_warm_reset_required(hub, |
| 2602 | portstatus)) | ||
| 2603 | return -ENOTCONN; | ||
| 2604 | |||
| 2605 | return 0; | ||
| 2543 | } | 2606 | } |
| 2544 | 2607 | ||
| 2608 | delay: | ||
| 2545 | /* switch to the long delay after two short delay failures */ | 2609 | /* switch to the long delay after two short delay failures */ |
| 2546 | if (delay_time >= 2 * HUB_SHORT_RESET_TIME) | 2610 | if (delay_time >= 2 * HUB_SHORT_RESET_TIME) |
| 2547 | delay = HUB_LONG_RESET_TIME; | 2611 | delay = HUB_LONG_RESET_TIME; |
| @@ -2565,14 +2629,11 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1, | |||
| 2565 | msleep(10 + 40); | 2629 | msleep(10 + 40); |
| 2566 | update_devnum(udev, 0); | 2630 | update_devnum(udev, 0); |
| 2567 | hcd = bus_to_hcd(udev->bus); | 2631 | hcd = bus_to_hcd(udev->bus); |
| 2568 | if (hcd->driver->reset_device) { | 2632 | /* The xHC may think the device is already reset, |
| 2569 | *status = hcd->driver->reset_device(hcd, udev); | 2633 | * so ignore the status. |
| 2570 | if (*status < 0) { | 2634 | */ |
| 2571 | dev_err(&udev->dev, "Cannot reset " | 2635 | if (hcd->driver->reset_device) |
| 2572 | "HCD device state\n"); | 2636 | hcd->driver->reset_device(hcd, udev); |
| 2573 | break; | ||
| 2574 | } | ||
| 2575 | } | ||
| 2576 | } | 2637 | } |
| 2577 | /* FALL THROUGH */ | 2638 | /* FALL THROUGH */ |
| 2578 | case -ENOTCONN: | 2639 | case -ENOTCONN: |
| @@ -2580,16 +2641,16 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1, | |||
| 2580 | clear_port_feature(hub->hdev, | 2641 | clear_port_feature(hub->hdev, |
| 2581 | port1, USB_PORT_FEAT_C_RESET); | 2642 | port1, USB_PORT_FEAT_C_RESET); |
| 2582 | /* FIXME need disconnect() for NOTATTACHED device */ | 2643 | /* FIXME need disconnect() for NOTATTACHED device */ |
| 2583 | if (warm) { | 2644 | if (hub_is_superspeed(hub->hdev)) { |
| 2584 | clear_port_feature(hub->hdev, port1, | 2645 | clear_port_feature(hub->hdev, port1, |
| 2585 | USB_PORT_FEAT_C_BH_PORT_RESET); | 2646 | USB_PORT_FEAT_C_BH_PORT_RESET); |
| 2586 | clear_port_feature(hub->hdev, port1, | 2647 | clear_port_feature(hub->hdev, port1, |
| 2587 | USB_PORT_FEAT_C_PORT_LINK_STATE); | 2648 | USB_PORT_FEAT_C_PORT_LINK_STATE); |
| 2588 | } else { | 2649 | } |
| 2650 | if (!warm) | ||
| 2589 | usb_set_device_state(udev, *status | 2651 | usb_set_device_state(udev, *status |
| 2590 | ? USB_STATE_NOTATTACHED | 2652 | ? USB_STATE_NOTATTACHED |
| 2591 | : USB_STATE_DEFAULT); | 2653 | : USB_STATE_DEFAULT); |
| 2592 | } | ||
| 2593 | break; | 2654 | break; |
| 2594 | } | 2655 | } |
| 2595 | } | 2656 | } |
| @@ -4638,9 +4699,14 @@ static void hub_events(void) | |||
| 4638 | * SS.Inactive state. | 4699 | * SS.Inactive state. |
| 4639 | */ | 4700 | */ |
| 4640 | if (hub_port_warm_reset_required(hub, portstatus)) { | 4701 | if (hub_port_warm_reset_required(hub, portstatus)) { |
| 4702 | int status; | ||
| 4703 | |||
| 4641 | dev_dbg(hub_dev, "warm reset port %d\n", i); | 4704 | dev_dbg(hub_dev, "warm reset port %d\n", i); |
| 4642 | hub_port_reset(hub, i, NULL, | 4705 | status = hub_port_reset(hub, i, NULL, |
| 4643 | HUB_BH_RESET_TIME, true); | 4706 | HUB_BH_RESET_TIME, true); |
| 4707 | if (status < 0) | ||
| 4708 | hub_port_disable(hub, i, 1); | ||
| 4709 | connect_change = 0; | ||
| 4644 | } | 4710 | } |
| 4645 | 4711 | ||
| 4646 | if (connect_change) | 4712 | if (connect_change) |
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index a686cf4905b..68914429482 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
| @@ -761,12 +761,39 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
| 761 | break; | 761 | break; |
| 762 | case USB_PORT_FEAT_LINK_STATE: | 762 | case USB_PORT_FEAT_LINK_STATE: |
| 763 | temp = xhci_readl(xhci, port_array[wIndex]); | 763 | temp = xhci_readl(xhci, port_array[wIndex]); |
| 764 | |||
| 765 | /* Disable port */ | ||
| 766 | if (link_state == USB_SS_PORT_LS_SS_DISABLED) { | ||
| 767 | xhci_dbg(xhci, "Disable port %d\n", wIndex); | ||
| 768 | temp = xhci_port_state_to_neutral(temp); | ||
| 769 | /* | ||
| 770 | * Clear all change bits, so that we get a new | ||
| 771 | * connection event. | ||
| 772 | */ | ||
| 773 | temp |= PORT_CSC | PORT_PEC | PORT_WRC | | ||
| 774 | PORT_OCC | PORT_RC | PORT_PLC | | ||
| 775 | PORT_CEC; | ||
| 776 | xhci_writel(xhci, temp | PORT_PE, | ||
| 777 | port_array[wIndex]); | ||
| 778 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
| 779 | break; | ||
| 780 | } | ||
| 781 | |||
| 782 | /* Put link in RxDetect (enable port) */ | ||
| 783 | if (link_state == USB_SS_PORT_LS_RX_DETECT) { | ||
| 784 | xhci_dbg(xhci, "Enable port %d\n", wIndex); | ||
| 785 | xhci_set_link_state(xhci, port_array, wIndex, | ||
| 786 | link_state); | ||
| 787 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
| 788 | break; | ||
| 789 | } | ||
| 790 | |||
| 764 | /* Software should not attempt to set | 791 | /* Software should not attempt to set |
| 765 | * port link state above '5' (Rx.Detect) and the port | 792 | * port link state above '3' (U3) and the port |
| 766 | * must be enabled. | 793 | * must be enabled. |
| 767 | */ | 794 | */ |
| 768 | if ((temp & PORT_PE) == 0 || | 795 | if ((temp & PORT_PE) == 0 || |
| 769 | (link_state > USB_SS_PORT_LS_RX_DETECT)) { | 796 | (link_state > USB_SS_PORT_LS_U3)) { |
| 770 | xhci_warn(xhci, "Cannot set link state.\n"); | 797 | xhci_warn(xhci, "Cannot set link state.\n"); |
| 771 | goto error; | 798 | goto error; |
| 772 | } | 799 | } |
| @@ -957,6 +984,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
| 957 | int max_ports; | 984 | int max_ports; |
| 958 | __le32 __iomem **port_array; | 985 | __le32 __iomem **port_array; |
| 959 | struct xhci_bus_state *bus_state; | 986 | struct xhci_bus_state *bus_state; |
| 987 | bool reset_change = false; | ||
| 960 | 988 | ||
| 961 | max_ports = xhci_get_ports(hcd, &port_array); | 989 | max_ports = xhci_get_ports(hcd, &port_array); |
| 962 | bus_state = &xhci->bus_state[hcd_index(hcd)]; | 990 | bus_state = &xhci->bus_state[hcd_index(hcd)]; |
| @@ -988,6 +1016,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
| 988 | buf[(i + 1) / 8] |= 1 << (i + 1) % 8; | 1016 | buf[(i + 1) / 8] |= 1 << (i + 1) % 8; |
| 989 | status = 1; | 1017 | status = 1; |
| 990 | } | 1018 | } |
| 1019 | if ((temp & PORT_RC)) | ||
| 1020 | reset_change = true; | ||
| 1021 | } | ||
| 1022 | if (!status && !reset_change) { | ||
| 1023 | xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); | ||
| 1024 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
| 991 | } | 1025 | } |
| 992 | spin_unlock_irqrestore(&xhci->lock, flags); | 1026 | spin_unlock_irqrestore(&xhci->lock, flags); |
| 993 | return status ? retval : 0; | 1027 | return status ? retval : 0; |
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fb51c7085ad..35616ffbe3a 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
| @@ -1250,6 +1250,8 @@ static unsigned int xhci_microframes_to_exponent(struct usb_device *udev, | |||
| 1250 | static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, | 1250 | static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, |
| 1251 | struct usb_host_endpoint *ep) | 1251 | struct usb_host_endpoint *ep) |
| 1252 | { | 1252 | { |
| 1253 | if (ep->desc.bInterval == 0) | ||
| 1254 | return 0; | ||
| 1253 | return xhci_microframes_to_exponent(udev, ep, | 1255 | return xhci_microframes_to_exponent(udev, ep, |
| 1254 | ep->desc.bInterval, 0, 15); | 1256 | ep->desc.bInterval, 0, 15); |
| 1255 | } | 1257 | } |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index cbb44b7b9d6..59fb5c677db 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
| @@ -1725,6 +1725,15 @@ cleanup: | |||
| 1725 | if (bogus_port_status) | 1725 | if (bogus_port_status) |
| 1726 | return; | 1726 | return; |
| 1727 | 1727 | ||
| 1728 | /* | ||
| 1729 | * xHCI port-status-change events occur when the "or" of all the | ||
| 1730 | * status-change bits in the portsc register changes from 0 to 1. | ||
| 1731 | * New status changes won't cause an event if any other change | ||
| 1732 | * bits are still set. When an event occurs, switch over to | ||
| 1733 | * polling to avoid losing status changes. | ||
| 1734 | */ | ||
| 1735 | xhci_dbg(xhci, "%s: starting port polling.\n", __func__); | ||
| 1736 | set_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
| 1728 | spin_unlock(&xhci->lock); | 1737 | spin_unlock(&xhci->lock); |
| 1729 | /* Pass this up to the core */ | 1738 | /* Pass this up to the core */ |
| 1730 | usb_hcd_poll_rh_status(hcd); | 1739 | usb_hcd_poll_rh_status(hcd); |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5c72c431bab..f1f01a834ba 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
| @@ -884,6 +884,11 @@ int xhci_suspend(struct xhci_hcd *xhci) | |||
| 884 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) | 884 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) |
| 885 | return -EINVAL; | 885 | return -EINVAL; |
| 886 | 886 | ||
| 887 | /* Don't poll the roothubs on bus suspend. */ | ||
| 888 | xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); | ||
| 889 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
| 890 | del_timer_sync(&hcd->rh_timer); | ||
| 891 | |||
| 887 | spin_lock_irq(&xhci->lock); | 892 | spin_lock_irq(&xhci->lock); |
| 888 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 893 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
| 889 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); | 894 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); |
| @@ -1069,6 +1074,11 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) | |||
| 1069 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) | 1074 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) |
| 1070 | compliance_mode_recovery_timer_init(xhci); | 1075 | compliance_mode_recovery_timer_init(xhci); |
| 1071 | 1076 | ||
| 1077 | /* Re-enable port polling. */ | ||
| 1078 | xhci_dbg(xhci, "%s: starting port polling.\n", __func__); | ||
| 1079 | set_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
| 1080 | usb_hcd_poll_rh_status(hcd); | ||
| 1081 | |||
| 1072 | return retval; | 1082 | return retval; |
| 1073 | } | 1083 | } |
| 1074 | #endif /* CONFIG_PM */ | 1084 | #endif /* CONFIG_PM */ |
