diff options
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 1057 | 
1 files changed, 782 insertions, 275 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index fef5a1f9d48..aa79e874904 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -20,49 +20,153 @@   * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */ + +#include <linux/slab.h> +#include <linux/device.h>  #include <asm/unaligned.h>  #include "xhci.h" +#include "xhci-trace.h"  #define	PORT_WAKE_BITS	(PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)  #define	PORT_RWC_BITS	(PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \  			 PORT_RC | PORT_PLC | PORT_PE) -static void xhci_hub_descriptor(struct xhci_hcd *xhci, -		struct usb_hub_descriptor *desc) +/* USB 3.0 BOS descriptor and a capability descriptor, combined */ +static u8 usb_bos_descriptor [] = { +	USB_DT_BOS_SIZE,		/*  __u8 bLength, 5 bytes */ +	USB_DT_BOS,			/*  __u8 bDescriptorType */ +	0x0F, 0x00,			/*  __le16 wTotalLength, 15 bytes */ +	0x1,				/*  __u8 bNumDeviceCaps */ +	/* First device capability */ +	USB_DT_USB_SS_CAP_SIZE,		/*  __u8 bLength, 10 bytes */ +	USB_DT_DEVICE_CAPABILITY,	/* Device Capability */ +	USB_SS_CAP_TYPE,		/* bDevCapabilityType, SUPERSPEED_USB */ +	0x00,				/* bmAttributes, LTM off by default */ +	USB_5GBPS_OPERATION, 0x00,	/* wSpeedsSupported, 5Gbps only */ +	0x03,				/* bFunctionalitySupport, +					   USB 3.0 speed only */ +	0x00,				/* bU1DevExitLat, set later. */ +	0x00, 0x00			/* __le16 bU2DevExitLat, set later. */ +}; + + +static void xhci_common_hub_descriptor(struct xhci_hcd *xhci, +		struct usb_hub_descriptor *desc, int ports)  { -	int ports;  	u16 temp; -	ports = HCS_MAX_PORTS(xhci->hcs_params1); - -	/* USB 3.0 hubs have a different descriptor, but we fake this for now */ -	desc->bDescriptorType = 0x29;  	desc->bPwrOn2PwrGood = 10;	/* xhci section 5.4.9 says 20ms max */  	desc->bHubContrCurrent = 0;  	desc->bNbrPorts = ports; -	temp = 1 + (ports / 8); -	desc->bDescLength = 7 + 2 * temp; - -	/* Why does core/hcd.h define bitmap?  It's just confusing. */ -	memset(&desc->DeviceRemovable[0], 0, temp); -	memset(&desc->DeviceRemovable[temp], 0xff, temp); - -	/* Ugh, these should be #defines, FIXME */ -	/* Using table 11-13 in USB 2.0 spec. */  	temp = 0; -	/* Bits 1:0 - support port power switching, or power always on */ +	/* Bits 1:0 - support per-port power switching, or power always on */  	if (HCC_PPC(xhci->hcc_params)) -		temp |= 0x0001; +		temp |= HUB_CHAR_INDV_PORT_LPSM;  	else -		temp |= 0x0002; +		temp |= HUB_CHAR_NO_LPSM;  	/* Bit  2 - root hubs are not part of a compound device */  	/* Bits 4:3 - individual port over current protection */ -	temp |= 0x0008; +	temp |= HUB_CHAR_INDV_PORT_OCPM;  	/* Bits 6:5 - no TTs in root ports */  	/* Bit  7 - no port indicators */ -	desc->wHubCharacteristics = (__force __u16) cpu_to_le16(temp); +	desc->wHubCharacteristics = cpu_to_le16(temp); +} + +/* Fill in the USB 2.0 roothub descriptor */ +static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, +		struct usb_hub_descriptor *desc) +{ +	int ports; +	u16 temp; +	__u8 port_removable[(USB_MAXCHILDREN + 1 + 7) / 8]; +	u32 portsc; +	unsigned int i; + +	ports = xhci->num_usb2_ports; + +	xhci_common_hub_descriptor(xhci, desc, ports); +	desc->bDescriptorType = USB_DT_HUB; +	temp = 1 + (ports / 8); +	desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp; + +	/* The Device Removable bits are reported on a byte granularity. +	 * If the port doesn't exist within that byte, the bit is set to 0. +	 */ +	memset(port_removable, 0, sizeof(port_removable)); +	for (i = 0; i < ports; i++) { +		portsc = readl(xhci->usb2_ports[i]); +		/* If a device is removable, PORTSC reports a 0, same as in the +		 * hub descriptor DeviceRemovable bits. +		 */ +		if (portsc & PORT_DEV_REMOVE) +			/* This math is hairy because bit 0 of DeviceRemovable +			 * is reserved, and bit 1 is for port 1, etc. +			 */ +			port_removable[(i + 1) / 8] |= 1 << ((i + 1) % 8); +	} + +	/* ch11.h defines a hub descriptor that has room for USB_MAXCHILDREN +	 * ports on it.  The USB 2.0 specification says that there are two +	 * variable length fields at the end of the hub descriptor: +	 * DeviceRemovable and PortPwrCtrlMask.  But since we can have less than +	 * USB_MAXCHILDREN ports, we may need to use the DeviceRemovable array +	 * to set PortPwrCtrlMask bits.  PortPwrCtrlMask must always be set to +	 * 0xFF, so we initialize the both arrays (DeviceRemovable and +	 * PortPwrCtrlMask) to 0xFF.  Then we set the DeviceRemovable for each +	 * set of ports that actually exist. +	 */ +	memset(desc->u.hs.DeviceRemovable, 0xff, +			sizeof(desc->u.hs.DeviceRemovable)); +	memset(desc->u.hs.PortPwrCtrlMask, 0xff, +			sizeof(desc->u.hs.PortPwrCtrlMask)); + +	for (i = 0; i < (ports + 1 + 7) / 8; i++) +		memset(&desc->u.hs.DeviceRemovable[i], port_removable[i], +				sizeof(__u8)); +} + +/* Fill in the USB 3.0 roothub descriptor */ +static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, +		struct usb_hub_descriptor *desc) +{ +	int ports; +	u16 port_removable; +	u32 portsc; +	unsigned int i; + +	ports = xhci->num_usb3_ports; +	xhci_common_hub_descriptor(xhci, desc, ports); +	desc->bDescriptorType = USB_DT_SS_HUB; +	desc->bDescLength = USB_DT_SS_HUB_SIZE; + +	/* header decode latency should be zero for roothubs, +	 * see section 4.23.5.2. +	 */ +	desc->u.ss.bHubHdrDecLat = 0; +	desc->u.ss.wHubDelay = 0; + +	port_removable = 0; +	/* bit 0 is reserved, bit 1 is for port 1, etc. */ +	for (i = 0; i < ports; i++) { +		portsc = readl(xhci->usb3_ports[i]); +		if (portsc & PORT_DEV_REMOVE) +			port_removable |= 1 << (i + 1); +	} + +	desc->u.ss.DeviceRemovable = cpu_to_le16(port_removable); +} + +static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, +		struct usb_hub_descriptor *desc) +{ + +	if (hcd->speed == HCD_USB3) +		xhci_usb3_hub_descriptor(hcd, xhci, desc); +	else +		xhci_usb2_hub_descriptor(hcd, xhci, desc); +  }  static unsigned int xhci_port_speed(unsigned int port_status) @@ -71,8 +175,6 @@ static unsigned int xhci_port_speed(unsigned int port_status)  		return USB_PORT_STAT_LOW_SPEED;  	if (DEV_HIGHSPEED(port_status))  		return USB_PORT_STAT_HIGH_SPEED; -	if (DEV_SUPERSPEED(port_status)) -		return USB_PORT_STAT_SUPER_SPEED;  	/*  	 * FIXME: Yes, we should check for full speed, but the core uses that as  	 * a default in portspeed() in usb/core/hub.c (which is the only place @@ -135,17 +237,22 @@ u32 xhci_port_state_to_neutral(u32 state)  /*   * find slot id based on port number. + * @port: The one-based port number from one of the two split roothubs.   */ -int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port) +int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, +		u16 port)  {  	int slot_id;  	int i; +	enum usb_device_speed speed;  	slot_id = 0;  	for (i = 0; i < MAX_HC_SLOTS; i++) {  		if (!xhci->devs[i])  			continue; -		if (xhci->devs[i]->port == port) { +		speed = xhci->devs[i]->udev->speed; +		if (((speed == USB_SPEED_SUPER) == (hcd->speed == HCD_USB3)) +				&& xhci->devs[i]->fake_port == port) {  			slot_id = i;  			break;  		} @@ -165,7 +272,6 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)  	struct xhci_virt_device *virt_dev;  	struct xhci_command *cmd;  	unsigned long flags; -	int timeleft;  	int ret;  	int i; @@ -179,34 +285,31 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)  	spin_lock_irqsave(&xhci->lock, flags);  	for (i = LAST_EP_INDEX; i > 0; i--) { -		if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) -			xhci_queue_stop_endpoint(xhci, slot_id, i, suspend); +		if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) { +			struct xhci_command *command; +			command = xhci_alloc_command(xhci, false, false, +						     GFP_NOWAIT); +			if (!command) { +				spin_unlock_irqrestore(&xhci->lock, flags); +				xhci_free_command(xhci, cmd); +				return -ENOMEM; + +			} +			xhci_queue_stop_endpoint(xhci, command, slot_id, i, +						 suspend); +		}  	} -	cmd->command_trb = xhci->cmd_ring->enqueue; -	list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list); -	xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend); +	xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);  	xhci_ring_cmd_db(xhci);  	spin_unlock_irqrestore(&xhci->lock, flags);  	/* Wait for last stop endpoint command to finish */ -	timeleft = wait_for_completion_interruptible_timeout( -			cmd->completion, -			USB_CTRL_SET_TIMEOUT); -	if (timeleft <= 0) { -		xhci_warn(xhci, "%s while waiting for stop endpoint command\n", -				timeleft == 0 ? "Timeout" : "Signal"); -		spin_lock_irqsave(&xhci->lock, flags); -		/* The timeout might have raced with the event ring handler, so -		 * only delete from the list if the item isn't poisoned. -		 */ -		if (cmd->cmd_list.next != LIST_POISON1) -			list_del(&cmd->cmd_list); -		spin_unlock_irqrestore(&xhci->lock, flags); +	wait_for_completion(cmd->completion); + +	if (cmd->status == COMP_CMD_ABORT || cmd->status == COMP_CMD_STOP) { +		xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n");  		ret = -ETIME; -		goto command_cleanup;  	} - -command_cleanup:  	xhci_free_command(xhci, cmd);  	return ret;  } @@ -226,18 +329,25 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)  	return;  } -static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex, -		u32 __iomem *addr, u32 port_status) +static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, +		u16 wIndex, __le32 __iomem *addr, u32 port_status)  { +	/* Don't allow the USB core to disable SuperSpeed ports. */ +	if (hcd->speed == HCD_USB3) { +		xhci_dbg(xhci, "Ignoring request to disable " +				"SuperSpeed port.\n"); +		return; +	} +  	/* Write 1 to disable the port */ -	xhci_writel(xhci, port_status | PORT_PE, addr); -	port_status = xhci_readl(xhci, addr); +	writel(port_status | PORT_PE, addr); +	port_status = readl(addr);  	xhci_dbg(xhci, "disable port, actual port %d status  = 0x%x\n",  			wIndex, port_status);  }  static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, -		u16 wIndex, u32 __iomem *addr, u32 port_status) +		u16 wIndex, __le32 __iomem *addr, u32 port_status)  {  	char *port_change_bit;  	u32 status; @@ -247,6 +357,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,  		status = PORT_RC;  		port_change_bit = "reset";  		break; +	case USB_PORT_FEAT_C_BH_PORT_RESET: +		status = PORT_WRC; +		port_change_bit = "warm(BH) reset"; +		break;  	case USB_PORT_FEAT_C_CONNECTION:  		status = PORT_CSC;  		port_change_bit = "connect"; @@ -263,29 +377,327 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,  		status = PORT_PLC;  		port_change_bit = "suspend/resume";  		break; +	case USB_PORT_FEAT_C_PORT_LINK_STATE: +		status = PORT_PLC; +		port_change_bit = "link state"; +		break;  	default:  		/* Should never happen */  		return;  	}  	/* Change bits are all write 1 to clear */ -	xhci_writel(xhci, port_status | status, addr); -	port_status = xhci_readl(xhci, addr); +	writel(port_status | status, addr); +	port_status = readl(addr);  	xhci_dbg(xhci, "clear port %s change, actual port %d status  = 0x%x\n",  			port_change_bit, wIndex, port_status);  } +static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array) +{ +	int max_ports; +	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); + +	if (hcd->speed == HCD_USB3) { +		max_ports = xhci->num_usb3_ports; +		*port_array = xhci->usb3_ports; +	} else { +		max_ports = xhci->num_usb2_ports; +		*port_array = xhci->usb2_ports; +	} + +	return max_ports; +} + +void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, +				int port_id, u32 link_state) +{ +	u32 temp; + +	temp = readl(port_array[port_id]); +	temp = xhci_port_state_to_neutral(temp); +	temp &= ~PORT_PLS_MASK; +	temp |= PORT_LINK_STROBE | link_state; +	writel(temp, port_array[port_id]); +} + +static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, +		__le32 __iomem **port_array, int port_id, u16 wake_mask) +{ +	u32 temp; + +	temp = readl(port_array[port_id]); +	temp = xhci_port_state_to_neutral(temp); + +	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT) +		temp |= PORT_WKCONN_E; +	else +		temp &= ~PORT_WKCONN_E; + +	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT) +		temp |= PORT_WKDISC_E; +	else +		temp &= ~PORT_WKDISC_E; + +	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT) +		temp |= PORT_WKOC_E; +	else +		temp &= ~PORT_WKOC_E; + +	writel(temp, port_array[port_id]); +} + +/* Test and clear port RWC bit */ +void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, +				int port_id, u32 port_bit) +{ +	u32 temp; + +	temp = readl(port_array[port_id]); +	if (temp & port_bit) { +		temp = xhci_port_state_to_neutral(temp); +		temp |= port_bit; +		writel(temp, port_array[port_id]); +	} +} + +/* Updates Link Status for USB 2.1 port */ +static void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg) +{ +	if ((status_reg & PORT_PLS_MASK) == XDEV_U2) +		*status |= USB_PORT_STAT_L1; +} + +/* Updates Link Status for super Speed port */ +static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg) +{ +	u32 pls = status_reg & PORT_PLS_MASK; + +	/* resume state is a xHCI internal state. +	 * Do not report it to usb core. +	 */ +	if (pls == XDEV_RESUME) +		return; + +	/* When the CAS bit is set then warm reset +	 * should be performed on port +	 */ +	if (status_reg & PORT_CAS) { +		/* The CAS bit can be set while the port is +		 * in any link state. +		 * Only roothubs have CAS bit, so we +		 * pretend to be in compliance mode +		 * unless we're already in compliance +		 * or the inactive state. +		 */ +		if (pls != USB_SS_PORT_LS_COMP_MOD && +		    pls != USB_SS_PORT_LS_SS_INACTIVE) { +			pls = USB_SS_PORT_LS_COMP_MOD; +		} +		/* Return also connection bit - +		 * hub state machine resets port +		 * when this bit is set. +		 */ +		pls |= USB_PORT_STAT_CONNECTION; +	} else { +		/* +		 * If CAS bit isn't set but the Port is already at +		 * Compliance Mode, fake a connection so the USB core +		 * notices the Compliance state and resets the port. +		 * This resolves an issue generated by the SN65LVPE502CP +		 * in which sometimes the port enters compliance mode +		 * caused by a delay on the host-device negotiation. +		 */ +		if (pls == USB_SS_PORT_LS_COMP_MOD) +			pls |= USB_PORT_STAT_CONNECTION; +	} + +	/* update status field */ +	*status |= pls; +} + +/* + * Function for Compliance Mode Quirk. + * + * This Function verifies if all xhc USB3 ports have entered U0, if so, + * the compliance mode timer is deleted. A port won't enter + * compliance mode if it has previously entered U0. + */ +static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, +				    u16 wIndex) +{ +	u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1); +	bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0); + +	if (!(xhci->quirks & XHCI_COMP_MODE_QUIRK)) +		return; + +	if ((xhci->port_status_u0 != all_ports_seen_u0) && port_in_u0) { +		xhci->port_status_u0 |= 1 << wIndex; +		if (xhci->port_status_u0 == all_ports_seen_u0) { +			del_timer_sync(&xhci->comp_mode_recovery_timer); +			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, +				"All USB3 ports have entered U0 already!"); +			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, +				"Compliance Mode Recovery Timer Deleted."); +		} +	} +} + +/* + * 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. + *  - Drop and reacquire the xHCI lock, in order to wait for port resume. + */ +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, +		unsigned long flags) +	__releases(&xhci->lock) +	__acquires(&xhci->lock) +{ +	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])) { +			int time_left; + +			xhci_dbg(xhci, "Resume USB2 port %d\n", +					wIndex + 1); +			bus_state->resume_done[wIndex] = 0; +			clear_bit(wIndex, &bus_state->resuming_ports); + +			set_bit(wIndex, &bus_state->rexit_ports); +			xhci_set_link_state(xhci, port_array, wIndex, +					XDEV_U0); + +			spin_unlock_irqrestore(&xhci->lock, flags); +			time_left = wait_for_completion_timeout( +					&bus_state->rexit_done[wIndex], +					msecs_to_jiffies( +						XHCI_MAX_REXIT_TIMEOUT)); +			spin_lock_irqsave(&xhci->lock, flags); + +			if (time_left) { +				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); +			} else { +				int port_status = readl(port_array[wIndex]); +				xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n", +						XHCI_MAX_REXIT_TIMEOUT, +						port_status); +				status |= USB_PORT_STAT_SUSPEND; +				clear_bit(wIndex, &bus_state->rexit_ports); +			} + +			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 */ +	if (hcd->speed == HCD_USB3) { +		xhci_hub_report_usb3_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); +	} else { +		xhci_hub_report_usb2_link_state(&status, raw_port_status); +	} +	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)  {  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); -	int ports; +	int max_ports;  	unsigned long flags; -	u32 temp, temp1, status; +	u32 temp, status;  	int retval = 0; -	u32 __iomem *addr; +	__le32 __iomem **port_array;  	int slot_id; +	struct xhci_bus_state *bus_state; +	u16 link_state = 0; +	u16 wake_mask = 0; +	u16 timeout = 0; -	ports = HCS_MAX_PORTS(xhci->hcs_params1); +	max_ports = xhci_get_ports(hcd, &port_array); +	bus_state = &xhci->bus_state[hcd_index(hcd)];  	spin_lock_irqsave(&xhci->lock, flags);  	switch (typeReq) { @@ -294,100 +706,97 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  		memset(buf, 0, 4);  		break;  	case GetHubDescriptor: -		xhci_hub_descriptor(xhci, (struct usb_hub_descriptor *) buf); +		/* Check to make sure userspace is asking for the USB 3.0 hub +		 * descriptor for the USB 3.0 roothub.  If not, we stall the +		 * endpoint, like external hubs do. +		 */ +		if (hcd->speed == HCD_USB3 && +				(wLength < USB_DT_SS_HUB_SIZE || +				 wValue != (USB_DT_SS_HUB << 8))) { +			xhci_dbg(xhci, "Wrong hub descriptor type for " +					"USB 3.0 roothub.\n"); +			goto error; +		} +		xhci_hub_descriptor(hcd, xhci, +				(struct usb_hub_descriptor *) buf);  		break; -	case GetPortStatus: -		if (!wIndex || wIndex > ports) +	case DeviceRequest | USB_REQ_GET_DESCRIPTOR: +		if ((wValue & 0xff00) != (USB_DT_BOS << 8))  			goto error; -		wIndex--; -		status = 0; -		addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); -		temp = xhci_readl(xhci, addr); -		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; -		/* -		 * FIXME ignoring reset and USB 2.1/3.0 specific -		 * changes -		 */ -		if ((temp & PORT_PLS_MASK) == XDEV_U3 -			&& (temp & PORT_POWER)) -			status |= 1 << USB_PORT_FEAT_SUSPEND; -		if ((temp & PORT_PLS_MASK) == XDEV_RESUME) { -			if ((temp & PORT_RESET) || !(temp & PORT_PE)) -				goto error; -			if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies, -						xhci->resume_done[wIndex])) { -				xhci_dbg(xhci, "Resume USB2 port %d\n", -					wIndex + 1); -				xhci->resume_done[wIndex] = 0; -				temp1 = xhci_port_state_to_neutral(temp); -				temp1 &= ~PORT_PLS_MASK; -				temp1 |= PORT_LINK_STROBE | XDEV_U0; -				xhci_writel(xhci, temp1, addr); -				xhci_dbg(xhci, "set port %d resume\n", -					wIndex + 1); -				slot_id = xhci_find_slot_id_by_port(xhci, -								 wIndex + 1); -				if (!slot_id) { -					xhci_dbg(xhci, "slot_id is zero\n"); -					goto error; -				} -				xhci_ring_device(xhci, slot_id); -				xhci->port_c_suspend[wIndex >> 5] |= -						1 << (wIndex & 31); -				xhci->suspended_ports[wIndex >> 5] &= -						~(1 << (wIndex & 31)); -			} -		} -		if ((temp & PORT_PLS_MASK) == XDEV_U0 -			&& (temp & PORT_POWER) -			&& (xhci->suspended_ports[wIndex >> 5] & -			    (1 << (wIndex & 31)))) { -			xhci->suspended_ports[wIndex >> 5] &= -					~(1 << (wIndex & 31)); -			xhci->port_c_suspend[wIndex >> 5] |= -					1 << (wIndex & 31); +		if (hcd->speed != HCD_USB3) +			goto error; + +		/* Set the U1 and U2 exit latencies. */ +		memcpy(buf, &usb_bos_descriptor, +				USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); +		if ((xhci->quirks & XHCI_LPM_SUPPORT)) { +			temp = readl(&xhci->cap_regs->hcs_params3); +			buf[12] = HCS_U1_LATENCY(temp); +			put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);  		} -		if (temp & PORT_CONNECT) { -			status |= USB_PORT_STAT_CONNECTION; -			status |= xhci_port_speed(temp); + +		/* Indicate whether the host has LTM support. */ +		temp = readl(&xhci->cap_regs->hcc_params); +		if (HCC_LTC(temp)) +			buf[8] |= USB_LTM_SUPPORT; + +		spin_unlock_irqrestore(&xhci->lock, flags); +		return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; +	case GetPortStatus: +		if (!wIndex || wIndex > max_ports) +			goto error; +		wIndex--; +		temp = readl(port_array[wIndex]); +		if (temp == 0xffffffff) { +			retval = -ENODEV; +			break;  		} -		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) -			status |= USB_PORT_STAT_POWER; -		if (xhci->port_c_suspend[wIndex >> 5] & (1 << (wIndex & 31))) -			status |= 1 << USB_PORT_FEAT_C_SUSPEND; +		status = xhci_get_port_status(hcd, bus_state, port_array, +				wIndex, temp, flags); +		if (status == 0xffffffff) +			goto error; + +		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: +		if (wValue == USB_PORT_FEAT_LINK_STATE) +			link_state = (wIndex & 0xff00) >> 3; +		if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK) +			wake_mask = wIndex & 0xff00; +		/* The MSB of wIndex is the U1/U2 timeout */ +		timeout = (wIndex & 0xff00) >> 8;  		wIndex &= 0xff; -		if (!wIndex || wIndex > ports) +		if (!wIndex || wIndex > max_ports)  			goto error;  		wIndex--; -		addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); -		temp = xhci_readl(xhci, addr); +		temp = readl(port_array[wIndex]); +		if (temp == 0xffffffff) { +			retval = -ENODEV; +			break; +		}  		temp = xhci_port_state_to_neutral(temp); +		/* FIXME: What new port features do we need to support? */  		switch (wValue) {  		case USB_PORT_FEAT_SUSPEND: -			temp = xhci_readl(xhci, addr); +			temp = readl(port_array[wIndex]); +			if ((temp & PORT_PLS_MASK) != XDEV_U0) { +				/* Resume the port to U0 first */ +				xhci_set_link_state(xhci, port_array, wIndex, +							XDEV_U0); +				spin_unlock_irqrestore(&xhci->lock, flags); +				msleep(10); +				spin_lock_irqsave(&xhci->lock, flags); +			}  			/* In spec software should not attempt to suspend  			 * a port unless the port reports that it is in the  			 * enabled (PED = ‘1’,PLS < ‘3’) state.  			 */ +			temp = readl(port_array[wIndex]);  			if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)  				|| (temp & PORT_PLS_MASK) >= XDEV_U3) {  				xhci_warn(xhci, "USB core suspending device " @@ -395,7 +804,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  				goto error;  			} -			slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1); +			slot_id = xhci_find_slot_id_by_port(hcd, xhci, +					wIndex + 1);  			if (!slot_id) {  				xhci_warn(xhci, "slot_id is zero\n");  				goto error; @@ -405,18 +815,76 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			xhci_stop_device(xhci, slot_id, 1);  			spin_lock_irqsave(&xhci->lock, flags); -			temp = xhci_port_state_to_neutral(temp); -			temp &= ~PORT_PLS_MASK; -			temp |= PORT_LINK_STROBE | XDEV_U3; -			xhci_writel(xhci, temp, addr); +			xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3);  			spin_unlock_irqrestore(&xhci->lock, flags);  			msleep(10); /* wait device to enter */  			spin_lock_irqsave(&xhci->lock, flags); -			temp = xhci_readl(xhci, addr); -			xhci->suspended_ports[wIndex >> 5] |= -					1 << (wIndex & (31)); +			temp = readl(port_array[wIndex]); +			bus_state->suspended_ports |= 1 << wIndex; +			break; +		case USB_PORT_FEAT_LINK_STATE: +			temp = readl(port_array[wIndex]); + +			/* Disable port */ +			if (link_state == USB_SS_PORT_LS_SS_DISABLED) { +				xhci_dbg(xhci, "Disable port %d\n", wIndex); +				temp = xhci_port_state_to_neutral(temp); +				/* +				 * Clear all change bits, so that we get a new +				 * connection event. +				 */ +				temp |= PORT_CSC | PORT_PEC | PORT_WRC | +					PORT_OCC | PORT_RC | PORT_PLC | +					PORT_CEC; +				writel(temp | PORT_PE, port_array[wIndex]); +				temp = readl(port_array[wIndex]); +				break; +			} + +			/* Put link in RxDetect (enable port) */ +			if (link_state == USB_SS_PORT_LS_RX_DETECT) { +				xhci_dbg(xhci, "Enable port %d\n", wIndex); +				xhci_set_link_state(xhci, port_array, wIndex, +						link_state); +				temp = readl(port_array[wIndex]); +				break; +			} + +			/* Software should not attempt to set +			 * port link state above '3' (U3) and the port +			 * must be enabled. +			 */ +			if ((temp & PORT_PE) == 0 || +				(link_state > USB_SS_PORT_LS_U3)) { +				xhci_warn(xhci, "Cannot set link state.\n"); +				goto error; +			} + +			if (link_state == USB_SS_PORT_LS_U3) { +				slot_id = xhci_find_slot_id_by_port(hcd, xhci, +						wIndex + 1); +				if (slot_id) { +					/* unlock to execute stop endpoint +					 * commands */ +					spin_unlock_irqrestore(&xhci->lock, +								flags); +					xhci_stop_device(xhci, slot_id, 1); +					spin_lock_irqsave(&xhci->lock, flags); +				} +			} + +			xhci_set_link_state(xhci, port_array, wIndex, +						link_state); + +			spin_unlock_irqrestore(&xhci->lock, flags); +			msleep(20); /* wait device to enter */ +			spin_lock_irqsave(&xhci->lock, flags); + +			temp = readl(port_array[wIndex]); +			if (link_state == USB_SS_PORT_LS_U3) +				bus_state->suspended_ports |= 1 << wIndex;  			break;  		case USB_PORT_FEAT_POWER:  			/* @@ -425,69 +893,96 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			 * However, khubd will ignore the roothub events until  			 * the roothub is registered.  			 */ -			xhci_writel(xhci, temp | PORT_POWER, addr); +			writel(temp | PORT_POWER, port_array[wIndex]); -			temp = xhci_readl(xhci, addr); +			temp = readl(port_array[wIndex]);  			xhci_dbg(xhci, "set port power, actual port %d status  = 0x%x\n", wIndex, temp); + +			spin_unlock_irqrestore(&xhci->lock, flags); +			temp = usb_acpi_power_manageable(hcd->self.root_hub, +					wIndex); +			if (temp) +				usb_acpi_set_power_state(hcd->self.root_hub, +						wIndex, true); +			spin_lock_irqsave(&xhci->lock, flags);  			break;  		case USB_PORT_FEAT_RESET:  			temp = (temp | PORT_RESET); -			xhci_writel(xhci, temp, addr); +			writel(temp, port_array[wIndex]); -			temp = xhci_readl(xhci, addr); +			temp = readl(port_array[wIndex]);  			xhci_dbg(xhci, "set port reset, actual port %d status  = 0x%x\n", wIndex, temp);  			break; +		case USB_PORT_FEAT_REMOTE_WAKE_MASK: +			xhci_set_remote_wake_mask(xhci, port_array, +					wIndex, wake_mask); +			temp = readl(port_array[wIndex]); +			xhci_dbg(xhci, "set port remote wake mask, " +					"actual port %d status  = 0x%x\n", +					wIndex, temp); +			break; +		case USB_PORT_FEAT_BH_PORT_RESET: +			temp |= PORT_WR; +			writel(temp, port_array[wIndex]); + +			temp = readl(port_array[wIndex]); +			break; +		case USB_PORT_FEAT_U1_TIMEOUT: +			if (hcd->speed != HCD_USB3) +				goto error; +			temp = readl(port_array[wIndex] + PORTPMSC); +			temp &= ~PORT_U1_TIMEOUT_MASK; +			temp |= PORT_U1_TIMEOUT(timeout); +			writel(temp, port_array[wIndex] + PORTPMSC); +			break; +		case USB_PORT_FEAT_U2_TIMEOUT: +			if (hcd->speed != HCD_USB3) +				goto error; +			temp = readl(port_array[wIndex] + PORTPMSC); +			temp &= ~PORT_U2_TIMEOUT_MASK; +			temp |= PORT_U2_TIMEOUT(timeout); +			writel(temp, port_array[wIndex] + PORTPMSC); +			break;  		default:  			goto error;  		} -		temp = xhci_readl(xhci, addr); /* unblock any posted writes */ +		/* unblock any posted writes */ +		temp = readl(port_array[wIndex]);  		break;  	case ClearPortFeature: -		if (!wIndex || wIndex > ports) +		if (!wIndex || wIndex > max_ports)  			goto error;  		wIndex--; -		addr = &xhci->op_regs->port_status_base + -			NUM_PORT_REGS*(wIndex & 0xff); -		temp = xhci_readl(xhci, addr); +		temp = readl(port_array[wIndex]); +		if (temp == 0xffffffff) { +			retval = -ENODEV; +			break; +		} +		/* FIXME: What new port features do we need to support? */  		temp = xhci_port_state_to_neutral(temp);  		switch (wValue) {  		case USB_PORT_FEAT_SUSPEND: -			temp = xhci_readl(xhci, addr); +			temp = readl(port_array[wIndex]);  			xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");  			xhci_dbg(xhci, "PORTSC %04x\n", temp);  			if (temp & PORT_RESET)  				goto error; -			if (temp & XDEV_U3) { +			if ((temp & PORT_PLS_MASK) == XDEV_U3) {  				if ((temp & PORT_PE) == 0)  					goto error; -				if (DEV_SUPERSPEED(temp)) { -					temp = xhci_port_state_to_neutral(temp); -					temp &= ~PORT_PLS_MASK; -					temp |= PORT_LINK_STROBE | XDEV_U0; -					xhci_writel(xhci, temp, addr); -					xhci_readl(xhci, addr); -				} else { -					temp = xhci_port_state_to_neutral(temp); -					temp &= ~PORT_PLS_MASK; -					temp |= PORT_LINK_STROBE | XDEV_RESUME; -					xhci_writel(xhci, temp, addr); -					spin_unlock_irqrestore(&xhci->lock, -							       flags); -					msleep(20); -					spin_lock_irqsave(&xhci->lock, flags); - -					temp = xhci_readl(xhci, addr); -					temp = xhci_port_state_to_neutral(temp); -					temp &= ~PORT_PLS_MASK; -					temp |= PORT_LINK_STROBE | XDEV_U0; -					xhci_writel(xhci, temp, addr); -				} -				xhci->port_c_suspend[wIndex >> 5] |= -						1 << (wIndex & 31); +				xhci_set_link_state(xhci, port_array, wIndex, +							XDEV_RESUME); +				spin_unlock_irqrestore(&xhci->lock, flags); +				msleep(20); +				spin_lock_irqsave(&xhci->lock, flags); +				xhci_set_link_state(xhci, port_array, wIndex, +							XDEV_U0);  			} +			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(hcd, xhci, +					wIndex + 1);  			if (!slot_id) {  				xhci_dbg(xhci, "slot_id is zero\n");  				goto error; @@ -495,17 +990,30 @@ 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[wIndex >> 5] &= -					~(1 << (wIndex & 31)); +			bus_state->port_c_suspend &= ~(1 << wIndex);  		case USB_PORT_FEAT_C_RESET: +		case USB_PORT_FEAT_C_BH_PORT_RESET:  		case USB_PORT_FEAT_C_CONNECTION:  		case USB_PORT_FEAT_C_OVER_CURRENT:  		case USB_PORT_FEAT_C_ENABLE: +		case USB_PORT_FEAT_C_PORT_LINK_STATE:  			xhci_clear_port_change_bit(xhci, wValue, wIndex, -					addr, temp); +					port_array[wIndex], temp);  			break;  		case USB_PORT_FEAT_ENABLE: -			xhci_disable_port(xhci, wIndex, addr, temp); +			xhci_disable_port(hcd, xhci, wIndex, +					port_array[wIndex], temp); +			break; +		case USB_PORT_FEAT_POWER: +			writel(temp & ~PORT_POWER, port_array[wIndex]); + +			spin_unlock_irqrestore(&xhci->lock, flags); +			temp = usb_acpi_power_manageable(hcd->self.root_hub, +					wIndex); +			if (temp) +				usb_acpi_set_power_state(hcd->self.root_hub, +						wIndex, false); +			spin_lock_irqsave(&xhci->lock, flags);  			break;  		default:  			goto error; @@ -535,31 +1043,47 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)  	u32 mask;  	int i, retval;  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); -	int ports; -	u32 __iomem *addr; +	int max_ports; +	__le32 __iomem **port_array; +	struct xhci_bus_state *bus_state; +	bool reset_change = false; -	ports = HCS_MAX_PORTS(xhci->hcs_params1); +	max_ports = xhci_get_ports(hcd, &port_array); +	bus_state = &xhci->bus_state[hcd_index(hcd)];  	/* Initial status is no changes */ -	retval = (ports + 8) / 8; +	retval = (max_ports + 8) / 8;  	memset(buf, 0, retval); -	status = 0; -	mask = PORT_CSC | PORT_PEC | PORT_OCC; +	/* +	 * Inform the usbcore about resume-in-progress by returning +	 * a non-zero value even if there are no status changes. +	 */ +	status = bus_state->resuming_ports; + +	mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;  	spin_lock_irqsave(&xhci->lock, flags);  	/* For each port, did anything change?  If so, set that bit in buf. */ -	for (i = 0; i < ports; i++) { -		addr = &xhci->op_regs->port_status_base + -			NUM_PORT_REGS*i; -		temp = xhci_readl(xhci, addr); +	for (i = 0; i < max_ports; i++) { +		temp = readl(port_array[i]); +		if (temp == 0xffffffff) { +			retval = -ENODEV; +			break; +		}  		if ((temp & mask) != 0 || -			(xhci->port_c_suspend[i >> 5] &	1 << (i & 31)) || -			(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;  		} +		if ((temp & PORT_RC)) +			reset_change = true; +	} +	if (!status && !reset_change) { +		xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); +		clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);  	}  	spin_unlock_irqrestore(&xhci->lock, flags);  	return status ? retval : 0; @@ -570,42 +1094,39 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)  int xhci_bus_suspend(struct usb_hcd *hcd)  {  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); -	int port; +	int max_ports, port_index; +	__le32 __iomem **port_array; +	struct xhci_bus_state *bus_state;  	unsigned long flags; -	xhci_dbg(xhci, "suspend root hub\n"); +	max_ports = xhci_get_ports(hcd, &port_array); +	bus_state = &xhci->bus_state[hcd_index(hcd)];  	spin_lock_irqsave(&xhci->lock, flags);  	if (hcd->self.root_hub->do_remote_wakeup) { -		port = HCS_MAX_PORTS(xhci->hcs_params1); -		while (port--) { -			if (xhci->resume_done[port] != 0) { -				spin_unlock_irqrestore(&xhci->lock, flags); -				xhci_dbg(xhci, "suspend failed because " -						"port %d is resuming\n", -						port + 1); -				return -EBUSY; -			} +		if (bus_state->resuming_ports) { +			spin_unlock_irqrestore(&xhci->lock, flags); +			xhci_dbg(xhci, "suspend failed because " +						"a port is resuming\n"); +			return -EBUSY;  		}  	} -	port = HCS_MAX_PORTS(xhci->hcs_params1); -	xhci->bus_suspended = 0; -	while (port--) { +	port_index = max_ports; +	bus_state->bus_suspended = 0; +	while (port_index--) {  		/* suspend the port if the port is not suspended */ -		u32 __iomem *addr;  		u32 t1, t2;  		int slot_id; -		addr = &xhci->op_regs->port_status_base + -			NUM_PORT_REGS * (port & 0xff); -		t1 = xhci_readl(xhci, addr); +		t1 = readl(port_array[port_index]);  		t2 = xhci_port_state_to_neutral(t1);  		if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { -			xhci_dbg(xhci, "port %d not suspended\n", port); -			slot_id = xhci_find_slot_id_by_port(xhci, port + 1); +			xhci_dbg(xhci, "port %d not suspended\n", port_index); +			slot_id = xhci_find_slot_id_by_port(hcd, xhci, +					port_index + 1);  			if (slot_id) {  				spin_unlock_irqrestore(&xhci->lock, flags);  				xhci_stop_device(xhci, slot_id, 1); @@ -613,9 +1134,15 @@ int xhci_bus_suspend(struct usb_hcd *hcd)  			}  			t2 &= ~PORT_PLS_MASK;  			t2 |= PORT_LINK_STROBE | XDEV_U3; -			set_bit(port, &xhci->bus_suspended); +			set_bit(port_index, &bus_state->bus_suspended);  		} -		if (hcd->self.root_hub->do_remote_wakeup) { +		/* USB core sets remote wake mask for USB 3.0 hubs, +		 * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME +		 * is enabled, so also enable remote wake here. +		 */ +		if (hcd->self.root_hub->do_remote_wakeup +				&& device_may_wakeup(hcd->self.controller)) { +  			if (t1 & PORT_CONNECT) {  				t2 |= PORT_WKOC_E | PORT_WKDISC_E;  				t2 &= ~PORT_WKCONN_E; @@ -628,22 +1155,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)  		t1 = xhci_port_state_to_neutral(t1);  		if (t1 != t2) -			xhci_writel(xhci, t2, addr); - -		if (DEV_HIGHSPEED(t1)) { -			/* enable remote wake up for USB 2.0 */ -			u32 __iomem *addr; -			u32 tmp; - -			addr = &xhci->op_regs->port_power_base + -				NUM_PORT_REGS * (port & 0xff); -			tmp = xhci_readl(xhci, addr); -			tmp |= PORT_RWE; -			xhci_writel(xhci, tmp, addr); -		} +			writel(t2, port_array[port_index]);  	}  	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;  } @@ -651,13 +1166,16 @@ int xhci_bus_suspend(struct usb_hcd *hcd)  int xhci_bus_resume(struct usb_hcd *hcd)  {  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); -	int port; +	int max_ports, port_index; +	__le32 __iomem **port_array; +	struct xhci_bus_state *bus_state;  	u32 temp;  	unsigned long flags; -	xhci_dbg(xhci, "resume root hub\n"); +	max_ports = xhci_get_ports(hcd, &port_array); +	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); @@ -667,76 +1185,65 @@ int xhci_bus_resume(struct usb_hcd *hcd)  	}  	/* delay the irqs */ -	temp = xhci_readl(xhci, &xhci->op_regs->command); +	temp = readl(&xhci->op_regs->command);  	temp &= ~CMD_EIE; -	xhci_writel(xhci, temp, &xhci->op_regs->command); +	writel(temp, &xhci->op_regs->command); -	port = HCS_MAX_PORTS(xhci->hcs_params1); -	while (port--) { +	port_index = max_ports; +	while (port_index--) {  		/* Check whether need resume ports. If needed  		   resume port and disable remote wakeup */ -		u32 __iomem *addr;  		u32 temp;  		int slot_id; -		addr = &xhci->op_regs->port_status_base + -			NUM_PORT_REGS * (port & 0xff); -		temp = xhci_readl(xhci, addr); +		temp = readl(port_array[port_index]);  		if (DEV_SUPERSPEED(temp))  			temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);  		else  			temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); -		if (test_bit(port, &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); -				temp &= ~PORT_PLS_MASK; -				temp |= PORT_LINK_STROBE | XDEV_U0; -				xhci_writel(xhci, temp, addr); +				xhci_set_link_state(xhci, port_array, +							port_index, XDEV_U0);  			} else { -				temp = xhci_port_state_to_neutral(temp); -				temp &= ~PORT_PLS_MASK; -				temp |= PORT_LINK_STROBE | XDEV_RESUME; -				xhci_writel(xhci, temp, addr); +				xhci_set_link_state(xhci, port_array, +						port_index, XDEV_RESUME);  				spin_unlock_irqrestore(&xhci->lock, flags);  				msleep(20);  				spin_lock_irqsave(&xhci->lock, flags); -				temp = xhci_readl(xhci, addr); -				temp = xhci_port_state_to_neutral(temp); -				temp &= ~PORT_PLS_MASK; -				temp |= PORT_LINK_STROBE | XDEV_U0; -				xhci_writel(xhci, temp, addr); +				xhci_set_link_state(xhci, port_array, +							port_index, XDEV_U0);  			} -			slot_id = xhci_find_slot_id_by_port(xhci, port + 1); +			/* wait for the port to enter U0 and report port link +			 * state change. +			 */ +			spin_unlock_irqrestore(&xhci->lock, flags); +			msleep(20); +			spin_lock_irqsave(&xhci->lock, flags); + +			/* Clear PLC */ +			xhci_test_and_clear_bit(xhci, port_array, port_index, +						PORT_PLC); + +			slot_id = xhci_find_slot_id_by_port(hcd, +					xhci, port_index + 1);  			if (slot_id)  				xhci_ring_device(xhci, slot_id);  		} else -			xhci_writel(xhci, temp, addr); - -		if (DEV_HIGHSPEED(temp)) { -			/* disable remote wake up for USB 2.0 */ -			u32 __iomem *addr; -			u32 tmp; - -			addr = &xhci->op_regs->port_power_base + -				NUM_PORT_REGS * (port & 0xff); -			tmp = xhci_readl(xhci, addr); -			tmp &= ~PORT_RWE; -			xhci_writel(xhci, tmp, addr); -		} +			writel(temp, port_array[port_index]);  	} -	(void) xhci_readl(xhci, &xhci->op_regs->command); +	(void) readl(&xhci->op_regs->command); -	xhci->next_statechange = jiffies + msecs_to_jiffies(5); -	hcd->state = HC_STATE_RUNNING; +	bus_state->next_statechange = jiffies + msecs_to_jiffies(5);  	/* re-enable irqs */ -	temp = xhci_readl(xhci, &xhci->op_regs->command); +	temp = readl(&xhci->op_regs->command);  	temp |= CMD_EIE; -	xhci_writel(xhci, temp, &xhci->op_regs->command); -	temp = xhci_readl(xhci, &xhci->op_regs->command); +	writel(temp, &xhci->op_regs->command); +	temp = readl(&xhci->op_regs->command);  	spin_unlock_irqrestore(&xhci->lock, flags);  	return 0;  | 
