/*
* Set the run bit and wait for the host to be running.
*/
-int xhci_start(struct xhci_hcd *xhci)
+static int xhci_start(struct xhci_hcd *xhci)
{
u32 temp;
int ret;
return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
}
-static irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)
-{
- irqreturn_t ret;
-
- set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-
- ret = xhci_irq(hcd);
-
- return ret;
-}
-
/*
* Free IRQs
* free all IRQs request
static int xhci_setup_msix(struct xhci_hcd *xhci)
{
int i, ret = 0;
- struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
/*
* calculate number of msi-x vectors supported.
goto disable_msix;
}
+ hcd->msix_enabled = 1;
return ret;
disable_msix:
/* Free any IRQs and disable MSI-X */
static void xhci_cleanup_msix(struct xhci_hcd *xhci)
{
- struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
xhci_free_irq(xhci);
pci_disable_msi(pdev);
}
+ hcd->msix_enabled = 0;
return;
}
return retval;
}
-/*
- * Called in interrupt context when there might be work
- * queued on the event ring
- *
- * xhci->lock must be held by caller.
- */
-static void xhci_work(struct xhci_hcd *xhci)
-{
- u32 temp;
- u64 temp_64;
-
- /*
- * Clear the op reg interrupt status first,
- * so we can receive interrupts from other MSI-X interrupters.
- * Write 1 to clear the interrupt status.
- */
- temp = xhci_readl(xhci, &xhci->op_regs->status);
- temp |= STS_EINT;
- xhci_writel(xhci, temp, &xhci->op_regs->status);
- /* FIXME when MSI-X is supported and there are multiple vectors */
- /* Clear the MSI-X event interrupt status */
-
- /* Acknowledge the interrupt */
- temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
- temp |= 0x3;
- xhci_writel(xhci, temp, &xhci->ir_set->irq_pending);
- /* Flush posted writes */
- xhci_readl(xhci, &xhci->ir_set->irq_pending);
-
- if (xhci->xhc_state & XHCI_STATE_DYING)
- xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
- "Shouldn't IRQs be disabled?\n");
- else
- /* FIXME this should be a delayed service routine
- * that clears the EHB.
- */
- xhci_handle_event(xhci);
-
- /* Clear the event handler busy flag (RW1C); the event ring should be empty. */
- temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
- xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
- /* Flush posted writes -- FIXME is this necessary? */
- xhci_readl(xhci, &xhci->ir_set->irq_pending);
-}
-
/*-------------------------------------------------------------------------*/
-/*
- * xHCI spec says we can get an interrupt, and if the HC has an error condition,
- * we might get bad data out of the event ring. Section 4.10.2.7 has a list of
- * indicators of an event TRB error, but we check the status *first* to be safe.
- */
-irqreturn_t xhci_irq(struct usb_hcd *hcd)
-{
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- u32 temp, temp2;
- union xhci_trb *trb;
-
- spin_lock(&xhci->lock);
- trb = xhci->event_ring->dequeue;
- /* Check if the xHC generated the interrupt, or the irq is shared */
- temp = xhci_readl(xhci, &xhci->op_regs->status);
- temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending);
- if (temp == 0xffffffff && temp2 == 0xffffffff)
- goto hw_died;
-
- if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) {
- spin_unlock(&xhci->lock);
- return IRQ_NONE;
- }
- xhci_dbg(xhci, "op reg status = %08x\n", temp);
- xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2);
- xhci_dbg(xhci, "Event ring dequeue ptr:\n");
- xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
- (unsigned long long)xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb),
- lower_32_bits(trb->link.segment_ptr),
- upper_32_bits(trb->link.segment_ptr),
- (unsigned int) trb->link.intr_target,
- (unsigned int) trb->link.control);
-
- if (temp & STS_FATAL) {
- xhci_warn(xhci, "WARNING: Host System Error\n");
- xhci_halt(xhci);
-hw_died:
- xhci_to_hcd(xhci)->state = HC_STATE_HALT;
- spin_unlock(&xhci->lock);
- return -ESHUTDOWN;
- }
-
- xhci_work(xhci);
- spin_unlock(&xhci->lock);
-
- return IRQ_HANDLED;
-}
#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-void xhci_event_ring_work(unsigned long arg)
+static void xhci_event_ring_work(unsigned long arg)
{
unsigned long flags;
int temp;
xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp));
xhci_writel(xhci, ER_IRQ_ENABLE(temp),
&xhci->ir_set->irq_pending);
- xhci_print_ir_set(xhci, xhci->ir_set, 0);
+ xhci_print_ir_set(xhci, 0);
if (NUM_TEST_NOOPS > 0)
doorbell = xhci_setup_one_noop(xhci);
spin_lock_irq(&xhci->lock);
xhci_halt(xhci);
xhci_reset(xhci);
- xhci_cleanup_msix(xhci);
spin_unlock_irq(&xhci->lock);
+ xhci_cleanup_msix(xhci);
+
#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
/* Tell the event ring poll function not to reschedule */
xhci->zombie = 1;
temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
xhci_writel(xhci, ER_IRQ_DISABLE(temp),
&xhci->ir_set->irq_pending);
- xhci_print_ir_set(xhci, xhci->ir_set, 0);
+ xhci_print_ir_set(xhci, 0);
xhci_dbg(xhci, "cleaning up memory\n");
xhci_mem_cleanup(xhci);
spin_lock_irq(&xhci->lock);
xhci_halt(xhci);
- xhci_cleanup_msix(xhci);
spin_unlock_irq(&xhci->lock);
+ xhci_cleanup_msix(xhci);
+
xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n",
xhci_readl(xhci, &xhci->op_regs->status));
}
+#ifdef CONFIG_PM
+static void xhci_save_registers(struct xhci_hcd *xhci)
+{
+ xhci->s3.command = xhci_readl(xhci, &xhci->op_regs->command);
+ xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification);
+ xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
+ xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg);
+ xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+ xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control);
+ xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size);
+ xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
+ xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+}
+
+static void xhci_restore_registers(struct xhci_hcd *xhci)
+{
+ xhci_writel(xhci, xhci->s3.command, &xhci->op_regs->command);
+ xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
+ xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
+ xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg);
+ xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
+ xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control);
+ xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size);
+ xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
+}
+
+static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
+{
+ u64 val_64;
+
+ /* step 2: initialize command ring buffer */
+ val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+ val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
+ (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
+ xhci->cmd_ring->dequeue) &
+ (u64) ~CMD_RING_RSVD_BITS) |
+ xhci->cmd_ring->cycle_state;
+ xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
+ (long unsigned long) val_64);
+ xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
+}
+
+/*
+ * The whole command ring must be cleared to zero when we suspend the host.
+ *
+ * The host doesn't save the command ring pointer in the suspend well, so we
+ * need to re-program it on resume. Unfortunately, the pointer must be 64-byte
+ * aligned, because of the reserved bits in the command ring dequeue pointer
+ * register. Therefore, we can't just set the dequeue pointer back in the
+ * middle of the ring (TRBs are 16-byte aligned).
+ */
+static void xhci_clear_command_ring(struct xhci_hcd *xhci)
+{
+ struct xhci_ring *ring;
+ struct xhci_segment *seg;
+
+ ring = xhci->cmd_ring;
+ seg = ring->deq_seg;
+ do {
+ memset(seg->trbs, 0, SEGMENT_SIZE);
+ seg = seg->next;
+ } while (seg != ring->deq_seg);
+
+ /* Reset the software enqueue and dequeue pointers */
+ ring->deq_seg = ring->first_seg;
+ ring->dequeue = ring->first_seg->trbs;
+ ring->enq_seg = ring->deq_seg;
+ ring->enqueue = ring->dequeue;
+
+ /*
+ * Ring is now zeroed, so the HW should look for change of ownership
+ * when the cycle bit is set to 1.
+ */
+ ring->cycle_state = 1;
+
+ /*
+ * Reset the hardware dequeue pointer.
+ * Yes, this will need to be re-written after resume, but we're paranoid
+ * and want to make sure the hardware doesn't access bogus memory
+ * because, say, the BIOS or an SMI started the host without changing
+ * the command ring pointers.
+ */
+ xhci_set_cmd_ring_deq(xhci);
+}
+
+/*
+ * Stop HC (not bus-specific)
+ *
+ * This is called when the machine transition into S3/S4 mode.
+ *
+ */
+int xhci_suspend(struct xhci_hcd *xhci)
+{
+ int rc = 0;
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ u32 command;
+ int i;
+
+ spin_lock_irq(&xhci->lock);
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ /* step 1: stop endpoint */
+ /* skipped assuming that port suspend has done */
+
+ /* step 2: clear Run/Stop bit */
+ command = xhci_readl(xhci, &xhci->op_regs->command);
+ command &= ~CMD_RUN;
+ xhci_writel(xhci, command, &xhci->op_regs->command);
+ if (handshake(xhci, &xhci->op_regs->status,
+ STS_HALT, STS_HALT, 100*100)) {
+ xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
+ spin_unlock_irq(&xhci->lock);
+ return -ETIMEDOUT;
+ }
+ xhci_clear_command_ring(xhci);
+
+ /* step 3: save registers */
+ xhci_save_registers(xhci);
+
+ /* step 4: set CSS flag */
+ command = xhci_readl(xhci, &xhci->op_regs->command);
+ command |= CMD_CSS;
+ xhci_writel(xhci, command, &xhci->op_regs->command);
+ if (handshake(xhci, &xhci->op_regs->status, STS_SAVE, 0, 10*100)) {
+ xhci_warn(xhci, "WARN: xHC CMD_CSS timeout\n");
+ spin_unlock_irq(&xhci->lock);
+ return -ETIMEDOUT;
+ }
+ spin_unlock_irq(&xhci->lock);
+
+ /* step 5: remove core well power */
+ /* synchronize irq when using MSI-X */
+ if (xhci->msix_entries) {
+ for (i = 0; i < xhci->msix_count; i++)
+ synchronize_irq(xhci->msix_entries[i].vector);
+ }
+
+ return rc;
+}
+
+/*
+ * start xHC (not bus-specific)
+ *
+ * This is called when the machine transition from S3/S4 mode.
+ *
+ */
+int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
+{
+ u32 command, temp = 0;
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ int old_state, retval;
+
+ old_state = hcd->state;
+ if (time_before(jiffies, xhci->next_statechange))
+ msleep(100);
+
+ spin_lock_irq(&xhci->lock);
+
+ if (!hibernated) {
+ /* step 1: restore register */
+ xhci_restore_registers(xhci);
+ /* step 2: initialize command ring buffer */
+ xhci_set_cmd_ring_deq(xhci);
+ /* step 3: restore state and start state*/
+ /* step 3: set CRS flag */
+ command = xhci_readl(xhci, &xhci->op_regs->command);
+ command |= CMD_CRS;
+ xhci_writel(xhci, command, &xhci->op_regs->command);
+ if (handshake(xhci, &xhci->op_regs->status,
+ STS_RESTORE, 0, 10*100)) {
+ xhci_dbg(xhci, "WARN: xHC CMD_CSS timeout\n");
+ spin_unlock_irq(&xhci->lock);
+ return -ETIMEDOUT;
+ }
+ temp = xhci_readl(xhci, &xhci->op_regs->status);
+ }
+
+ /* If restore operation fails, re-initialize the HC during resume */
+ if ((temp & STS_SRE) || hibernated) {
+ usb_root_hub_lost_power(hcd->self.root_hub);
+
+ xhci_dbg(xhci, "Stop HCD\n");
+ xhci_halt(xhci);
+ xhci_reset(xhci);
+ spin_unlock_irq(&xhci->lock);
+ xhci_cleanup_msix(xhci);
+
+#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
+ /* Tell the event ring poll function not to reschedule */
+ xhci->zombie = 1;
+ del_timer_sync(&xhci->event_ring_timer);
+#endif
+
+ xhci_dbg(xhci, "// Disabling event ring interrupts\n");
+ temp = xhci_readl(xhci, &xhci->op_regs->status);
+ xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
+ temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+ xhci_writel(xhci, ER_IRQ_DISABLE(temp),
+ &xhci->ir_set->irq_pending);
+ xhci_print_ir_set(xhci, 0);
+
+ xhci_dbg(xhci, "cleaning up memory\n");
+ xhci_mem_cleanup(xhci);
+ xhci_dbg(xhci, "xhci_stop completed - status = %x\n",
+ xhci_readl(xhci, &xhci->op_regs->status));
+
+ xhci_dbg(xhci, "Initialize the HCD\n");
+ retval = xhci_init(hcd);
+ if (retval)
+ return retval;
+
+ xhci_dbg(xhci, "Start the HCD\n");
+ retval = xhci_run(hcd);
+ if (!retval)
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ hcd->state = HC_STATE_SUSPENDED;
+ return retval;
+ }
+
+ /* step 4: set Run/Stop bit */
+ command = xhci_readl(xhci, &xhci->op_regs->command);
+ command |= CMD_RUN;
+ xhci_writel(xhci, command, &xhci->op_regs->command);
+ handshake(xhci, &xhci->op_regs->status, STS_HALT,
+ 0, 250 * 1000);
+
+ /* step 5: walk topology and initialize portsc,
+ * portpmsc and portli
+ */
+ /* this is done in bus_resume */
+
+ /* step 6: restart each of the previously
+ * Running endpoints by ringing their doorbells
+ */
+
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ if (!hibernated)
+ hcd->state = old_state;
+ else
+ hcd->state = HC_STATE_SUSPENDED;
+
+ spin_unlock_irq(&xhci->lock);
+ return 0;
+}
+#endif /* CONFIG_PM */
+
/*-------------------------------------------------------------------------*/
/**
/* Returns 1 if the arguments are OK;
* returns 0 this is a root hub; returns -EINVAL for NULL pointers.
*/
-int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
- struct usb_host_endpoint *ep, int check_ep, const char *func) {
+static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep, int check_ep, bool check_virt_dev,
+ const char *func) {
+ struct xhci_hcd *xhci;
+ struct xhci_virt_device *virt_dev;
+
if (!hcd || (check_ep && !ep) || !udev) {
printk(KERN_DEBUG "xHCI %s called with invalid args\n",
func);
func);
return 0;
}
- if (!udev->slot_id) {
- printk(KERN_DEBUG "xHCI %s called with unaddressed device\n",
- func);
- return -EINVAL;
+
+ if (check_virt_dev) {
+ xhci = hcd_to_xhci(hcd);
+ if (!udev->slot_id || !xhci->devs
+ || !xhci->devs[udev->slot_id]) {
+ printk(KERN_DEBUG "xHCI %s called with unaddressed "
+ "device\n", func);
+ return -EINVAL;
+ }
+
+ virt_dev = xhci->devs[udev->slot_id];
+ if (virt_dev->udev != udev) {
+ printk(KERN_DEBUG "xHCI %s called with udev and "
+ "virt_dev does not match\n", func);
+ return -EINVAL;
+ }
}
+
return 1;
}
struct urb_priv *urb_priv;
int size, i;
- if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
+ if (!urb || xhci_check_args(hcd, urb->dev, urb->ep,
+ true, true, __func__) <= 0)
return -EINVAL;
slot_id = urb->dev->slot_id;
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
- if (!xhci->devs || !xhci->devs[slot_id]) {
- if (!in_interrupt())
- dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n");
- ret = -EINVAL;
- goto exit;
- }
if (!HCD_HW_ACCESSIBLE(hcd)) {
if (!in_interrupt())
xhci_dbg(xhci, "urb submitted during PCI suspend\n");
return -ESHUTDOWN;
}
+/* Get the right ring for the given URB.
+ * If the endpoint supports streams, boundary check the URB's stream ID.
+ * If the endpoint doesn't support streams, return the singular endpoint ring.
+ */
+static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
+ struct urb *urb)
+{
+ unsigned int slot_id;
+ unsigned int ep_index;
+ unsigned int stream_id;
+ struct xhci_virt_ep *ep;
+
+ slot_id = urb->dev->slot_id;
+ ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+ stream_id = urb->stream_id;
+ ep = &xhci->devs[slot_id]->eps[ep_index];
+ /* Common case: no streams */
+ if (!(ep->ep_state & EP_HAS_STREAMS))
+ return ep->ring;
+
+ if (stream_id == 0) {
+ xhci_warn(xhci,
+ "WARN: Slot ID %u, ep index %u has streams, "
+ "but URB has no stream ID.\n",
+ slot_id, ep_index);
+ return NULL;
+ }
+
+ if (stream_id < ep->stream_info->num_streams)
+ return ep->stream_info->stream_rings[stream_id];
+
+ xhci_warn(xhci,
+ "WARN: Slot ID %u, ep index %u has "
+ "stream IDs 1 to %u allocated, "
+ "but stream ID %u is requested.\n",
+ slot_id, ep_index,
+ ep->stream_info->num_streams - 1,
+ stream_id);
+ return NULL;
+}
+
/*
* Remove the URB's TD from the endpoint ring. This may cause the HC to stop
* USB transfers, potentially stopping in the middle of a TRB buffer. The HC
ep->stop_cmd_timer.expires = jiffies +
XHCI_STOP_EP_CMD_TIMEOUT * HZ;
add_timer(&ep->stop_cmd_timer);
- xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index);
+ xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index, 0);
xhci_ring_cmd_db(xhci);
}
done:
u32 new_add_flags, new_drop_flags, new_slot_info;
int ret;
- ret = xhci_check_args(hcd, udev, ep, 1, __func__);
+ ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
if (ret <= 0)
return ret;
xhci = hcd_to_xhci(hcd);
return 0;
}
- if (!xhci->devs || !xhci->devs[udev->slot_id]) {
- xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
- __func__);
- return -EINVAL;
- }
-
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
out_ctx = xhci->devs[udev->slot_id]->out_ctx;
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
u32 new_add_flags, new_drop_flags, new_slot_info;
int ret = 0;
- ret = xhci_check_args(hcd, udev, ep, 1, __func__);
+ ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
if (ret <= 0) {
/* So we won't queue a reset ep command for a root hub */
ep->hcpriv = NULL;
return 0;
}
- if (!xhci->devs || !xhci->devs[udev->slot_id]) {
- xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
- __func__);
- return -EINVAL;
- }
-
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
out_ctx = xhci->devs[udev->slot_id]->out_ctx;
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
cmd_completion = command->completion;
cmd_status = &command->status;
command->command_trb = xhci->cmd_ring->enqueue;
+
+ /* Enqueue pointer can be left pointing to the link TRB,
+ * we must handle that
+ */
+ if ((command->command_trb->link.control & TRB_TYPE_BITMASK)
+ == TRB_TYPE(TRB_LINK))
+ command->command_trb =
+ xhci->cmd_ring->enq_seg->next->trbs;
+
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
} else {
in_ctx = virt_dev->in_ctx;
struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_slot_ctx *slot_ctx;
- ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
+ ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
if (ret <= 0)
return ret;
xhci = hcd_to_xhci(hcd);
- if (!udev->slot_id || !xhci->devs || !xhci->devs[udev->slot_id]) {
- xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
- __func__);
- return -EINVAL;
- }
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
virt_dev = xhci->devs[udev->slot_id];
xhci_dbg_ctx(xhci, virt_dev->out_ctx,
LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
+ /* Free any rings that were dropped, but not changed. */
+ for (i = 1; i < 31; ++i) {
+ if ((ctrl_ctx->drop_flags & (1 << (i + 1))) &&
+ !(ctrl_ctx->add_flags & (1 << (i + 1))))
+ xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
+ }
xhci_zero_in_ctx(xhci, virt_dev);
- /* Install new rings and free or cache any old rings */
+ /*
+ * Install any rings for completely new endpoints or changed endpoints,
+ * and free or cache any old rings from changed endpoints.
+ */
for (i = 1; i < 31; ++i) {
if (!virt_dev->eps[i].new_ring)
continue;
struct xhci_virt_device *virt_dev;
int i, ret;
- ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
+ ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
if (ret <= 0)
return;
xhci = hcd_to_xhci(hcd);
- if (!xhci->devs || !xhci->devs[udev->slot_id]) {
- xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
- __func__);
- return;
- }
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
virt_dev = xhci->devs[udev->slot_id];
/* Free any rings allocated for added endpoints */
xhci_dbg_ctx(xhci, in_ctx, xhci_last_valid_endpoint(add_flags));
}
-void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
+static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
struct xhci_dequeue_state *deq_state)
{
if (!ep)
return -EINVAL;
- ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, __func__);
+ ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, true, __func__);
if (ret <= 0)
return -EINVAL;
if (ep->ss_ep_comp.bmAttributes == 0) {
* Wait for the Reset Device command to finish. Remove all structures
* associated with the endpoints that were disabled. Clear the input device
* structure? Cache the rings? Reset the control endpoint 0 max packet size?
+ *
+ * If the virt_dev to be reset does not exist or does not match the udev,
+ * it means the device is lost, possibly due to the xHC restore error and
+ * re-initialization during S3/S4. In this case, call xhci_alloc_dev() to
+ * re-allocate the device.
*/
-int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
+int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
{
int ret, i;
unsigned long flags;
struct xhci_command *reset_device_cmd;
int timeleft;
int last_freed_endpoint;
+ struct xhci_slot_ctx *slot_ctx;
- ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
+ ret = xhci_check_args(hcd, udev, NULL, 0, false, __func__);
if (ret <= 0)
return ret;
xhci = hcd_to_xhci(hcd);
slot_id = udev->slot_id;
virt_dev = xhci->devs[slot_id];
if (!virt_dev) {
- xhci_dbg(xhci, "%s called with invalid slot ID %u\n",
- __func__, slot_id);
- return -EINVAL;
+ xhci_dbg(xhci, "The device to be reset with slot ID %u does "
+ "not exist. Re-allocate the device\n", slot_id);
+ ret = xhci_alloc_dev(hcd, udev);
+ if (ret == 1)
+ return 0;
+ else
+ return -EINVAL;
+ }
+
+ if (virt_dev->udev != udev) {
+ /* If the virt_dev and the udev does not match, this virt_dev
+ * may belong to another udev.
+ * Re-allocate the device.
+ */
+ xhci_dbg(xhci, "The device to be reset with slot ID %u does "
+ "not match the udev. Re-allocate the device\n",
+ slot_id);
+ ret = xhci_alloc_dev(hcd, udev);
+ if (ret == 1)
+ return 0;
+ else
+ return -EINVAL;
}
+ /* If device is not setup, there is no point in resetting it */
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+ if (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state)) ==
+ SLOT_STATE_DISABLED)
+ return 0;
+
xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id);
/* Allocate the command structure that holds the struct completion.
* Assume we're in process context, since the normal device reset
/* Attempt to submit the Reset Device command to the command ring */
spin_lock_irqsave(&xhci->lock, flags);
reset_device_cmd->command_trb = xhci->cmd_ring->enqueue;
+
+ /* Enqueue pointer can be left pointing to the link TRB,
+ * we must handle that
+ */
+ if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK)
+ == TRB_TYPE(TRB_LINK))
+ reset_device_cmd->command_trb =
+ xhci->cmd_ring->enq_seg->next->trbs;
+
list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
ret = xhci_queue_reset_device(xhci, slot_id);
if (ret) {
struct xhci_virt_device *virt_dev;
unsigned long flags;
u32 state;
- int i;
+ int i, ret;
- if (udev->slot_id == 0)
+ ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
+ if (ret <= 0)
return;
+
virt_dev = xhci->devs[udev->slot_id];
- if (!virt_dev)
- return;
/* Stop any wayward timer functions (which may grab the lock) */
for (i = 0; i < 31; ++i) {
xhci_err(xhci, "Error while assigning device slot ID\n");
return 0;
}
- /* xhci_alloc_virt_device() does not touch rings; no need to lock */
- if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_KERNEL)) {
+ /* xhci_alloc_virt_device() does not touch rings; no need to lock.
+ * Use GFP_NOIO, since this function can be called from
+ * xhci_discover_or_reset_device(), which may be called as part of
+ * mass storage driver error handling.
+ */
+ if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_NOIO)) {
/* Disable slot, if we can do it without mem alloc */
xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
spin_lock_irqsave(&xhci->lock, flags);
virt_dev = xhci->devs[udev->slot_id];
- /* If this is a Set Address to an unconfigured device, setup ep 0 */
- if (!udev->config)
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
+ /*
+ * If this is the first Set Address since device plug-in or
+ * virt_device realloaction after a resume with an xHCI power loss,
+ * then set up the slot context.
+ */
+ if (!slot_ctx->dev_info)
xhci_setup_addressable_virt_dev(xhci, udev);
+ /* Otherwise, update the control endpoint ring enqueue pointer. */
else
xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev);
- /* Otherwise, assume the core has the device configured how it wants */
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
* address given back to us by the HC.
*/
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
- udev->devnum = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1;
+ /* Use kernel assigned address for devices; store xHC assigned
+ * address locally. */
+ virt_dev->address = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1;
/* Zero the input context control for later use */
ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
ctrl_ctx->add_flags = 0;
ctrl_ctx->drop_flags = 0;
- xhci_dbg(xhci, "Device address = %d\n", udev->devnum);
- /* XXX Meh, not sure if anyone else but choose_address uses this. */
- set_bit(udev->devnum, udev->bus->devmap.devicemap);
+ xhci_dbg(xhci, "Internal device address = %d\n", virt_dev->address);
return 0;
}