xhci: Refactor bus suspend state into a struct.
authorSarah Sharp <sarah.a.sharp@linux.intel.com>
Wed, 15 Dec 2010 20:47:14 +0000 (12:47 -0800)
committerSarah Sharp <sarah.a.sharp@linux.intel.com>
Mon, 14 Mar 2011 01:23:36 +0000 (18:23 -0700)
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: Sarah Sharp <sarah.a.sharp@linux.intel.com>
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h

index 89ff025..4944ba1 100644 (file)
@@ -291,6 +291,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
        u32 __iomem *port_array[15 + USB_MAXCHILDREN];
        int i;
        int slot_id;
+       struct xhci_bus_state *bus_state;
 
        ports = HCS_MAX_PORTS(xhci->hcs_params1);
        for (i = 0; i < ports; i++) {
@@ -300,6 +301,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        port_array[i] =
                                xhci->usb2_ports[i - xhci->num_usb3_ports];
        }
+       bus_state = &xhci->bus_state[hcd_index(hcd)];
 
        spin_lock_irqsave(&xhci->lock, flags);
        switch (typeReq) {
@@ -336,10 +338,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        if ((temp & PORT_RESET) || !(temp & PORT_PE))
                                goto error;
                        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",
                                        wIndex + 1);
-                               xhci->resume_done[wIndex] = 0;
+                               bus_state->resume_done[wIndex] = 0;
                                temp1 = xhci_port_state_to_neutral(temp);
                                temp1 &= ~PORT_PLS_MASK;
                                temp1 |= PORT_LINK_STROBE | XDEV_U0;
@@ -354,15 +356,15 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                        goto error;
                                }
                                xhci_ring_device(xhci, slot_id);
-                               xhci->port_c_suspend |= 1 << wIndex;
-                               xhci->suspended_ports &= ~(1 << wIndex);
+                               bus_state->port_c_suspend |= 1 << wIndex;
+                               bus_state->suspended_ports &= ~(1 << wIndex);
                        }
                }
                if ((temp & PORT_PLS_MASK) == XDEV_U0
                        && (temp & PORT_POWER)
-                       && (xhci->suspended_ports & (1 << wIndex))) {
-                       xhci->suspended_ports &= ~(1 << wIndex);
-                       xhci->port_c_suspend |= 1 << wIndex;
+                       && (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;
@@ -376,7 +378,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        status |= USB_PORT_STAT_RESET;
                if (temp & PORT_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;
                xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
                put_unaligned(cpu_to_le32(status), (__le32 *) buf);
@@ -422,7 +424,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        spin_lock_irqsave(&xhci->lock, flags);
 
                        temp = xhci_readl(xhci, port_array[wIndex]);
-                       xhci->suspended_ports |= 1 << wIndex;
+                       bus_state->suspended_ports |= 1 << wIndex;
                        break;
                case USB_PORT_FEAT_POWER:
                        /*
@@ -493,7 +495,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                        xhci_writel(xhci, temp,
                                                        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);
@@ -504,7 +506,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        xhci_ring_device(xhci, slot_id);
                        break;
                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_CONNECTION:
                case USB_PORT_FEAT_C_OVER_CURRENT:
@@ -546,6 +548,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        int ports;
        u32 __iomem *port_array[15 + USB_MAXCHILDREN];
+       struct xhci_bus_state *bus_state;
 
        ports = HCS_MAX_PORTS(xhci->hcs_params1);
        for (i = 0; i < ports; i++) {
@@ -555,6 +558,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
                        port_array[i] =
                                xhci->usb2_ports[i - xhci->num_usb3_ports];
        }
+       bus_state = &xhci->bus_state[hcd_index(hcd)];
 
        /* Initial status is no changes */
        retval = (ports + 8) / 8;
@@ -568,9 +572,9 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
        for (i = 0; i < ports; i++) {
                temp = xhci_readl(xhci, port_array[i]);
                if ((temp & mask) != 0 ||
-                       (xhci->port_c_suspend & 1 << i) ||
-                       (xhci->resume_done[i] && time_after_eq(
-                           jiffies, xhci->resume_done[i]))) {
+                       (bus_state->port_c_suspend & 1 << i) ||
+                       (bus_state->resume_done[i] && time_after_eq(
+                           jiffies, bus_state->resume_done[i]))) {
                        buf[(i + 1) / 8] |= 1 << (i + 1) % 8;
                        status = 1;
                }
@@ -587,6 +591,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
        int max_ports, port_index;
        u32 __iomem *port_array[15 + USB_MAXCHILDREN];
        int i;
+       struct xhci_bus_state *bus_state;
        unsigned long flags;
 
        xhci_dbg(xhci, "suspend root hub\n");
@@ -598,13 +603,14 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                        port_array[i] =
                                xhci->usb2_ports[i - xhci->num_usb3_ports];
        }
+       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 (xhci->resume_done[port_index] != 0) {
+                       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",
@@ -615,7 +621,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
        }
 
        port_index = max_ports;
-       xhci->bus_suspended = 0;
+       bus_state->bus_suspended = 0;
        while (port_index--) {
                /* suspend the port if the port is not suspended */
                u32 t1, t2;
@@ -635,7 +641,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                        }
                        t2 &= ~PORT_PLS_MASK;
                        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 (t1 & PORT_CONNECT) {
@@ -667,7 +673,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                }
        }
        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);
        return 0;
 }
