Loading drivers/usb/host/xhci-hub.c +119 −91 Original line number Diff line number Diff line Loading @@ -534,104 +534,51 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) } } int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) /* * Converts a raw xHCI port status into the format that external USB 2.0 or USB * 3.0 hubs use. * * Possible side effects: * - Mark a port as being done with device resume, * and ring the endpoint doorbells. * - Stop the Synopsys redriver Compliance Mode polling. */ static u32 xhci_get_port_status(struct usb_hcd *hcd, struct xhci_bus_state *bus_state, __le32 __iomem **port_array, u16 wIndex, u32 raw_port_status) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports; unsigned long flags; u32 temp, status; int retval = 0; __le32 __iomem **port_array; u32 status = 0; int slot_id; struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; u16 timeout = 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; /* Set the U1 and U2 exit latencies. */ memcpy(buf, &usb_bos_descriptor, USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); buf[12] = HCS_U1_LATENCY(temp); put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); /* Indicate whether the host has LTM support. */ temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); if (HCC_LTC(temp)) buf[8] |= USB_LTM_SUPPORT; spin_unlock_irqrestore(&xhci->lock, flags); return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; case GetPortStatus: if (!wIndex || wIndex > max_ports) goto error; wIndex--; status = 0; temp = xhci_readl(xhci, port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; } xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); /* wPortChange bits */ if (temp & PORT_CSC) if (raw_port_status & PORT_CSC) status |= USB_PORT_STAT_C_CONNECTION << 16; if (temp & PORT_PEC) if (raw_port_status & PORT_PEC) status |= USB_PORT_STAT_C_ENABLE << 16; if ((temp & PORT_OCC)) if ((raw_port_status & PORT_OCC)) status |= USB_PORT_STAT_C_OVERCURRENT << 16; if ((temp & PORT_RC)) if ((raw_port_status & PORT_RC)) status |= USB_PORT_STAT_C_RESET << 16; /* USB3.0 only */ if (hcd->speed == HCD_USB3) { if ((temp & PORT_PLC)) if ((raw_port_status & PORT_PLC)) status |= USB_PORT_STAT_C_LINK_STATE << 16; if ((temp & PORT_WRC)) if ((raw_port_status & 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)) if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3 && (raw_port_status & 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 ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME && !DEV_SUPERSPEED(raw_port_status)) { if ((raw_port_status & PORT_RESET) || !(raw_port_status & PORT_PE)) return 0xffffffff; if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) { xhci_dbg(xhci, "Resume USB2 port %d\n", Loading @@ -646,7 +593,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, wIndex + 1); if (!slot_id) { xhci_dbg(xhci, "slot_id is zero\n"); goto error; return 0xffffffff; } xhci_ring_device(xhci, slot_id); bus_state->port_c_suspend |= 1 << wIndex; Loading @@ -661,24 +608,24 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, status |= USB_PORT_STAT_SUSPEND; } } if ((temp & PORT_PLS_MASK) == XDEV_U0 && (temp & PORT_POWER) if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 && (raw_port_status & 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) { if (raw_port_status & PORT_CONNECT) { status |= USB_PORT_STAT_CONNECTION; status |= xhci_port_speed(temp); status |= xhci_port_speed(raw_port_status); } if (temp & PORT_PE) if (raw_port_status & PORT_PE) status |= USB_PORT_STAT_ENABLE; if (temp & PORT_OC) if (raw_port_status & PORT_OC) status |= USB_PORT_STAT_OVERCURRENT; if (temp & PORT_RESET) if (raw_port_status & PORT_RESET) status |= USB_PORT_STAT_RESET; if (temp & PORT_POWER) { if (raw_port_status & PORT_POWER) { if (hcd->speed == HCD_USB3) status |= USB_SS_PORT_STAT_POWER; else Loading @@ -686,16 +633,97 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } /* Update Port Link State for super speed ports*/ if (hcd->speed == HCD_USB3) { xhci_hub_report_link_state(&status, temp); xhci_hub_report_link_state(&status, raw_port_status); /* * Verify if all USB3 Ports Have entered U0 already. * Delete Compliance Mode Timer if so. */ xhci_del_comp_mod_timer(xhci, temp, wIndex); xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex); } if (bus_state->port_c_suspend & (1 << wIndex)) status |= 1 << USB_PORT_FEAT_C_SUSPEND; return status; } int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports; unsigned long flags; u32 temp, status; int retval = 0; __le32 __iomem **port_array; int slot_id; struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; u16 timeout = 0; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; spin_lock_irqsave(&xhci->lock, flags); switch (typeReq) { case GetHubStatus: /* No power source, over-current reported per port */ memset(buf, 0, 4); break; case GetHubDescriptor: /* Check to make sure userspace is asking for the USB 3.0 hub * descriptor for the USB 3.0 roothub. If not, we stall the * endpoint, like external hubs do. */ if (hcd->speed == HCD_USB3 && (wLength < USB_DT_SS_HUB_SIZE || wValue != (USB_DT_SS_HUB << 8))) { xhci_dbg(xhci, "Wrong hub descriptor type for " "USB 3.0 roothub.\n"); goto error; } xhci_hub_descriptor(hcd, xhci, (struct usb_hub_descriptor *) buf); break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: if ((wValue & 0xff00) != (USB_DT_BOS << 8)) goto error; if (hcd->speed != HCD_USB3) goto error; /* Set the U1 and U2 exit latencies. */ memcpy(buf, &usb_bos_descriptor, USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); buf[12] = HCS_U1_LATENCY(temp); put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); /* Indicate whether the host has LTM support. */ temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); if (HCC_LTC(temp)) buf[8] |= USB_LTM_SUPPORT; spin_unlock_irqrestore(&xhci->lock, flags); return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; case GetPortStatus: if (!wIndex || wIndex > max_ports) goto error; wIndex--; temp = xhci_readl(xhci, port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; } status = xhci_get_port_status(hcd, bus_state, port_array, wIndex, temp); if (status == 0xffffffff) goto error; xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); xhci_dbg(xhci, "Get port status returned 0x%x\n", status); put_unaligned(cpu_to_le32(status), (__le32 *) buf); break; case SetPortFeature: Loading Loading
drivers/usb/host/xhci-hub.c +119 −91 Original line number Diff line number Diff line Loading @@ -534,104 +534,51 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) } } int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) /* * Converts a raw xHCI port status into the format that external USB 2.0 or USB * 3.0 hubs use. * * Possible side effects: * - Mark a port as being done with device resume, * and ring the endpoint doorbells. * - Stop the Synopsys redriver Compliance Mode polling. */ static u32 xhci_get_port_status(struct usb_hcd *hcd, struct xhci_bus_state *bus_state, __le32 __iomem **port_array, u16 wIndex, u32 raw_port_status) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports; unsigned long flags; u32 temp, status; int retval = 0; __le32 __iomem **port_array; u32 status = 0; int slot_id; struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; u16 timeout = 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; /* Set the U1 and U2 exit latencies. */ memcpy(buf, &usb_bos_descriptor, USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); buf[12] = HCS_U1_LATENCY(temp); put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); /* Indicate whether the host has LTM support. */ temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); if (HCC_LTC(temp)) buf[8] |= USB_LTM_SUPPORT; spin_unlock_irqrestore(&xhci->lock, flags); return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; case GetPortStatus: if (!wIndex || wIndex > max_ports) goto error; wIndex--; status = 0; temp = xhci_readl(xhci, port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; } xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); /* wPortChange bits */ if (temp & PORT_CSC) if (raw_port_status & PORT_CSC) status |= USB_PORT_STAT_C_CONNECTION << 16; if (temp & PORT_PEC) if (raw_port_status & PORT_PEC) status |= USB_PORT_STAT_C_ENABLE << 16; if ((temp & PORT_OCC)) if ((raw_port_status & PORT_OCC)) status |= USB_PORT_STAT_C_OVERCURRENT << 16; if ((temp & PORT_RC)) if ((raw_port_status & PORT_RC)) status |= USB_PORT_STAT_C_RESET << 16; /* USB3.0 only */ if (hcd->speed == HCD_USB3) { if ((temp & PORT_PLC)) if ((raw_port_status & PORT_PLC)) status |= USB_PORT_STAT_C_LINK_STATE << 16; if ((temp & PORT_WRC)) if ((raw_port_status & 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)) if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3 && (raw_port_status & 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 ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME && !DEV_SUPERSPEED(raw_port_status)) { if ((raw_port_status & PORT_RESET) || !(raw_port_status & PORT_PE)) return 0xffffffff; if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) { xhci_dbg(xhci, "Resume USB2 port %d\n", Loading @@ -646,7 +593,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, wIndex + 1); if (!slot_id) { xhci_dbg(xhci, "slot_id is zero\n"); goto error; return 0xffffffff; } xhci_ring_device(xhci, slot_id); bus_state->port_c_suspend |= 1 << wIndex; Loading @@ -661,24 +608,24 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, status |= USB_PORT_STAT_SUSPEND; } } if ((temp & PORT_PLS_MASK) == XDEV_U0 && (temp & PORT_POWER) if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 && (raw_port_status & 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) { if (raw_port_status & PORT_CONNECT) { status |= USB_PORT_STAT_CONNECTION; status |= xhci_port_speed(temp); status |= xhci_port_speed(raw_port_status); } if (temp & PORT_PE) if (raw_port_status & PORT_PE) status |= USB_PORT_STAT_ENABLE; if (temp & PORT_OC) if (raw_port_status & PORT_OC) status |= USB_PORT_STAT_OVERCURRENT; if (temp & PORT_RESET) if (raw_port_status & PORT_RESET) status |= USB_PORT_STAT_RESET; if (temp & PORT_POWER) { if (raw_port_status & PORT_POWER) { if (hcd->speed == HCD_USB3) status |= USB_SS_PORT_STAT_POWER; else Loading @@ -686,16 +633,97 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } /* Update Port Link State for super speed ports*/ if (hcd->speed == HCD_USB3) { xhci_hub_report_link_state(&status, temp); xhci_hub_report_link_state(&status, raw_port_status); /* * Verify if all USB3 Ports Have entered U0 already. * Delete Compliance Mode Timer if so. */ xhci_del_comp_mod_timer(xhci, temp, wIndex); xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex); } if (bus_state->port_c_suspend & (1 << wIndex)) status |= 1 << USB_PORT_FEAT_C_SUSPEND; return status; } int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports; unsigned long flags; u32 temp, status; int retval = 0; __le32 __iomem **port_array; int slot_id; struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; u16 timeout = 0; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; spin_lock_irqsave(&xhci->lock, flags); switch (typeReq) { case GetHubStatus: /* No power source, over-current reported per port */ memset(buf, 0, 4); break; case GetHubDescriptor: /* Check to make sure userspace is asking for the USB 3.0 hub * descriptor for the USB 3.0 roothub. If not, we stall the * endpoint, like external hubs do. */ if (hcd->speed == HCD_USB3 && (wLength < USB_DT_SS_HUB_SIZE || wValue != (USB_DT_SS_HUB << 8))) { xhci_dbg(xhci, "Wrong hub descriptor type for " "USB 3.0 roothub.\n"); goto error; } xhci_hub_descriptor(hcd, xhci, (struct usb_hub_descriptor *) buf); break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: if ((wValue & 0xff00) != (USB_DT_BOS << 8)) goto error; if (hcd->speed != HCD_USB3) goto error; /* Set the U1 and U2 exit latencies. */ memcpy(buf, &usb_bos_descriptor, USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); buf[12] = HCS_U1_LATENCY(temp); put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); /* Indicate whether the host has LTM support. */ temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); if (HCC_LTC(temp)) buf[8] |= USB_LTM_SUPPORT; spin_unlock_irqrestore(&xhci->lock, flags); return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; case GetPortStatus: if (!wIndex || wIndex > max_ports) goto error; wIndex--; temp = xhci_readl(xhci, port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; } status = xhci_get_port_status(hcd, bus_state, port_array, wIndex, temp); if (status == 0xffffffff) goto error; xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); xhci_dbg(xhci, "Get port status returned 0x%x\n", status); put_unaligned(cpu_to_le32(status), (__le32 *) buf); break; case SetPortFeature: Loading