Commit 20b67cf5 authored by Sarah Sharp's avatar Sarah Sharp

xhci: Refactor bus suspend state into a struct.

There are several variables in the xhci_hcd structure that are related to
bus suspend and resume state.  There are a couple different port status
arrays that are accessed by port index.  Move those variables into a
separate structure, xhci_bus_state.  Stash that structure in xhci_hcd.

When we have two roothhubs that can be suspended and resumed separately,
we can have two xhci_bus_states, and index into the port arrays in each
structure with the fake roothub port index (not the real hardware port
index).
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
parent 5308a91b
...@@ -291,6 +291,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -291,6 +291,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u32 __iomem *port_array[15 + USB_MAXCHILDREN]; u32 __iomem *port_array[15 + USB_MAXCHILDREN];
int i; int i;
int slot_id; int slot_id;
struct xhci_bus_state *bus_state;
ports = HCS_MAX_PORTS(xhci->hcs_params1); ports = HCS_MAX_PORTS(xhci->hcs_params1);
for (i = 0; i < ports; i++) { for (i = 0; i < ports; i++) {
...@@ -300,6 +301,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -300,6 +301,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
port_array[i] = port_array[i] =
xhci->usb2_ports[i - xhci->num_usb3_ports]; xhci->usb2_ports[i - xhci->num_usb3_ports];
} }
bus_state = &xhci->bus_state[hcd_index(hcd)];
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
switch (typeReq) { switch (typeReq) {
...@@ -336,10 +338,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -336,10 +338,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if ((temp & PORT_RESET) || !(temp & PORT_PE)) if ((temp & PORT_RESET) || !(temp & PORT_PE))
goto error; goto error;
if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies, if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies,
xhci->resume_done[wIndex])) { bus_state->resume_done[wIndex])) {
xhci_dbg(xhci, "Resume USB2 port %d\n", xhci_dbg(xhci, "Resume USB2 port %d\n",
wIndex + 1); wIndex + 1);
xhci->resume_done[wIndex] = 0; bus_state->resume_done[wIndex] = 0;
temp1 = xhci_port_state_to_neutral(temp); temp1 = xhci_port_state_to_neutral(temp);
temp1 &= ~PORT_PLS_MASK; temp1 &= ~PORT_PLS_MASK;
temp1 |= PORT_LINK_STROBE | XDEV_U0; temp1 |= PORT_LINK_STROBE | XDEV_U0;
...@@ -354,15 +356,15 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -354,15 +356,15 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
goto error; goto error;
} }
xhci_ring_device(xhci, slot_id); xhci_ring_device(xhci, slot_id);
xhci->port_c_suspend |= 1 << wIndex; bus_state->port_c_suspend |= 1 << wIndex;
xhci->suspended_ports &= ~(1 << wIndex); bus_state->suspended_ports &= ~(1 << wIndex);
} }
} }
if ((temp & PORT_PLS_MASK) == XDEV_U0 if ((temp & PORT_PLS_MASK) == XDEV_U0
&& (temp & PORT_POWER) && (temp & PORT_POWER)
&& (xhci->suspended_ports & (1 << wIndex))) { && (bus_state->suspended_ports & (1 << wIndex))) {
xhci->suspended_ports &= ~(1 << wIndex); bus_state->suspended_ports &= ~(1 << wIndex);
xhci->port_c_suspend |= 1 << wIndex; bus_state->port_c_suspend |= 1 << wIndex;
} }
if (temp & PORT_CONNECT) { if (temp & PORT_CONNECT) {
status |= USB_PORT_STAT_CONNECTION; status |= USB_PORT_STAT_CONNECTION;
...@@ -376,7 +378,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -376,7 +378,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
status |= USB_PORT_STAT_RESET; status |= USB_PORT_STAT_RESET;
if (temp & PORT_POWER) if (temp & PORT_POWER)
status |= USB_PORT_STAT_POWER; status |= USB_PORT_STAT_POWER;
if (xhci->port_c_suspend & (1 << wIndex)) if (bus_state->port_c_suspend & (1 << wIndex))
status |= 1 << USB_PORT_FEAT_C_SUSPEND; status |= 1 << USB_PORT_FEAT_C_SUSPEND;
xhci_dbg(xhci, "Get port status returned 0x%x\n", status); xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
put_unaligned(cpu_to_le32(status), (__le32 *) buf); put_unaligned(cpu_to_le32(status), (__le32 *) buf);
...@@ -422,7 +424,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -422,7 +424,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
temp = xhci_readl(xhci, port_array[wIndex]); temp = xhci_readl(xhci, port_array[wIndex]);
xhci->suspended_ports |= 1 << wIndex; bus_state->suspended_ports |= 1 << wIndex;
break; break;
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
/* /*
...@@ -493,7 +495,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -493,7 +495,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_writel(xhci, temp, xhci_writel(xhci, temp,
port_array[wIndex]); port_array[wIndex]);
} }
xhci->port_c_suspend |= 1 << wIndex; bus_state->port_c_suspend |= 1 << wIndex;
} }
slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1); slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1);
...@@ -504,7 +506,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -504,7 +506,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_ring_device(xhci, slot_id); xhci_ring_device(xhci, slot_id);
break; break;
case USB_PORT_FEAT_C_SUSPEND: case USB_PORT_FEAT_C_SUSPEND:
xhci->port_c_suspend &= ~(1 << wIndex); bus_state->port_c_suspend &= ~(1 << wIndex);
case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_RESET:
case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_CONNECTION:
case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_OVER_CURRENT:
...@@ -546,6 +548,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) ...@@ -546,6 +548,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int ports; int ports;
u32 __iomem *port_array[15 + USB_MAXCHILDREN]; u32 __iomem *port_array[15 + USB_MAXCHILDREN];
struct xhci_bus_state *bus_state;
ports = HCS_MAX_PORTS(xhci->hcs_params1); ports = HCS_MAX_PORTS(xhci->hcs_params1);
for (i = 0; i < ports; i++) { for (i = 0; i < ports; i++) {
...@@ -555,6 +558,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) ...@@ -555,6 +558,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
port_array[i] = port_array[i] =
xhci->usb2_ports[i - xhci->num_usb3_ports]; xhci->usb2_ports[i - xhci->num_usb3_ports];
} }
bus_state = &xhci->bus_state[hcd_index(hcd)];
/* Initial status is no changes */ /* Initial status is no changes */
retval = (ports + 8) / 8; retval = (ports + 8) / 8;
...@@ -568,9 +572,9 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) ...@@ -568,9 +572,9 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
for (i = 0; i < ports; i++) { for (i = 0; i < ports; i++) {
temp = xhci_readl(xhci, port_array[i]); temp = xhci_readl(xhci, port_array[i]);
if ((temp & mask) != 0 || if ((temp & mask) != 0 ||
(xhci->port_c_suspend & 1 << i) || (bus_state->port_c_suspend & 1 << i) ||
(xhci->resume_done[i] && time_after_eq( (bus_state->resume_done[i] && time_after_eq(
jiffies, xhci->resume_done[i]))) { jiffies, bus_state->resume_done[i]))) {
buf[(i + 1) / 8] |= 1 << (i + 1) % 8; buf[(i + 1) / 8] |= 1 << (i + 1) % 8;
status = 1; status = 1;
} }
...@@ -587,6 +591,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) ...@@ -587,6 +591,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
int max_ports, port_index; int max_ports, port_index;
u32 __iomem *port_array[15 + USB_MAXCHILDREN]; u32 __iomem *port_array[15 + USB_MAXCHILDREN];
int i; int i;
struct xhci_bus_state *bus_state;
unsigned long flags; unsigned long flags;
xhci_dbg(xhci, "suspend root hub\n"); xhci_dbg(xhci, "suspend root hub\n");
...@@ -598,13 +603,14 @@ int xhci_bus_suspend(struct usb_hcd *hcd) ...@@ -598,13 +603,14 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
port_array[i] = port_array[i] =
xhci->usb2_ports[i - xhci->num_usb3_ports]; xhci->usb2_ports[i - xhci->num_usb3_ports];
} }
bus_state = &xhci->bus_state[hcd_index(hcd)];
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
if (hcd->self.root_hub->do_remote_wakeup) { if (hcd->self.root_hub->do_remote_wakeup) {
port_index = max_ports; port_index = max_ports;
while (port_index--) { while (port_index--) {
if (xhci->resume_done[port_index] != 0) { if (bus_state->resume_done[port_index] != 0) {
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "suspend failed because " xhci_dbg(xhci, "suspend failed because "
"port %d is resuming\n", "port %d is resuming\n",
...@@ -615,7 +621,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) ...@@ -615,7 +621,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
} }
port_index = max_ports; port_index = max_ports;
xhci->bus_suspended = 0; bus_state->bus_suspended = 0;
while (port_index--) { while (port_index--) {
/* suspend the port if the port is not suspended */ /* suspend the port if the port is not suspended */
u32 t1, t2; u32 t1, t2;
...@@ -635,7 +641,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) ...@@ -635,7 +641,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
} }
t2 &= ~PORT_PLS_MASK; t2 &= ~PORT_PLS_MASK;
t2 |= PORT_LINK_STROBE | XDEV_U3; t2 |= PORT_LINK_STROBE | XDEV_U3;
set_bit(port_index, &xhci->bus_suspended); set_bit(port_index, &bus_state->bus_suspended);
} }
if (hcd->self.root_hub->do_remote_wakeup) { if (hcd->self.root_hub->do_remote_wakeup) {
if (t1 & PORT_CONNECT) { if (t1 & PORT_CONNECT) {
...@@ -667,7 +673,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) ...@@ -667,7 +673,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
} }
} }
hcd->state = HC_STATE_SUSPENDED; hcd->state = HC_STATE_SUSPENDED;
xhci->next_statechange = jiffies + msecs_to_jiffies(10); bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
return 0; return 0;
} }
...@@ -678,6 +684,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) ...@@ -678,6 +684,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
int max_ports, port_index; int max_ports, port_index;
u32 __iomem *port_array[15 + USB_MAXCHILDREN]; u32 __iomem *port_array[15 + USB_MAXCHILDREN];
int i; int i;
struct xhci_bus_state *bus_state;
u32 temp; u32 temp;
unsigned long flags; unsigned long flags;
...@@ -690,8 +697,9 @@ int xhci_bus_resume(struct usb_hcd *hcd) ...@@ -690,8 +697,9 @@ int xhci_bus_resume(struct usb_hcd *hcd)
port_array[i] = port_array[i] =
xhci->usb2_ports[i - xhci->num_usb3_ports]; xhci->usb2_ports[i - xhci->num_usb3_ports];
} }
bus_state = &xhci->bus_state[hcd_index(hcd)];
if (time_before(jiffies, xhci->next_statechange)) if (time_before(jiffies, bus_state->next_statechange))
msleep(5); msleep(5);
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
...@@ -717,7 +725,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) ...@@ -717,7 +725,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
else else
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
if (test_bit(port_index, &xhci->bus_suspended) && if (test_bit(port_index, &bus_state->bus_suspended) &&
(temp & PORT_PLS_MASK)) { (temp & PORT_PLS_MASK)) {
if (DEV_SUPERSPEED(temp)) { if (DEV_SUPERSPEED(temp)) {
temp = xhci_port_state_to_neutral(temp); temp = xhci_port_state_to_neutral(temp);
...@@ -763,7 +771,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) ...@@ -763,7 +771,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
(void) xhci_readl(xhci, &xhci->op_regs->command); (void) xhci_readl(xhci, &xhci->op_regs->command);
xhci->next_statechange = jiffies + msecs_to_jiffies(5); bus_state->next_statechange = jiffies + msecs_to_jiffies(5);
/* re-enable irqs */ /* re-enable irqs */
temp = xhci_readl(xhci, &xhci->op_regs->command); temp = xhci_readl(xhci, &xhci->op_regs->command);
temp |= CMD_EIE; temp |= CMD_EIE;
......
...@@ -1451,7 +1451,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) ...@@ -1451,7 +1451,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->page_size = 0; xhci->page_size = 0;
xhci->page_shift = 0; xhci->page_shift = 0;
xhci->bus_suspended = 0; xhci->bus_state[0].bus_suspended = 0;
} }
static int xhci_test_trb_in_td(struct xhci_hcd *xhci, static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
...@@ -1971,7 +1971,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) ...@@ -1971,7 +1971,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
for (i = 0; i < MAX_HC_SLOTS; ++i) for (i = 0; i < MAX_HC_SLOTS; ++i)
xhci->devs[i] = NULL; xhci->devs[i] = NULL;
for (i = 0; i < USB_MAXCHILDREN; ++i) for (i = 0; i < USB_MAXCHILDREN; ++i)
xhci->resume_done[i] = 0; xhci->bus_state[0].resume_done[i] = 0;
if (scratchpad_alloc(xhci, flags)) if (scratchpad_alloc(xhci, flags))
goto fail; goto fail;
......
...@@ -1166,7 +1166,9 @@ static void handle_port_status(struct xhci_hcd *xhci, ...@@ -1166,7 +1166,9 @@ static void handle_port_status(struct xhci_hcd *xhci,
unsigned int faked_port_index; unsigned int faked_port_index;
u32 __iomem *port_array[15 + USB_MAXCHILDREN]; u32 __iomem *port_array[15 + USB_MAXCHILDREN];
int i; int i;
struct xhci_bus_state *bus_state;
bus_state = &xhci->bus_state[0];
/* Port status change events always have a successful completion code */ /* Port status change events always have a successful completion code */
if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) { if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
xhci_warn(xhci, "WARN: xHC returned failed port status event\n"); xhci_warn(xhci, "WARN: xHC returned failed port status event\n");
...@@ -1225,10 +1227,10 @@ static void handle_port_status(struct xhci_hcd *xhci, ...@@ -1225,10 +1227,10 @@ static void handle_port_status(struct xhci_hcd *xhci,
xhci_writel(xhci, temp, port_array[faked_port_index]); xhci_writel(xhci, temp, port_array[faked_port_index]);
} else { } else {
xhci_dbg(xhci, "resume HS port %d\n", port_id); xhci_dbg(xhci, "resume HS port %d\n", port_id);
xhci->resume_done[port_id - 1] = jiffies + bus_state->resume_done[port_id - 1] = jiffies +
msecs_to_jiffies(20); msecs_to_jiffies(20);
mod_timer(&hcd->rh_timer, mod_timer(&hcd->rh_timer,
xhci->resume_done[port_id - 1]); bus_state->resume_done[port_id - 1]);
/* Do the rest in GetPortStatus */ /* Do the rest in GetPortStatus */
} }
} }
......
...@@ -694,7 +694,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) ...@@ -694,7 +694,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *hcd = xhci_to_hcd(xhci);
int retval; int retval;
if (time_before(jiffies, xhci->next_statechange)) /* Wait a bit if the bus needs to settle from the transistion to
* suspend.
*/
if (time_before(jiffies, xhci->bus_state[0].next_statechange))
msleep(100); msleep(100);
spin_lock_irq(&xhci->lock); spin_lock_irq(&xhci->lock);
......
...@@ -1161,6 +1161,22 @@ struct s3_save { ...@@ -1161,6 +1161,22 @@ struct s3_save {
u64 erst_dequeue; u64 erst_dequeue;
}; };
struct xhci_bus_state {
unsigned long bus_suspended;
unsigned long next_statechange;
/* Port suspend arrays are indexed by the portnum of the fake roothub */
/* ports suspend status arrays - max 31 ports for USB2, 15 for USB3 */
u32 port_c_suspend;
u32 suspended_ports;
unsigned long resume_done[USB_MAXCHILDREN];
};
static inline unsigned int hcd_index(struct usb_hcd *hcd)
{
return 0;
}
/* There is one ehci_hci structure per controller */ /* There is one ehci_hci structure per controller */
struct xhci_hcd { struct xhci_hcd {
struct usb_hcd *main_hcd; struct usb_hcd *main_hcd;
...@@ -1225,9 +1241,6 @@ struct xhci_hcd { ...@@ -1225,9 +1241,6 @@ struct xhci_hcd {
/* Host controller watchdog timer structures */ /* Host controller watchdog timer structures */
unsigned int xhc_state; unsigned int xhc_state;
unsigned long bus_suspended;
unsigned long next_statechange;
u32 command; u32 command;
struct s3_save s3; struct s3_save s3;
/* Host controller is dying - not responding to commands. "I'm not dead yet!" /* Host controller is dying - not responding to commands. "I'm not dead yet!"
...@@ -1249,11 +1262,10 @@ struct xhci_hcd { ...@@ -1249,11 +1262,10 @@ struct xhci_hcd {
#define XHCI_LINK_TRB_QUIRK (1 << 0) #define XHCI_LINK_TRB_QUIRK (1 << 0)
#define XHCI_RESET_EP_QUIRK (1 << 1) #define XHCI_RESET_EP_QUIRK (1 << 1)
#define XHCI_NEC_HOST (1 << 2) #define XHCI_NEC_HOST (1 << 2)
/* port suspend change*/ /* There's only one roothub to keep track of bus suspend info for
u32 port_c_suspend; * (right now).
/* which ports are suspended */ */
u32 suspended_ports; struct xhci_bus_state bus_state[1];
unsigned long resume_done[USB_MAXCHILDREN];
/* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */ /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
u8 *port_array; u8 *port_array;
/* Array of pointers to USB 3.0 PORTSC registers */ /* Array of pointers to USB 3.0 PORTSC registers */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment