int xhci_bus_suspend(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports, port_index; __le32 __iomem **port_array; struct xhci_bus_state *bus_state; unsigned long flags; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; spin_lock_irqsave(&xhci->lock, flags); if (hcd->self.root_hub->do_remote_wakeup) { port_index = max_ports; while (port_index--) { if (bus_state->resume_done[port_index] != 0) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "suspend failed because " "port %d is resuming\n", port_index + 1); return -EBUSY; } } } port_index = max_ports; bus_state->bus_suspended = 0; while (port_index--) { /* suspend the port if the port is not suspended */ u32 t1, t2; int slot_id; t1 = xhci_readl(xhci, port_array[port_index]); t2 = xhci_port_state_to_neutral(t1); if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { xhci_dbg(xhci, "port %d not suspended\n", port_index); slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); if (slot_id) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_stop_device(xhci, slot_id, 1); spin_lock_irqsave(&xhci->lock, flags); } t2 &= ~PORT_PLS_MASK; t2 |= PORT_LINK_STROBE | XDEV_U3; set_bit(port_index, &bus_state->bus_suspended); } /* USB core sets remote wake mask for USB 3.0 hubs, * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND * is enabled, so also enable remote wake here. */ if (hcd->self.root_hub->do_remote_wakeup) { if (t1 & PORT_CONNECT) { t2 |= PORT_WKOC_E | PORT_WKDISC_E; t2 &= ~PORT_WKCONN_E; } else { t2 |= PORT_WKOC_E | PORT_WKCONN_E; t2 &= ~PORT_WKDISC_E; } } else t2 &= ~PORT_WAKE_BITS; t1 = xhci_port_state_to_neutral(t1); if (t1 != t2) { xhci_writel(xhci, t2, port_array[port_index]); if (xhci->quirks & XHCI_PORTSC_DELAY) ndelay(100); } if (hcd->speed != HCD_USB3) { /* enable remote wake up for USB 2.0 */ __le32 __iomem *addr; u32 tmp; /* Add one to the port status register address to get * the port power control register address. */ addr = port_array[port_index] + 1; tmp = xhci_readl(xhci, addr); tmp |= PORT_RWE; xhci_writel(xhci, tmp, addr); if (xhci->quirks & XHCI_PORTSC_DELAY) ndelay(100); } } hcd->state = HC_STATE_SUSPENDED; bus_state->next_statechange = jiffies + msecs_to_jiffies(10); spin_unlock_irqrestore(&xhci->lock, flags); return 0; }
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 ports; unsigned long flags; u32 temp, status; int retval = 0; u32 __iomem *addr; char *port_change_bit; ports = HCS_MAX_PORTS(xhci->hcs_params1); 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: xhci_hub_descriptor(xhci, (struct usb_hub_descriptor *) buf); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; status = 0; addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); temp = xhci_readl(xhci, addr); xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); /* wPortChange bits */ if (temp & PORT_CSC) status |= 1 << USB_PORT_FEAT_C_CONNECTION; if (temp & PORT_PEC) status |= 1 << USB_PORT_FEAT_C_ENABLE; if ((temp & PORT_OCC)) status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; /* * FIXME ignoring suspend, reset, and USB 2.1/3.0 specific * changes */ if (temp & PORT_CONNECT) { status |= 1 << USB_PORT_FEAT_CONNECTION; status |= xhci_port_speed(temp); } if (temp & PORT_PE) status |= 1 << USB_PORT_FEAT_ENABLE; if (temp & PORT_OC) status |= 1 << USB_PORT_FEAT_OVER_CURRENT; if (temp & PORT_RESET) status |= 1 << USB_PORT_FEAT_RESET; if (temp & PORT_POWER) status |= 1 << USB_PORT_FEAT_POWER; xhci_dbg(xhci, "Get port status returned 0x%x\n", status); put_unaligned(cpu_to_le32(status), (__le32 *) buf); break; case SetPortFeature: wIndex &= 0xff; if (!wIndex || wIndex > ports) goto error; wIndex--; addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); temp = xhci_readl(xhci, addr); temp = xhci_port_state_to_neutral(temp); switch (wValue) { case USB_PORT_FEAT_POWER: /* * 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, addr); temp = xhci_readl(xhci, addr); xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); xhci_writel(xhci, temp, addr); temp = xhci_readl(xhci, addr); xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); break; default: goto error; } temp = xhci_readl(xhci, addr); /* unblock any posted writes */ break; case ClearPortFeature: if (!wIndex || wIndex > ports) goto error; wIndex--; addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); temp = xhci_readl(xhci, addr); temp = xhci_port_state_to_neutral(temp); switch (wValue) { case USB_PORT_FEAT_C_RESET: status = PORT_RC; port_change_bit = "reset"; break; case USB_PORT_FEAT_C_CONNECTION: status = PORT_CSC; port_change_bit = "connect"; break; case USB_PORT_FEAT_C_OVER_CURRENT: status = PORT_OCC; port_change_bit = "over-current"; break; case USB_PORT_FEAT_ENABLE: status = 0; temp &= ~((u32)PORT_PE); port_change_bit = "enable"; break; default: goto error; } /* Change bits are all write 1 to clear */ xhci_writel(xhci, temp | status, addr); temp = xhci_readl(xhci, addr); xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n", port_change_bit, wIndex, temp); temp = xhci_readl(xhci, addr); /* unblock any posted writes */ break; default: error: /* "stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&xhci->lock, flags); return retval; }
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; u32 __iomem *status_reg = NULL; u32 i, command, num_ports, selector; 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; 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]); 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); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); xhci_dbg(xhci, "set port %d resume\n", wIndex + 1); 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); 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; 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); break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); 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); 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 (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; } temp = xhci_readl(xhci, status_reg); temp |= selector << 28; xhci_writel(xhci, temp, status_reg); 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_POWER: /* * Turn off ports even if there isn't per-port * swithing. 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, "clear PP, port %d status = 0x%x\n", wIndex, temp); 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; default: goto error; } break; default: error: /* "stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&xhci->lock, flags); return retval; }
static void xhci_print_cap_regs(struct xhci_hcd *xhci) { u32 temp; xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs); temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, "CAPLENGTH: 0x%x\n", (unsigned int) HC_LENGTH(temp)); xhci_dbg(xhci, "HCIVERSION: 0x%x\n", (unsigned int) HC_VERSION(temp)); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n", (unsigned int) temp); xhci_dbg(xhci, " Max device slots: %u\n", (unsigned int) HCS_MAX_SLOTS(temp)); xhci_dbg(xhci, " Max interrupters: %u\n", (unsigned int) HCS_MAX_INTRS(temp)); xhci_dbg(xhci, " Max ports: %u\n", (unsigned int) HCS_MAX_PORTS(temp)); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n", (unsigned int) temp); xhci_dbg(xhci, " Isoc scheduling threshold: %u\n", (unsigned int) HCS_IST(temp)); xhci_dbg(xhci, " Maximum allowed segments in event ring: %u\n", (unsigned int) HCS_ERST_MAX(temp)); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " Worst case U1 device exit latency: %u\n", (unsigned int) HCS_U1_LATENCY(temp)); xhci_dbg(xhci, " Worst case U2 device exit latency: %u\n", (unsigned int) HCS_U2_LATENCY(temp)); temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " HC generates %s bit addresses\n", HCC_64BIT_ADDR(temp) ? "64" : "32"); /* FIXME */ xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n"); temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off); xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK); }
int xhci_bus_suspend(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports, port_index; __le32 __iomem **port_array; struct xhci_bus_state *bus_state; unsigned long flags; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; spin_lock_irqsave(&xhci->lock, flags); if (hcd->self.root_hub->do_remote_wakeup) { if (bus_state->resuming_ports) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "suspend failed because " "a port is resuming\n"); return -EBUSY; } } port_index = max_ports; bus_state->bus_suspended = 0; while (port_index--) { /* suspend the port if the port is not suspended */ u32 t1, t2; int slot_id; t1 = xhci_readl(xhci, port_array[port_index]); t2 = xhci_port_state_to_neutral(t1); if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { xhci_dbg(xhci, "port %d not suspended\n", port_index); slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); if (slot_id) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_stop_device(xhci, slot_id, 1); spin_lock_irqsave(&xhci->lock, flags); } t2 &= ~PORT_PLS_MASK; t2 |= PORT_LINK_STROBE | XDEV_U3; set_bit(port_index, &bus_state->bus_suspended); } /* USB core sets remote wake mask for USB 3.0 hubs, * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND * is enabled, so also enable remote wake here. */ if (hcd->self.root_hub->do_remote_wakeup) { if (t1 & PORT_CONNECT) { t2 |= PORT_WKOC_E | PORT_WKDISC_E; t2 &= ~PORT_WKCONN_E; } else { t2 |= PORT_WKOC_E | PORT_WKCONN_E; t2 &= ~PORT_WKDISC_E; } } else t2 &= ~PORT_WAKE_BITS; t1 = xhci_port_state_to_neutral(t1); if (t1 != t2) { xhci_writel(xhci, t2, port_array[port_index]); } hcd->state = HC_STATE_SUSPENDED; bus_state->next_statechange = jiffies + msecs_to_jiffies(10); spin_unlock_irqrestore(&xhci->lock, flags); return 0; } int xhci_bus_resume(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports, port_index; __le32 __iomem **port_array; struct xhci_bus_state *bus_state; u32 temp; unsigned long flags; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; if (time_before(jiffies, bus_state->next_statechange)) msleep(5); spin_lock_irqsave(&xhci->lock, flags); if (!HCD_HW_ACCESSIBLE(hcd)) { spin_unlock_irqrestore(&xhci->lock, flags); return -ESHUTDOWN; } /* delay the irqs */ temp = xhci_readl(xhci, &xhci->op_regs->command); temp &= ~CMD_EIE; xhci_writel(xhci, temp, &xhci->op_regs->command); port_index = max_ports; while (port_index--) { /* Check whether need resume ports. If needed resume port and disable remote wakeup */ u32 temp; int slot_id; temp = xhci_readl(xhci, port_array[port_index]); if (DEV_SUPERSPEED(temp)) temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); else temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); if (test_bit(port_index, &bus_state->bus_suspended) && (temp & PORT_PLS_MASK)) { if (DEV_SUPERSPEED(temp)) { xhci_set_link_state(xhci, port_array, port_index, XDEV_U0); } else { xhci_set_link_state(xhci, port_array, port_index, XDEV_RESUME); spin_unlock_irqrestore(&xhci->lock, flags); msleep(20); spin_lock_irqsave(&xhci->lock, flags); xhci_set_link_state(xhci, port_array, port_index, XDEV_U0); } /* wait for the port to enter U0 and report port link * state change. */ spin_unlock_irqrestore(&xhci->lock, flags); msleep(20); spin_lock_irqsave(&xhci->lock, flags); /* Clear PLC */ xhci_test_and_clear_bit(xhci, port_array, port_index, PORT_PLC); slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); if (slot_id) xhci_ring_device(xhci, slot_id); } else { xhci_writel(xhci, temp, port_array[port_index]); } (void) xhci_readl(xhci, &xhci->op_regs->command); bus_state->next_statechange = jiffies + msecs_to_jiffies(5); /* re-enable irqs */ temp = xhci_readl(xhci, &xhci->op_regs->command); temp |= CMD_EIE; xhci_writel(xhci, temp, &xhci->op_regs->command); temp = xhci_readl(xhci, &xhci->op_regs->command); spin_unlock_irqrestore(&xhci->lock, flags); return 0; }
static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(dev); /* Look for vendor-specific quirks */ if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK || pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1400)) { if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && pdev->revision == 0x0) { xhci->quirks |= XHCI_RESET_EP_QUIRK; xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" " endpoint cmd after reset endpoint\n"); } /* Fresco Logic confirms: all revisions of this chip do not * support MSI, even though some of them claim to in their PCI * capabilities. */ xhci->quirks |= XHCI_BROKEN_MSI; xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " "has broken MSI implementation\n", pdev->revision); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_NEC) xhci->quirks |= XHCI_NEC_HOST; if (pdev->vendor == PCI_VENDOR_ID_AMD && xhci->hci_version == 0x96) xhci->quirks |= XHCI_AMD_0x96_HOST; /* AMD PLL quirk */ if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) xhci->quirks |= XHCI_AMD_PLL_FIX; if (pdev->vendor == PCI_VENDOR_ID_AMD) xhci->quirks |= XHCI_TRUST_TX_LENGTH; if (pdev->vendor == PCI_VENDOR_ID_INTEL) xhci->quirks |= XHCI_AVOID_BEI; if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { xhci->quirks |= XHCI_EP_LIMIT_QUIRK; xhci->limit_active_eps = 64; xhci->quirks |= XHCI_SW_BW_CHECKING; /* * PPT desktop boards DH77EB and DH77DF will power back on after * a few seconds of being shutdown. The fix for this is to * switch the ports from xHCI to EHCI on shutdown. We can't use * DMI information to find those particular boards (since each * vendor will change the board name), so we have to key off all * PPT chipsets. */ xhci->quirks |= XHCI_SPURIOUS_REBOOT; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) { xhci->quirks |= XHCI_PME_STUCK_QUIRK; } if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_ASROCK_P67) { xhci->quirks |= XHCI_RESET_ON_RESUME; xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_RENESAS && pdev->device == 0x0015) xhci->quirks |= XHCI_RESET_ON_RESUME; if (pdev->vendor == PCI_VENDOR_ID_VIA) xhci->quirks |= XHCI_RESET_ON_RESUME; }
static void xhci_print_cap_regs(struct xhci_hcd *xhci) { u32 temp; u32 hci_version; xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs); temp = readl(&xhci->cap_regs->hc_capbase); hci_version = HC_VERSION(temp); xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, "CAPLENGTH: 0x%x\n", (unsigned int) HC_LENGTH(temp)); xhci_dbg(xhci, "HCIVERSION: 0x%x\n", hci_version); temp = readl(&xhci->cap_regs->hcs_params1); xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n", (unsigned int) temp); xhci_dbg(xhci, " Max device slots: %u\n", (unsigned int) HCS_MAX_SLOTS(temp)); xhci_dbg(xhci, " Max interrupters: %u\n", (unsigned int) HCS_MAX_INTRS(temp)); xhci_dbg(xhci, " Max ports: %u\n", (unsigned int) HCS_MAX_PORTS(temp)); temp = readl(&xhci->cap_regs->hcs_params2); xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n", (unsigned int) temp); xhci_dbg(xhci, " Isoc scheduling threshold: %u\n", (unsigned int) HCS_IST(temp)); xhci_dbg(xhci, " Maximum allowed segments in event ring: %u\n", (unsigned int) HCS_ERST_MAX(temp)); temp = readl(&xhci->cap_regs->hcs_params3); xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " Worst case U1 device exit latency: %u\n", (unsigned int) HCS_U1_LATENCY(temp)); xhci_dbg(xhci, " Worst case U2 device exit latency: %u\n", (unsigned int) HCS_U2_LATENCY(temp)); temp = readl(&xhci->cap_regs->hcc_params); xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " HC generates %s bit addresses\n", HCC_64BIT_ADDR(temp) ? "64" : "32"); xhci_dbg(xhci, " HC %s Contiguous Frame ID Capability\n", HCC_CFC(temp) ? "has" : "hasn't"); xhci_dbg(xhci, " HC %s generate Stopped - Short Package event\n", HCC_SPC(temp) ? "can" : "can't"); /* FIXME */ xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n"); temp = readl(&xhci->cap_regs->run_regs_off); xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK); /* xhci 1.1 controllers have the HCCPARAMS2 register */ if (hci_version > 0x100) { temp = readl(&xhci->cap_regs->hcc_params2); xhci_dbg(xhci, "HCC PARAMS2 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " HC %s Force save context capability", HCC2_FSC(temp) ? "supports" : "doesn't support"); xhci_dbg(xhci, " HC %s Large ESIT Payload Capability", HCC2_LEC(temp) ? "supports" : "doesn't support"); xhci_dbg(xhci, " HC %s Extended TBC capability", HCC2_ETC(temp) ? "supports" : "doesn't support"); } }
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, max_portpmsc; unsigned long flags; u32 temp, status; int retval = 0; __le32 __iomem **port_array; __le32 __iomem **portpmsc_array; int slot_id; struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; u8 selector; max_ports = xhci_get_ports(hcd, &port_array); max_portpmsc = xhci_get_portpmsc(hcd, &portpmsc_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; 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]); 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 ((temp & PORT_CEC)) status |= USB_PORT_STAT_C_CONFIG_ERROR << 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); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); xhci_dbg(xhci, "set port %d resume\n", wIndex + 1); 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); 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(xhci, &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: selector = wIndex >> 8; if (wValue == USB_PORT_FEAT_LINK_STATE) link_state = (wIndex & 0xff00) >> 3; if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK) wake_mask = wIndex & 0xff00; wIndex &= 0xff; if (!wIndex || wIndex > max_ports) goto error; 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: /* * 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); break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); 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); break; /* * For downstream facing ports (these): one hub port is put * into test mode according to USB2 11.24.2.13, then the hub * must be reset (which for root hub now means rmmod+modprobe, * or else system reboot). See EHCI 2.3.9 and 4.14 for info * about the EHCI-specific stuff. */ case USB_PORT_FEAT_TEST: #ifdef CONFIG_HOST_COMPLIANT_TEST retval = xhci_port_test(hcd, selector, wIndex, flags); if (retval < 0) { xhci_err(xhci, "USB2 Host Test Fail!!!\n"); goto error; } #endif 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; 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: case USB_PORT_FEAT_C_PORT_CONFIG_ERROR: 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; default: goto error; } break; default: error: /* "stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&xhci->lock, flags); return retval; }
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 ports; unsigned long flags; u32 temp, temp1, status; int retval = 0; u32 __iomem **port_array; int slot_id; struct xhci_bus_state *bus_state; if (hcd->speed == HCD_USB3) { ports = xhci->num_usb3_ports; port_array = xhci->usb3_ports; } else { ports = xhci->num_usb2_ports; port_array = xhci->usb2_ports; } 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 GetPortStatus: if (!wIndex || wIndex > 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); /* FIXME - should we return a port status value like the USB * 3.0 external hubs do? */ /* 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; /* * FIXME ignoring reset and USB 2.1/3.0 specific * changes */ if ((temp & PORT_PLS_MASK) == XDEV_U3 && (temp & PORT_POWER)) status |= 1 << USB_PORT_FEAT_SUSPEND; if ((temp & PORT_PLS_MASK) == XDEV_RESUME) { if ((temp & PORT_RESET) || !(temp & PORT_PE)) goto error; if (!DEV_SUPERSPEED(temp) && 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; temp1 = xhci_port_state_to_neutral(temp); temp1 &= ~PORT_PLS_MASK; temp1 |= PORT_LINK_STROBE | XDEV_U0; xhci_writel(xhci, temp1, port_array[wIndex]); xhci_dbg(xhci, "set port %d resume\n", wIndex + 1); 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); bus_state->port_c_suspend |= 1 << wIndex; bus_state->suspended_ports &= ~(1 << wIndex); } } if ((temp & PORT_PLS_MASK) == XDEV_U0 && (temp & PORT_POWER) && (bus_state->suspended_ports & (1 << wIndex))) { bus_state->suspended_ports &= ~(1 << wIndex); 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) status |= USB_PORT_STAT_POWER; 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: wIndex &= 0xff; if (!wIndex || wIndex > ports) goto error; 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]); /* 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. */ 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); temp = xhci_port_state_to_neutral(temp); temp &= ~PORT_PLS_MASK; temp |= PORT_LINK_STROBE | XDEV_U3; xhci_writel(xhci, temp, port_array[wIndex]); 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_POWER: /* * 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); break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); 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); break; default: goto error; } /* unblock any posted writes */ temp = xhci_readl(xhci, port_array[wIndex]); break; case ClearPortFeature: if (!wIndex || wIndex > 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 & XDEV_U3) { if ((temp & PORT_PE) == 0) goto error; if (DEV_SUPERSPEED(temp)) { temp = xhci_port_state_to_neutral(temp); temp &= ~PORT_PLS_MASK; temp |= PORT_LINK_STROBE | XDEV_U0; xhci_writel(xhci, temp, port_array[wIndex]); xhci_readl(xhci, port_array[wIndex]); } else { temp = xhci_port_state_to_neutral(temp); temp &= ~PORT_PLS_MASK; temp |= PORT_LINK_STROBE | XDEV_RESUME; xhci_writel(xhci, temp, port_array[wIndex]); spin_unlock_irqrestore(&xhci->lock, flags); msleep(20); spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, port_array[wIndex]); temp = xhci_port_state_to_neutral(temp); temp &= ~PORT_PLS_MASK; temp |= PORT_LINK_STROBE | XDEV_U0; xhci_writel(xhci, temp, port_array[wIndex]); } 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_CONNECTION: case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_ENABLE: 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; default: goto error; } break; default: error: /* "stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&xhci->lock, flags); return retval; }
int xhci_bus_resume(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports, port_index; u32 __iomem **port_array; struct xhci_bus_state *bus_state; u32 temp; unsigned long flags; if (hcd->speed == HCD_USB3) { max_ports = xhci->num_usb3_ports; port_array = xhci->usb3_ports; xhci_dbg(xhci, "resume USB 3.0 root hub\n"); } else { max_ports = xhci->num_usb2_ports; port_array = xhci->usb2_ports; xhci_dbg(xhci, "resume USB 2.0 root hub\n"); } bus_state = &xhci->bus_state[hcd_index(hcd)]; if (time_before(jiffies, bus_state->next_statechange)) msleep(5); spin_lock_irqsave(&xhci->lock, flags); if (!HCD_HW_ACCESSIBLE(hcd)) { spin_unlock_irqrestore(&xhci->lock, flags); return -ESHUTDOWN; } /* delay the irqs */ temp = xhci_readl(xhci, &xhci->op_regs->command); temp &= ~CMD_EIE; xhci_writel(xhci, temp, &xhci->op_regs->command); port_index = max_ports; while (port_index--) { /* Check whether need resume ports. If needed resume port and disable remote wakeup */ u32 temp; int slot_id; temp = xhci_readl(xhci, port_array[port_index]); if (DEV_SUPERSPEED(temp)) temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); else temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); if (test_bit(port_index, &bus_state->bus_suspended) && (temp & PORT_PLS_MASK)) { if (DEV_SUPERSPEED(temp)) { temp = xhci_port_state_to_neutral(temp); temp &= ~PORT_PLS_MASK; temp |= PORT_LINK_STROBE | XDEV_U0; xhci_writel(xhci, temp, port_array[port_index]); } else { temp = xhci_port_state_to_neutral(temp); temp &= ~PORT_PLS_MASK; temp |= PORT_LINK_STROBE | XDEV_RESUME; xhci_writel(xhci, temp, port_array[port_index]); spin_unlock_irqrestore(&xhci->lock, flags); msleep(20); spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, port_array[port_index]); temp = xhci_port_state_to_neutral(temp); temp &= ~PORT_PLS_MASK; temp |= PORT_LINK_STROBE | XDEV_U0; xhci_writel(xhci, temp, port_array[port_index]); } slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); if (slot_id) xhci_ring_device(xhci, slot_id); } else xhci_writel(xhci, temp, port_array[port_index]); if (DEV_HIGHSPEED(temp)) { /* disable remote wake up for USB 2.0 */ u32 __iomem *addr; u32 tmp; /* Add one to the port status register address to get * the port power control register address. */ addr = port_array[port_index] + 1; tmp = xhci_readl(xhci, addr); tmp &= ~PORT_RWE; xhci_writel(xhci, tmp, addr); } } (void) xhci_readl(xhci, &xhci->op_regs->command); bus_state->next_statechange = jiffies + msecs_to_jiffies(5); /* re-enable irqs */ temp = xhci_readl(xhci, &xhci->op_regs->command); temp |= CMD_EIE; xhci_writel(xhci, temp, &xhci->op_regs->command); temp = xhci_readl(xhci, &xhci->op_regs->command); spin_unlock_irqrestore(&xhci->lock, flags); return 0; }
void xhci_dbg_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep) { int i, j; int last_ep_ctx = 31; /* Fields are 32 bits wide, DMA addresses are in bytes */ int field_size = 32 / 8; int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); if (last_ep < 31) last_ep_ctx = last_ep + 1; for (i = 0; i < last_ep_ctx; ++i) { struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i); dma_addr_t dma = ctx->dma + ((unsigned long)ep_ctx - (unsigned long)ctx->bytes); xhci_dbg(xhci, "Endpoint %02d Context:\n", i); #if 0 /* original code */ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", &ep_ctx->ep_info, (unsigned long long)dma, ep_ctx->ep_info); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n", &ep_ctx->ep_info2, (unsigned long long)dma, ep_ctx->ep_info2); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", &ep_ctx->deq, (unsigned long long)dma, ep_ctx->deq); dma += 2*field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", &ep_ctx->tx_info, (unsigned long long)dma, ep_ctx->tx_info); dma += field_size; for (j = 0; j < 3; ++j) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", &ep_ctx->reserved[j], (unsigned long long)dma, ep_ctx->reserved[j], j); dma += field_size; } #else /* 2010/6/28, modified by Panasonic for little-endian access to the data structures in host memory */ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", &ep_ctx->ep_info, (unsigned long long)dma, xhci_desc_readl(xhci, &ep_ctx->ep_info)); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n", &ep_ctx->ep_info2, (unsigned long long)dma, xhci_desc_readl(xhci, &ep_ctx->ep_info2)); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", &ep_ctx->deq, (unsigned long long)dma, xhci_desc_read_64(xhci, &ep_ctx->deq)); dma += 2*field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", &ep_ctx->tx_info, (unsigned long long)dma, xhci_desc_readl(xhci, &ep_ctx->tx_info)); dma += field_size; for (j = 0; j < 3; ++j) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", &ep_ctx->reserved[j], (unsigned long long)dma, xhci_desc_readl(xhci, &ep_ctx->reserved[j]), j); dma += field_size; } #endif if (csz) dbg_rsvd64(xhci, (u64 *)ep_ctx, dma); } }
void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx) { /* Fields are 32 bits wide, DMA addresses are in bytes */ int field_size = 32 / 8; int i; struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx); dma_addr_t dma = ctx->dma + ((unsigned long)slot_ctx - (unsigned long)ctx->bytes); int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); xhci_dbg(xhci, "Slot Context:\n"); #if 0 /* original code */ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n", &slot_ctx->dev_info, (unsigned long long)dma, slot_ctx->dev_info); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n", &slot_ctx->dev_info2, (unsigned long long)dma, slot_ctx->dev_info2); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n", &slot_ctx->tt_info, (unsigned long long)dma, slot_ctx->tt_info); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n", &slot_ctx->dev_state, (unsigned long long)dma, slot_ctx->dev_state); dma += field_size; for (i = 0; i < 4; ++i) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", &slot_ctx->reserved[i], (unsigned long long)dma, slot_ctx->reserved[i], i); dma += field_size; } #else /* 2010/6/28, modified by Panasonic for little-endian access to the data structures in host memory */ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n", &slot_ctx->dev_info, (unsigned long long)dma, xhci_desc_readl(xhci, &slot_ctx->dev_info)); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n", &slot_ctx->dev_info2, (unsigned long long)dma, xhci_desc_readl(xhci, &slot_ctx->dev_info2)); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n", &slot_ctx->tt_info, (unsigned long long)dma, xhci_desc_readl(xhci, &slot_ctx->tt_info)); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n", &slot_ctx->dev_state, (unsigned long long)dma, xhci_desc_readl(xhci, &slot_ctx->dev_state)); dma += field_size; for (i = 0; i < 4; ++i) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", &slot_ctx->reserved[i], (unsigned long long)dma, xhci_desc_readl(xhci, &slot_ctx->reserved[i]), i); dma += field_size; } #endif if (csz) dbg_rsvd64(xhci, (u64 *)slot_ctx, dma); }
/** * Debug a transfer request block (TRB). */ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb) { u64 address; #if 0 /* original code */ u32 type = xhci_readl(xhci, &trb->link.control) & TRB_TYPE_BITMASK; #else /* 2010/6/28,2010/7/16 modified by Panasonic for little-endian access to the data structures in host memory */ u32 type = xhci_desc_readl(xhci, &trb->link.control) & TRB_TYPE_BITMASK; #endif switch (type) { case TRB_TYPE(TRB_LINK): xhci_dbg(xhci, "Link TRB:\n"); xhci_print_trb_offsets(xhci, trb); #if 0 /* original code */ address = trb->link.segment_ptr; xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address); xhci_dbg(xhci, "Interrupter target = 0x%x\n", GET_INTR_TARGET(trb->link.intr_target)); xhci_dbg(xhci, "Cycle bit = %u\n", (unsigned int) (trb->link.control & TRB_CYCLE)); xhci_dbg(xhci, "Toggle cycle bit = %u\n", (unsigned int) (trb->link.control & LINK_TOGGLE)); xhci_dbg(xhci, "No Snoop bit = %u\n", (unsigned int) (trb->link.control & TRB_NO_SNOOP)); #else /* 2010/6/28,2010/7/16 modified by Panasonic for little-endian access to the data structures in host memory */ address = xhci_desc_read_64(xhci, &trb->link.segment_ptr); xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address); xhci_dbg(xhci, "Interrupter target = 0x%x\n", GET_INTR_TARGET(xhci_desc_readl(xhci, &trb->link.intr_target))); xhci_dbg(xhci, "Cycle bit = %u\n", (unsigned int) (xhci_desc_readl(xhci, &trb->link.control) & TRB_CYCLE)); xhci_dbg(xhci, "Toggle cycle bit = %u\n", (unsigned int) (xhci_desc_readl(xhci, &trb->link.control) & LINK_TOGGLE)); xhci_dbg(xhci, "No Snoop bit = %u\n", (unsigned int) (xhci_desc_readl(xhci, &trb->link.control) & TRB_NO_SNOOP)); #endif break; case TRB_TYPE(TRB_TRANSFER): #if 0 /* original code */ address = trb->trans_event.buffer; #else /* 2010/6/28,2010/7/16 modified by Panasonic for little-endian access to the data structures in host memory */ address = xhci_desc_read_64(xhci, &trb->trans_event.buffer); #endif /* * FIXME: look at flags to figure out if it's an address or if * the data is directly in the buffer field. */ xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address); break; case TRB_TYPE(TRB_COMPLETION): #if 0 /* original code */ address = trb->event_cmd.cmd_trb; xhci_dbg(xhci, "Command TRB pointer = %llu\n", address); xhci_dbg(xhci, "Completion status = %u\n", (unsigned int) GET_COMP_CODE(trb->event_cmd.status)); xhci_dbg(xhci, "Flags = 0x%x\n", (unsigned int) trb->event_cmd.flags); #else /* 2010/6/28,2010/7/16 modified by Panasonic for little-endian access to the data structures in host memory */ address = xhci_desc_read_64(xhci, &trb->event_cmd.cmd_trb); xhci_dbg(xhci, "Command TRB pointer = %llu\n", address); xhci_dbg(xhci, "Completion status = %u\n", (unsigned int) GET_COMP_CODE(xhci_desc_readl(xhci, &trb->event_cmd.status))); xhci_dbg(xhci, "Flags = 0x%x\n", (unsigned int) xhci_desc_readl(xhci, &trb->event_cmd.flags)); #endif break; default: xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n", (unsigned int) type>>10); xhci_print_trb_offsets(xhci, trb); break; } }
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 ports; unsigned long flags; u32 temp, status; int retval = 0; u32 __iomem *addr; ports = HCS_MAX_PORTS(xhci->hcs_params1); 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: xhci_hub_descriptor(xhci, (struct usb_hub_descriptor *) buf); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; status = 0; addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); temp = xhci_readl(xhci, addr); 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_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) status |= USB_PORT_STAT_POWER; xhci_dbg(xhci, "Get port status returned 0x%x\n", status); put_unaligned(cpu_to_le32(status), (__le32 *) buf); break; case SetPortFeature: wIndex &= 0xff; if (!wIndex || wIndex > ports) goto error; wIndex--; addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); temp = xhci_readl(xhci, addr); temp = xhci_port_state_to_neutral(temp); switch (wValue) { case USB_PORT_FEAT_POWER: printk(KERN_INFO "[xhci-hub] usb2mode:[%d]\n", usb2mode); /* * 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. */ if(usb2mode==1) { printk(KERN_INFO "[xhci] USB3 port power off\n"); xhci_writel(xhci, (temp | PORT_PE), addr); xhci_writel(xhci, (temp & ~(PORT_POWER)), addr); xhci_writel(xhci, ((temp & ~PORT_PLS_MASK) | PORT_WR | PORT_PLC | XDEV_U0 | PORT_RESET | PORT_LINK_STROBE), addr); } else if(usb2mode==2) { printk(KERN_INFO "[xhci] USB3 port power off\n"); xhci_writel(xhci, (temp | PORT_PE), addr); xhci_writel(xhci, (temp | PORT_POWER), addr); xhci_writel(xhci, ((temp & ~PORT_PLS_MASK) | PORT_WR | PORT_PLC | XDEV_U0 | PORT_RESET | PORT_LINK_STROBE), addr); } else { xhci_writel(xhci, temp | PORT_POWER, addr); } temp = xhci_readl(xhci, addr); xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); xhci_writel(xhci, temp, addr); temp = xhci_readl(xhci, addr); xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); break; default: goto error; } temp = xhci_readl(xhci, addr); /* unblock any posted writes */ break; case ClearPortFeature: if (!wIndex || wIndex > ports) goto error; wIndex--; addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); temp = xhci_readl(xhci, addr); temp = xhci_port_state_to_neutral(temp); switch (wValue) { case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_ENABLE: xhci_clear_port_change_bit(xhci, wValue, wIndex, addr, temp); break; case USB_PORT_FEAT_ENABLE: xhci_disable_port(xhci, wIndex, addr, temp); break; default: goto error; } break; default: error: /* "stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&xhci->lock, flags); return retval; }
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) { unsigned long flags; int timeleft; struct xhci_virt_device *virt_dev; int ret = 0; struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_slot_ctx *slot_ctx; struct xhci_input_control_ctx *ctrl_ctx; u64 temp_64; if (!udev->slot_id) { xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id); return -EINVAL; } virt_dev = xhci->devs[udev->slot_id]; if (!udev->config) xhci_setup_addressable_virt_dev(xhci, udev); xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); spin_lock_irqsave(&xhci->lock, flags); ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, udev->slot_id); if (ret) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); return ret; } xhci_ring_cmd_db(xhci); spin_unlock_irqrestore(&xhci->lock, flags); timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, USB_CTRL_SET_TIMEOUT); if (timeleft <= 0) { xhci_warn(xhci, "%s while waiting for a slot\n", timeleft == 0 ? "Timeout" : "Signal"); return -ETIME; } switch (virt_dev->cmd_status) { case COMP_CTX_STATE: case COMP_EBADSLT: xhci_err(xhci, "Setup ERROR: address device command for slot %d.\n", udev->slot_id); ret = -EINVAL; break; case COMP_TX_ERR: dev_warn(&udev->dev, "Device not responding to set address.\n"); ret = -EPROTO; break; case COMP_SUCCESS: xhci_dbg(xhci, "Successful Address Device command\n"); break; default: xhci_err(xhci, "ERROR: unexpected command completion " "code 0x%x.\n", virt_dev->cmd_status); xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); ret = -EINVAL; break; } if (ret) { return ret; } temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64); xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n", udev->slot_id, &xhci->dcbaa->dev_context_ptrs[udev->slot_id], (unsigned long long) xhci->dcbaa->dev_context_ptrs[udev->slot_id]); xhci_dbg(xhci, "Output Context DMA address = %#08llx\n", (unsigned long long)virt_dev->out_ctx->dma); xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); udev->devnum = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1; 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); set_bit(udev->devnum, udev->bus->devmap.devicemap); return 0; }
int xhci_bus_suspend(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports, port_index; __le32 __iomem **port_array; struct xhci_bus_state *bus_state; unsigned long flags; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; spin_lock_irqsave(&xhci->lock, flags); if (hcd->self.root_hub->do_remote_wakeup) { if (bus_state->resuming_ports) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "suspend failed because " "a port is resuming\n"); return -EBUSY; } } port_index = max_ports; bus_state->bus_suspended = 0; while (port_index--) { /* suspend the port if the port is not suspended */ u32 t1, t2; int slot_id; t1 = xhci_readl(xhci, port_array[port_index]); t2 = xhci_port_state_to_neutral(t1); if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { xhci_dbg(xhci, "port %d not suspended\n", port_index); slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); if (slot_id) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_stop_device(xhci, slot_id, 1); spin_lock_irqsave(&xhci->lock, flags); } t2 &= ~PORT_PLS_MASK; t2 |= PORT_LINK_STROBE | XDEV_U3; set_bit(port_index, &bus_state->bus_suspended); } /* USB core sets remote wake mask for USB 3.0 hubs, * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME * is enabled, so also enable remote wake here. */ if (hcd->self.root_hub->do_remote_wakeup) { if (t1 & PORT_CONNECT) { t2 |= PORT_WKOC_E | PORT_WKDISC_E; t2 &= ~PORT_WKCONN_E; } else { t2 |= PORT_WKOC_E | PORT_WKCONN_E; t2 &= ~PORT_WKDISC_E; } } else t2 &= ~PORT_WAKE_BITS; t1 = xhci_port_state_to_neutral(t1); if (t1 != t2) xhci_writel(xhci, t2, port_array[port_index]); } hcd->state = HC_STATE_SUSPENDED; bus_state->next_statechange = jiffies + msecs_to_jiffies(10); spin_unlock_irqrestore(&xhci->lock, flags); return 0; }
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_virt_device *vdev; struct xhci_command *config_cmd; struct xhci_input_control_ctx *ctrl_ctx; struct xhci_slot_ctx *slot_ctx; unsigned long flags; unsigned think_time; int ret; if (!hdev->parent) return 0; vdev = xhci->devs[hdev->slot_id]; if (!vdev) { xhci_warn(xhci, "Cannot update hub desc for unknown device.\n"); return -EINVAL; } config_cmd = xhci_alloc_command(xhci, true, mem_flags); if (!config_cmd) { xhci_dbg(xhci, "Could not allocate xHCI command structure.\n"); return -ENOMEM; } spin_lock_irqsave(&xhci->lock, flags); xhci_slot_copy(xhci, config_cmd->in_ctx, vdev->out_ctx); ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx); ctrl_ctx->add_flags |= SLOT_FLAG; slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx); slot_ctx->dev_info |= DEV_HUB; if (tt->multi) slot_ctx->dev_info |= DEV_MTT; if (xhci->hci_version > 0x95) { xhci_dbg(xhci, "xHCI version %x needs hub " "TT think time and number of ports\n", (unsigned int) xhci->hci_version); slot_ctx->dev_info2 |= XHCI_MAX_PORTS(hdev->maxchild); think_time = tt->think_time; if (think_time != 0) think_time = (think_time / 666) - 1; slot_ctx->tt_info |= TT_THINK_TIME(think_time); } else { xhci_dbg(xhci, "xHCI version %x doesn't need hub " "TT think time or number of ports\n", (unsigned int) xhci->hci_version); } slot_ctx->dev_state = 0; spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "Set up %s for hub device.\n", (xhci->hci_version > 0x95) ? "configure endpoint" : "evaluate context"); xhci_dbg(xhci, "Slot %u Input Context:\n", hdev->slot_id); xhci_dbg_ctx(xhci, config_cmd->in_ctx, 0); if (xhci->hci_version > 0x95) ret = xhci_configure_endpoint(xhci, hdev, config_cmd, false, false); else ret = xhci_configure_endpoint(xhci, hdev, config_cmd, true, false); xhci_dbg(xhci, "Slot %u Output Context:\n", hdev->slot_id); xhci_dbg_ctx(xhci, vdev->out_ctx, 0); xhci_free_command(xhci, config_cmd); return ret; }
static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(dev); /* Look for vendor-specific quirks */ if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK || pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1400)) { if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && pdev->revision == 0x0) { xhci->quirks |= XHCI_RESET_EP_QUIRK; xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" " endpoint cmd after reset endpoint\n"); } if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && pdev->revision == 0x4) { xhci->quirks |= XHCI_SLOW_SUSPEND; xhci_dbg(xhci, "QUIRK: Fresco Logic xHC revision %u" "must be suspended extra slowly", pdev->revision); } /* Fresco Logic confirms: all revisions of this chip do not * support MSI, even though some of them claim to in their PCI * capabilities. */ xhci->quirks |= XHCI_BROKEN_MSI; xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " "has broken MSI implementation\n", pdev->revision); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_NEC) xhci->quirks |= XHCI_NEC_HOST; if (pdev->vendor == PCI_VENDOR_ID_AMD && xhci->hci_version == 0x96) xhci->quirks |= XHCI_AMD_0x96_HOST; /* AMD PLL quirk */ if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) xhci->quirks |= XHCI_AMD_PLL_FIX; if (pdev->vendor == PCI_VENDOR_ID_AMD) xhci->quirks |= XHCI_TRUST_TX_LENGTH; if (pdev->vendor == PCI_VENDOR_ID_INTEL) xhci->quirks |= XHCI_AVOID_BEI; if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { xhci->quirks |= XHCI_EP_LIMIT_QUIRK; xhci->limit_active_eps = 64; xhci->quirks |= XHCI_SW_BW_CHECKING; /* * PPT desktop boards DH77EB and DH77DF will power back on after * a few seconds of being shutdown. The fix for this is to * switch the ports from xHCI to EHCI on shutdown. We can't use * DMI information to find those particular boards (since each * vendor will change the board name), so we have to key off all * PPT chipsets. */ xhci->quirks |= XHCI_SPURIOUS_REBOOT; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI)) { /* Workaround for occasional spurious wakeups from S5 (or * any other sleep) on Haswell machines with LPT and LPT-LP * with the new Intel BIOS */ /* Limit the quirk to only known vendors, as this triggers * yet another BIOS bug on some other machines * https://bugzilla.kernel.org/show_bug.cgi?id=66171 */ if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP) xhci->quirks |= XHCI_SPURIOUS_WAKEUP; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) { xhci->quirks |= XHCI_PME_STUCK_QUIRK; } if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_ASROCK_P67) { xhci->quirks |= XHCI_RESET_ON_RESUME; xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_RENESAS && pdev->device == 0x0015) xhci->quirks |= XHCI_RESET_ON_RESUME; if (pdev->vendor == PCI_VENDOR_ID_VIA) xhci->quirks |= XHCI_RESET_ON_RESUME; }
void xhci_event_ring_work(unsigned long arg) { unsigned long flags; int temp; u64 temp_64; struct xhci_hcd *xhci = (struct xhci_hcd *) arg; int i, j; xhci_dbg(xhci, "Poll event ring: %lu\n", jiffies); spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, &xhci->op_regs->status); xhci_dbg(xhci, "op reg status = 0x%x\n", temp); if (temp == 0xffffffff) { xhci_dbg(xhci, "HW died, polling stopped.\n"); spin_unlock_irqrestore(&xhci->lock, flags); return; } temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp); xhci_dbg(xhci, "No-op commands handled = %d\n", xhci->noops_handled); xhci_dbg(xhci, "HC error bitmask = 0x%x\n", xhci->error_bitmask); xhci->error_bitmask = 0; xhci_dbg(xhci, "Event ring:\n"); xhci_debug_segment(xhci, xhci->event_ring->deq_seg); 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, "Command ring:\n"); xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg); xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); xhci_dbg_cmd_ptrs(xhci); for (i = 0; i < MAX_HC_SLOTS; ++i) { if (!xhci->devs[i]) continue; for (j = 0; j < 31; ++j) { struct xhci_ring *ring = xhci->devs[i]->eps[j].ring; if (!ring) continue; xhci_dbg(xhci, "Dev %d endpoint ring %d:\n", i, j); xhci_debug_segment(xhci, ring->deq_seg); } } if (xhci->noops_submitted != NUM_TEST_NOOPS) if (xhci_setup_one_noop(xhci)) xhci_ring_cmd_db(xhci); spin_unlock_irqrestore(&xhci->lock, flags); if (!xhci->zombie) mod_timer(&xhci->event_ring_timer, jiffies + POLL_TIMEOUT * HZ); else xhci_dbg(xhci, "Quit polling the event ring.\n"); }
/* called during probe() after chip reset completes */ static int xhci_pci_setup(struct usb_hcd *hcd) { struct xhci_hcd *xhci; struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int retval; u32 temp; hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; if (usb_hcd_is_primary_hcd(hcd)) { xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL); if (!xhci) return -ENOMEM; *((struct xhci_hcd **) hcd->hcd_priv) = xhci; xhci->main_hcd = hcd; /* Mark the first roothub as being USB 2.0. * The xHCI driver will register the USB 3.0 roothub. */ hcd->speed = HCD_USB2; hcd->self.root_hub->speed = USB_SPEED_HIGH; /* * USB 2.0 roothub under xHCI has an integrated TT, * (rate matching hub) as opposed to having an OHCI/UHCI * companion controller. */ hcd->has_tt = 1; } else { /* xHCI private pointer was set in xhci_pci_probe for the second * registered roothub. */ xhci = hcd_to_xhci(hcd); temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); if (HCC_64BIT_ADDR(temp)) { xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); } else { dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); } return 0; } xhci->cap_regs = hcd->regs; xhci->op_regs = hcd->regs + HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); xhci->run_regs = hcd->regs + (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK); /* Cache read-only capability registers */ xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); xhci->hci_version = HC_VERSION(xhci->hcc_params); xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); xhci_print_registers(xhci); /* Look for vendor-specific quirks */ if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK || pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1400)) { if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && pdev->revision == 0x0) { xhci->quirks |= XHCI_RESET_EP_QUIRK; xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" " endpoint cmd after reset endpoint\n"); } /* Fresco Logic confirms: all revisions of this chip do not * support MSI, even though some of them claim to in their PCI * capabilities. */ xhci->quirks |= XHCI_BROKEN_MSI; xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " "has broken MSI implementation\n", pdev->revision); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_NEC) xhci->quirks |= XHCI_NEC_HOST; if (pdev->vendor == PCI_VENDOR_ID_AMD && xhci->hci_version == 0x96) xhci->quirks |= XHCI_AMD_0x96_HOST; /* AMD PLL quirk */ if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) xhci->quirks |= XHCI_AMD_PLL_FIX; if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { xhci->quirks |= XHCI_SPURIOUS_SUCCESS; xhci->quirks |= XHCI_EP_LIMIT_QUIRK; xhci->limit_active_eps = 64; /* * PPT desktop boards DH77EB and DH77DF will power back on after * a few seconds of being shutdown. The fix for this is to * switch the ports from xHCI to EHCI on shutdown. We can't use * DMI information to find those particular boards (since each * vendor will change the board name), so we have to key off all * PPT chipsets. */ xhci->quirks |= XHCI_SPURIOUS_REBOOT; } if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_ASROCK_P67) { xhci->quirks |= XHCI_RESET_ON_RESUME; xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_VIA) xhci->quirks |= XHCI_RESET_ON_RESUME; /* Make sure the HC is halted. */ retval = xhci_halt(xhci); if (retval) goto error; xhci_dbg(xhci, "Resetting HCD\n"); /* Reset the internal HC memory state and registers. */ retval = xhci_reset(xhci); if (retval) goto error; xhci_dbg(xhci, "Reset complete\n"); temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); if (HCC_64BIT_ADDR(temp)) { xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); } else { dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); } xhci_dbg(xhci, "Calling HCD init\n"); /* Initialize HCD and host controller data structures. */ retval = xhci_init(hcd); if (retval) goto error; xhci_dbg(xhci, "Called HCD init\n"); pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); /* Find any debug ports */ retval = xhci_pci_reinit(xhci, pdev); if (!retval) return retval; error: kfree(xhci); return retval; }
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; }
int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags) { struct xhci_virt_device *dev; int i; /* Slot ID 0 is reserved */ if (slot_id == 0 || xhci->devs[slot_id]) { xhci_warn(xhci, "Bad Slot ID %d\n", slot_id); return 0; } xhci->devs[slot_id] = kzalloc(sizeof(*xhci->devs[slot_id]), flags); if (!xhci->devs[slot_id]) return 0; dev = xhci->devs[slot_id]; /* Allocate the (output) device context that will be used in the HC. */ dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags); if (!dev->out_ctx) goto fail; xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, (unsigned long long)dev->out_ctx->dma); /* Allocate the (input) device context for address device command */ dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags); if (!dev->in_ctx) goto fail; xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, (unsigned long long)dev->in_ctx->dma); /* Initialize the cancellation list and watchdog timers for each ep */ for (i = 0; i < 31; i++) { xhci_init_endpoint_timer(xhci, &dev->eps[i]); INIT_LIST_HEAD(&dev->eps[i].cancelled_td_list); } /* Allocate endpoint 0 ring */ dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, flags); if (!dev->eps[0].ring) goto fail; /* Allocate pointers to the ring cache */ dev->ring_cache = kzalloc( sizeof(struct xhci_ring *)*XHCI_MAX_RINGS_CACHED, flags); if (!dev->ring_cache) goto fail; dev->num_rings_cached = 0; init_completion(&dev->cmd_completion); INIT_LIST_HEAD(&dev->cmd_list); /* Point to output device context in dcbaa. */ xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma; xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", slot_id, &xhci->dcbaa->dev_context_ptrs[slot_id], (unsigned long long) xhci->dcbaa->dev_context_ptrs[slot_id]); return 1; fail: xhci_free_virt_device(xhci, slot_id); return 0; }
int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep) { struct xhci_hcd *xhci; struct xhci_container_ctx *in_ctx, *out_ctx; struct xhci_input_control_ctx *ctrl_ctx; struct xhci_slot_ctx *slot_ctx; unsigned int last_ctx; unsigned int ep_index; struct xhci_ep_ctx *ep_ctx; u32 drop_flag; u32 new_add_flags, new_drop_flags, new_slot_info; int ret; ret = xhci_check_args(hcd, udev, ep, 1, __func__); if (ret <= 0) return ret; xhci = hcd_to_xhci(hcd); xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); drop_flag = xhci_get_endpoint_flag(&ep->desc); if (drop_flag == SLOT_FLAG || drop_flag == EP0_FLAG) { xhci_dbg(xhci, "xHCI %s - can't drop slot or ep 0 %#x\n", __func__, drop_flag); 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); ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED || ctrl_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) { xhci_warn(xhci, "xHCI %s called with disabled ep %p\n", __func__, ep); return 0; } ctrl_ctx->drop_flags |= drop_flag; new_drop_flags = ctrl_ctx->drop_flags; ctrl_ctx->add_flags &= ~drop_flag; new_add_flags = ctrl_ctx->add_flags; last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags); slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); if ((slot_ctx->dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) { slot_ctx->dev_info &= ~LAST_CTX_MASK; slot_ctx->dev_info |= LAST_CTX(last_ctx); } new_slot_info = slot_ctx->dev_info; xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep); xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", (unsigned int) ep->desc.bEndpointAddress, udev->slot_id, (unsigned int) new_drop_flags, (unsigned int) new_add_flags, (unsigned int) new_slot_info); return 0; }
static void xhci_print_op_regs(struct xhci_hcd *xhci) { xhci_dbg(xhci, "xHCI operational registers at %p:\n", xhci->op_regs); xhci_print_command_reg(xhci); xhci_print_status(xhci); }
int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep) { struct xhci_hcd *xhci; struct xhci_container_ctx *in_ctx, *out_ctx; unsigned int ep_index; struct xhci_ep_ctx *ep_ctx; struct xhci_slot_ctx *slot_ctx; struct xhci_input_control_ctx *ctrl_ctx; u32 added_ctxs; unsigned int last_ctx; u32 new_add_flags, new_drop_flags, new_slot_info; int ret = 0; ret = xhci_check_args(hcd, udev, ep, 1, __func__); if (ret <= 0) { ep->hcpriv = NULL; return ret; } xhci = hcd_to_xhci(hcd); added_ctxs = xhci_get_endpoint_flag(&ep->desc); last_ctx = xhci_last_valid_endpoint(added_ctxs); if (added_ctxs == SLOT_FLAG || added_ctxs == EP0_FLAG) { xhci_dbg(xhci, "xHCI %s - can't add slot or ep 0 %#x\n", __func__, added_ctxs); 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); ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); if (ctrl_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) { xhci_warn(xhci, "xHCI %s called with enabled ep %p\n", __func__, ep); return 0; } if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id], udev, ep, GFP_KERNEL) < 0) { dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n", __func__, ep->desc.bEndpointAddress); return -ENOMEM; } ctrl_ctx->add_flags |= added_ctxs; new_add_flags = ctrl_ctx->add_flags; new_drop_flags = ctrl_ctx->drop_flags; slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); if ((slot_ctx->dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) { slot_ctx->dev_info &= ~LAST_CTX_MASK; slot_ctx->dev_info |= LAST_CTX(last_ctx); } new_slot_info = slot_ctx->dev_info; ep->hcpriv = udev; xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", (unsigned int) ep->desc.bEndpointAddress, udev->slot_id, (unsigned int) new_drop_flags, (unsigned int) new_add_flags, (unsigned int) new_slot_info); return 0; }
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; 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; 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]); 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; xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); xhci_dbg(xhci, "set port %d resume\n", wIndex + 1); 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); 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; } /* Port Link State */ if (hcd->speed == HCD_USB3) { /* resume state is a xHCI internal state. * Do not report it to usb core. */ if ((temp & PORT_PLS_MASK) != XDEV_RESUME) status |= (temp & PORT_PLS_MASK); } 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; wIndex &= 0xff; if (!wIndex || wIndex > max_ports) goto error; 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]); /* Software should not attempt to set * port link state above '5' (Rx.Detect) and the port * must be enabled. */ if ((temp & PORT_PE) == 0 || (link_state > USB_SS_PORT_LS_RX_DETECT)) { 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: /* * 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]); if (xhci->quirks & XHCI_PORTSC_DELAY) ndelay(100); temp = xhci_readl(xhci, port_array[wIndex]); xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); xhci_writel(xhci, temp, port_array[wIndex]); if (xhci->quirks & XHCI_PORTSC_DELAY) ndelay(100); temp = xhci_readl(xhci, port_array[wIndex]); xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); 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]); if (xhci->quirks & XHCI_PORTSC_DELAY) ndelay(100); temp = xhci_readl(xhci, port_array[wIndex]); 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; default: goto error; } break; default: error: /* "stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&xhci->lock, flags); return retval; }
static void xhci_quiesce(struct xhci_hcd *xhci) { BUG_ON(!HC_IS_RUNNING(xhci_to_hcd(xhci)->state)); xhci_dbg(xhci, "Finished quiescing -- code not written yet\n"); }
/* Setup an xHCI virtual device for a Set Address command */ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev) { struct xhci_virt_device *dev; struct xhci_ep_ctx *ep0_ctx; struct usb_device *top_dev; struct xhci_slot_ctx *slot_ctx; struct xhci_input_control_ctx *ctrl_ctx; dev = xhci->devs[udev->slot_id]; /* Slot ID 0 is reserved */ if (udev->slot_id == 0 || !dev) { xhci_warn(xhci, "Slot ID %d is not assigned to this device\n", udev->slot_id); return -EINVAL; } ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0); ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx); slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx); /* 2) New slot context and endpoint 0 context are valid*/ ctrl_ctx->add_flags = SWAP32(SLOT_FLAG | EP0_FLAG); /* 3) Only the control endpoint is valid - one endpoint context */ slot_ctx->dev_info |= SWAP32(LAST_CTX(1)); slot_ctx->dev_info |= SWAP32((u32) udev->route); switch (udev->speed) { case USB_SPEED_SUPER: slot_ctx->dev_info |= SWAP32((u32) SLOT_SPEED_SS); break; case USB_SPEED_HIGH: slot_ctx->dev_info |= SWAP32((u32) SLOT_SPEED_HS); break; case USB_SPEED_FULL: slot_ctx->dev_info |= SWAP32((u32) SLOT_SPEED_FS); break; case USB_SPEED_LOW: slot_ctx->dev_info |= SWAP32((u32) SLOT_SPEED_LS); break; case USB_SPEED_VARIABLE: xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); return -EINVAL; break; default: /* Speed was set earlier, this shouldn't happen. */ BUG(); } /* Find the root hub port this device is under */ for (top_dev = udev; top_dev->parent && top_dev->parent->parent; top_dev = top_dev->parent) /* Found device below root hub */; slot_ctx->dev_info2 |= SWAP32((u32) ROOT_HUB_PORT(top_dev->portnum)); xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum); /* Is this a LS/FS device under a HS hub? */ if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) && udev->tt) { slot_ctx->tt_info = SWAP32(udev->tt->hub->slot_id); slot_ctx->tt_info |= SWAP32(udev->ttport << 8); if (udev->tt->multi) slot_ctx->dev_info |= SWAP32(DEV_MTT); } xhci_dbg(xhci, "udev->tt = %p\n", udev->tt); xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport); /* Step 4 - ring already allocated */ /* Step 5 */ ep0_ctx->ep_info2 = SWAP32(EP_TYPE(CTRL_EP)); /* * XXX: Not sure about wireless USB devices. */ switch (udev->speed) { case USB_SPEED_SUPER: ep0_ctx->ep_info2 |= SWAP32(MAX_PACKET(512)); break; case USB_SPEED_HIGH: /* USB core guesses at a 64-byte max packet first for FS devices */ case USB_SPEED_FULL: ep0_ctx->ep_info2 |= SWAP32(MAX_PACKET(64)); break; case USB_SPEED_LOW: ep0_ctx->ep_info2 |= SWAP32(MAX_PACKET(8)); break; case USB_SPEED_VARIABLE: xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); return -EINVAL; break; default: /* New speed? */ BUG(); } /* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */ ep0_ctx->ep_info2 |= SWAP32(MAX_BURST(0)); ep0_ctx->ep_info2 |= SWAP32(ERROR_COUNT(3)); ep0_ctx->deq = SWAP64(dev->eps[0].ring->first_seg->dma); ep0_ctx->deq |= SWAP64(dev->eps[0].ring->cycle_state); /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ return 0; }
/* called during probe() after chip reset completes */ static int ubi32_xhci_drv_setup(struct usb_hcd *hcd) { struct xhci_hcd *xhci; int retval; u32 temp; hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; if (usb_hcd_is_primary_hcd(hcd)) { xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL); if (!xhci) return -ENOMEM; *((struct xhci_hcd **) hcd->hcd_priv) = xhci; xhci->main_hcd = hcd; /* Mark the first roothub as being USB 2.0. * The xHCI driver will register the USB 3.0 roothub. */ hcd->speed = HCD_USB2; hcd->self.root_hub->speed = USB_SPEED_HIGH; /* * USB 2.0 roothub under xHCI has an integrated TT, * (rate matching hub) as opposed to having an OHCI/UHCI * companion controller. */ hcd->has_tt = 1; } else { /* xHCI private pointer was set in xhci_pci_probe for the second * registered roothub. */ xhci = hcd_to_xhci(hcd); temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); if (HCC_64BIT_ADDR(temp)) { xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); } else { dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); } return 0; } xhci->cap_regs = hcd->regs; xhci->op_regs = hcd->regs + HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); xhci->run_regs = hcd->regs + (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK); /* Cache read-only capability registers */ xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); xhci->hci_version = HC_VERSION(xhci->hcc_params); xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); xhci_print_registers(xhci); /* Make sure the HC is halted. */ retval = xhci_halt(xhci); if (retval) goto error; xhci_dbg(xhci, "Resetting HCD\n"); /* Reset the internal HC memory state and registers. */ retval = xhci_reset(xhci); if (retval) goto error; xhci_dbg(xhci, "Reset complete\n"); temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); if (HCC_64BIT_ADDR(temp)) { xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); } else { dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); } xhci_dbg(xhci, "Calling HCD init\n"); /* Initialize HCD and host controller data structures. */ retval = xhci_init(hcd); if (retval) goto error; xhci_dbg(xhci, "Called HCD init\n"); if (!retval) return retval; error: kfree(xhci); return retval; }