/* * Set the run bit and wait for the host to be running. */ static int xhci_start(struct xhci_hcd *xhci) { u32 temp; int ret; temp = readl(&xhci->op_regs->command); temp |= (CMD_RUN); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.", temp); writel(temp, &xhci->op_regs->command); /* * Wait for the HCHalted Status bit to be 0 to indicate the host is * running. */ ret = xhci_handshake(&xhci->op_regs->status, STS_HALT, 0, XHCI_MAX_HALT_USEC); if (ret == -ETIMEDOUT) xhci_err(xhci, "Host took too long to start, " "waited %u microseconds.\n", XHCI_MAX_HALT_USEC); if (!ret) xhci->xhc_state &= ~XHCI_STATE_HALTED; return ret; }
static void xhci_start (hci_t *controller) { xhci_t *const xhci = XHCI_INST(controller); xhci->opreg->usbcmd |= USBCMD_RS; if (!xhci_handshake(&xhci->opreg->usbsts, USBSTS_HCH, 0, 1000000L)) xhci_debug("Controller didn't start within 1s\n"); }
static __maybe_unused int xhci_hub_port_warm_reset(struct xhci_hcd *xhci, int port) { void __iomem *portsc = xhci->usb_ports[port]; u32 reg; reg = xhci_port_state_to_neutral(readl(portsc)); writel(reg | PORT_WR, portsc); return xhci_handshake(portsc, PORT_RESET, 0, 10 * SECOND/USECOND); }
static int xhci_wait_ready(xhci_t *const xhci) { xhci_debug("Waiting for controller to be ready... "); if (!xhci_handshake(&xhci->opreg->usbsts, USBSTS_CNR, 0, 100000L)) { usb_debug("timeout!\n"); return -1; } usb_debug("ok.\n"); return 0; }
/* * Reset a halted HC. * * This resets pipelines, timers, counters, state machines, etc. * Transactions will be terminated immediately, and operational registers * will be set to their defaults. */ int xhci_reset(struct xhci_hcd *xhci) { u32 command; u32 state; int ret, i; state = readl(&xhci->op_regs->status); if ((state & STS_HALT) == 0) { xhci_warn(xhci, "Host controller not halted, aborting reset.\n"); return 0; } xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Reset the HC"); command = readl(&xhci->op_regs->command); command |= CMD_RESET; writel(command, &xhci->op_regs->command); ret = xhci_handshake(&xhci->op_regs->command, CMD_RESET, 0, 10 * 1000 * 1000); if (ret) return ret; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Wait for controller to be ready for doorbell rings"); /* * 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); for (i = 0; i < 2; ++i) { xhci->bus_state[i].port_c_suspend = 0; xhci->bus_state[i].suspended_ports = 0; xhci->bus_state[i].resuming_ports = 0; } return ret; }
static void xhci_reset(hci_t *const controller) { xhci_t *const xhci = XHCI_INST(controller); xhci_stop(controller); xhci->opreg->usbcmd |= USBCMD_HCRST; xhci_debug("Resetting controller... "); if (!xhci_handshake(&xhci->opreg->usbcmd, USBCMD_HCRST, 0, 1000000L)) usb_debug("timeout!\n"); else usb_debug("ok.\n"); }
/* * Force HC into halt state. * * Disable any IRQs and clear the run/stop bit. * HC will complete any current and actively pipelined transactions, and * should halt within 16 ms of the run/stop bit being cleared. * Read HC Halted bit in the status register to see when the HC is finished. */ int xhci_halt(struct xhci_hcd *xhci) { int ret; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Halt the HC"); xhci_quiesce(xhci); ret = xhci_handshake(&xhci->op_regs->status, STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); if (!ret) { xhci->xhc_state |= XHCI_STATE_HALTED; xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; } else xhci_warn(xhci, "Host not halted after %u microseconds.\n", XHCI_MAX_HALT_USEC); return ret; }
/* * 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, status; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; int retval = 0; bool comp_timer_running = false; if (!hcd->state) return 0; /* Wait a bit if either of the roothubs need to settle from the * transition into bus suspend. */ if (time_before(jiffies, xhci->bus_state[0].next_statechange) || time_before(jiffies, xhci->bus_state[1].next_statechange)) msleep(100); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); spin_lock_irq(&xhci->lock); if (xhci->quirks & XHCI_RESET_ON_RESUME) hibernated = true; 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 = readl(&xhci->op_regs->command); command |= CMD_CRS; writel(command, &xhci->op_regs->command); if (xhci_handshake(&xhci->op_regs->status, STS_RESTORE, 0, 10 * 1000)) { xhci_warn(xhci, "WARN: xHC restore state timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } temp = readl(&xhci->op_regs->status); } /* If restore operation fails, re-initialize the HC during resume */ if ((temp & STS_SRE) || hibernated) { if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !(xhci_all_ports_seen_u0(xhci))) { del_timer_sync(&xhci->comp_mode_recovery_timer); xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "Compliance Mode Recovery Timer deleted!"); } /* Let the USB core know _both_ roothubs lost power. */ usb_root_hub_lost_power(xhci->main_hcd->self.root_hub); usb_root_hub_lost_power(xhci->shared_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); xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = readl(&xhci->op_regs->status); writel(temp & ~STS_EINT, &xhci->op_regs->status); temp = readl(&xhci->ir_set->irq_pending); writel(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", readl(&xhci->op_regs->status)); /* USB core calls the PCI reinit and start functions twice: * first with the primary HCD, and then with the secondary HCD. * If we don't do the same, the host will never be started. */ if (!usb_hcd_is_primary_hcd(hcd)) secondary_hcd = hcd; else secondary_hcd = xhci->shared_hcd; xhci_dbg(xhci, "Initialize the xhci_hcd\n"); retval = xhci_init(hcd->primary_hcd); if (retval) return retval; comp_timer_running = true; xhci_dbg(xhci, "Start the primary HCD\n"); retval = xhci_run(hcd->primary_hcd); if (!retval) { xhci_dbg(xhci, "Start the secondary HCD\n"); retval = xhci_run(secondary_hcd); } hcd->state = HC_STATE_SUSPENDED; xhci->shared_hcd->state = HC_STATE_SUSPENDED; goto done; } /* step 4: set Run/Stop bit */ command = readl(&xhci->op_regs->command); command |= CMD_RUN; writel(command, &xhci->op_regs->command); xhci_handshake(&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 */ spin_unlock_irq(&xhci->lock); done: if (retval == 0) { /* Resume root hubs only when have pending events. */ status = readl(&xhci->op_regs->status); if (status & STS_EINT) { usb_hcd_resume_root_hub(hcd); usb_hcd_resume_root_hub(xhci->shared_hcd); } } /* * If system is subject to the Quirk, Compliance Mode Timer needs to * be re-initialized Always after a system resume. Ports are subject * to suffer the Compliance Mode issue again. It doesn't matter if * ports have entered previously to U0 before system's suspension. */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !comp_timer_running) compliance_mode_recovery_timer_init(xhci); /* Re-enable port polling. */ xhci_dbg(xhci, "%s: starting port polling.\n", __func__); set_bit(HCD_FLAG_POLL_RH, &hcd->flags); usb_hcd_poll_rh_status(hcd); set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); usb_hcd_poll_rh_status(xhci->shared_hcd); return retval; }
/* * Stop HC (not bus-specific) * * This is called when the machine transition into S3/S4 mode. * */ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) { int rc = 0; unsigned int delay = XHCI_MAX_HALT_USEC; struct usb_hcd *hcd = xhci_to_hcd(xhci); u32 command; if (!hcd->state) return 0; if (hcd->state != HC_STATE_SUSPENDED || xhci->shared_hcd->state != HC_STATE_SUSPENDED) return -EINVAL; /* Clear root port wake on bits if wakeup not allowed. */ if (!do_wakeup) xhci_disable_port_wake_on_bits(xhci); /* Don't poll the roothubs on bus suspend. */ xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); del_timer_sync(&hcd->rh_timer); clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); del_timer_sync(&xhci->shared_hcd->rh_timer); spin_lock_irq(&xhci->lock); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); /* step 1: stop endpoint */ /* skipped assuming that port suspend has done */ /* step 2: clear Run/Stop bit */ command = readl(&xhci->op_regs->command); command &= ~CMD_RUN; writel(command, &xhci->op_regs->command); /* Some chips from Fresco Logic need an extraordinary delay */ delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1; if (xhci_handshake(&xhci->op_regs->status, STS_HALT, STS_HALT, delay)) { 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 = readl(&xhci->op_regs->command); command |= CMD_CSS; writel(command, &xhci->op_regs->command); if (xhci_handshake(&xhci->op_regs->status, STS_SAVE, 0, 10 * 1000)) { xhci_warn(xhci, "WARN: xHC save state timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } spin_unlock_irq(&xhci->lock); /* * Deleting Compliance Mode Recovery Timer because the xHCI Host * is about to be suspended. */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && (!(xhci_all_ports_seen_u0(xhci)))) { del_timer_sync(&xhci->comp_mode_recovery_timer); xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "%s: compliance mode recovery timer deleted", __func__); } /* step 5: remove core well power */ /* synchronize irq when using MSI-X */ xhci_msix_sync_irqs(xhci); return rc; }
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports; unsigned long flags; u32 temp, status; int retval = 0; __le32 __iomem **port_array; int slot_id; struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; u16 timeout = 0; u32 __iomem *status_reg = NULL; u32 i, command, num_ports, selector; int time_left; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; spin_lock_irqsave(&xhci->lock, flags); switch (typeReq) { case GetHubStatus: /* No power source, over-current reported per port */ memset(buf, 0, 4); break; case GetHubDescriptor: /* Check to make sure userspace is asking for the USB 3.0 hub * descriptor for the USB 3.0 roothub. If not, we stall the * endpoint, like external hubs do. */ if (hcd->speed == HCD_USB3 && (wLength < USB_DT_SS_HUB_SIZE || wValue != (USB_DT_SS_HUB << 8))) { xhci_dbg(xhci, "Wrong hub descriptor type for " "USB 3.0 roothub.\n"); goto error; } xhci_hub_descriptor(hcd, xhci, (struct usb_hub_descriptor *) buf); break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: if ((wValue & 0xff00) != (USB_DT_BOS << 8)) goto error; if (hcd->speed != HCD_USB3) goto error; /* Set the U1 and U2 exit latencies. */ memcpy(buf, &usb_bos_descriptor, USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); buf[12] = HCS_U1_LATENCY(temp); put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); /* Indicate whether the host has LTM support. */ temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); if (HCC_LTC(temp)) buf[8] |= USB_LTM_SUPPORT; spin_unlock_irqrestore(&xhci->lock, flags); return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; case GetPortStatus: if (!wIndex || wIndex > max_ports) goto error; wIndex--; status = 0; temp = xhci_readl(xhci, port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; } xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); /* wPortChange bits */ if (temp & PORT_CSC) status |= USB_PORT_STAT_C_CONNECTION << 16; if (temp & PORT_PEC) status |= USB_PORT_STAT_C_ENABLE << 16; if ((temp & PORT_OCC)) status |= USB_PORT_STAT_C_OVERCURRENT << 16; if ((temp & PORT_RC)) status |= USB_PORT_STAT_C_RESET << 16; /* USB3.0 only */ if (hcd->speed == HCD_USB3) { if ((temp & PORT_PLC)) status |= USB_PORT_STAT_C_LINK_STATE << 16; if ((temp & PORT_WRC)) status |= USB_PORT_STAT_C_BH_RESET << 16; } if (hcd->speed != HCD_USB3) { if ((temp & PORT_PLS_MASK) == XDEV_U3 && (temp & PORT_POWER)) status |= USB_PORT_STAT_SUSPEND; } if ((temp & PORT_PLS_MASK) == XDEV_RESUME && !DEV_SUPERSPEED(temp)) { if ((temp & PORT_RESET) || !(temp & PORT_PE)) goto error; if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) { xhci_dbg(xhci, "Resume USB2 port %d\n", wIndex + 1); bus_state->resume_done[wIndex] = 0; clear_bit(wIndex, &bus_state->resuming_ports); set_bit(wIndex, &bus_state->rexit_ports); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); spin_unlock_irqrestore(&xhci->lock, flags); time_left = wait_for_completion_timeout( &(bus_state->rexit_done[wIndex]), msecs_to_jiffies(XHCI_MAX_REXIT_TIMEOUT)); spin_lock_irqsave(&xhci->lock, flags); if (time_left) { slot_id = xhci_find_slot_id_by_port(hcd, xhci, wIndex + 1); if (!slot_id) { xhci_dbg(xhci, "slot_id is zero\n"); return 0xffffffff; } xhci_dbg(xhci, "set port %d resume\n", wIndex + 1); xhci_ring_device(xhci, slot_id); } else { xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n", XHCI_MAX_REXIT_TIMEOUT, temp); status |= USB_PORT_STAT_SUSPEND; clear_bit(wIndex, &bus_state->rexit_ports); } bus_state->port_c_suspend |= 1 << wIndex; bus_state->suspended_ports &= ~(1 << wIndex); } else { /* * The resume has been signaling for less than * 20ms. Report the port status as SUSPEND, * let the usbcore check port status again * and clear resume signaling later. */ status |= USB_PORT_STAT_SUSPEND; } } if ((temp & PORT_PLS_MASK) == XDEV_U0 && (temp & PORT_POWER) && (bus_state->suspended_ports & (1 << wIndex))) { bus_state->suspended_ports &= ~(1 << wIndex); if (hcd->speed != HCD_USB3) bus_state->port_c_suspend |= 1 << wIndex; } if (temp & PORT_CONNECT) { status |= USB_PORT_STAT_CONNECTION; status |= xhci_port_speed(temp); } if (temp & PORT_PE) status |= USB_PORT_STAT_ENABLE; if (temp & PORT_OC) status |= USB_PORT_STAT_OVERCURRENT; if (temp & PORT_RESET) status |= USB_PORT_STAT_RESET; if (temp & PORT_POWER) { if (hcd->speed == HCD_USB3) status |= USB_SS_PORT_STAT_POWER; else status |= USB_PORT_STAT_POWER; } /* Update Port Link State for super speed ports*/ if (hcd->speed == HCD_USB3) { xhci_hub_report_link_state(&status, temp); /* * Verify if all USB3 Ports Have entered U0 already. * Delete Compliance Mode Timer if so. */ xhci_del_comp_mod_timer(xhci, temp, wIndex); } if (bus_state->port_c_suspend & (1 << wIndex)) status |= 1 << USB_PORT_FEAT_C_SUSPEND; xhci_dbg(xhci, "Get port status returned 0x%x\n", status); put_unaligned(cpu_to_le32(status), (__le32 *) buf); break; case SetPortFeature: if (wValue == USB_PORT_FEAT_LINK_STATE) link_state = (wIndex & 0xff00) >> 3; if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK) wake_mask = wIndex & 0xff00; selector = wIndex >> 8; /* The MSB of wIndex is the U1/U2 timeout */ timeout = (wIndex & 0xff00) >> 8; wIndex &= 0xff; if (!wIndex || wIndex > max_ports) goto error; wIndex--; status_reg = &xhci->op_regs->port_power_base + NUM_PORT_REGS*wIndex; temp = xhci_readl(xhci, port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; } temp = xhci_port_state_to_neutral(temp); /* FIXME: What new port features do we need to support? */ switch (wValue) { case USB_PORT_FEAT_SUSPEND: temp = xhci_readl(xhci, port_array[wIndex]); if ((temp & PORT_PLS_MASK) != XDEV_U0) { /* Resume the port to U0 first */ xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); spin_unlock_irqrestore(&xhci->lock, flags); msleep(10); spin_lock_irqsave(&xhci->lock, flags); } /* In spec software should not attempt to suspend * a port unless the port reports that it is in the * enabled (PED = ‘1’,PLS < ‘3’) state. */ temp = xhci_readl(xhci, port_array[wIndex]); if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) || (temp & PORT_PLS_MASK) >= XDEV_U3) { xhci_warn(xhci, "USB core suspending device " "not in U0/U1/U2.\n"); goto error; } slot_id = xhci_find_slot_id_by_port(hcd, xhci, wIndex + 1); if (!slot_id) { xhci_warn(xhci, "slot_id is zero\n"); goto error; } /* unlock to execute stop endpoint commands */ spin_unlock_irqrestore(&xhci->lock, flags); xhci_stop_device(xhci, slot_id, 1); spin_lock_irqsave(&xhci->lock, flags); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3); spin_unlock_irqrestore(&xhci->lock, flags); msleep(10); /* wait device to enter */ spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, port_array[wIndex]); bus_state->suspended_ports |= 1 << wIndex; break; case USB_PORT_FEAT_LINK_STATE: temp = xhci_readl(xhci, port_array[wIndex]); /* Disable port */ if (link_state == USB_SS_PORT_LS_SS_DISABLED) { xhci_dbg(xhci, "Disable port %d\n", wIndex); temp = xhci_port_state_to_neutral(temp); /* * Clear all change bits, so that we get a new * connection event. */ temp |= PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | PORT_RC | PORT_PLC | PORT_CEC; xhci_writel(xhci, temp | PORT_PE, port_array[wIndex]); temp = xhci_readl(xhci, port_array[wIndex]); break; } /* Put link in RxDetect (enable port) */ if (link_state == USB_SS_PORT_LS_RX_DETECT) { xhci_dbg(xhci, "Enable port %d\n", wIndex); xhci_set_link_state(xhci, port_array, wIndex, link_state); temp = xhci_readl(xhci, port_array[wIndex]); break; } /* Software should not attempt to set * port link state above '3' (U3) and the port * must be enabled. */ if ((temp & PORT_PE) == 0 || (link_state > USB_SS_PORT_LS_U3)) { xhci_warn(xhci, "Cannot set link state.\n"); goto error; } if (link_state == USB_SS_PORT_LS_U3) { slot_id = xhci_find_slot_id_by_port(hcd, xhci, wIndex + 1); if (slot_id) { /* unlock to execute stop endpoint * commands */ spin_unlock_irqrestore(&xhci->lock, flags); xhci_stop_device(xhci, slot_id, 1); spin_lock_irqsave(&xhci->lock, flags); } } xhci_set_link_state(xhci, port_array, wIndex, link_state); spin_unlock_irqrestore(&xhci->lock, flags); msleep(20); /* wait device to enter */ spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, port_array[wIndex]); if (link_state == USB_SS_PORT_LS_U3) bus_state->suspended_ports |= 1 << wIndex; break; case USB_PORT_FEAT_POWER: /* FIXME Do not turn on BYT XHCI port 6 power, * Disable this port's power to disable HSIC hub */ if ((xhci->quirks & XHCI_PORT_DISABLE_QUIRK) && (wIndex == 5)) { temp = xhci_readl(xhci, port_array[wIndex]); temp &= ~PORT_POWER; xhci_writel(xhci, temp, port_array[wIndex]); break; } /* * Turn on ports, even if there isn't per-port switching. * HC will report connect events even before this is set. * However, khubd will ignore the roothub events until * the roothub is registered. */ xhci_writel(xhci, temp | PORT_POWER, port_array[wIndex]); temp = xhci_readl(xhci, port_array[wIndex]); xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); spin_unlock_irqrestore(&xhci->lock, flags); temp = usb_acpi_power_manageable(hcd->self.root_hub, wIndex); if (temp) usb_acpi_set_power_state(hcd->self.root_hub, wIndex, true); spin_lock_irqsave(&xhci->lock, flags); break; case USB_PORT_FEAT_RESET: /* * WR solution to individual USB3.0 UMS address fail due * to link state unstable after Hot reset. */ if ((xhci->quirks & XHCI_FORCE_WR) && (DEV_SUPERSPEED(temp))) temp = (temp | PORT_WR); else temp = (temp | PORT_RESET); if (xhci->quirks & XHCI_PORT_RESET) quirk_intel_xhci_port_reset(hcd->self.controller, false); xhci_writel(xhci, temp, port_array[wIndex]); temp = xhci_readl(xhci, port_array[wIndex]); xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); if (xhci->quirks & XHCI_PORT_RESET) { int delay_time; spin_unlock_irqrestore(&xhci->lock, flags); for (delay_time = 0; delay_time < 800; delay_time += 10) { if (!(temp & PORT_RESET)) break; mdelay(2); temp = xhci_readl(xhci, port_array[wIndex]); } spin_lock_irqsave(&xhci->lock, flags); quirk_intel_xhci_port_reset(hcd->self.controller, true); } break; case USB_PORT_FEAT_REMOTE_WAKE_MASK: xhci_set_remote_wake_mask(xhci, port_array, wIndex, wake_mask); temp = xhci_readl(xhci, port_array[wIndex]); xhci_dbg(xhci, "set port remote wake mask, " "actual port %d status = 0x%x\n", wIndex, temp); break; case USB_PORT_FEAT_BH_PORT_RESET: temp |= PORT_WR; xhci_writel(xhci, temp, port_array[wIndex]); temp = xhci_readl(xhci, port_array[wIndex]); break; case USB_PORT_FEAT_TEST: if (!selector || selector >= 5 || !status_reg) goto error; /* * Disable all Device Slots. */ for (i = 0; i < MAX_HC_SLOTS; i++) { if (xhci->dcbaa->dev_context_ptrs[i]) { if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, i)) { xhci_err(xhci, "Disable slot[%d] failed!\n", i); goto error; } xhci_dbg(xhci, "Disable Slot[%d].\n", i); } } /* * All ports shall be in the Disable state (PP = 0) */ xhci_dbg(xhci, "Disable all port (PP = 0)\n"); num_ports = HCS_MAX_PORTS(xhci->hcs_params1); for (i = 0; i < num_ports; i++) { u32 __iomem *sreg = &xhci->op_regs->port_status_base + NUM_PORT_REGS*i; temp = xhci_readl(xhci, sreg); temp &= ~PORT_POWER; xhci_writel(xhci, temp, sreg); } /* Set the Run/Stop (R/S) bit in the USBCMD * register to a '0' and wait for HCHalted(HCH) bit * in the USBSTS register, to transition to a '1'. */ xhci_dbg(xhci, "Stop controller\n"); command = xhci_readl(xhci, &xhci->op_regs->command); command &= ~CMD_RUN; xhci_writel(xhci, command, &xhci->op_regs->command); if (xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT, STS_HALT, 100*100)) { xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n"); return -ETIMEDOUT; } /* * start to test */ xhci_dbg(xhci, "test case:"); switch (selector) { case 1: xhci_dbg(xhci, "TEST_J\n"); break; case 2: xhci_dbg(xhci, "TEST_K\n"); break; case 3: xhci_dbg(xhci, "TEST_SE0_NAK\n"); break; case 4: xhci_dbg(xhci, "TEST_PACKET\n"); break; default: xhci_dbg(xhci, "Invalide test case!\n"); goto error; } /* prevent controller enters Low power state in Test mode. * some controller will exit Test mode once enter low power * mode */ pm_runtime_get(hcd->self.controller); temp = xhci_readl(xhci, status_reg); temp |= selector << 28; xhci_writel(xhci, temp, status_reg); break; case USB_PORT_FEAT_U1_TIMEOUT: if (hcd->speed != HCD_USB3) goto error; temp = xhci_readl(xhci, port_array[wIndex] + PORTPMSC); temp &= ~PORT_U1_TIMEOUT_MASK; temp |= PORT_U1_TIMEOUT(timeout); xhci_writel(xhci, temp, port_array[wIndex] + PORTPMSC); break; case USB_PORT_FEAT_U2_TIMEOUT: if (hcd->speed != HCD_USB3) goto error; temp = xhci_readl(xhci, port_array[wIndex] + PORTPMSC); temp &= ~PORT_U2_TIMEOUT_MASK; temp |= PORT_U2_TIMEOUT(timeout); xhci_writel(xhci, temp, port_array[wIndex] + PORTPMSC); break; default: goto error; } /* unblock any posted writes */ temp = xhci_readl(xhci, port_array[wIndex]); break; case ClearPortFeature: if (!wIndex || wIndex > max_ports) goto error; wIndex--; temp = xhci_readl(xhci, port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; } /* FIXME: What new port features do we need to support? */ temp = xhci_port_state_to_neutral(temp); switch (wValue) { case USB_PORT_FEAT_SUSPEND: temp = xhci_readl(xhci, port_array[wIndex]); xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n"); xhci_dbg(xhci, "PORTSC %04x\n", temp); if (temp & PORT_RESET) goto error; if ((temp & PORT_PLS_MASK) == XDEV_U3) { if ((temp & PORT_PE) == 0) goto error; xhci_set_link_state(xhci, port_array, wIndex, XDEV_RESUME); spin_unlock_irqrestore(&xhci->lock, flags); msleep(20); spin_lock_irqsave(&xhci->lock, flags); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); } bus_state->port_c_suspend |= 1 << wIndex; slot_id = xhci_find_slot_id_by_port(hcd, xhci, wIndex + 1); if (!slot_id) { xhci_dbg(xhci, "slot_id is zero\n"); goto error; } xhci_ring_device(xhci, slot_id); break; case USB_PORT_FEAT_C_SUSPEND: bus_state->port_c_suspend &= ~(1 << wIndex); case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_BH_PORT_RESET: case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_ENABLE: case USB_PORT_FEAT_C_PORT_LINK_STATE: xhci_clear_port_change_bit(xhci, wValue, wIndex, port_array[wIndex], temp); break; case USB_PORT_FEAT_ENABLE: xhci_disable_port(hcd, xhci, wIndex, port_array[wIndex], temp); break; case USB_PORT_FEAT_POWER: xhci_writel(xhci, temp & ~PORT_POWER, port_array[wIndex]); spin_unlock_irqrestore(&xhci->lock, flags); temp = usb_acpi_power_manageable(hcd->self.root_hub, wIndex); if (temp) usb_acpi_set_power_state(hcd->self.root_hub, wIndex, false); spin_lock_irqsave(&xhci->lock, flags); break; default: goto error; } break; default: error: /* "stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&xhci->lock, flags); return retval; }