summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2019-07-01 08:16:08 -0600
committerJens Axboe <axboe@kernel.dk>2019-07-01 08:16:08 -0600
commit5be1f9d82fa73c199ebeee2866dbac83e419c897 (patch)
treeaed1aec34f40b5e0f36dceea8b58d9cfdb41d233 /drivers/usb/host
parentff91064ea37c8323eba31cc3d2e22464f107b50d (diff)
parent4b972a01a7da614b4796475f933094751a295a2f (diff)
Merge tag 'v5.2-rc6' into for-5.3/block
Merge 5.2-rc6 into for-5.3/block, so we get the same page merge leak fix. Otherwise we end up having conflicts with future patches between for-5.3/block and master that touch this area. In particular, it makes the bio_full() fix hard to backport to stable. * tag 'v5.2-rc6': (482 commits) Linux 5.2-rc6 Revert "iommu/vt-d: Fix lock inversion between iommu->lock and device_domain_lock" Bluetooth: Fix regression with minimum encryption key size alignment tcp: refine memory limit test in tcp_fragment() x86/vdso: Prevent segfaults due to hoisted vclock reads SUNRPC: Fix a credential refcount leak Revert "SUNRPC: Declare RPC timers as TIMER_DEFERRABLE" net :sunrpc :clnt :Fix xps refcount imbalance on the error path NFS4: Only set creation opendata if O_CREAT ARM: 8867/1: vdso: pass --be8 to linker if necessary KVM: nVMX: reorganize initial steps of vmx_set_nested_state KVM: PPC: Book3S HV: Invalidate ERAT when flushing guest TLB entries habanalabs: use u64_to_user_ptr() for reading user pointers nfsd: replace Jeff by Chuck as nfsd co-maintainer inet: clear num_timeout reqsk_alloc() PCI/P2PDMA: Ignore root complex whitelist when an IOMMU is present net: mvpp2: debugfs: Add pmap to fs dump ipv6: Default fib6_type to RTN_UNICAST when not set net: hns3: Fix inconsistent indenting net/af_iucv: always register net_device notifier ...
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/xhci-ring.c15
-rw-r--r--drivers/usb/host/xhci.c25
-rw-r--r--drivers/usb/host/xhci.h9
3 files changed, 43 insertions, 6 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,
usb_hcd_resume_root_hub(hcd);
}
- if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE)
+ if (hcd->speed >= HCD_USB3 &&
+ (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1);
+ if (slot_id && xhci->devs[slot_id])
+ xhci->devs[slot_id]->flags |= VDEV_PORT_ERROR;
bus_state->port_remote_wakeup &= ~(1 << hcd_portnum);
+ }
if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
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,
{
struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
struct xhci_command *command;
+
+ /*
+ * Avoid resetting endpoint if link is inactive. Can cause host hang.
+ * Device will be reset soon to recover the link so don't do anything
+ */
+ if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR)
+ return;
+
command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
if (!command)
return;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 20db378a6012..3f79f35d0b19 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
xhci_dbg(xhci, "urb submitted during PCI suspend\n");
return -ESHUTDOWN;
}
+ if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) {
+ xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n");
+ return -ENODEV;
+ }
if (usb_endpoint_xfer_isoc(&urb->ep->desc))
num_tds = urb->number_of_packets;
@@ -3754,6 +3758,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
}
/* If necessary, update the number of active TTs on this root port */
xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps);
+ virt_dev->flags = 0;
ret = 0;
command_cleanup:
@@ -5060,16 +5065,26 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
} else {
/*
* Some 3.1 hosts return sbrn 0x30, use xhci supported protocol
- * minor revision instead of sbrn
+ * minor revision instead of sbrn. Minor revision is a two digit
+ * BCD containing minor and sub-minor numbers, only show minor.
*/
- minor_rev = xhci->usb3_rhub.min_rev;
- if (minor_rev) {
+ minor_rev = xhci->usb3_rhub.min_rev / 0x10;
+
+ switch (minor_rev) {
+ case 2:
+ hcd->speed = HCD_USB32;
+ hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
+ hcd->self.root_hub->rx_lanes = 2;
+ hcd->self.root_hub->tx_lanes = 2;
+ break;
+ case 1:
hcd->speed = HCD_USB31;
hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
+ break;
}
- xhci_info(xhci, "Host supports USB 3.%x %s SuperSpeed\n",
+ xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n",
minor_rev,
- minor_rev ? "Enhanced" : "");
+ minor_rev ? "Enhanced " : "");
xhci->usb3_rhub.hcd = hcd;
/* xHCI private pointer was set in xhci_pci_probe for the second
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 {
u8 real_port;
struct xhci_interval_bw_table *bw_table;
struct xhci_tt_bw_info *tt_info;
+ /*
+ * flags for state tracking based on events and issued commands.
+ * Software can not rely on states from output contexts because of
+ * latency between events and xHC updating output context values.
+ * See xhci 1.1 section 4.8.3 for more details
+ */
+ unsigned long flags;
+#define VDEV_PORT_ERROR BIT(0) /* Port error, link inactive */
+
/* The current max exit latency for the enabled USB3 link states. */
u16 current_mel;
/* Used for the debugfs interfaces. */