10f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp/*
20f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * xHCI host controller driver
30f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp *
40f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * Copyright (C) 2008 Intel Corp.
50f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp *
60f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * Author: Sarah Sharp
70f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * Some code borrowed from the Linux EHCI driver.
80f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp *
90f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * This program is free software; you can redistribute it and/or modify
100f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * it under the terms of the GNU General Public License version 2 as
110f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * published by the Free Software Foundation.
120f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp *
130f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * This program is distributed in the hope that it will be useful, but
140f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
150f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
160f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * for more details.
170f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp *
180f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * You should have received a copy of the GNU General Public License
190f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * along with this program; if not, write to the Free Software Foundation,
200f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
210f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp */
220f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
23ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman
24ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman#include <linux/slab.h>
250f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp#include <asm/unaligned.h>
260f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
270f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp#include "xhci.h"
284bdfe4c38fd5b06da558050a3288a0a48825a3e7Xenia Ragiadakou#include "xhci-trace.h"
290f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
309777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu#define	PORT_WAKE_BITS	(PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)
319777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu#define	PORT_RWC_BITS	(PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
329777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			 PORT_RC | PORT_PLC | PORT_PE)
339777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
343415fc94bba86b397f1fefec3c904bfc57de7038Sebastian Andrzej Siewior/* USB 3.0 BOS descriptor and a capability descriptor, combined */
3548e8236114c12c5366e032fc517e1bd376369a56Sarah Sharpstatic u8 usb_bos_descriptor [] = {
3648e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	USB_DT_BOS_SIZE,		/*  __u8 bLength, 5 bytes */
3748e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	USB_DT_BOS,			/*  __u8 bDescriptorType */
3848e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	0x0F, 0x00,			/*  __le16 wTotalLength, 15 bytes */
3948e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	0x1,				/*  __u8 bNumDeviceCaps */
4048e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	/* First device capability */
4148e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	USB_DT_USB_SS_CAP_SIZE,		/*  __u8 bLength, 10 bytes */
4248e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	USB_DT_DEVICE_CAPABILITY,	/* Device Capability */
4348e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	USB_SS_CAP_TYPE,		/* bDevCapabilityType, SUPERSPEED_USB */
4448e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	0x00,				/* bmAttributes, LTM off by default */
4548e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	USB_5GBPS_OPERATION, 0x00,	/* wSpeedsSupported, 5Gbps only */
4648e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	0x03,				/* bFunctionalitySupport,
4748e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp					   USB 3.0 speed only */
4848e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	0x00,				/* bU1DevExitLat, set later. */
4948e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	0x00, 0x00			/* __le16 bU2DevExitLat, set later. */
5048e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp};
5148e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp
5248e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp
534bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharpstatic void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
544bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		struct usb_hub_descriptor *desc, int ports)
550f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp{
560f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	u16 temp;
570f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
580f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	desc->bPwrOn2PwrGood = 10;	/* xhci section 5.4.9 says 20ms max */
590f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	desc->bHubContrCurrent = 0;
600f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
610f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	desc->bNbrPorts = ports;
620f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	temp = 0;
63c8421147926fcacf53081a36438a0bed394da9f5Aman Deep	/* Bits 1:0 - support per-port power switching, or power always on */
640f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	if (HCC_PPC(xhci->hcc_params))
65c8421147926fcacf53081a36438a0bed394da9f5Aman Deep		temp |= HUB_CHAR_INDV_PORT_LPSM;
660f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	else
67c8421147926fcacf53081a36438a0bed394da9f5Aman Deep		temp |= HUB_CHAR_NO_LPSM;
680f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	/* Bit  2 - root hubs are not part of a compound device */
690f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	/* Bits 4:3 - individual port over current protection */
70c8421147926fcacf53081a36438a0bed394da9f5Aman Deep	temp |= HUB_CHAR_INDV_PORT_OCPM;
710f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	/* Bits 6:5 - no TTs in root ports */
720f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	/* Bit  7 - no port indicators */
7328ccd2962c66556d7037b2d9f1c11cdcd3b805d5Matt Evans	desc->wHubCharacteristics = cpu_to_le16(temp);
740f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp}
750f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
764bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp/* Fill in the USB 2.0 roothub descriptor */
774bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharpstatic void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
784bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		struct usb_hub_descriptor *desc)
794bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp{
804bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	int ports;
814bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	u16 temp;
824bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	__u8 port_removable[(USB_MAXCHILDREN + 1 + 7) / 8];
834bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	u32 portsc;
844bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	unsigned int i;
854bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
864bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	ports = xhci->num_usb2_ports;
874bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
884bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	xhci_common_hub_descriptor(xhci, desc, ports);
89c8421147926fcacf53081a36438a0bed394da9f5Aman Deep	desc->bDescriptorType = USB_DT_HUB;
904bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	temp = 1 + (ports / 8);
91c8421147926fcacf53081a36438a0bed394da9f5Aman Deep	desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp;
924bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
934bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	/* The Device Removable bits are reported on a byte granularity.
944bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 * If the port doesn't exist within that byte, the bit is set to 0.
954bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 */
964bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	memset(port_removable, 0, sizeof(port_removable));
974bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	for (i = 0; i < ports; i++) {
98b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou		portsc = readl(xhci->usb2_ports[i]);
994bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		/* If a device is removable, PORTSC reports a 0, same as in the
1004bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		 * hub descriptor DeviceRemovable bits.
1014bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		 */
1024bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		if (portsc & PORT_DEV_REMOVE)
1034bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp			/* This math is hairy because bit 0 of DeviceRemovable
1044bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp			 * is reserved, and bit 1 is for port 1, etc.
1054bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp			 */
1064bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp			port_removable[(i + 1) / 8] |= 1 << ((i + 1) % 8);
1074bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	}
1084bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
1094bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	/* ch11.h defines a hub descriptor that has room for USB_MAXCHILDREN
1104bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 * ports on it.  The USB 2.0 specification says that there are two
1114bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 * variable length fields at the end of the hub descriptor:
1124bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 * DeviceRemovable and PortPwrCtrlMask.  But since we can have less than
1134bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 * USB_MAXCHILDREN ports, we may need to use the DeviceRemovable array
1144bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 * to set PortPwrCtrlMask bits.  PortPwrCtrlMask must always be set to
1154bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 * 0xFF, so we initialize the both arrays (DeviceRemovable and
1164bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 * PortPwrCtrlMask) to 0xFF.  Then we set the DeviceRemovable for each
1174bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 * set of ports that actually exist.
1184bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 */
1194bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	memset(desc->u.hs.DeviceRemovable, 0xff,
1204bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp			sizeof(desc->u.hs.DeviceRemovable));
1214bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	memset(desc->u.hs.PortPwrCtrlMask, 0xff,
1224bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp			sizeof(desc->u.hs.PortPwrCtrlMask));
1234bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
1244bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	for (i = 0; i < (ports + 1 + 7) / 8; i++)
1254bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		memset(&desc->u.hs.DeviceRemovable[i], port_removable[i],
1264bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp				sizeof(__u8));
1274bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp}
1284bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
1294bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp/* Fill in the USB 3.0 roothub descriptor */
1304bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharpstatic void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
1314bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		struct usb_hub_descriptor *desc)
1324bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp{
1334bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	int ports;
1344bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	u16 port_removable;
1354bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	u32 portsc;
1364bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	unsigned int i;
1374bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
1384bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	ports = xhci->num_usb3_ports;
1394bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	xhci_common_hub_descriptor(xhci, desc, ports);
140c8421147926fcacf53081a36438a0bed394da9f5Aman Deep	desc->bDescriptorType = USB_DT_SS_HUB;
141c8421147926fcacf53081a36438a0bed394da9f5Aman Deep	desc->bDescLength = USB_DT_SS_HUB_SIZE;
1424bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
1434bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	/* header decode latency should be zero for roothubs,
1444bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 * see section 4.23.5.2.
1454bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	 */
1464bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	desc->u.ss.bHubHdrDecLat = 0;
1474bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	desc->u.ss.wHubDelay = 0;
1484bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
1494bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	port_removable = 0;
1504bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	/* bit 0 is reserved, bit 1 is for port 1, etc. */
1514bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	for (i = 0; i < ports; i++) {
152b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou		portsc = readl(xhci->usb3_ports[i]);
1534bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		if (portsc & PORT_DEV_REMOVE)
1544bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp			port_removable |= 1 << (i + 1);
1554bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	}
15627c411c95a8e9ed92be658abf1d63e22873a3a66Lan Tianyu
15727c411c95a8e9ed92be658abf1d63e22873a3a66Lan Tianyu	desc->u.ss.DeviceRemovable = cpu_to_le16(port_removable);
1584bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp}
1594bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
1604bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharpstatic void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
1614bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		struct usb_hub_descriptor *desc)
1624bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp{
1634bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
1644bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	if (hcd->speed == HCD_USB3)
1654bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		xhci_usb3_hub_descriptor(hcd, xhci, desc);
1664bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp	else
1674bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		xhci_usb2_hub_descriptor(hcd, xhci, desc);
1684bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
1694bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp}
1704bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp
1710f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharpstatic unsigned int xhci_port_speed(unsigned int port_status)
1720f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp{
1730f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	if (DEV_LOWSPEED(port_status))
174288ead45fa6637e959015d055304f521cbbc0575Alan Stern		return USB_PORT_STAT_LOW_SPEED;
1750f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	if (DEV_HIGHSPEED(port_status))
176288ead45fa6637e959015d055304f521cbbc0575Alan Stern		return USB_PORT_STAT_HIGH_SPEED;
1770f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	/*
1780f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	 * FIXME: Yes, we should check for full speed, but the core uses that as
1790f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	 * a default in portspeed() in usb/core/hub.c (which is the only place
180288ead45fa6637e959015d055304f521cbbc0575Alan Stern	 * USB_PORT_STAT_*_SPEED is used).
1810f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	 */
1820f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	return 0;
1830f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp}
1840f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
1850f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp/*
1860f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * These bits are Read Only (RO) and should be saved and written to the
1870f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * registers: 0, 3, 10:13, 30
1880f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * connect status, over-current status, port speed, and device removable.
1890f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * connect status and port speed are also sticky - meaning they're in
1900f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * the AUX well and they aren't changed by a hot, warm, or cold reset.
1910f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp */
1920f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp#define	XHCI_PORT_RO	((1<<0) | (1<<3) | (0xf<<10) | (1<<30))
1930f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp/*
1940f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * These bits are RW; writing a 0 clears the bit, writing a 1 sets the bit:
1950f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * bits 5:8, 9, 14:15, 25:27
1960f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * link state, port power, port indicator state, "wake on" enable state
1970f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp */
1980f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp#define XHCI_PORT_RWS	((0xf<<5) | (1<<9) | (0x3<<14) | (0x7<<25))
1990f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp/*
2000f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * These bits are RW; writing a 1 sets the bit, writing a 0 has no effect:
2010f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * bit 4 (port reset)
2020f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp */
2030f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp#define	XHCI_PORT_RW1S	((1<<4))
2040f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp/*
2050f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * These bits are RW; writing a 1 clears the bit, writing a 0 has no effect:
2060f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * bits 1, 17, 18, 19, 20, 21, 22, 23
2070f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * port enable/disable, and
2080f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * change bits: connect, PED, warm port reset changed (reserved zero for USB 2.0 ports),
2090f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * over-current, reset, link state, and L1 change
2100f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp */
2110f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp#define XHCI_PORT_RW1CS	((1<<1) | (0x7f<<17))
2120f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp/*
2130f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * Bit 16 is RW, and writing a '1' to it causes the link state control to be
2140f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * latched in
2150f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp */
2160f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp#define	XHCI_PORT_RW	((1<<16))
2170f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp/*
2180f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * These bits are Reserved Zero (RsvdZ) and zero should be written to them:
2190f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * bits 2, 24, 28:31
2200f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp */
2210f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp#define	XHCI_PORT_RZ	((1<<2) | (1<<24) | (0xf<<28))
2220f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
2230f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp/*
2240f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * Given a port state, this function returns a value that would result in the
2250f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * port being in the same state, if the value was written to the port status
2260f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * control register.
2270f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * Save Read Only (RO) bits and save read/write bits where
2280f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * writing a 0 clears the bit and writing a 1 sets the bit (RWS).
2290f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
2300f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp */
231561925318725a41189a69f36ebe99199b3fb84c4Andiry Xuu32 xhci_port_state_to_neutral(u32 state)
2320f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp{
2330f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	/* Save read-only status and port state */
2340f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
2350f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp}
2360f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
237be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu/*
238be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu * find slot id based on port number.
239f6ff0ac878eb420011fa2448851dd48c3a7e7b31Sarah Sharp * @port: The one-based port number from one of the two split roothubs.
240be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu */
2415233630fcdd6f7d415dcbed264031439cab73f9dSarah Sharpint xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
2425233630fcdd6f7d415dcbed264031439cab73f9dSarah Sharp		u16 port)
243be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu{
244be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	int slot_id;
245be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	int i;
246f6ff0ac878eb420011fa2448851dd48c3a7e7b31Sarah Sharp	enum usb_device_speed speed;
247be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
248be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	slot_id = 0;
249be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	for (i = 0; i < MAX_HC_SLOTS; i++) {
250be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		if (!xhci->devs[i])
251be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			continue;
252f6ff0ac878eb420011fa2448851dd48c3a7e7b31Sarah Sharp		speed = xhci->devs[i]->udev->speed;
253f6ff0ac878eb420011fa2448851dd48c3a7e7b31Sarah Sharp		if (((speed == USB_SPEED_SUPER) == (hcd->speed == HCD_USB3))
254fe30182c2553f491e5dc12074c8e52163d3bfbc7Sarah Sharp				&& xhci->devs[i]->fake_port == port) {
255be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			slot_id = i;
256be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			break;
257be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		}
258be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	}
259be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
260be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	return slot_id;
261be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu}
262be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
263be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu/*
264be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu * Stop device
265be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu * It issues stop endpoint command for EP 0 to 30. And wait the last command
266be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu * to complete.
267be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu * suspend will set to 1, if suspend bit need to set in command.
268be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu */
269be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xustatic int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
270be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu{
271be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	struct xhci_virt_device *virt_dev;
272be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	struct xhci_command *cmd;
273be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	unsigned long flags;
274be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	int ret;
275be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	int i;
276be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
277be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	ret = 0;
278be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	virt_dev = xhci->devs[slot_id];
279be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
280be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	if (!cmd) {
281be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		xhci_dbg(xhci, "Couldn't allocate command structure.\n");
282be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		return -ENOMEM;
283be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	}
284be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
285be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	spin_lock_irqsave(&xhci->lock, flags);
286be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	for (i = LAST_EP_INDEX; i > 0; i--) {
287ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman		if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) {
288ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman			struct xhci_command *command;
289ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman			command = xhci_alloc_command(xhci, false, false,
290be3de32107091c266b00a48265fe7e06233af4f0Mathias Nyman						     GFP_NOWAIT);
291ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman			if (!command) {
292ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman				spin_unlock_irqrestore(&xhci->lock, flags);
293ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman				xhci_free_command(xhci, cmd);
294ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman				return -ENOMEM;
295ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman
296ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman			}
297ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman			xhci_queue_stop_endpoint(xhci, command, slot_id, i,
298ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman						 suspend);
299ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman		}
300be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	}
301ddba5cd0aeff5bbed92ebdf4b1223300b0541e78Mathias Nyman	xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
302be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	xhci_ring_cmd_db(xhci);
303be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	spin_unlock_irqrestore(&xhci->lock, flags);
304be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
305be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	/* Wait for last stop endpoint command to finish */
306c311e391a7efd101250c0e123286709b7e736249Mathias Nyman	wait_for_completion(cmd->completion);
307c311e391a7efd101250c0e123286709b7e736249Mathias Nyman
308c311e391a7efd101250c0e123286709b7e736249Mathias Nyman	if (cmd->status == COMP_CMD_ABORT || cmd->status == COMP_CMD_STOP) {
309c311e391a7efd101250c0e123286709b7e736249Mathias Nyman		xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n");
310be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		ret = -ETIME;
311be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	}
312be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	xhci_free_command(xhci, cmd);
313be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	return ret;
314be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu}
315be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
316be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu/*
317be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu * Ring device, it rings the all doorbells unconditionally.
318be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu */
319561925318725a41189a69f36ebe99199b3fb84c4Andiry Xuvoid xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
320be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu{
321b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede	int i, s;
322b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede	struct xhci_virt_ep *ep;
323b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede
324b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede	for (i = 0; i < LAST_EP_INDEX + 1; i++) {
325b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede		ep = &xhci->devs[slot_id]->eps[i];
326be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
327b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede		if (ep->ep_state & EP_HAS_STREAMS) {
328b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede			for (s = 1; s < ep->stream_info->num_streams; s++)
329b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede				xhci_ring_ep_doorbell(xhci, slot_id, i, s);
330b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede		} else if (ep->ring && ep->ring->dequeue) {
331be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			xhci_ring_ep_doorbell(xhci, slot_id, i, 0);
332b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede		}
333b7f9696bd1b170dbff44b1b374b1473278bd2c53Hans de Goede	}
334be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
335be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	return;
336be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu}
337be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
338f6ff0ac878eb420011fa2448851dd48c3a7e7b31Sarah Sharpstatic void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
33928ccd2962c66556d7037b2d9f1c11cdcd3b805d5Matt Evans		u16 wIndex, __le32 __iomem *addr, u32 port_status)
3406219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp{
3416dd0a3a7e0793dbeae1b951f091025d8cf896cb4Sarah Sharp	/* Don't allow the USB core to disable SuperSpeed ports. */
342f6ff0ac878eb420011fa2448851dd48c3a7e7b31Sarah Sharp	if (hcd->speed == HCD_USB3) {
3436dd0a3a7e0793dbeae1b951f091025d8cf896cb4Sarah Sharp		xhci_dbg(xhci, "Ignoring request to disable "
3446dd0a3a7e0793dbeae1b951f091025d8cf896cb4Sarah Sharp				"SuperSpeed port.\n");
3456dd0a3a7e0793dbeae1b951f091025d8cf896cb4Sarah Sharp		return;
3466dd0a3a7e0793dbeae1b951f091025d8cf896cb4Sarah Sharp	}
3476dd0a3a7e0793dbeae1b951f091025d8cf896cb4Sarah Sharp
3486219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp	/* Write 1 to disable the port */
349204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou	writel(port_status | PORT_PE, addr);
350b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou	port_status = readl(addr);
3516219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp	xhci_dbg(xhci, "disable port, actual port %d status  = 0x%x\n",
3526219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp			wIndex, port_status);
3536219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp}
3546219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp
35534fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharpstatic void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
35628ccd2962c66556d7037b2d9f1c11cdcd3b805d5Matt Evans		u16 wIndex, __le32 __iomem *addr, u32 port_status)
35734fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp{
35834fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp	char *port_change_bit;
35934fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp	u32 status;
36034fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp
36134fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp	switch (wValue) {
36234fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp	case USB_PORT_FEAT_C_RESET:
36334fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		status = PORT_RC;
36434fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		port_change_bit = "reset";
36534fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		break;
366a11496ebf37534177d67222285e8debed7a39788Andiry Xu	case USB_PORT_FEAT_C_BH_PORT_RESET:
367a11496ebf37534177d67222285e8debed7a39788Andiry Xu		status = PORT_WRC;
368a11496ebf37534177d67222285e8debed7a39788Andiry Xu		port_change_bit = "warm(BH) reset";
369a11496ebf37534177d67222285e8debed7a39788Andiry Xu		break;
37034fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp	case USB_PORT_FEAT_C_CONNECTION:
37134fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		status = PORT_CSC;
37234fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		port_change_bit = "connect";
37334fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		break;
37434fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp	case USB_PORT_FEAT_C_OVER_CURRENT:
37534fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		status = PORT_OCC;
37634fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		port_change_bit = "over-current";
37734fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		break;
3786219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp	case USB_PORT_FEAT_C_ENABLE:
3796219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp		status = PORT_PEC;
3806219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp		port_change_bit = "enable/disable";
3816219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp		break;
382be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	case USB_PORT_FEAT_C_SUSPEND:
383be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		status = PORT_PLC;
384be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		port_change_bit = "suspend/resume";
385be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		break;
38685387c0ea3e1cd85ad9d7215917ff5e71ca2aea3Andiry Xu	case USB_PORT_FEAT_C_PORT_LINK_STATE:
38785387c0ea3e1cd85ad9d7215917ff5e71ca2aea3Andiry Xu		status = PORT_PLC;
38885387c0ea3e1cd85ad9d7215917ff5e71ca2aea3Andiry Xu		port_change_bit = "link state";
38985387c0ea3e1cd85ad9d7215917ff5e71ca2aea3Andiry Xu		break;
39034fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp	default:
39134fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		/* Should never happen */
39234fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp		return;
39334fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp	}
39434fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp	/* Change bits are all write 1 to clear */
395204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou	writel(port_status | status, addr);
396b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou	port_status = readl(addr);
39734fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp	xhci_dbg(xhci, "clear port %s change, actual port %d status  = 0x%x\n",
39834fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp			port_change_bit, wIndex, port_status);
39934fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp}
40034fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp
401a0885924326f79e157847010a9aaf49b058b30dchuajun listatic int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
402a0885924326f79e157847010a9aaf49b058b30dchuajun li{
403a0885924326f79e157847010a9aaf49b058b30dchuajun li	int max_ports;
404a0885924326f79e157847010a9aaf49b058b30dchuajun li	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
405a0885924326f79e157847010a9aaf49b058b30dchuajun li
406a0885924326f79e157847010a9aaf49b058b30dchuajun li	if (hcd->speed == HCD_USB3) {
407a0885924326f79e157847010a9aaf49b058b30dchuajun li		max_ports = xhci->num_usb3_ports;
408a0885924326f79e157847010a9aaf49b058b30dchuajun li		*port_array = xhci->usb3_ports;
409a0885924326f79e157847010a9aaf49b058b30dchuajun li	} else {
410a0885924326f79e157847010a9aaf49b058b30dchuajun li		max_ports = xhci->num_usb2_ports;
411a0885924326f79e157847010a9aaf49b058b30dchuajun li		*port_array = xhci->usb2_ports;
412a0885924326f79e157847010a9aaf49b058b30dchuajun li	}
413a0885924326f79e157847010a9aaf49b058b30dchuajun li
414a0885924326f79e157847010a9aaf49b058b30dchuajun li	return max_ports;
415a0885924326f79e157847010a9aaf49b058b30dchuajun li}
416a0885924326f79e157847010a9aaf49b058b30dchuajun li
417c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xuvoid xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
418c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu				int port_id, u32 link_state)
419c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu{
420c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu	u32 temp;
421c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu
422b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou	temp = readl(port_array[port_id]);
423c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu	temp = xhci_port_state_to_neutral(temp);
424c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu	temp &= ~PORT_PLS_MASK;
425c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu	temp |= PORT_LINK_STROBE | link_state;
426204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou	writel(temp, port_array[port_id]);
427c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu}
428c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu
429ed384bd3a8faab3b3e09fd2cab8a7dc95851d771Felipe Balbistatic void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
4304296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		__le32 __iomem **port_array, int port_id, u16 wake_mask)
4314296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp{
4324296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp	u32 temp;
4334296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp
434b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou	temp = readl(port_array[port_id]);
4354296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp	temp = xhci_port_state_to_neutral(temp);
4364296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp
4374296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT)
4384296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		temp |= PORT_WKCONN_E;
4394296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp	else
4404296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		temp &= ~PORT_WKCONN_E;
4414296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp
4424296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT)
4434296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		temp |= PORT_WKDISC_E;
4444296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp	else
4454296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		temp &= ~PORT_WKDISC_E;
4464296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp
4474296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT)
4484296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		temp |= PORT_WKOC_E;
4494296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp	else
4504296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		temp &= ~PORT_WKOC_E;
4514296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp
452204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou	writel(temp, port_array[port_id]);
4534296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp}
4544296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp
455d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu/* Test and clear port RWC bit */
456d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xuvoid xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
457d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu				int port_id, u32 port_bit)
458d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu{
459d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu	u32 temp;
460d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu
461b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou	temp = readl(port_array[port_id]);
462d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu	if (temp & port_bit) {
463d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu		temp = xhci_port_state_to_neutral(temp);
464d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu		temp |= port_bit;
465204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou		writel(temp, port_array[port_id]);
466d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu	}
467d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu}
468d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu
469063ebeb4335312d05bdf6fb4fc0e41500c6c0afbSarah Sharp/* Updates Link Status for USB 2.1 port */
470063ebeb4335312d05bdf6fb4fc0e41500c6c0afbSarah Sharpstatic void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg)
471063ebeb4335312d05bdf6fb4fc0e41500c6c0afbSarah Sharp{
472063ebeb4335312d05bdf6fb4fc0e41500c6c0afbSarah Sharp	if ((status_reg & PORT_PLS_MASK) == XDEV_U2)
473063ebeb4335312d05bdf6fb4fc0e41500c6c0afbSarah Sharp		*status |= USB_PORT_STAT_L1;
474063ebeb4335312d05bdf6fb4fc0e41500c6c0afbSarah Sharp}
475063ebeb4335312d05bdf6fb4fc0e41500c6c0afbSarah Sharp
4768bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon/* Updates Link Status for super Speed port */
47796908589a8b2584b1185f834d365f5cc360e8226Felipe Balbistatic void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
47896908589a8b2584b1185f834d365f5cc360e8226Felipe Balbi		u32 *status, u32 status_reg)
4798bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon{
4808bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	u32 pls = status_reg & PORT_PLS_MASK;
4818bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon
4828bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	/* resume state is a xHCI internal state.
4838bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	 * Do not report it to usb core.
4848bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	 */
4858bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	if (pls == XDEV_RESUME)
4868bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		return;
4878bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon
4888bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	/* When the CAS bit is set then warm reset
4898bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	 * should be performed on port
4908bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	 */
4918bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	if (status_reg & PORT_CAS) {
4928bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		/* The CAS bit can be set while the port is
4938bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		 * in any link state.
4948bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		 * Only roothubs have CAS bit, so we
4958bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		 * pretend to be in compliance mode
4968bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		 * unless we're already in compliance
4978bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		 * or the inactive state.
4988bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		 */
4998bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		if (pls != USB_SS_PORT_LS_COMP_MOD &&
5008bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		    pls != USB_SS_PORT_LS_SS_INACTIVE) {
5018bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon			pls = USB_SS_PORT_LS_COMP_MOD;
5028bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		}
5038bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		/* Return also connection bit -
5048bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		 * hub state machine resets port
5058bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		 * when this bit is set.
5068bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		 */
5078bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon		pls |= USB_PORT_STAT_CONNECTION;
50871c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes	} else {
50971c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		/*
51071c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		 * If CAS bit isn't set but the Port is already at
51171c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		 * Compliance Mode, fake a connection so the USB core
51271c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		 * notices the Compliance state and resets the port.
51371c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		 * This resolves an issue generated by the SN65LVPE502CP
51471c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		 * in which sometimes the port enters compliance mode
51571c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		 * caused by a delay on the host-device negotiation.
51671c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		 */
51796908589a8b2584b1185f834d365f5cc360e8226Felipe Balbi		if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
51896908589a8b2584b1185f834d365f5cc360e8226Felipe Balbi				(pls == USB_SS_PORT_LS_COMP_MOD))
51971c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes			pls |= USB_PORT_STAT_CONNECTION;
5208bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	}
52171c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes
5228bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	/* update status field */
5238bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon	*status |= pls;
5248bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon}
5258bea2bd37df08aaa599aa361a9f8b836ba98e554Stanislaw Ledwon
52671c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes/*
52771c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes * Function for Compliance Mode Quirk.
52871c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes *
52971c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes * This Function verifies if all xhc USB3 ports have entered U0, if so,
53071c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes * the compliance mode timer is deleted. A port won't enter
53171c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes * compliance mode if it has previously entered U0.
53271c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes */
5335f20cf12a63650afe1871c7b2c89ee84ec3c6182Sachin Kamatstatic void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status,
5345f20cf12a63650afe1871c7b2c89ee84ec3c6182Sachin Kamat				    u16 wIndex)
53571c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes{
53671c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes	u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1);
53771c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes	bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0);
53871c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes
53971c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes	if (!(xhci->quirks & XHCI_COMP_MODE_QUIRK))
54071c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		return;
54171c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes
54271c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes	if ((xhci->port_status_u0 != all_ports_seen_u0) && port_in_u0) {
54371c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		xhci->port_status_u0 |= 1 << wIndex;
54471c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		if (xhci->port_status_u0 == all_ports_seen_u0) {
54571c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes			del_timer_sync(&xhci->comp_mode_recovery_timer);
5464bdfe4c38fd5b06da558050a3288a0a48825a3e7Xenia Ragiadakou			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
5474bdfe4c38fd5b06da558050a3288a0a48825a3e7Xenia Ragiadakou				"All USB3 ports have entered U0 already!");
5484bdfe4c38fd5b06da558050a3288a0a48825a3e7Xenia Ragiadakou			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
5494bdfe4c38fd5b06da558050a3288a0a48825a3e7Xenia Ragiadakou				"Compliance Mode Recovery Timer Deleted.");
55071c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes		}
55171c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes	}
55271c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes}
55371c731a296f1b08a3724bd1b514b64f1bda87a23Alexis R. Cortes
554eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp/*
555eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp * Converts a raw xHCI port status into the format that external USB 2.0 or USB
556eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp * 3.0 hubs use.
557eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp *
558eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp * Possible side effects:
559eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp *  - Mark a port as being done with device resume,
560eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp *    and ring the endpoint doorbells.
561eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp *  - Stop the Synopsys redriver Compliance Mode polling.
5628b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp *  - Drop and reacquire the xHCI lock, in order to wait for port resume.
563eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp */
564eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharpstatic u32 xhci_get_port_status(struct usb_hcd *hcd,
565eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		struct xhci_bus_state *bus_state,
566eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		__le32 __iomem **port_array,
5678b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp		u16 wIndex, u32 raw_port_status,
5688b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp		unsigned long flags)
5698b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp	__releases(&xhci->lock)
5708b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp	__acquires(&xhci->lock)
571eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp{
572eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
573eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	u32 status = 0;
574eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	int slot_id;
575eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp
576eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	/* wPortChange bits */
577eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (raw_port_status & PORT_CSC)
578eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status |= USB_PORT_STAT_C_CONNECTION << 16;
579eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (raw_port_status & PORT_PEC)
580eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status |= USB_PORT_STAT_C_ENABLE << 16;
581eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if ((raw_port_status & PORT_OCC))
582eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status |= USB_PORT_STAT_C_OVERCURRENT << 16;
583eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if ((raw_port_status & PORT_RC))
584eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status |= USB_PORT_STAT_C_RESET << 16;
585eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	/* USB3.0 only */
586eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (hcd->speed == HCD_USB3) {
587eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		if ((raw_port_status & PORT_PLC))
588eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			status |= USB_PORT_STAT_C_LINK_STATE << 16;
589eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		if ((raw_port_status & PORT_WRC))
590eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			status |= USB_PORT_STAT_C_BH_RESET << 16;
591eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	}
592eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp
593eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (hcd->speed != HCD_USB3) {
594eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3
595eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp				&& (raw_port_status & PORT_POWER))
596eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			status |= USB_PORT_STAT_SUSPEND;
597eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	}
598eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME &&
599eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			!DEV_SUPERSPEED(raw_port_status)) {
600eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		if ((raw_port_status & PORT_RESET) ||
601eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp				!(raw_port_status & PORT_PE))
602eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			return 0xffffffff;
603eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		if (time_after_eq(jiffies,
604eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp					bus_state->resume_done[wIndex])) {
6058b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp			int time_left;
6068b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp
607eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			xhci_dbg(xhci, "Resume USB2 port %d\n",
608eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp					wIndex + 1);
609eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			bus_state->resume_done[wIndex] = 0;
610eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			clear_bit(wIndex, &bus_state->resuming_ports);
6118b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp
6128b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp			set_bit(wIndex, &bus_state->rexit_ports);
613eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			xhci_set_link_state(xhci, port_array, wIndex,
614eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp					XDEV_U0);
6158b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp
6168b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp			spin_unlock_irqrestore(&xhci->lock, flags);
6178b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp			time_left = wait_for_completion_timeout(
6188b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp					&bus_state->rexit_done[wIndex],
6198b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp					msecs_to_jiffies(
6208b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp						XHCI_MAX_REXIT_TIMEOUT));
6218b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp			spin_lock_irqsave(&xhci->lock, flags);
6228b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp
6238b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp			if (time_left) {
6248b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp				slot_id = xhci_find_slot_id_by_port(hcd,
6258b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp						xhci, wIndex + 1);
6268b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp				if (!slot_id) {
6278b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp					xhci_dbg(xhci, "slot_id is zero\n");
6288b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp					return 0xffffffff;
6298b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp				}
6308b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp				xhci_ring_device(xhci, slot_id);
6318b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp			} else {
632b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou				int port_status = readl(port_array[wIndex]);
6338b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp				xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n",
6348b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp						XHCI_MAX_REXIT_TIMEOUT,
6358b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp						port_status);
6368b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp				status |= USB_PORT_STAT_SUSPEND;
6378b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp				clear_bit(wIndex, &bus_state->rexit_ports);
638eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			}
6398b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp
640eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			bus_state->port_c_suspend |= 1 << wIndex;
641eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			bus_state->suspended_ports &= ~(1 << wIndex);
642eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		} else {
643eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			/*
644eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			 * The resume has been signaling for less than
645eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			 * 20ms. Report the port status as SUSPEND,
646eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			 * let the usbcore check port status again
647eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			 * and clear resume signaling later.
648eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			 */
649eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			status |= USB_PORT_STAT_SUSPEND;
650eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		}
651eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	}
652eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0
653eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			&& (raw_port_status & PORT_POWER)
654eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			&& (bus_state->suspended_ports & (1 << wIndex))) {
655eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		bus_state->suspended_ports &= ~(1 << wIndex);
656eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		if (hcd->speed != HCD_USB3)
657eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			bus_state->port_c_suspend |= 1 << wIndex;
658eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	}
659eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (raw_port_status & PORT_CONNECT) {
660eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status |= USB_PORT_STAT_CONNECTION;
661eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status |= xhci_port_speed(raw_port_status);
662eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	}
663eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (raw_port_status & PORT_PE)
664eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status |= USB_PORT_STAT_ENABLE;
665eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (raw_port_status & PORT_OC)
666eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status |= USB_PORT_STAT_OVERCURRENT;
667eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (raw_port_status & PORT_RESET)
668eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status |= USB_PORT_STAT_RESET;
669eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (raw_port_status & PORT_POWER) {
670eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		if (hcd->speed == HCD_USB3)
671eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			status |= USB_SS_PORT_STAT_POWER;
672eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		else
673eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			status |= USB_PORT_STAT_POWER;
674eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	}
675063ebeb4335312d05bdf6fb4fc0e41500c6c0afbSarah Sharp	/* Update Port Link State */
676eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (hcd->speed == HCD_USB3) {
67796908589a8b2584b1185f834d365f5cc360e8226Felipe Balbi		xhci_hub_report_usb3_link_state(xhci, &status, raw_port_status);
678eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		/*
679eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		 * Verify if all USB3 Ports Have entered U0 already.
680eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		 * Delete Compliance Mode Timer if so.
681eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		 */
682eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex);
683063ebeb4335312d05bdf6fb4fc0e41500c6c0afbSarah Sharp	} else {
684063ebeb4335312d05bdf6fb4fc0e41500c6c0afbSarah Sharp		xhci_hub_report_usb2_link_state(&status, raw_port_status);
685eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	}
686eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	if (bus_state->port_c_suspend & (1 << wIndex))
687eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status |= 1 << USB_PORT_FEAT_C_SUSPEND;
688eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp
689eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp	return status;
690eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp}
691eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp
6920f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharpint xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
6930f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		u16 wIndex, char *buf, u16 wLength)
6940f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp{
6950f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
696a0885924326f79e157847010a9aaf49b058b30dchuajun li	int max_ports;
6970f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	unsigned long flags;
698c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu	u32 temp, status;
6990f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	int retval = 0;
70028ccd2962c66556d7037b2d9f1c11cdcd3b805d5Matt Evans	__le32 __iomem **port_array;
701be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu	int slot_id;
70220b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	struct xhci_bus_state *bus_state;
7032c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu	u16 link_state = 0;
7044296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp	u16 wake_mask = 0;
705797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp	u16 timeout = 0;
7060f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
707a0885924326f79e157847010a9aaf49b058b30dchuajun li	max_ports = xhci_get_ports(hcd, &port_array);
70820b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	bus_state = &xhci->bus_state[hcd_index(hcd)];
7090f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
7100f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	spin_lock_irqsave(&xhci->lock, flags);
7110f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	switch (typeReq) {
7120f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	case GetHubStatus:
7130f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		/* No power source, over-current reported per port */
7140f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		memset(buf, 0, 4);
7150f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		break;
7160f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	case GetHubDescriptor:
7174bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		/* Check to make sure userspace is asking for the USB 3.0 hub
7184bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		 * descriptor for the USB 3.0 roothub.  If not, we stall the
7194bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		 * endpoint, like external hubs do.
7204bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		 */
7214bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		if (hcd->speed == HCD_USB3 &&
7224bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp				(wLength < USB_DT_SS_HUB_SIZE ||
7234bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp				 wValue != (USB_DT_SS_HUB << 8))) {
7244bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp			xhci_dbg(xhci, "Wrong hub descriptor type for "
7254bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp					"USB 3.0 roothub.\n");
7264bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp			goto error;
7274bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		}
728f6ff0ac878eb420011fa2448851dd48c3a7e7b31Sarah Sharp		xhci_hub_descriptor(hcd, xhci,
729f6ff0ac878eb420011fa2448851dd48c3a7e7b31Sarah Sharp				(struct usb_hub_descriptor *) buf);
7300f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		break;
73148e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
73248e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp		if ((wValue & 0xff00) != (USB_DT_BOS << 8))
73348e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp			goto error;
73448e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp
73548e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp		if (hcd->speed != HCD_USB3)
73648e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp			goto error;
73748e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp
738af3a23ef4e5fbaf33f0afdda7d26442f036ba795Sarah Sharp		/* Set the U1 and U2 exit latencies. */
73948e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp		memcpy(buf, &usb_bos_descriptor,
74048e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp				USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE);
74125cd2882e2fc8bd8ed7acaee0ec979f11feda6d7Sarah Sharp		if ((xhci->quirks & XHCI_LPM_SUPPORT)) {
74225cd2882e2fc8bd8ed7acaee0ec979f11feda6d7Sarah Sharp			temp = readl(&xhci->cap_regs->hcs_params3);
74325cd2882e2fc8bd8ed7acaee0ec979f11feda6d7Sarah Sharp			buf[12] = HCS_U1_LATENCY(temp);
74425cd2882e2fc8bd8ed7acaee0ec979f11feda6d7Sarah Sharp			put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
74525cd2882e2fc8bd8ed7acaee0ec979f11feda6d7Sarah Sharp		}
74648e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp
747af3a23ef4e5fbaf33f0afdda7d26442f036ba795Sarah Sharp		/* Indicate whether the host has LTM support. */
748b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou		temp = readl(&xhci->cap_regs->hcc_params);
749af3a23ef4e5fbaf33f0afdda7d26442f036ba795Sarah Sharp		if (HCC_LTC(temp))
750af3a23ef4e5fbaf33f0afdda7d26442f036ba795Sarah Sharp			buf[8] |= USB_LTM_SUPPORT;
751af3a23ef4e5fbaf33f0afdda7d26442f036ba795Sarah Sharp
75248e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp		spin_unlock_irqrestore(&xhci->lock, flags);
75348e8236114c12c5366e032fc517e1bd376369a56Sarah Sharp		return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
7540f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	case GetPortStatus:
755a0885924326f79e157847010a9aaf49b058b30dchuajun li		if (!wIndex || wIndex > max_ports)
7560f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			goto error;
7570f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		wIndex--;
758b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou		temp = readl(port_array[wIndex]);
759f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp		if (temp == 0xffffffff) {
760f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp			retval = -ENODEV;
761f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp			break;
762f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp		}
763eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		status = xhci_get_port_status(hcd, bus_state, port_array,
7648b3d45705e54075cfb9d4212dbca9ea82c85c4b8Sarah Sharp				wIndex, temp, flags);
765eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		if (status == 0xffffffff)
766eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp			goto error;
7670ed9a57e052a3d20df052a2ff12a3b42380867aaAndiry Xu
768eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp		xhci_dbg(xhci, "get port status, actual port %d status  = 0x%x\n",
769eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp				wIndex, temp);
7700f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
771eae5b17621d1053c81bec24e5dd5094bf50b31c6Sarah Sharp
7720f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		put_unaligned(cpu_to_le32(status), (__le32 *) buf);
7730f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		break;
7740f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	case SetPortFeature:
7752c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu		if (wValue == USB_PORT_FEAT_LINK_STATE)
7762c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			link_state = (wIndex & 0xff00) >> 3;
7774296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
7784296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp			wake_mask = wIndex & 0xff00;
779797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp		/* The MSB of wIndex is the U1/U2 timeout */
780797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp		timeout = (wIndex & 0xff00) >> 8;
7810f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		wIndex &= 0xff;
782a0885924326f79e157847010a9aaf49b058b30dchuajun li		if (!wIndex || wIndex > max_ports)
7830f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			goto error;
7840f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		wIndex--;
785b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou		temp = readl(port_array[wIndex]);
786f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp		if (temp == 0xffffffff) {
787f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp			retval = -ENODEV;
788f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp			break;
789f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp		}
7900f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		temp = xhci_port_state_to_neutral(temp);
7914bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		/* FIXME: What new port features do we need to support? */
7920f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		switch (wValue) {
793be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		case USB_PORT_FEAT_SUSPEND:
794b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex]);
79565580b4321eb36f16ae8b5987bfa1bb948fc5112Andiry Xu			if ((temp & PORT_PLS_MASK) != XDEV_U0) {
79665580b4321eb36f16ae8b5987bfa1bb948fc5112Andiry Xu				/* Resume the port to U0 first */
79765580b4321eb36f16ae8b5987bfa1bb948fc5112Andiry Xu				xhci_set_link_state(xhci, port_array, wIndex,
79865580b4321eb36f16ae8b5987bfa1bb948fc5112Andiry Xu							XDEV_U0);
79965580b4321eb36f16ae8b5987bfa1bb948fc5112Andiry Xu				spin_unlock_irqrestore(&xhci->lock, flags);
80065580b4321eb36f16ae8b5987bfa1bb948fc5112Andiry Xu				msleep(10);
80165580b4321eb36f16ae8b5987bfa1bb948fc5112Andiry Xu				spin_lock_irqsave(&xhci->lock, flags);
80265580b4321eb36f16ae8b5987bfa1bb948fc5112Andiry Xu			}
803be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			/* In spec software should not attempt to suspend
804be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			 * a port unless the port reports that it is in the
805be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			 * enabled (PED = ‘1’,PLS < ‘3’) state.
806be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			 */
807b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex]);
808be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
809be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu				|| (temp & PORT_PLS_MASK) >= XDEV_U3) {
810be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu				xhci_warn(xhci, "USB core suspending device "
811be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu					  "not in U0/U1/U2.\n");
812be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu				goto error;
813be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			}
814be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
8155233630fcdd6f7d415dcbed264031439cab73f9dSarah Sharp			slot_id = xhci_find_slot_id_by_port(hcd, xhci,
8165233630fcdd6f7d415dcbed264031439cab73f9dSarah Sharp					wIndex + 1);
817be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			if (!slot_id) {
818be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu				xhci_warn(xhci, "slot_id is zero\n");
819be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu				goto error;
820be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			}
821be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			/* unlock to execute stop endpoint commands */
822be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			spin_unlock_irqrestore(&xhci->lock, flags);
823be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			xhci_stop_device(xhci, slot_id, 1);
824be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			spin_lock_irqsave(&xhci->lock, flags);
825be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
826c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu			xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3);
827be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
828be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			spin_unlock_irqrestore(&xhci->lock, flags);
829be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			msleep(10); /* wait device to enter */
830be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			spin_lock_irqsave(&xhci->lock, flags);
831be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
832b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex]);
83320b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp			bus_state->suspended_ports |= 1 << wIndex;
834be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			break;
8352c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu		case USB_PORT_FEAT_LINK_STATE:
836b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex]);
83741e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp
83841e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp			/* Disable port */
83941e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp			if (link_state == USB_SS_PORT_LS_SS_DISABLED) {
84041e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				xhci_dbg(xhci, "Disable port %d\n", wIndex);
84141e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				temp = xhci_port_state_to_neutral(temp);
84241e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				/*
84341e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				 * Clear all change bits, so that we get a new
84441e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				 * connection event.
84541e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				 */
84641e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				temp |= PORT_CSC | PORT_PEC | PORT_WRC |
84741e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp					PORT_OCC | PORT_RC | PORT_PLC |
84841e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp					PORT_CEC;
849204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou				writel(temp | PORT_PE, port_array[wIndex]);
850b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou				temp = readl(port_array[wIndex]);
85141e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				break;
85241e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp			}
85341e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp
85441e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp			/* Put link in RxDetect (enable port) */
85541e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp			if (link_state == USB_SS_PORT_LS_RX_DETECT) {
85641e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				xhci_dbg(xhci, "Enable port %d\n", wIndex);
85741e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				xhci_set_link_state(xhci, port_array, wIndex,
85841e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp						link_state);
859b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou				temp = readl(port_array[wIndex]);
86041e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				break;
86141e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp			}
86241e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp
8632c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			/* Software should not attempt to set
86441e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp			 * port link state above '3' (U3) and the port
8652c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			 * must be enabled.
8662c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			 */
8672c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			if ((temp & PORT_PE) == 0 ||
86841e7e056cdc662f704fa9262e5c6e213b4ab45ddSarah Sharp				(link_state > USB_SS_PORT_LS_U3)) {
8692c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu				xhci_warn(xhci, "Cannot set link state.\n");
8702c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu				goto error;
8712c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			}
8722c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu
8732c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			if (link_state == USB_SS_PORT_LS_U3) {
8742c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu				slot_id = xhci_find_slot_id_by_port(hcd, xhci,
8752c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu						wIndex + 1);
8762c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu				if (slot_id) {
8772c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu					/* unlock to execute stop endpoint
8782c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu					 * commands */
8792c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu					spin_unlock_irqrestore(&xhci->lock,
8802c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu								flags);
8812c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu					xhci_stop_device(xhci, slot_id, 1);
8822c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu					spin_lock_irqsave(&xhci->lock, flags);
8832c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu				}
8842c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			}
8852c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu
886c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu			xhci_set_link_state(xhci, port_array, wIndex,
887c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu						link_state);
8882c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu
8892c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			spin_unlock_irqrestore(&xhci->lock, flags);
8902c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			msleep(20); /* wait device to enter */
8912c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			spin_lock_irqsave(&xhci->lock, flags);
8922c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu
893b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex]);
8942c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			if (link_state == USB_SS_PORT_LS_U3)
8952c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu				bus_state->suspended_ports |= 1 << wIndex;
8962c44178032b046c4113c40d0d459a0d36e39b920Andiry Xu			break;
8970f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		case USB_PORT_FEAT_POWER:
8980f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			/*
8990f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			 * Turn on ports, even if there isn't per-port switching.
9000f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			 * HC will report connect events even before this is set.
90137ebb54915dc42944f6ae92fe53b9531c3903801Petr Mladek			 * However, hub_wq will ignore the roothub events until
9020f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			 * the roothub is registered.
9030f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			 */
904204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou			writel(temp | PORT_POWER, port_array[wIndex]);
9050f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
906b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex]);
9070f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			xhci_dbg(xhci, "set port power, actual port %d status  = 0x%x\n", wIndex, temp);
908f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu
909170ed807340b4db0a5e010c2e4da43cf5a2c9a29Lan Tianyu			spin_unlock_irqrestore(&xhci->lock, flags);
910f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu			temp = usb_acpi_power_manageable(hcd->self.root_hub,
911f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu					wIndex);
912f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu			if (temp)
913f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu				usb_acpi_set_power_state(hcd->self.root_hub,
914f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu						wIndex, true);
915170ed807340b4db0a5e010c2e4da43cf5a2c9a29Lan Tianyu			spin_lock_irqsave(&xhci->lock, flags);
9160f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			break;
9170f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		case USB_PORT_FEAT_RESET:
9180f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			temp = (temp | PORT_RESET);
919204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou			writel(temp, port_array[wIndex]);
9200f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
921b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex]);
9220f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			xhci_dbg(xhci, "set port reset, actual port %d status  = 0x%x\n", wIndex, temp);
9230f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			break;
9244296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		case USB_PORT_FEAT_REMOTE_WAKE_MASK:
9254296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp			xhci_set_remote_wake_mask(xhci, port_array,
9264296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp					wIndex, wake_mask);
927b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex]);
9284296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp			xhci_dbg(xhci, "set port remote wake mask, "
9294296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp					"actual port %d status  = 0x%x\n",
9304296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp					wIndex, temp);
9314296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp			break;
932a11496ebf37534177d67222285e8debed7a39788Andiry Xu		case USB_PORT_FEAT_BH_PORT_RESET:
933a11496ebf37534177d67222285e8debed7a39788Andiry Xu			temp |= PORT_WR;
934204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou			writel(temp, port_array[wIndex]);
935a11496ebf37534177d67222285e8debed7a39788Andiry Xu
936b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex]);
937a11496ebf37534177d67222285e8debed7a39788Andiry Xu			break;
938797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp		case USB_PORT_FEAT_U1_TIMEOUT:
939797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp			if (hcd->speed != HCD_USB3)
940797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp				goto error;
941b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex] + PORTPMSC);
942797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp			temp &= ~PORT_U1_TIMEOUT_MASK;
943797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp			temp |= PORT_U1_TIMEOUT(timeout);
944204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou			writel(temp, port_array[wIndex] + PORTPMSC);
945797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp			break;
946797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp		case USB_PORT_FEAT_U2_TIMEOUT:
947797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp			if (hcd->speed != HCD_USB3)
948797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp				goto error;
949b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex] + PORTPMSC);
950797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp			temp &= ~PORT_U2_TIMEOUT_MASK;
951797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp			temp |= PORT_U2_TIMEOUT(timeout);
952204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou			writel(temp, port_array[wIndex] + PORTPMSC);
953797b0ca5e6283b4cc0bdeeb0e5915f21522ba85fSarah Sharp			break;
9540f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		default:
9550f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			goto error;
9560f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		}
9575308a91b9fc1a8f94b860c2589b06908a97cba7eSarah Sharp		/* unblock any posted writes */
958b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou		temp = readl(port_array[wIndex]);
9590f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		break;
9600f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	case ClearPortFeature:
961a0885924326f79e157847010a9aaf49b058b30dchuajun li		if (!wIndex || wIndex > max_ports)
9620f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			goto error;
9630f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		wIndex--;
964b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou		temp = readl(port_array[wIndex]);
965f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp		if (temp == 0xffffffff) {
966f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp			retval = -ENODEV;
967f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp			break;
968f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp		}
9694bbb0ace9a3de8392527e3c87926309d541d3b00Sarah Sharp		/* FIXME: What new port features do we need to support? */
9700f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		temp = xhci_port_state_to_neutral(temp);
9710f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		switch (wValue) {
972be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		case USB_PORT_FEAT_SUSPEND:
973b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou			temp = readl(port_array[wIndex]);
974be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
975be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			xhci_dbg(xhci, "PORTSC %04x\n", temp);
976be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			if (temp & PORT_RESET)
977be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu				goto error;
9785ac04bf190e6f8b17238aef179ebd7f2bdfec919Andiry Xu			if ((temp & PORT_PLS_MASK) == XDEV_U3) {
979be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu				if ((temp & PORT_PE) == 0)
980be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu					goto error;
981be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
982c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu				xhci_set_link_state(xhci, port_array, wIndex,
983c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu							XDEV_RESUME);
984c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu				spin_unlock_irqrestore(&xhci->lock, flags);
985a7114230f6bd925f1c734d8ca1c32c93bf956aedAndiry Xu				msleep(20);
986a7114230f6bd925f1c734d8ca1c32c93bf956aedAndiry Xu				spin_lock_irqsave(&xhci->lock, flags);
987c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu				xhci_set_link_state(xhci, port_array, wIndex,
988c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu							XDEV_U0);
989be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			}
990a7114230f6bd925f1c734d8ca1c32c93bf956aedAndiry Xu			bus_state->port_c_suspend |= 1 << wIndex;
991be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu
9925233630fcdd6f7d415dcbed264031439cab73f9dSarah Sharp			slot_id = xhci_find_slot_id_by_port(hcd, xhci,
9935233630fcdd6f7d415dcbed264031439cab73f9dSarah Sharp					wIndex + 1);
994be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			if (!slot_id) {
995be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu				xhci_dbg(xhci, "slot_id is zero\n");
996be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu				goto error;
997be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			}
998be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			xhci_ring_device(xhci, slot_id);
999be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu			break;
1000be88fe4f4dda93e3264a887745123b1e6c4a6845Andiry Xu		case USB_PORT_FEAT_C_SUSPEND:
100120b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp			bus_state->port_c_suspend &= ~(1 << wIndex);
10020f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		case USB_PORT_FEAT_C_RESET:
1003a11496ebf37534177d67222285e8debed7a39788Andiry Xu		case USB_PORT_FEAT_C_BH_PORT_RESET:
10040f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		case USB_PORT_FEAT_C_CONNECTION:
10050f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		case USB_PORT_FEAT_C_OVER_CURRENT:
10066219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp		case USB_PORT_FEAT_C_ENABLE:
100785387c0ea3e1cd85ad9d7215917ff5e71ca2aea3Andiry Xu		case USB_PORT_FEAT_C_PORT_LINK_STATE:
100834fb562a436ca50e13c05e7584c9d62f151052bfSarah Sharp			xhci_clear_port_change_bit(xhci, wValue, wIndex,
10095308a91b9fc1a8f94b860c2589b06908a97cba7eSarah Sharp					port_array[wIndex], temp);
10100f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			break;
10116219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp		case USB_PORT_FEAT_ENABLE:
1012f6ff0ac878eb420011fa2448851dd48c3a7e7b31Sarah Sharp			xhci_disable_port(hcd, xhci, wIndex,
10135308a91b9fc1a8f94b860c2589b06908a97cba7eSarah Sharp					port_array[wIndex], temp);
10146219c047d3fe18dee4916d6898fc94f5a7ffd156Sarah Sharp			break;
1015693d8eb853f62a1341cf59df151b12c053f34e8aLan Tianyu		case USB_PORT_FEAT_POWER:
1016204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou			writel(temp & ~PORT_POWER, port_array[wIndex]);
1017f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu
1018170ed807340b4db0a5e010c2e4da43cf5a2c9a29Lan Tianyu			spin_unlock_irqrestore(&xhci->lock, flags);
1019f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu			temp = usb_acpi_power_manageable(hcd->self.root_hub,
1020f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu					wIndex);
1021f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu			if (temp)
1022f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu				usb_acpi_set_power_state(hcd->self.root_hub,
1023f7ac7787ad361e31a7972e2854ed8dc2eedfac3bLan Tianyu						wIndex, false);
1024170ed807340b4db0a5e010c2e4da43cf5a2c9a29Lan Tianyu			spin_lock_irqsave(&xhci->lock, flags);
1025693d8eb853f62a1341cf59df151b12c053f34e8aLan Tianyu			break;
10260f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		default:
10270f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			goto error;
10280f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		}
10290f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		break;
10300f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	default:
10310f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharperror:
10320f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		/* "stall" on error */
10330f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		retval = -EPIPE;
10340f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	}
10350f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	spin_unlock_irqrestore(&xhci->lock, flags);
10360f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	return retval;
10370f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp}
10380f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
10390f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp/*
10400f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * Returns 0 if the status hasn't changed, or the number of bytes in buf.
10410f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * Ports are 0-indexed from the HCD point of view,
10420f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * and 1-indexed from the USB core pointer of view.
10430f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp *
10440f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * Note that the status change bits will be cleared as soon as a port status
10450f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp * change event is generated, so we use the saved status from that event.
10460f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp */
10470f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharpint xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
10480f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp{
10490f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	unsigned long flags;
10500f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	u32 temp, status;
1051561925318725a41189a69f36ebe99199b3fb84c4Andiry Xu	u32 mask;
10520f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	int i, retval;
10530f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
1054a0885924326f79e157847010a9aaf49b058b30dchuajun li	int max_ports;
105528ccd2962c66556d7037b2d9f1c11cdcd3b805d5Matt Evans	__le32 __iomem **port_array;
105620b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	struct xhci_bus_state *bus_state;
1057c52804a472649b2e5005342308739434cbd51119Sarah Sharp	bool reset_change = false;
10580f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
1059a0885924326f79e157847010a9aaf49b058b30dchuajun li	max_ports = xhci_get_ports(hcd, &port_array);
106020b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	bus_state = &xhci->bus_state[hcd_index(hcd)];
10610f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
10620f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	/* Initial status is no changes */
1063a0885924326f79e157847010a9aaf49b058b30dchuajun li	retval = (max_ports + 8) / 8;
1064419a8e81686b844c9682e8f1721e6795f3264ee6William Gulland	memset(buf, 0, retval);
1065f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu
1066f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu	/*
1067f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu	 * Inform the usbcore about resume-in-progress by returning
1068f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu	 * a non-zero value even if there are no status changes.
1069f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu	 */
1070f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu	status = bus_state->resuming_ports;
10710f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp
107244f4c3ed60fb21e1d2dd98304390ac121e6c7c6dGreg Kroah-Hartman	mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
1073561925318725a41189a69f36ebe99199b3fb84c4Andiry Xu
10740f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	spin_lock_irqsave(&xhci->lock, flags);
10750f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	/* For each port, did anything change?  If so, set that bit in buf. */
1076a0885924326f79e157847010a9aaf49b058b30dchuajun li	for (i = 0; i < max_ports; i++) {
1077b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou		temp = readl(port_array[i]);
1078f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp		if (temp == 0xffffffff) {
1079f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp			retval = -ENODEV;
1080f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp			break;
1081f9de8151877b4f01cc8e124b0e213a6c6c78d970Sarah Sharp		}
1082561925318725a41189a69f36ebe99199b3fb84c4Andiry Xu		if ((temp & mask) != 0 ||
108320b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp			(bus_state->port_c_suspend & 1 << i) ||
108420b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp			(bus_state->resume_done[i] && time_after_eq(
108520b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp			    jiffies, bus_state->resume_done[i]))) {
1086419a8e81686b844c9682e8f1721e6795f3264ee6William Gulland			buf[(i + 1) / 8] |= 1 << (i + 1) % 8;
10870f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp			status = 1;
10880f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp		}
1089c52804a472649b2e5005342308739434cbd51119Sarah Sharp		if ((temp & PORT_RC))
1090c52804a472649b2e5005342308739434cbd51119Sarah Sharp			reset_change = true;
1091c52804a472649b2e5005342308739434cbd51119Sarah Sharp	}
1092c52804a472649b2e5005342308739434cbd51119Sarah Sharp	if (!status && !reset_change) {
1093c52804a472649b2e5005342308739434cbd51119Sarah Sharp		xhci_dbg(xhci, "%s: stopping port polling.\n", __func__);
1094c52804a472649b2e5005342308739434cbd51119Sarah Sharp		clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
10950f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	}
10960f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	spin_unlock_irqrestore(&xhci->lock, flags);
10970f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp	return status ? retval : 0;
10980f2a79300a1471cf92ab43af165ea13555c8b0a5Sarah Sharp}
10999777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
11009777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu#ifdef CONFIG_PM
11019777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
11029777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xuint xhci_bus_suspend(struct usb_hcd *hcd)
11039777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu{
11049777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
1105518e848ea8e2932ce18ce2daef8ad5f55a145f27Sarah Sharp	int max_ports, port_index;
110628ccd2962c66556d7037b2d9f1c11cdcd3b805d5Matt Evans	__le32 __iomem **port_array;
110720b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	struct xhci_bus_state *bus_state;
11089777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	unsigned long flags;
11099777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
1110a0885924326f79e157847010a9aaf49b058b30dchuajun li	max_ports = xhci_get_ports(hcd, &port_array);
111120b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	bus_state = &xhci->bus_state[hcd_index(hcd)];
11129777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
11139777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	spin_lock_irqsave(&xhci->lock, flags);
11149777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
11159777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	if (hcd->self.root_hub->do_remote_wakeup) {
1116f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu		if (bus_state->resuming_ports) {
1117f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu			spin_unlock_irqrestore(&xhci->lock, flags);
1118f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu			xhci_dbg(xhci, "suspend failed because "
1119f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu						"a port is resuming\n");
1120f370b9968a220a3d79d870dd7dee674cc0ff3d10Andiry Xu			return -EBUSY;
11219777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		}
11229777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	}
11239777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
1124518e848ea8e2932ce18ce2daef8ad5f55a145f27Sarah Sharp	port_index = max_ports;
112520b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	bus_state->bus_suspended = 0;
1126518e848ea8e2932ce18ce2daef8ad5f55a145f27Sarah Sharp	while (port_index--) {
11279777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		/* suspend the port if the port is not suspended */
11289777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		u32 t1, t2;
11299777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		int slot_id;
11309777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
1131b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou		t1 = readl(port_array[port_index]);
11329777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		t2 = xhci_port_state_to_neutral(t1);
11339777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
11349777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) {
1135518e848ea8e2932ce18ce2daef8ad5f55a145f27Sarah Sharp			xhci_dbg(xhci, "port %d not suspended\n", port_index);
11365233630fcdd6f7d415dcbed264031439cab73f9dSarah Sharp			slot_id = xhci_find_slot_id_by_port(hcd, xhci,
1137518e848ea8e2932ce18ce2daef8ad5f55a145f27Sarah Sharp					port_index + 1);
11389777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			if (slot_id) {
11399777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				spin_unlock_irqrestore(&xhci->lock, flags);
11409777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				xhci_stop_device(xhci, slot_id, 1);
11419777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				spin_lock_irqsave(&xhci->lock, flags);
11429777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			}
11439777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			t2 &= ~PORT_PLS_MASK;
11449777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			t2 |= PORT_LINK_STROBE | XDEV_U3;
114520b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp			set_bit(port_index, &bus_state->bus_suspended);
11469777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		}
11474296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		/* USB core sets remote wake mask for USB 3.0 hubs,
114884ebc10294a3d7be4c66f51070b7aedbaa24de9bAlan Stern		 * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME
11494296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		 * is enabled, so also enable remote wake here.
11504296c70a5ec316903ef037ed15f154dd3d354ad7Sarah Sharp		 */
11519b41ebd3cf0f68d8cad779d3eeba336f78262e43Lu Baolu		if (hcd->self.root_hub->do_remote_wakeup) {
11529777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			if (t1 & PORT_CONNECT) {
11539777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				t2 |= PORT_WKOC_E | PORT_WKDISC_E;
11549777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				t2 &= ~PORT_WKCONN_E;
11559777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			} else {
11569777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				t2 |= PORT_WKOC_E | PORT_WKCONN_E;
11579777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				t2 &= ~PORT_WKDISC_E;
11589777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			}
11599777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		} else
11609777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			t2 &= ~PORT_WAKE_BITS;
11619777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
11629777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		t1 = xhci_port_state_to_neutral(t1);
11639777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		if (t1 != t2)
1164204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou			writel(t2, port_array[port_index]);
11659777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	}
11669777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	hcd->state = HC_STATE_SUSPENDED;
116720b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
11689777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	spin_unlock_irqrestore(&xhci->lock, flags);
11699777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	return 0;
11709777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu}
11719777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
11729777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xuint xhci_bus_resume(struct usb_hcd *hcd)
11739777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu{
11749777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
1175518e848ea8e2932ce18ce2daef8ad5f55a145f27Sarah Sharp	int max_ports, port_index;
117628ccd2962c66556d7037b2d9f1c11cdcd3b805d5Matt Evans	__le32 __iomem **port_array;
117720b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	struct xhci_bus_state *bus_state;
11789777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	u32 temp;
11799777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	unsigned long flags;
11809777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
1181a0885924326f79e157847010a9aaf49b058b30dchuajun li	max_ports = xhci_get_ports(hcd, &port_array);
118220b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	bus_state = &xhci->bus_state[hcd_index(hcd)];
11839777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
118420b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	if (time_before(jiffies, bus_state->next_statechange))
11859777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		msleep(5);
11869777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
11879777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	spin_lock_irqsave(&xhci->lock, flags);
11889777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	if (!HCD_HW_ACCESSIBLE(hcd)) {
11899777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		spin_unlock_irqrestore(&xhci->lock, flags);
11909777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		return -ESHUTDOWN;
11919777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	}
11929777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
11939777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	/* delay the irqs */
1194b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou	temp = readl(&xhci->op_regs->command);
11959777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	temp &= ~CMD_EIE;
1196204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou	writel(temp, &xhci->op_regs->command);
11979777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
1198518e848ea8e2932ce18ce2daef8ad5f55a145f27Sarah Sharp	port_index = max_ports;
1199518e848ea8e2932ce18ce2daef8ad5f55a145f27Sarah Sharp	while (port_index--) {
12009777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		/* Check whether need resume ports. If needed
12019777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		   resume port and disable remote wakeup */
12029777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		u32 temp;
12039777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		int slot_id;
12049777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
1205b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou		temp = readl(port_array[port_index]);
12069777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		if (DEV_SUPERSPEED(temp))
12079777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
12089777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		else
12099777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
121020b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp		if (test_bit(port_index, &bus_state->bus_suspended) &&
12119777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		    (temp & PORT_PLS_MASK)) {
12129777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			if (DEV_SUPERSPEED(temp)) {
1213c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu				xhci_set_link_state(xhci, port_array,
1214c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu							port_index, XDEV_U0);
12159777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			} else {
1216c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu				xhci_set_link_state(xhci, port_array,
1217c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu						port_index, XDEV_RESUME);
12189777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
12199777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				spin_unlock_irqrestore(&xhci->lock, flags);
12209777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				msleep(20);
12219777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				spin_lock_irqsave(&xhci->lock, flags);
12229777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
1223c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu				xhci_set_link_state(xhci, port_array,
1224c9682dffceb4bb3bdf6df4c0c87c4b887b03f5b7Andiry Xu							port_index, XDEV_U0);
12259777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			}
12264f0871a6c7811a433513c3788a7cce27033bb8b8Andiry Xu			/* wait for the port to enter U0 and report port link
12274f0871a6c7811a433513c3788a7cce27033bb8b8Andiry Xu			 * state change.
12284f0871a6c7811a433513c3788a7cce27033bb8b8Andiry Xu			 */
12294f0871a6c7811a433513c3788a7cce27033bb8b8Andiry Xu			spin_unlock_irqrestore(&xhci->lock, flags);
12304f0871a6c7811a433513c3788a7cce27033bb8b8Andiry Xu			msleep(20);
12314f0871a6c7811a433513c3788a7cce27033bb8b8Andiry Xu			spin_lock_irqsave(&xhci->lock, flags);
12324f0871a6c7811a433513c3788a7cce27033bb8b8Andiry Xu
12334f0871a6c7811a433513c3788a7cce27033bb8b8Andiry Xu			/* Clear PLC */
1234d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu			xhci_test_and_clear_bit(xhci, port_array, port_index,
1235d2f52c9e585bbb1a3c164e02b8dcd0d996c67353Andiry Xu						PORT_PLC);
12364f0871a6c7811a433513c3788a7cce27033bb8b8Andiry Xu
12375233630fcdd6f7d415dcbed264031439cab73f9dSarah Sharp			slot_id = xhci_find_slot_id_by_port(hcd,
12385233630fcdd6f7d415dcbed264031439cab73f9dSarah Sharp					xhci, port_index + 1);
12399777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu			if (slot_id)
12409777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu				xhci_ring_device(xhci, slot_id);
12419777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu		} else
1242204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou			writel(temp, port_array[port_index]);
12439777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	}
12449777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
1245b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou	(void) readl(&xhci->op_regs->command);
12469777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
124720b67cf51fa606442bb343afad0ee1a393a6afb3Sarah Sharp	bus_state->next_statechange = jiffies + msecs_to_jiffies(5);
12489777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	/* re-enable irqs */
1249b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou	temp = readl(&xhci->op_regs->command);
12509777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	temp |= CMD_EIE;
1251204b7793f2a9935e9a08524d0b4bb51b990d518eXenia Ragiadakou	writel(temp, &xhci->op_regs->command);
1252b0ba9720846c980d053b1ffcd766fddfbef95d4cXenia Ragiadakou	temp = readl(&xhci->op_regs->command);
12539777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
12549777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	spin_unlock_irqrestore(&xhci->lock, flags);
12559777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu	return 0;
12569777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu}
12579777e3ce907d4cb5a513902a87ecd03b52499569Andiry Xu
1258436a389096e1feda2c382cad83b6a8d6de8615a0Sarah Sharp#endif	/* CONFIG_PM */
1259