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>
This commit is contained in:
parent
57d04eb131
commit
eae5b17621
|
@ -534,6 +534,118 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(&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)
|
||||
{
|
||||
|
@ -598,104 +710,20 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
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);
|
||||
status = xhci_get_port_status(hcd, bus_state, port_array,
|
||||
wIndex, temp);
|
||||
if (status == 0xffffffff)
|
||||
goto error;
|
||||
|
||||
/* 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, 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…
Reference in New Issue