diff options
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 15 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 9 |
3 files changed, 28 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index feffceb31e8a..121782e22c01 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -1612,8 +1612,13 @@ static void handle_port_status(struct xhci_hcd *xhci, | |||
1612 | usb_hcd_resume_root_hub(hcd); | 1612 | usb_hcd_resume_root_hub(hcd); |
1613 | } | 1613 | } |
1614 | 1614 | ||
1615 | if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) | 1615 | if (hcd->speed >= HCD_USB3 && |
1616 | (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) { | ||
1617 | slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1); | ||
1618 | if (slot_id && xhci->devs[slot_id]) | ||
1619 | xhci->devs[slot_id]->flags |= VDEV_PORT_ERROR; | ||
1616 | bus_state->port_remote_wakeup &= ~(1 << hcd_portnum); | 1620 | bus_state->port_remote_wakeup &= ~(1 << hcd_portnum); |
1621 | } | ||
1617 | 1622 | ||
1618 | if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) { | 1623 | if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) { |
1619 | xhci_dbg(xhci, "port resume event for port %d\n", port_id); | 1624 | xhci_dbg(xhci, "port resume event for port %d\n", port_id); |
@@ -1801,6 +1806,14 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, | |||
1801 | { | 1806 | { |
1802 | struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; | 1807 | struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; |
1803 | struct xhci_command *command; | 1808 | struct xhci_command *command; |
1809 | |||
1810 | /* | ||
1811 | * Avoid resetting endpoint if link is inactive. Can cause host hang. | ||
1812 | * Device will be reset soon to recover the link so don't do anything | ||
1813 | */ | ||
1814 | if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) | ||
1815 | return; | ||
1816 | |||
1804 | command = xhci_alloc_command(xhci, false, GFP_ATOMIC); | 1817 | command = xhci_alloc_command(xhci, false, GFP_ATOMIC); |
1805 | if (!command) | 1818 | if (!command) |
1806 | return; | 1819 | return; |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 20db378a6012..78a2a937dd83 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -1466,6 +1466,10 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag | |||
1466 | xhci_dbg(xhci, "urb submitted during PCI suspend\n"); | 1466 | xhci_dbg(xhci, "urb submitted during PCI suspend\n"); |
1467 | return -ESHUTDOWN; | 1467 | return -ESHUTDOWN; |
1468 | } | 1468 | } |
1469 | if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) { | ||
1470 | xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n"); | ||
1471 | return -ENODEV; | ||
1472 | } | ||
1469 | 1473 | ||
1470 | if (usb_endpoint_xfer_isoc(&urb->ep->desc)) | 1474 | if (usb_endpoint_xfer_isoc(&urb->ep->desc)) |
1471 | num_tds = urb->number_of_packets; | 1475 | num_tds = urb->number_of_packets; |
@@ -3754,6 +3758,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, | |||
3754 | } | 3758 | } |
3755 | /* If necessary, update the number of active TTs on this root port */ | 3759 | /* If necessary, update the number of active TTs on this root port */ |
3756 | xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps); | 3760 | xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps); |
3761 | virt_dev->flags = 0; | ||
3757 | ret = 0; | 3762 | ret = 0; |
3758 | 3763 | ||
3759 | command_cleanup: | 3764 | command_cleanup: |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 7f8b950d1a73..92e764c54154 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1010,6 +1010,15 @@ struct xhci_virt_device { | |||
1010 | u8 real_port; | 1010 | u8 real_port; |
1011 | struct xhci_interval_bw_table *bw_table; | 1011 | struct xhci_interval_bw_table *bw_table; |
1012 | struct xhci_tt_bw_info *tt_info; | 1012 | struct xhci_tt_bw_info *tt_info; |
1013 | /* | ||
1014 | * flags for state tracking based on events and issued commands. | ||
1015 | * Software can not rely on states from output contexts because of | ||
1016 | * latency between events and xHC updating output context values. | ||
1017 | * See xhci 1.1 section 4.8.3 for more details | ||
1018 | */ | ||
1019 | unsigned long flags; | ||
1020 | #define VDEV_PORT_ERROR BIT(0) /* Port error, link inactive */ | ||
1021 | |||
1013 | /* The current max exit latency for the enabled USB3 link states. */ | 1022 | /* The current max exit latency for the enabled USB3 link states. */ |
1014 | u16 current_mel; | 1023 | u16 current_mel; |
1015 | /* Used for the debugfs interfaces. */ | 1024 | /* Used for the debugfs interfaces. */ |