aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r--drivers/usb/host/xhci.c89
1 files changed, 67 insertions, 22 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 7fa58c99f126..3f79f35d0b19 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -9,6 +9,7 @@
*/
#include <linux/pci.h>
+#include <linux/iopoll.h>
#include <linux/irq.h>
#include <linux/log2.h>
#include <linux/module.h>
@@ -52,7 +53,6 @@ static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)
return false;
}
-/* TODO: copied from ehci-hcd.c - can this be refactored? */
/*
* xhci_handshake - spin reading hc until handshake completes or fails
* @ptr: address of hc register to be read
@@ -69,18 +69,16 @@ static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)
int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)
{
u32 result;
+ int ret;
- do {
- result = readl(ptr);
- if (result == ~(u32)0) /* card removed */
- return -ENODEV;
- result &= mask;
- if (result == done)
- return 0;
- udelay(1);
- usec--;
- } while (usec > 0);
- return -ETIMEDOUT;
+ ret = readl_poll_timeout_atomic(ptr, result,
+ (result & mask) == done ||
+ result == U32_MAX,
+ 1, usec);
+ if (result == U32_MAX) /* card removed */
+ return -ENODEV;
+
+ return ret;
}
/*
@@ -893,7 +891,7 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
struct xhci_port **ports;
int port_index;
unsigned long flags;
- u32 t1, t2;
+ u32 t1, t2, portsc;
spin_lock_irqsave(&xhci->lock, flags);
@@ -902,10 +900,15 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
ports = xhci->usb3_rhub.ports;
while (port_index--) {
t1 = readl(ports[port_index]->addr);
+ portsc = t1;
t1 = xhci_port_state_to_neutral(t1);
t2 = t1 & ~PORT_WAKE_BITS;
- if (t1 != t2)
+ if (t1 != t2) {
writel(t2, ports[port_index]->addr);
+ xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n",
+ xhci->usb3_rhub.hcd->self.busnum,
+ port_index + 1, portsc, t2);
+ }
}
/* disable usb2 ports Wake bits */
@@ -913,12 +916,16 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
ports = xhci->usb2_rhub.ports;
while (port_index--) {
t1 = readl(ports[port_index]->addr);
+ portsc = t1;
t1 = xhci_port_state_to_neutral(t1);
t2 = t1 & ~PORT_WAKE_BITS;
- if (t1 != t2)
+ if (t1 != t2) {
writel(t2, ports[port_index]->addr);
+ xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n",
+ xhci->usb2_rhub.hcd->self.busnum,
+ port_index + 1, portsc, t2);
+ }
}
-
spin_unlock_irqrestore(&xhci->lock, flags);
}
@@ -1238,6 +1245,21 @@ EXPORT_SYMBOL_GPL(xhci_resume);
/*-------------------------------------------------------------------------*/
+/*
+ * Bypass the DMA mapping if URB is suitable for Immediate Transfer (IDT),
+ * we'll copy the actual data into the TRB address register. This is limited to
+ * transfers up to 8 bytes on output endpoints of any kind with wMaxPacketSize
+ * >= 8 bytes. If suitable for IDT only one Transfer TRB per TD is allowed.
+ */
+static int xhci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ if (xhci_urb_suitable_for_idt(urb))
+ return 0;
+
+ return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+}
+
/**
* xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and
* HCDs. Find the index for an endpoint given its descriptor. Use the return
@@ -1444,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;
@@ -1783,6 +1809,7 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
struct xhci_container_ctx *in_ctx;
unsigned int ep_index;
struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_ep_ctx *ep_ctx;
u32 added_ctxs;
u32 new_add_flags, new_drop_flags;
struct xhci_virt_device *virt_dev;
@@ -1873,6 +1900,9 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
/* Store the usb_device pointer for later use */
ep->hcpriv = udev;
+ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
+ trace_xhci_add_endpoint(ep_ctx);
+
xhci_debugfs_create_endpoint(xhci, virt_dev, ep_index);
xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
@@ -2747,6 +2777,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
}
slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx);
+
+ trace_xhci_configure_endpoint_ctrl_ctx(ctrl_ctx);
trace_xhci_configure_endpoint(slot_ctx);
if (!ctx_change)
@@ -3726,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:
@@ -4012,6 +4045,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
le32_to_cpu(slot_ctx->dev_info) >> 27);
+ trace_xhci_address_ctrl_ctx(ctrl_ctx);
spin_lock_irqsave(&xhci->lock, flags);
trace_xhci_setup_device(virt_dev);
ret = xhci_queue_address_device(xhci, command, virt_dev->in_ctx->dma,
@@ -4289,7 +4323,6 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
pm_addr = ports[port_num]->addr + PORTPMSC;
pm_val = readl(pm_addr);
hlpm_addr = ports[port_num]->addr + PORTHLPMC;
- field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
enable ? "enable" : "disable", port_num + 1);
@@ -4301,6 +4334,7 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
* default one which works with mixed HIRD and BESL
* systems. See XHCI_DEFAULT_BESL definition in xhci.h
*/
+ field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
if ((field & USB_BESL_SUPPORT) &&
(field & USB_BESL_BASELINE_VALID))
hird = USB_GET_BESL_BASELINE(field);
@@ -5031,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
@@ -5154,6 +5198,7 @@ static const struct hc_driver xhci_hc_driver = {
/*
* managing i/o requests and associated device resources
*/
+ .map_urb_for_dma = xhci_map_urb_for_dma,
.urb_enqueue = xhci_urb_enqueue,
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev,