diff options
| -rw-r--r-- | drivers/usb/core/hub.c | 33 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 49 |
2 files changed, 41 insertions, 41 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index dcd78c15f8cd..93035d862c63 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
| @@ -2307,14 +2307,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) | |||
| 2307 | } | 2307 | } |
| 2308 | 2308 | ||
| 2309 | /* see 7.1.7.6 */ | 2309 | /* see 7.1.7.6 */ |
| 2310 | /* Clear PORT_POWER if it's a USB3.0 device connected to USB 3.0 | 2310 | if (hub_is_superspeed(hub->hdev)) |
| 2311 | * external hub. | 2311 | status = set_port_feature(hub->hdev, |
| 2312 | * FIXME: this is a temporary workaround to make the system able | 2312 | port1 | (USB_SS_PORT_LS_U3 << 3), |
| 2313 | * to suspend/resume. | 2313 | USB_PORT_FEAT_LINK_STATE); |
| 2314 | */ | ||
| 2315 | if ((hub->hdev->parent != NULL) && hub_is_superspeed(hub->hdev)) | ||
| 2316 | status = clear_port_feature(hub->hdev, port1, | ||
| 2317 | USB_PORT_FEAT_POWER); | ||
| 2318 | else | 2314 | else |
| 2319 | status = set_port_feature(hub->hdev, port1, | 2315 | status = set_port_feature(hub->hdev, port1, |
| 2320 | USB_PORT_FEAT_SUSPEND); | 2316 | USB_PORT_FEAT_SUSPEND); |
| @@ -2469,8 +2465,13 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) | |||
| 2469 | set_bit(port1, hub->busy_bits); | 2465 | set_bit(port1, hub->busy_bits); |
| 2470 | 2466 | ||
| 2471 | /* see 7.1.7.7; affects power usage, but not budgeting */ | 2467 | /* see 7.1.7.7; affects power usage, but not budgeting */ |
| 2472 | status = clear_port_feature(hub->hdev, | 2468 | if (hub_is_superspeed(hub->hdev)) |
| 2473 | port1, USB_PORT_FEAT_SUSPEND); | 2469 | status = set_port_feature(hub->hdev, |
| 2470 | port1 | (USB_SS_PORT_LS_U0 << 3), | ||
| 2471 | USB_PORT_FEAT_LINK_STATE); | ||
| 2472 | else | ||
| 2473 | status = clear_port_feature(hub->hdev, | ||
| 2474 | port1, USB_PORT_FEAT_SUSPEND); | ||
| 2474 | if (status) { | 2475 | if (status) { |
| 2475 | dev_dbg(hub->intfdev, "can't resume port %d, status %d\n", | 2476 | dev_dbg(hub->intfdev, "can't resume port %d, status %d\n", |
| 2476 | port1, status); | 2477 | port1, status); |
| @@ -2492,9 +2493,15 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) | |||
| 2492 | 2493 | ||
| 2493 | SuspendCleared: | 2494 | SuspendCleared: |
| 2494 | if (status == 0) { | 2495 | if (status == 0) { |
| 2495 | if (portchange & USB_PORT_STAT_C_SUSPEND) | 2496 | if (hub_is_superspeed(hub->hdev)) { |
| 2496 | clear_port_feature(hub->hdev, port1, | 2497 | if (portchange & USB_PORT_STAT_C_LINK_STATE) |
| 2497 | USB_PORT_FEAT_C_SUSPEND); | 2498 | clear_port_feature(hub->hdev, port1, |
| 2499 | USB_PORT_FEAT_C_PORT_LINK_STATE); | ||
| 2500 | } else { | ||
| 2501 | if (portchange & USB_PORT_STAT_C_SUSPEND) | ||
| 2502 | clear_port_feature(hub->hdev, port1, | ||
| 2503 | USB_PORT_FEAT_C_SUSPEND); | ||
| 2504 | } | ||
| 2498 | } | 2505 | } |
| 2499 | 2506 | ||
| 2500 | clear_bit(port1, hub->busy_bits); | 2507 | clear_bit(port1, hub->busy_bits); |
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 4a3ca99fc64e..e3ddc6a95afe 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
| @@ -483,7 +483,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
| 483 | && (temp & PORT_POWER) | 483 | && (temp & PORT_POWER) |
| 484 | && (bus_state->suspended_ports & (1 << wIndex))) { | 484 | && (bus_state->suspended_ports & (1 << wIndex))) { |
| 485 | bus_state->suspended_ports &= ~(1 << wIndex); | 485 | bus_state->suspended_ports &= ~(1 << wIndex); |
| 486 | bus_state->port_c_suspend |= 1 << wIndex; | 486 | if (hcd->speed != HCD_USB3) |
| 487 | bus_state->port_c_suspend |= 1 << wIndex; | ||
| 487 | } | 488 | } |
| 488 | if (temp & PORT_CONNECT) { | 489 | if (temp & PORT_CONNECT) { |
| 489 | status |= USB_PORT_STAT_CONNECTION; | 490 | status |= USB_PORT_STAT_CONNECTION; |
| @@ -656,35 +657,27 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
| 656 | if (temp & XDEV_U3) { | 657 | if (temp & XDEV_U3) { |
| 657 | if ((temp & PORT_PE) == 0) | 658 | if ((temp & PORT_PE) == 0) |
| 658 | goto error; | 659 | goto error; |
| 659 | if (DEV_SUPERSPEED(temp)) { | ||
| 660 | temp = xhci_port_state_to_neutral(temp); | ||
| 661 | temp &= ~PORT_PLS_MASK; | ||
| 662 | temp |= PORT_LINK_STROBE | XDEV_U0; | ||
| 663 | xhci_writel(xhci, temp, | ||
| 664 | port_array[wIndex]); | ||
| 665 | xhci_readl(xhci, port_array[wIndex]); | ||
| 666 | } else { | ||
| 667 | temp = xhci_port_state_to_neutral(temp); | ||
| 668 | temp &= ~PORT_PLS_MASK; | ||
| 669 | temp |= PORT_LINK_STROBE | XDEV_RESUME; | ||
| 670 | xhci_writel(xhci, temp, | ||
| 671 | port_array[wIndex]); | ||
| 672 | 660 | ||
| 673 | spin_unlock_irqrestore(&xhci->lock, | 661 | temp = xhci_port_state_to_neutral(temp); |
| 674 | flags); | 662 | temp &= ~PORT_PLS_MASK; |
| 675 | msleep(20); | 663 | temp |= PORT_LINK_STROBE | XDEV_RESUME; |
| 676 | spin_lock_irqsave(&xhci->lock, flags); | 664 | xhci_writel(xhci, temp, |
| 665 | port_array[wIndex]); | ||
| 677 | 666 | ||
| 678 | temp = xhci_readl(xhci, | 667 | spin_unlock_irqrestore(&xhci->lock, |
| 679 | port_array[wIndex]); | 668 | flags); |
| 680 | temp = xhci_port_state_to_neutral(temp); | 669 | msleep(20); |
| 681 | temp &= ~PORT_PLS_MASK; | 670 | spin_lock_irqsave(&xhci->lock, flags); |
| 682 | temp |= PORT_LINK_STROBE | XDEV_U0; | 671 | |
| 683 | xhci_writel(xhci, temp, | 672 | temp = xhci_readl(xhci, |
| 684 | port_array[wIndex]); | 673 | port_array[wIndex]); |
| 685 | } | 674 | temp = xhci_port_state_to_neutral(temp); |
| 686 | bus_state->port_c_suspend |= 1 << wIndex; | 675 | temp &= ~PORT_PLS_MASK; |
| 676 | temp |= PORT_LINK_STROBE | XDEV_U0; | ||
| 677 | xhci_writel(xhci, temp, | ||
| 678 | port_array[wIndex]); | ||
| 687 | } | 679 | } |
| 680 | bus_state->port_c_suspend |= 1 << wIndex; | ||
| 688 | 681 | ||
| 689 | slot_id = xhci_find_slot_id_by_port(hcd, xhci, | 682 | slot_id = xhci_find_slot_id_by_port(hcd, xhci, |
| 690 | wIndex + 1); | 683 | wIndex + 1); |
| @@ -755,7 +748,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
| 755 | memset(buf, 0, retval); | 748 | memset(buf, 0, retval); |
| 756 | status = 0; | 749 | status = 0; |
| 757 | 750 | ||
| 758 | mask = PORT_CSC | PORT_PEC | PORT_OCC; | 751 | mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC; |
| 759 | 752 | ||
| 760 | spin_lock_irqsave(&xhci->lock, flags); | 753 | spin_lock_irqsave(&xhci->lock, flags); |
| 761 | /* For each port, did anything change? If so, set that bit in buf. */ | 754 | /* For each port, did anything change? If so, set that bit in buf. */ |
