/* * Start the HC after it was halted. * * This function is called by the USB core when the HC driver is added. * Its opposite is xhci_stop(). * * xhci_init() must be called once before this function can be called. * Reset the HC, enable device slot contexts, program DCBAAP, and * set command ring pointer and event ring pointer. * * Setup MSI-X vectors and enable interrupts. */ int xhci_run(struct usb_hcd *hcd) { u32 temp; u64 temp_64; int ret; struct xhci_hcd *xhci = hcd_to_xhci(hcd); /* Start the xHCI host controller running only after the USB 2.0 roothub * is setup. */ hcd->uses_new_polling = 1; if (!usb_hcd_is_primary_hcd(hcd)) return xhci_run_finished(xhci); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run"); ret = xhci_try_enable_msi(hcd); if (ret) return ret; xhci_dbg(xhci, "Command ring memory map follows:\n"); xhci_debug_ring(xhci, xhci->cmd_ring); xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); xhci_dbg_cmd_ptrs(xhci); xhci_dbg(xhci, "ERST memory map follows:\n"); xhci_dbg_erst(xhci, &xhci->erst); xhci_dbg(xhci, "Event ring:\n"); xhci_debug_ring(xhci, xhci->event_ring); xhci_dbg_ring_ptrs(xhci, xhci->event_ring); temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); temp_64 &= ~ERST_PTR_MASK; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "ERST deq = 64'h%0lx", (long unsigned int) temp_64); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Set the interrupt modulation register"); temp = readl(&xhci->ir_set->irq_control); temp &= ~ER_IRQ_INTERVAL_MASK; temp |= (u32) 160; writel(temp, &xhci->ir_set->irq_control); /* Set the HCD state before we enable the irqs */ temp = readl(&xhci->op_regs->command); temp |= (CMD_EIE); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Enable interrupts, cmd = 0x%x.", temp); writel(temp, &xhci->op_regs->command); temp = readl(&xhci->ir_set->irq_pending); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Enabling event ring interrupter %p by writing 0x%x to irq_pending", xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp)); writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending); xhci_print_ir_set(xhci, 0); if (xhci->quirks & XHCI_NEC_HOST) { struct xhci_command *command; command = xhci_alloc_command(xhci, false, false, GFP_KERNEL); if (!command) return -ENOMEM; xhci_queue_vendor_command(xhci, command, 0, 0, 0, TRB_TYPE(TRB_NEC_GET_FW)); } xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_run for USB2 roothub"); return 0; }
int xhci_run(struct usb_hcd *hcd) { u32 temp; u64 temp_64; struct xhci_hcd *xhci = hcd_to_xhci(hcd); void (*doorbell)(struct xhci_hcd *) = NULL; hcd->uses_new_polling = 1; hcd->poll_rh = 0; xhci_dbg(xhci, "xhci_run\n"); #if 0 ret = xhci_setup_msix(xhci); if (!ret) return ret; return -ENOSYS; #endif #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING init_timer(&xhci->event_ring_timer); xhci->event_ring_timer.data = (unsigned long) xhci; xhci->event_ring_timer.function = xhci_event_ring_work; xhci->event_ring_timer.expires = jiffies + POLL_TIMEOUT * HZ; xhci->zombie = 0; xhci_dbg(xhci, "Setting event ring polling timer\n"); add_timer(&xhci->event_ring_timer); #endif xhci_dbg(xhci, "Command ring memory map follows:\n"); xhci_debug_ring(xhci, xhci->cmd_ring); xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); xhci_dbg_cmd_ptrs(xhci); xhci_dbg(xhci, "ERST memory map follows:\n"); xhci_dbg_erst(xhci, &xhci->erst); xhci_dbg(xhci, "Event ring:\n"); xhci_debug_ring(xhci, xhci->event_ring); xhci_dbg_ring_ptrs(xhci, xhci->event_ring); temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); temp_64 &= ~ERST_PTR_MASK; xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); xhci_dbg(xhci, "// Set the interrupt modulation register\n"); temp = xhci_readl(xhci, &xhci->ir_set->irq_control); temp &= ~ER_IRQ_INTERVAL_MASK; temp |= (u32) 160; xhci_writel(xhci, temp, &xhci->ir_set->irq_control); hcd->state = HC_STATE_RUNNING; temp = xhci_readl(xhci, &xhci->op_regs->command); temp |= (CMD_EIE); xhci_dbg(xhci, "// Enable interrupts, cmd = 0x%x.\n", temp); xhci_writel(xhci, temp, &xhci->op_regs->command); temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); xhci_dbg(xhci, "// Enabling event ring interrupter %p by writing 0x%x to irq_pending\n", 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); if (NUM_TEST_NOOPS > 0) doorbell = xhci_setup_one_noop(xhci); temp = xhci_readl(xhci, &xhci->op_regs->command); temp |= (CMD_RUN); xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", temp); xhci_writel(xhci, temp, &xhci->op_regs->command); temp = xhci_readl(xhci, &xhci->op_regs->command); xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp); if (doorbell) (*doorbell)(xhci); xhci_dbg(xhci, "Finished xhci_run\n"); return 0; }