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

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
Loading
Loading
Loading
Loading
+29 −21
Original line number Diff line number Diff line
@@ -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;
+2 −2
Original line number Diff line number Diff line
@@ -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;
+4 −2
Original line number Diff line number Diff line
@@ -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 */
		}
	}
+4 −1
Original line number Diff line number Diff line
@@ -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);
+20 −8
Original line number Diff line number Diff line
@@ -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 */