@@ -678,6 +684,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
        int max_ports, port_index;
        u32 __iomem *port_array[15 + USB_MAXCHILDREN];
        int i;
+       struct xhci_bus_state *bus_state;
        u32 temp;
        unsigned long flags;
 
@@ -690,8 +697,9 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                        port_array[i] =
                                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);
 
        spin_lock_irqsave(&xhci->lock, flags);
@@ -717,7 +725,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                        temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
                else
                        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)) {
                        if (DEV_SUPERSPEED(temp)) {
                                temp = xhci_port_state_to_neutral(temp);
@@ -763,7 +771,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
 
        (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 */
        temp = xhci_readl(xhci, &xhci->op_regs->command);
        temp |= CMD_EIE;
index 9688a58..bc809cb 100644 (file)
@@ -1451,7 +1451,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 
        xhci->page_size = 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,
@@ -1971,7 +1971,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        for (i = 0; i < MAX_HC_SLOTS; ++i)
                xhci->devs[i] = NULL;
        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))
                goto fail;
index 5825376..7cea248 100644 (file)
@@ -1166,7 +1166,9 @@ static void handle_port_status(struct xhci_hcd *xhci,
        unsigned int faked_port_index;
        u32 __iomem *port_array[15 + USB_MAXCHILDREN];
        int i;
+       struct xhci_bus_state *bus_state;
 
+       bus_state = &xhci->bus_state[0];
        /* Port status change events always have a successful completion code */
        if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
                xhci_warn(xhci, "WARN: xHC returned failed port status event\n");
@@ -1225,10 +1227,10 @@ static void handle_port_status(struct xhci_hcd *xhci,
                        xhci_writel(xhci, temp, port_array[faked_port_index]);
                } else {
                        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);
                        mod_timer(&hcd->rh_timer,
-                                 xhci->resume_done[port_id - 1]);
+                                 bus_state->resume_done[port_id - 1]);
                        /* Do the rest in GetPortStatus */
                }
        }
index a95108c..8d45bbd 100644 (file)
@@ -694,7 +694,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        struct usb_hcd          *hcd = xhci_to_hcd(xhci);
        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);
 
        spin_lock_irq(&xhci->lock);
index daa8858..c15470e 100644 (file)
@@ -1161,6 +1161,22 @@ struct s3_save {
        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 */
 struct xhci_hcd {
        struct usb_hcd *main_hcd;
@@ -1225,9 +1241,6 @@ struct xhci_hcd {
        /* Host controller watchdog timer structures */
        unsigned int            xhc_state;
 
-       unsigned long           bus_suspended;
-       unsigned long           next_statechange;
-
        u32                     command;
        struct s3_save          s3;
 /* Host controller is dying - not responding to commands. "I'm not dead yet!"
@@ -1249,11 +1262,10 @@ struct xhci_hcd {
 #define        XHCI_LINK_TRB_QUIRK     (1 << 0)
 #define XHCI_RESET_EP_QUIRK    (1 << 1)
 #define XHCI_NEC_HOST          (1 << 2)
-       /* port suspend change*/
-       u32                     port_c_suspend;
-       /* which ports are suspended */
-       u32                     suspended_ports;
-       unsigned long           resume_done[USB_MAXCHILDREN];
+       /* There's only one roothub to keep track of bus suspend info for
+        * (right now).
+        */
+       struct xhci_bus_state   bus_state[1];
        /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
        u8                      *port_array;
        /* Array of pointers to USB 3.0 PORTSC registers */