diff options
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r-- | drivers/usb/host/xhci.c | 65 |
1 files changed, 29 insertions, 36 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 2d378543bc3a..642610c78f58 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -65,7 +65,7 @@ static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring) * handshake done). There are two failure modes: "usec" have passed (major * hardware flakeout), or the register reads as all-ones (hardware removed). */ -int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) +int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us) { u32 result; int ret; @@ -73,7 +73,7 @@ int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) ret = readl_poll_timeout_atomic(ptr, result, (result & mask) == done || result == U32_MAX, - 1, usec); + 1, timeout_us); if (result == U32_MAX) /* card removed */ return -ENODEV; @@ -110,6 +110,7 @@ void xhci_quiesce(struct xhci_hcd *xhci) int xhci_halt(struct xhci_hcd *xhci) { int ret; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Halt the HC"); xhci_quiesce(xhci); @@ -119,8 +120,10 @@ int xhci_halt(struct xhci_hcd *xhci) xhci_warn(xhci, "Host halt failed, %d\n", ret); return ret; } + xhci->xhc_state |= XHCI_STATE_HALTED; xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; + return ret; } @@ -162,7 +165,7 @@ int xhci_start(struct xhci_hcd *xhci) * Transactions will be terminated immediately, and operational registers * will be set to their defaults. */ -int xhci_reset(struct xhci_hcd *xhci) +int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) { u32 command; u32 state; @@ -195,8 +198,7 @@ int xhci_reset(struct xhci_hcd *xhci) if (xhci->quirks & XHCI_INTEL_HOST) udelay(1000); - ret = xhci_handshake(&xhci->op_regs->command, - CMD_RESET, 0, 10 * 1000 * 1000); + ret = xhci_handshake(&xhci->op_regs->command, CMD_RESET, 0, timeout_us); if (ret) return ret; @@ -209,8 +211,7 @@ int xhci_reset(struct xhci_hcd *xhci) * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. */ - ret = xhci_handshake(&xhci->op_regs->status, - STS_CNR, 0, 10 * 1000 * 1000); + ret = xhci_handshake(&xhci->op_regs->status, STS_CNR, 0, timeout_us); xhci->usb2_rhub.bus_state.port_c_suspend = 0; xhci->usb2_rhub.bus_state.suspended_ports = 0; @@ -324,7 +325,7 @@ static int xhci_setup_msi(struct xhci_hcd *xhci) */ static int xhci_setup_msix(struct xhci_hcd *xhci) { - int i, ret = 0; + int i, ret; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); @@ -578,7 +579,7 @@ static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci) static int xhci_init(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int retval = 0; + int retval; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_init"); spin_lock_init(&xhci->lock); @@ -695,7 +696,7 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_run for USB2 roothub"); - xhci_dbc_init(xhci); + xhci_create_dbc_dev(xhci); xhci_debugfs_init(xhci); @@ -725,13 +726,13 @@ static void xhci_stop(struct usb_hcd *hcd) return; } - xhci_dbc_exit(xhci); + xhci_remove_dbc_dev(xhci); spin_lock_irq(&xhci->lock); xhci->xhc_state |= XHCI_STATE_HALTED; xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; xhci_halt(xhci); - xhci_reset(xhci); + xhci_reset(xhci, XHCI_RESET_SHORT_USEC); spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); @@ -784,7 +785,7 @@ void xhci_shutdown(struct usb_hcd *hcd) xhci_halt(xhci); /* Workaround for spurious wakeups at shutdown with HSW */ if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) - xhci_reset(xhci); + xhci_reset(xhci, XHCI_RESET_SHORT_USEC); spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); @@ -1170,7 +1171,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci_dbg(xhci, "Stop HCD\n"); xhci_halt(xhci); xhci_zero_64b_regs(xhci); - retval = xhci_reset(xhci); + retval = xhci_reset(xhci, XHCI_RESET_LONG_USEC); spin_unlock_irq(&xhci->lock); if (retval) return retval; @@ -3160,8 +3161,6 @@ rescan: ep_index = xhci_get_endpoint_index(&host_ep->desc); ep = &vdev->eps[ep_index]; - if (!ep) - goto done; /* wait for hub_tt_work to finish clearing hub TT */ if (ep->ep_state & EP_CLEARING_TT) { @@ -3219,8 +3218,6 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, return; ep_index = xhci_get_endpoint_index(&host_ep->desc); ep = &vdev->eps[ep_index]; - if (!ep) - return; /* Bail out if toggle is already being cleared by a endpoint reset */ spin_lock_irqsave(&xhci->lock, flags); @@ -3978,7 +3975,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id) struct xhci_command *command; unsigned long flags; u32 state; - int ret = 0; + int ret; command = xhci_alloc_command(xhci, true, GFP_KERNEL); if (!command) @@ -4014,7 +4011,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id) xhci_free_command(xhci, command); - return ret; + return 0; } /* @@ -4354,6 +4351,10 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, unsigned long flags; int ret; + command = xhci_alloc_command_with_ctx(xhci, true, GFP_KERNEL); + if (!command) + return -ENOMEM; + spin_lock_irqsave(&xhci->lock, flags); virt_dev = xhci->devs[udev->slot_id]; @@ -4370,10 +4371,10 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, } /* Attempt to issue an Evaluate Context command to change the MEL. */ - command = xhci->lpm_command; ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx); if (!ctrl_ctx) { spin_unlock_irqrestore(&xhci->lock, flags); + xhci_free_command(xhci, command); xhci_warn(xhci, "%s: Could not get input context, bad type.\n", __func__); return -ENOMEM; @@ -4400,6 +4401,9 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, virt_dev->current_mel = max_exit_latency; spin_unlock_irqrestore(&xhci->lock, flags); } + + xhci_free_command(xhci, command); + return ret; } @@ -4520,18 +4524,8 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, exit_latency = xhci_besl_encoding[hird]; spin_unlock_irqrestore(&xhci->lock, flags); - /* USB 3.0 code dedicate one xhci->lpm_command->in_ctx - * input context for link powermanagement evaluate - * context commands. It is protected by hcd->bandwidth - * mutex and is shared by all devices. We need to set - * the max ext latency in USB 2 BESL LPM as well, so - * use the same mutex and xhci_change_max_exit_latency() - */ - mutex_lock(hcd->bandwidth_mutex); ret = xhci_change_max_exit_latency(xhci, udev, exit_latency); - mutex_unlock(hcd->bandwidth_mutex); - if (ret < 0) return ret; spin_lock_irqsave(&xhci->lock, flags); @@ -4559,9 +4553,7 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, readl(pm_addr); if (udev->usb2_hw_lpm_besl_capable) { spin_unlock_irqrestore(&xhci->lock, flags); - mutex_lock(hcd->bandwidth_mutex); xhci_change_max_exit_latency(xhci, udev, 0); - mutex_unlock(hcd->bandwidth_mutex); readl_poll_timeout(ports[port_num]->addr, pm_val, (pm_val & PORT_PLS_MASK) == XDEV_U0, 100, 10000); @@ -5290,8 +5282,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) xhci->hcs_params1 = readl(&xhci->cap_regs->hcs_params1); xhci->hcs_params2 = readl(&xhci->cap_regs->hcs_params2); xhci->hcs_params3 = readl(&xhci->cap_regs->hcs_params3); - xhci->hcc_params = readl(&xhci->cap_regs->hc_capbase); - xhci->hci_version = HC_VERSION(xhci->hcc_params); + xhci->hci_version = HC_VERSION(readl(&xhci->cap_regs->hc_capbase)); xhci->hcc_params = readl(&xhci->cap_regs->hcc_params); if (xhci->hci_version > 0x100) xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); @@ -5316,7 +5307,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) xhci_dbg(xhci, "Resetting HCD\n"); /* Reset the internal HC memory state and registers. */ - retval = xhci_reset(xhci); + retval = xhci_reset(xhci, XHCI_RESET_LONG_USEC); if (retval) return retval; xhci_dbg(xhci, "Reset complete\n"); @@ -5505,6 +5496,7 @@ static int __init xhci_hcd_init(void) return -ENODEV; xhci_debugfs_create_root(); + xhci_dbc_init(); return 0; } @@ -5516,6 +5508,7 @@ static int __init xhci_hcd_init(void) static void __exit xhci_hcd_fini(void) { xhci_debugfs_remove_root(); + xhci_dbc_exit(); } module_init(xhci_hcd_init); |