| From a0e5974cd8eb63b95d53b73932035542cf56ca08 Mon Sep 17 00:00:00 2001 |
| From: Sarah Sharp <sarah.a.sharp@linux.intel.com> |
| Date: Tue, 2 Apr 2013 08:42:20 -0700 |
| Subject: xhci: Refactor port status into a new function. |
| |
| The hub control function is *way* too long. Refactor it into a new |
| function, and document the side effects of calling that function. |
| |
| Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> |
| (cherry picked from commit eae5b17621d1053c81bec24e5dd5094bf50b31c6) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/usb/host/xhci-hub.c | 210 ++++++++++++++++++++++++-------------------- |
| 1 file changed, 119 insertions(+), 91 deletions(-) |
| |
| --- a/drivers/usb/host/xhci-hub.c |
| +++ b/drivers/usb/host/xhci-hub.c |
| @@ -542,6 +542,118 @@ void xhci_del_comp_mod_timer(struct xhci |
| } |
| } |
| |
| +/* |
| + * 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); |
| + u32 status = 0; |
| + int slot_id; |
| + |
| + /* wPortChange bits */ |
| + if (raw_port_status & PORT_CSC) |
| + status |= USB_PORT_STAT_C_CONNECTION << 16; |
| + if (raw_port_status & PORT_PEC) |
| + status |= USB_PORT_STAT_C_ENABLE << 16; |
| + if ((raw_port_status & PORT_OCC)) |
| + status |= USB_PORT_STAT_C_OVERCURRENT << 16; |
| + if ((raw_port_status & PORT_RC)) |
| + status |= USB_PORT_STAT_C_RESET << 16; |
| + /* USB3.0 only */ |
| + if (hcd->speed == HCD_USB3) { |
| + if ((raw_port_status & PORT_PLC)) |
| + status |= USB_PORT_STAT_C_LINK_STATE << 16; |
| + if ((raw_port_status & PORT_WRC)) |
| + status |= USB_PORT_STAT_C_BH_RESET << 16; |
| + } |
| + |
| + if (hcd->speed != HCD_USB3) { |
| + if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3 |
| + && (raw_port_status & PORT_POWER)) |
| + status |= USB_PORT_STAT_SUSPEND; |
| + } |
| + 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", |
| + 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"); |
| + return 0xffffffff; |
| + } |
| + 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 ((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 (raw_port_status & PORT_CONNECT) { |
| + status |= USB_PORT_STAT_CONNECTION; |
| + status |= xhci_port_speed(raw_port_status); |
| + } |
| + if (raw_port_status & PORT_PE) |
| + status |= USB_PORT_STAT_ENABLE; |
| + if (raw_port_status & PORT_OC) |
| + status |= USB_PORT_STAT_OVERCURRENT; |
| + if (raw_port_status & PORT_RESET) |
| + status |= USB_PORT_STAT_RESET; |
| + if (raw_port_status & 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, raw_port_status); |
| + /* |
| + * Verify if all USB3 Ports Have entered U0 already. |
| + * Delete Compliance Mode Timer if so. |
| + */ |
| + 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) |
| { |
| @@ -606,104 +718,20 @@ int xhci_hub_control(struct usb_hcd *hcd |
| 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; |
| - } |
| + status = xhci_get_port_status(hcd, bus_state, port_array, |
| + wIndex, temp); |
| + if (status == 0xffffffff) |
| + goto error; |
| |
| - 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, 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: |