aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-orion.c3
-rw-r--r--drivers/usb/host/ehci-sysfs.c8
-rw-r--r--drivers/usb/host/xhci-mem.c17
-rw-r--r--drivers/usb/host/xhci-pci.c1
-rw-r--r--drivers/usb/host/xhci-ring.c99
-rw-r--r--drivers/usb/host/xhci.c25
6 files changed, 117 insertions, 36 deletions
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index bfcbb9aa8816..ee8d5faa0194 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -224,7 +224,8 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)
priv->phy = devm_phy_optional_get(&pdev->dev, "usb");
if (IS_ERR(priv->phy)) {
err = PTR_ERR(priv->phy);
- goto err_phy_get;
+ if (err != -ENOSYS)
+ goto err_phy_get;
} else {
err = phy_init(priv->phy);
if (err)
diff --git a/drivers/usb/host/ehci-sysfs.c b/drivers/usb/host/ehci-sysfs.c
index 5e44407aa099..5216f2b09d63 100644
--- a/drivers/usb/host/ehci-sysfs.c
+++ b/drivers/usb/host/ehci-sysfs.c
@@ -29,7 +29,7 @@ static ssize_t show_companion(struct device *dev,
int count = PAGE_SIZE;
char *ptr = buf;
- ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+ ehci = hcd_to_ehci(dev_get_drvdata(dev));
nports = HCS_N_PORTS(ehci->hcs_params);
for (index = 0; index < nports; ++index) {
@@ -54,7 +54,7 @@ static ssize_t store_companion(struct device *dev,
struct ehci_hcd *ehci;
int portnum, new_owner;
- ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+ ehci = hcd_to_ehci(dev_get_drvdata(dev));
new_owner = PORT_OWNER; /* Owned by companion */
if (sscanf(buf, "%d", &portnum) != 1)
return -EINVAL;
@@ -85,7 +85,7 @@ static ssize_t show_uframe_periodic_max(struct device *dev,
struct ehci_hcd *ehci;
int n;
- ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+ ehci = hcd_to_ehci(dev_get_drvdata(dev));
n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max);
return n;
}
@@ -101,7 +101,7 @@ static ssize_t store_uframe_periodic_max(struct device *dev,
unsigned long flags;
ssize_t ret;
- ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+ ehci = hcd_to_ehci(dev_get_drvdata(dev));
if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
return -EINVAL;
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 9a8c936cd42c..41f841fa6c4d 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1498,10 +1498,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
* use Event Data TRBs, and we don't chain in a link TRB on short
* transfers, we're basically dividing by 1.
*
- * xHCI 1.0 specification indicates that the Average TRB Length should
- * be set to 8 for control endpoints.
+ * xHCI 1.0 and 1.1 specification indicates that the Average TRB Length
+ * should be set to 8 for control endpoints.
*/
- if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version == 0x100)
+ if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100)
ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8));
else
ep_ctx->tx_info |=
@@ -1792,8 +1792,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
int size;
int i, j, num_ports;
- if (timer_pending(&xhci->cmd_timer))
- del_timer_sync(&xhci->cmd_timer);
+ del_timer_sync(&xhci->cmd_timer);
/* Free the Event Ring Segment Table and the actual Event Ring */
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
@@ -2321,6 +2320,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
INIT_LIST_HEAD(&xhci->cmd_list);
+ /* init command timeout timer */
+ setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout,
+ (unsigned long)xhci);
+
page_size = readl(&xhci->op_regs->page_size);
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Supported page size register = 0x%x", page_size);
@@ -2505,10 +2508,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
"Wrote ERST address to ir_set 0.");
xhci_print_ir_set(xhci, 0);
- /* init command timeout timer */
- setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout,
- (unsigned long)xhci);
-
/*
* XXX: Might need to set the Interrupter Moderation Register to
* something other than the default (~1ms minimum between interrupts).
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 2af32e26fafc..7e5c90eebb9c 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -135,6 +135,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) {
xhci->quirks |= XHCI_SPURIOUS_REBOOT;
+ xhci->quirks |= XHCI_SPURIOUS_WAKEUP;
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b3a0a2275f5a..41d7a05f8af4 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -302,6 +302,15 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
ret = xhci_handshake(&xhci->op_regs->cmd_ring,
CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
if (ret < 0) {
+ /* we are about to kill xhci, give it one more chance */
+ xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
+ &xhci->op_regs->cmd_ring);
+ udelay(1000);
+ ret = xhci_handshake(&xhci->op_regs->cmd_ring,
+ CMD_RING_RUNNING, 0, 3 * 1000 * 1000);
+ if (ret == 0)
+ return 0;
+
xhci_err(xhci, "Stopped the command ring failed, "
"maybe the host is dead\n");
xhci->xhc_state |= XHCI_STATE_DYING;
@@ -2230,6 +2239,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
u32 trb_comp_code;
int ret = 0;
int td_num = 0;
+ bool handling_skipped_tds = false;
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
xdev = xhci->devs[slot_id];
@@ -2363,6 +2373,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ep->skip = true;
xhci_dbg(xhci, "Miss service interval error, set skip flag\n");
goto cleanup;
+ case COMP_PING_ERR:
+ ep->skip = true;
+ xhci_dbg(xhci, "No Ping response error, Skip one Isoc TD\n");
+ goto cleanup;
default:
if (xhci_is_vendor_info_code(xhci, trb_comp_code)) {
status = 0;
@@ -2499,13 +2513,18 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ep, &status);
cleanup:
+
+
+ handling_skipped_tds = ep->skip &&
+ trb_comp_code != COMP_MISSED_INT &&
+ trb_comp_code != COMP_PING_ERR;
+
/*
- * Do not update event ring dequeue pointer if ep->skip is set.
- * Will roll back to continue process missed tds.
+ * Do not update event ring dequeue pointer if we're in a loop
+ * processing missed tds.
*/
- if (trb_comp_code == COMP_MISSED_INT || !ep->skip) {
+ if (!handling_skipped_tds)
inc_deq(xhci, xhci->event_ring);
- }
if (ret) {
urb = td->urb;
@@ -2540,7 +2559,7 @@ cleanup:
* Process them as short transfer until reach the td pointed by
* the event.
*/
- } while (ep->skip && trb_comp_code != COMP_MISSED_INT);
+ } while (handling_skipped_tds);
return 0;
}
@@ -3041,9 +3060,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct xhci_td *td;
struct scatterlist *sg;
int num_sgs;
- int trb_buff_len, this_sg_len, running_total;
+ int trb_buff_len, this_sg_len, running_total, ret;
unsigned int total_packet_count;
+ bool zero_length_needed;
bool first_trb;
+ int last_trb_num;
u64 addr;
bool more_trbs_coming;
@@ -3059,13 +3080,27 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length,
usb_endpoint_maxp(&urb->ep->desc));
- trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
+ ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
num_trbs, urb, 0, mem_flags);
- if (trb_buff_len < 0)
- return trb_buff_len;
+ if (ret < 0)
+ return ret;
urb_priv = urb->hcpriv;
+
+ /* Deal with URB_ZERO_PACKET - need one more td/trb */
+ zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET &&
+ urb_priv->length == 2;
+ if (zero_length_needed) {
+ num_trbs++;
+ xhci_dbg(xhci, "Creating zero length td.\n");
+ ret = prepare_transfer(xhci, xhci->devs[slot_id],
+ ep_index, urb->stream_id,
+ 1, urb, 1, mem_flags);
+ if (ret < 0)
+ return ret;
+ }
+
td = urb_priv->td[0];
/*
@@ -3095,6 +3130,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
trb_buff_len = urb->transfer_buffer_length;
first_trb = true;
+ last_trb_num = zero_length_needed ? 2 : 1;
/* Queue the first TRB, even if it's zero-length */
do {
u32 field = 0;
@@ -3112,12 +3148,15 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Chain all the TRBs together; clear the chain bit in the last
* TRB to indicate it's the last TRB in the chain.
*/
- if (num_trbs > 1) {
+ if (num_trbs > last_trb_num) {
field |= TRB_CHAIN;
- } else {
- /* FIXME - add check for ZERO_PACKET flag before this */
+ } else if (num_trbs == last_trb_num) {
td->last_trb = ep_ring->enqueue;
field |= TRB_IOC;
+ } else if (zero_length_needed && num_trbs == 1) {
+ trb_buff_len = 0;
+ urb_priv->td[1]->last_trb = ep_ring->enqueue;
+ field |= TRB_IOC;
}
/* Only set interrupt on short packet for IN endpoints */
@@ -3179,7 +3218,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (running_total + trb_buff_len > urb->transfer_buffer_length)
trb_buff_len =
urb->transfer_buffer_length - running_total;
- } while (running_total < urb->transfer_buffer_length);
+ } while (num_trbs > 0);
check_trb_math(urb, num_trbs, running_total);
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
@@ -3197,7 +3236,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
int num_trbs;
struct xhci_generic_trb *start_trb;
bool first_trb;
+ int last_trb_num;
bool more_trbs_coming;
+ bool zero_length_needed;
int start_cycle;
u32 field, length_field;
@@ -3228,7 +3269,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
num_trbs++;
running_total += TRB_MAX_BUFF_SIZE;
}
- /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
@@ -3237,6 +3277,20 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
return ret;
urb_priv = urb->hcpriv;
+
+ /* Deal with URB_ZERO_PACKET - need one more td/trb */
+ zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET &&
+ urb_priv->length == 2;
+ if (zero_length_needed) {
+ num_trbs++;
+ xhci_dbg(xhci, "Creating zero length td.\n");
+ ret = prepare_transfer(xhci, xhci->devs[slot_id],
+ ep_index, urb->stream_id,
+ 1, urb, 1, mem_flags);
+ if (ret < 0)
+ return ret;
+ }
+
td = urb_priv->td[0];
/*
@@ -3258,7 +3312,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
trb_buff_len = urb->transfer_buffer_length;
first_trb = true;
-
+ last_trb_num = zero_length_needed ? 2 : 1;
/* Queue the first TRB, even if it's zero-length */
do {
u32 remainder = 0;
@@ -3275,12 +3329,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Chain all the TRBs together; clear the chain bit in the last
* TRB to indicate it's the last TRB in the chain.
*/
- if (num_trbs > 1) {
+ if (num_trbs > last_trb_num) {
field |= TRB_CHAIN;
- } else {
- /* FIXME - add check for ZERO_PACKET flag before this */
+ } else if (num_trbs == last_trb_num) {
td->last_trb = ep_ring->enqueue;
field |= TRB_IOC;
+ } else if (zero_length_needed && num_trbs == 1) {
+ trb_buff_len = 0;
+ urb_priv->td[1]->last_trb = ep_ring->enqueue;
+ field |= TRB_IOC;
}
/* Only set interrupt on short packet for IN endpoints */
@@ -3318,7 +3375,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
trb_buff_len = urb->transfer_buffer_length - running_total;
if (trb_buff_len > TRB_MAX_BUFF_SIZE)
trb_buff_len = TRB_MAX_BUFF_SIZE;
- } while (running_total < urb->transfer_buffer_length);
+ } while (num_trbs > 0);
check_trb_math(urb, num_trbs, running_total);
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
@@ -3385,8 +3442,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (start_cycle == 0)
field |= 0x1;
- /* xHCI 1.0 6.4.1.2.1: Transfer Type field */
- if (xhci->hci_version == 0x100) {
+ /* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
+ if (xhci->hci_version >= 0x100) {
if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType & USB_DIR_IN)
field |= TRB_TX_TYPE(TRB_DATA_IN);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index c502c2277aeb..1e6d7579709e 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -146,7 +146,8 @@ static int xhci_start(struct xhci_hcd *xhci)
"waited %u microseconds.\n",
XHCI_MAX_HALT_USEC);
if (!ret)
- xhci->xhc_state &= ~XHCI_STATE_HALTED;
+ xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING);
+
return ret;
}
@@ -174,6 +175,16 @@ int xhci_reset(struct xhci_hcd *xhci)
command |= CMD_RESET;
writel(command, &xhci->op_regs->command);
+ /* Existing Intel xHCI controllers require a delay of 1 mS,
+ * after setting the CMD_RESET bit, and before accessing any
+ * HC registers. This allows the HC to complete the
+ * reset operation and be ready for HC register access.
+ * Without this delay, the subsequent HC register access,
+ * may result in a system hang very rarely.
+ */
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ udelay(1000);
+
ret = xhci_handshake(&xhci->op_regs->command,
CMD_RESET, 0, 10 * 1000 * 1000);
if (ret)
@@ -683,8 +694,11 @@ void xhci_stop(struct usb_hcd *hcd)
u32 temp;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ mutex_lock(&xhci->mutex);
+
if (!usb_hcd_is_primary_hcd(hcd)) {
xhci_only_stop_hcd(xhci->shared_hcd);
+ mutex_unlock(&xhci->mutex);
return;
}
@@ -723,6 +737,7 @@ void xhci_stop(struct usb_hcd *hcd)
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"xhci_stop completed - status = %x",
readl(&xhci->op_regs->status));
+ mutex_unlock(&xhci->mutex);
}
/*
@@ -1340,6 +1355,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
if (usb_endpoint_xfer_isoc(&urb->ep->desc))
size = urb->number_of_packets;
+ else if (usb_endpoint_is_bulk_out(&urb->ep->desc) &&
+ urb->transfer_buffer_length > 0 &&
+ urb->transfer_flags & URB_ZERO_PACKET &&
+ !(urb->transfer_buffer_length % usb_endpoint_maxp(&urb->ep->desc)))
+ size = 2;
else
size = 1;
@@ -3790,6 +3810,9 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
mutex_lock(&xhci->mutex);
+ if (xhci->xhc_state) /* dying or halted */
+ goto out;
+
if (!udev->slot_id) {
xhci_dbg_trace(xhci, trace_xhci_dbg_address,
"Bad Slot ID %d", udev->slot_id);