[kernel] fix ima patch, and add xhci_hcd suspend resume backport

Kyle McMartin kyle at fedoraproject.org
Mon Oct 18 17:40:54 UTC 2010


commit 9ecbc015d1e7cf485bc774f86c5e3362f69fe830
Author: Kyle McMartin <kyle at mcmartin.ca>
Date:   Mon Oct 18 13:40:37 2010 -0400

    fix ima patch, and add xhci_hcd suspend resume backport

 ...to-be-completely-disabled-and-default-off.patch |  268 ++---
 kernel.spec                                        |   13 +-
 xhci_hcd-suspend-resume.patch                      | 1289 ++++++++++++++++++++
 3 files changed, 1368 insertions(+), 202 deletions(-)
---
diff --git a/ima-allow-it-to-be-completely-disabled-and-default-off.patch b/ima-allow-it-to-be-completely-disabled-and-default-off.patch
index 91bdb75..4f8f1f1 100644
--- a/ima-allow-it-to-be-completely-disabled-and-default-off.patch
+++ b/ima-allow-it-to-be-completely-disabled-and-default-off.patch
@@ -1,137 +1,55 @@
-From 6887ac55c66179ecd6191c21cf9c629cb2317ca4 Mon Sep 17 00:00:00 2001
+From 785465d9cffd65b5a69dd2f465d2f7c917713220 Mon Sep 17 00:00:00 2001
 From: Kyle McMartin <kyle at mcmartin.ca>
-Date: Mon, 18 Oct 2010 02:08:35 -0400
-Subject: [PATCH] ima: allow it to be completely disabled (and default to off)
-
-Allow IMA to be entirely disabled, don't even bother calling into
-the provided hooks, and avoid initializing caches.
-
-(A lot of the hooks will test iint_initialized, and so this doubly
- disables them, since the iint cache won't be enabled. But hey, we
- avoid a pointless branch...)
+Date: Mon, 18 Oct 2010 13:30:39 -0400
+Subject: [PATCH] ima: provide a toggle to disable it entirely
 
 Signed-off-by: Kyle McMartin <kyle at redhat.com>
 ---
- include/linux/ima.h               |   66 +++++++++++++++++++++++++++++++++----
- security/integrity/ima/ima_iint.c |   13 +++++--
- security/integrity/ima/ima_main.c |   34 +++++++++++++------
- 3 files changed, 91 insertions(+), 22 deletions(-)
+ security/integrity/ima/ima.h      |    1 +
+ security/integrity/ima/ima_iint.c |    9 +++++++++
+ security/integrity/ima/ima_main.c |   24 +++++++++++++++++++++---
+ 3 files changed, 31 insertions(+), 3 deletions(-)
 
-diff --git a/include/linux/ima.h b/include/linux/ima.h
-index 975837e..2fa456d 100644
---- a/include/linux/ima.h
-+++ b/include/linux/ima.h
-@@ -14,13 +14,65 @@
- struct linux_binprm;
- 
- #ifdef CONFIG_IMA
--extern int ima_bprm_check(struct linux_binprm *bprm);
--extern int ima_inode_alloc(struct inode *inode);
--extern void ima_inode_free(struct inode *inode);
--extern int ima_file_check(struct file *file, int mask);
--extern void ima_file_free(struct file *file);
--extern int ima_file_mmap(struct file *file, unsigned long prot);
--extern void ima_counts_get(struct file *file);
-+
+diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
+index 3fbcd1d..65c3977 100644
+--- a/security/integrity/ima/ima.h
++++ b/security/integrity/ima/ima.h
+@@ -37,6 +37,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
+ /* set during initialization */
+ extern int iint_initialized;
+ extern int ima_initialized;
 +extern int ima_enabled;
-+
-+extern int __ima_bprm_check(struct linux_binprm *bprm);
-+extern int __ima_inode_alloc(struct inode *inode);
-+extern void __ima_inode_free(struct inode *inode);
-+extern int __ima_file_check(struct file *file, int mask);
-+extern void __ima_file_free(struct file *file);
-+extern int __ima_file_mmap(struct file *file, unsigned long prot);
-+extern void __ima_counts_get(struct file *file);
-+
-+static inline int ima_bprm_check(struct linux_binprm *bprm)
-+{
-+	if (ima_enabled)
-+		return __ima_bprm_check(bprm);
-+	return 0;
-+}
-+
-+static inline int ima_inode_alloc(struct inode *inode)
-+{
-+	if (ima_enabled)
-+		return __ima_inode_alloc(inode);
-+	return 0;
-+}
-+
-+static inline void ima_inode_free(struct inode *inode)
-+{
-+	if (ima_enabled)
-+		__ima_inode_free(inode);
-+	return;
-+}
-+
-+static inline int ima_file_check(struct file *file, int mask)
-+{
-+	if (ima_enabled)
-+		return __ima_file_check(file, mask);
-+	return 0;
-+}
-+
-+static inline void ima_file_free(struct file *file)
-+{
-+	if (ima_enabled)
-+		__ima_file_free(file);
-+	return;
-+}
-+
-+static inline int ima_file_mmap(struct file *file, unsigned long prot)
-+{
-+	if (ima_enabled)
-+		return __ima_file_mmap(file, prot);
-+	return 0;
-+}
-+
-+static inline void ima_counts_get(struct file *file)
-+{
-+	if (ima_enabled)
-+		return __ima_counts_get(file);
-+	return;
-+}
+ extern int ima_used_chip;
+ extern char *ima_hash;
  
- #else
- static inline int ima_bprm_check(struct linux_binprm *bprm)
 diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
-index afba4ae..767f026 100644
+index afba4ae..3d191ef 100644
 --- a/security/integrity/ima/ima_iint.c
 +++ b/security/integrity/ima/ima_iint.c
-@@ -46,10 +46,10 @@ out:
- }
- 
- /**
-- * ima_inode_alloc - allocate an iint associated with an inode
-+ * __ima_inode_alloc - allocate an iint associated with an inode
-  * @inode: pointer to the inode
-  */
--int ima_inode_alloc(struct inode *inode)
-+int __ima_inode_alloc(struct inode *inode)
- {
+@@ -54,6 +54,9 @@ int ima_inode_alloc(struct inode *inode)
  	struct ima_iint_cache *iint = NULL;
  	int rc = 0;
-@@ -107,12 +107,12 @@ void iint_rcu_free(struct rcu_head *rcu_head)
- }
  
- /**
-- * ima_inode_free - called on security_inode_free
-+ * __ima_inode_free - called on security_inode_free
-  * @inode: pointer to the inode
-  *
-  * Free the integrity information(iint) associated with an inode.
-  */
--void ima_inode_free(struct inode *inode)
-+void __ima_inode_free(struct inode *inode)
++	if (!ima_enabled)
++		return 0;
++
+ 	iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
+ 	if (!iint)
+ 		return -ENOMEM;
+@@ -116,6 +119,9 @@ void ima_inode_free(struct inode *inode)
  {
  	struct ima_iint_cache *iint;
  
-@@ -139,6 +139,11 @@ static void init_once(void *foo)
++	if (!ima_enabled)
++		return;
++
+ 	spin_lock(&ima_iint_lock);
+ 	iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode);
+ 	spin_unlock(&ima_iint_lock);
+@@ -139,6 +145,9 @@ static void init_once(void *foo)
  
  static int __init ima_iintcache_init(void)
  {
-+	extern int ima_enabled;
-+
 +	if (!ima_enabled)
 +		return 0;
 +
@@ -139,14 +57,14 @@ index afba4ae..767f026 100644
  	    kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
  			      SLAB_PANIC, init_once);
 diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
-index e662b89..92e084c 100644
+index e662b89..6e91905 100644
 --- a/security/integrity/ima/ima_main.c
 +++ b/security/integrity/ima/ima_main.c
 @@ -26,6 +26,7 @@
  #include "ima.h"
  
  int ima_initialized;
-+int ima_enabled = 0;
++int ima_enabled;
  
  char *ima_hash = "sha1";
  static int __init hash_setup(char *str)
@@ -165,102 +83,54 @@ index e662b89..92e084c 100644
  struct ima_imbalance {
  	struct hlist_node node;
  	unsigned long fsmagic;
-@@ -130,7 +139,7 @@ static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
- }
- 
- /*
-- * ima_counts_get - increment file counts
-+ * __ima_counts_get - increment file counts
-  *
-  * Maintain read/write counters for all files, but only
-  * invalidate the PCR for measured files:
-@@ -140,7 +149,7 @@ static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
-  * 	  could result in a file measurement error.
-  *
-  */
--void ima_counts_get(struct file *file)
-+void __ima_counts_get(struct file *file)
- {
- 	struct dentry *dentry = file->f_path.dentry;
- 	struct inode *inode = dentry->d_inode;
-@@ -204,13 +213,13 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
- }
+@@ -148,7 +157,7 @@ void ima_counts_get(struct file *file)
+ 	struct ima_iint_cache *iint;
+ 	int rc;
  
- /**
-- * ima_file_free - called on __fput()
-+ * __ima_file_free - called on __fput()
-  * @file: pointer to file structure being freed
-  *
-  * Flag files that changed, based on i_version;
-  * and decrement the iint readcount/writecount.
-  */
--void ima_file_free(struct file *file)
-+void __ima_file_free(struct file *file)
- {
+-	if (!iint_initialized || !S_ISREG(inode->i_mode))
++	if (!ima_enabled || !iint_initialized || !S_ISREG(inode->i_mode))
+ 		return;
+ 	iint = ima_iint_find_get(inode);
+ 	if (!iint)
+@@ -215,7 +224,7 @@ void ima_file_free(struct file *file)
  	struct inode *inode = file->f_dentry->d_inode;
  	struct ima_iint_cache *iint;
-@@ -255,7 +264,7 @@ out:
- }
  
- /**
-- * ima_file_mmap - based on policy, collect/store measurement.
-+ * __ima_file_mmap - based on policy, collect/store measurement.
-  * @file: pointer to the file to be measured (May be NULL)
-  * @prot: contains the protection that will be applied by the kernel.
-  *
-@@ -265,7 +274,7 @@ out:
-  * Return 0 on success, an error code on failure.
-  * (Based on the results of appraise_measurement().)
-  */
--int ima_file_mmap(struct file *file, unsigned long prot)
-+int __ima_file_mmap(struct file *file, unsigned long prot)
+-	if (!iint_initialized || !S_ISREG(inode->i_mode))
++	if (!ima_enabled || !iint_initialized || !S_ISREG(inode->i_mode))
+ 		return;
+ 	iint = ima_iint_find_get(inode);
+ 	if (!iint)
+@@ -269,7 +278,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
  {
  	int rc;
  
-@@ -278,7 +287,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
- }
- 
- /**
-- * ima_bprm_check - based on policy, collect/store measurement.
-+ * __ima_bprm_check - based on policy, collect/store measurement.
-  * @bprm: contains the linux_binprm structure
-  *
-  * The OS protects against an executable file, already open for write,
-@@ -290,7 +299,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
-  * Return 0 on success, an error code on failure.
-  * (Based on the results of appraise_measurement().)
-  */
--int ima_bprm_check(struct linux_binprm *bprm)
-+int __ima_bprm_check(struct linux_binprm *bprm)
+-	if (!file)
++	if (!ima_enabled || !file)
+ 		return 0;
+ 	if (prot & PROT_EXEC)
+ 		rc = process_measurement(file, file->f_dentry->d_name.name,
+@@ -294,6 +303,9 @@ int ima_bprm_check(struct linux_binprm *bprm)
  {
  	int rc;
  
-@@ -300,7 +309,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
- }
- 
- /**
-- * ima_path_check - based on policy, collect/store measurement.
-+ * __ima_path_check - based on policy, collect/store measurement.
-  * @file: pointer to the file to be measured
-  * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE
-  *
-@@ -309,7 +318,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
-  * Always return 0 and audit dentry_open failures.
-  * (Return code will be based upon measurement appraisal.)
-  */
--int ima_file_check(struct file *file, int mask)
-+int __ima_file_check(struct file *file, int mask)
++	if (!ima_enabled)
++		return 0;
++
+ 	rc = process_measurement(bprm->file, bprm->filename,
+ 				 MAY_EXEC, BPRM_CHECK);
+ 	return 0;
+@@ -313,6 +325,9 @@ int ima_file_check(struct file *file, int mask)
  {
  	int rc;
  
-@@ -318,12 +327,15 @@ int ima_file_check(struct file *file, int mask)
++	if (!ima_enabled)
++		return 0;
++
+ 	rc = process_measurement(file, file->f_dentry->d_name.name,
+ 				 mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
  				 FILE_CHECK);
- 	return 0;
- }
--EXPORT_SYMBOL_GPL(ima_file_check);
-+EXPORT_SYMBOL_GPL(__ima_file_check);
- 
- static int __init init_ima(void)
+@@ -324,6 +339,9 @@ static int __init init_ima(void)
  {
  	int error;
  
diff --git a/kernel.spec b/kernel.spec
index e1faa17..5834a67 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -51,7 +51,7 @@ Summary: The Linux kernel
 # For non-released -rc kernels, this will be prepended with "0.", so
 # for example a 3 here will become 0.3
 #
-%global baserelease 39
+%global baserelease 40
 %global fedora_build %{baserelease}
 
 # base_sublevel is the kernel version we're starting with and patching
@@ -617,6 +617,8 @@ Patch380: linux-2.6-defaults-pci_no_msi.patch
 Patch381: linux-2.6-defaults-pci_use_crs.patch
 Patch383: linux-2.6-defaults-aspm.patch
 
+Patch385: ima-allow-it-to-be-completely-disabled-and-default-off.patch
+
 Patch390: linux-2.6-defaults-acpi-video.patch
 Patch391: linux-2.6-acpi-video-dos.patch
 Patch393: acpi-ec-add-delay-before-write.patch
@@ -727,7 +729,7 @@ Patch12302: pnpacpi-cope-with-invalid-device-ids.patch
 
 Patch12303: dmar-disable-when-ricoh-multifunction.patch
 
-Patch12304: ima-allow-it-to-be-completely-disabled-and-default-off.patch
+Patch12305: xhci_hcd-suspend-resume.patch
 
 %endif
 
@@ -1213,6 +1215,8 @@ ApplyPatch linux-2.6-defaults-pci_use_crs.patch
 # enable ASPM by default on hardware we expect to work
 ApplyPatch linux-2.6-defaults-aspm.patch
 
+ApplyPatch ima-allow-it-to-be-completely-disabled-and-default-off.patch
+
 #
 # SCSI Bits.
 #
@@ -1345,7 +1349,7 @@ ApplyPatch pnpacpi-cope-with-invalid-device-ids.patch
 # rhbz#605888
 ApplyPatch dmar-disable-when-ricoh-multifunction.patch
 
-ApplyPatch ima-allow-it-to-be-completely-disabled-and-default-off.patch
+ApplyPatch xhci_hcd-suspend-resume.patch
 
 # END OF PATCH APPLICATIONS
 
@@ -1954,6 +1958,9 @@ fi
 #                 ||     ||
 
 %changelog
+* Mon Oct 18 2010 Kyle McMartin <kyle at redhat.com> 2.6.36-0.40.rc8.git0
+- Backport xHCI suspend/resume code from linux-next.
+
 * Mon Oct 18 2010 Kyle McMartin <kyle at redhat.com>
 - ima: Default it to off, pass ima=on to enable. Reduce impact of the option
   when disabled.
diff --git a/xhci_hcd-suspend-resume.patch b/xhci_hcd-suspend-resume.patch
new file mode 100644
index 0000000..ffbaeb4
--- /dev/null
+++ b/xhci_hcd-suspend-resume.patch
@@ -0,0 +1,1289 @@
+commit 5e5563661948c57f72cc16b3a0cc5dc205ed4900
+Author: Andiry Xu <andiry.xu at amd.com>
+Date:   Thu Oct 14 07:23:06 2010 -0700
+
+    USB: xHCI: PCI power management implementation
+    
+    This patch implements the PCI suspend/resume.
+    
+    Please refer to xHCI spec for doing the suspend/resume operation.
+    
+    For S3, CSS/SRS in USBCMD is used to save/restore the internal state.
+    However, an error maybe occurs while restoring the internal state.
+    In this case, it means that HC internal state is wrong and HC will be
+    re-initialized.
+    
+    Signed-off-by: Libin Yang <libin.yang at amd.com>
+    Signed-off-by: Dong Nguyen <dong.nguyen at amd.com>
+    Signed-off-by: Andiry Xu <andiry.xu at amd.com>
+    Signed-off-by: Sarah Sharp <sarah.a.sharp at linux.intel.com>
+    Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+
+commit 96520f33d383c9a3ba1ca571cac5fa75325728f5
+Author: Andiry Xu <andiry.xu at amd.com>
+Date:   Thu Oct 14 07:23:03 2010 -0700
+
+    USB: xHCI: bus power management implementation
+    
+    This patch implements xHCI bus suspend/resume function hook.
+    
+    In the patch it goes through all the ports and suspend/resume
+    the ports if needed.
+    
+    If any port is in remote wakeup, abort bus suspend as what ehci/ohci do.
+    
+    Signed-off-by: Libin Yang <libin.yang at amd.com>
+    Signed-off-by: Crane Cai <crane.cai at amd.com>
+    Signed-off-by: Andiry Xu <andiry.xu at amd.com>
+    Signed-off-by: Sarah Sharp <sarah.a.sharp at linux.intel.com>
+    Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+
+commit 7b29198e193ab6f5e8bfcd48c59340b8c7689f5c
+Author: Andiry Xu <andiry.xu at amd.com>
+Date:   Thu Oct 14 07:23:00 2010 -0700
+
+    USB: xHCI: port remote wakeup implementation
+    
+    This commit implements port remote wakeup.
+    
+    When a port is in U3 state and resume signaling is detected from a device,
+    the port transitions to the Resume state, and the xHC generates a Port Status
+    Change Event.
+    
+    For USB3 port, software write a '0' to the PLS field to complete the resume
+    signaling. For USB2 port, the resume should be signaling for at least 20ms,
+    irq handler set a timer for port remote wakeup, and then finishes process in
+    hub_control GetPortStatus.
+    
+    Some codes are borrowed from EHCI code.
+    
+    Signed-off-by: Andiry Xu <andiry.xu at amd.com>
+    Signed-off-by: Sarah Sharp <sarah.a.sharp at linux.intel.com>
+    Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+
+commit 9ada0dec259dfe796a757ff2c9b63a05e6408e5f
+Author: Andiry Xu <andiry.xu at amd.com>
+Date:   Thu Oct 14 07:22:57 2010 -0700
+
+    USB: xHCI: port power management implementation
+    
+    Add software trigger USB device suspend resume function hook.
+    Do port suspend & resume in terms of xHCI spec.
+    
+    Port Suspend:
+    Stop all endpoints via Stop Endpoint Command with Suspend (SP) flag set.
+    Place individual ports into suspend mode by writing '3' for Port Link State
+    (PLS) field into PORTSC register. This can only be done when the port is in
+    Enabled state. When writing, the Port Link State Write Strobe (LWS) bit shall
+    be set to '1'.
+    Allocate an xhci_command and stash it in xhci_virt_device to wait completion for
+    the last Stop Endpoint Command.  Use the Suspend bit in TRB to indicate the Stop
+    Endpoint Command is for port suspend. Based on Sarah's suggestion.
+    
+    Port Resume:
+    Write '0' in PLS field, device will transition to running state.
+    Ring an endpoints' doorbell to restart it.
+    
+    Ref: USB device remote wake need another patch to implement. For details of
+    how USB subsystem do power management, please see:
+        Documentation/usb/power-management.txt
+    
+    Signed-off-by: Crane Cai <crane.cai at amd.com>
+    Signed-off-by: Libin Yang <libin.yang at amd.com>
+    Signed-off-by: Andiry Xu <andiry.xu at amd.com>
+    Signed-off-by: Sarah Sharp <sarah.a.sharp at linux.intel.com>
+    Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+
+ drivers/usb/host/xhci-hub.c  |  424 +++++++++++++++++++++++++++++++++++++++++-
+ drivers/usb/host/xhci-mem.c  |    4 +
+ drivers/usb/host/xhci-pci.c  |   36 ++++-
+ drivers/usb/host/xhci-ring.c |  101 +++++++++-
+ drivers/usb/host/xhci.c      |  212 +++++++++++++++++++++-
+ drivers/usb/host/xhci.h      |   46 +++++-
+ 6 files changed, 805 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
+index a1a7a97..7f2f63c 100644
+--- a/drivers/usb/host/xhci-hub.c
++++ b/drivers/usb/host/xhci-hub.c
+@@ -24,6 +24,10 @@
+ 
+ #include "xhci.h"
+ 
++#define	PORT_WAKE_BITS	(PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)
++#define	PORT_RWC_BITS	(PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
++			 PORT_RC | PORT_PLC | PORT_PE)
++
+ static void xhci_hub_descriptor(struct xhci_hcd *xhci,
+ 		struct usb_hub_descriptor *desc)
+ {
+@@ -123,12 +127,105 @@ static unsigned int xhci_port_speed(unsigned int port_status)
+  * writing a 0 clears the bit and writing a 1 sets the bit (RWS).
+  * For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
+  */
+-static u32 xhci_port_state_to_neutral(u32 state)
++u32 xhci_port_state_to_neutral(u32 state)
+ {
+ 	/* Save read-only status and port state */
+ 	return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
+ }
+ 
++/*
++ * find slot id based on port number.
++ */
++int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port)
++{
++	int slot_id;
++	int i;
++
++	slot_id = 0;
++	for (i = 0; i < MAX_HC_SLOTS; i++) {
++		if (!xhci->devs[i])
++			continue;
++		if (xhci->devs[i]->port == port) {
++			slot_id = i;
++			break;
++		}
++	}
++
++	return slot_id;
++}
++
++/*
++ * Stop device
++ * It issues stop endpoint command for EP 0 to 30. And wait the last command
++ * to complete.
++ * suspend will set to 1, if suspend bit need to set in command.
++ */
++static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
++{
++	struct xhci_virt_device *virt_dev;
++	struct xhci_command *cmd;
++	unsigned long flags;
++	int timeleft;
++	int ret;
++	int i;
++
++	ret = 0;
++	virt_dev = xhci->devs[slot_id];
++	cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
++	if (!cmd) {
++		xhci_dbg(xhci, "Couldn't allocate command structure.\n");
++		return -ENOMEM;
++	}
++
++	spin_lock_irqsave(&xhci->lock, flags);
++	for (i = LAST_EP_INDEX; i > 0; i--) {
++		if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue)
++			xhci_queue_stop_endpoint(xhci, slot_id, i, suspend);
++	}
++	cmd->command_trb = xhci->cmd_ring->enqueue;
++	list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list);
++	xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend);
++	xhci_ring_cmd_db(xhci);
++	spin_unlock_irqrestore(&xhci->lock, flags);
++
++	/* Wait for last stop endpoint command to finish */
++	timeleft = wait_for_completion_interruptible_timeout(
++			cmd->completion,
++			USB_CTRL_SET_TIMEOUT);
++	if (timeleft <= 0) {
++		xhci_warn(xhci, "%s while waiting for stop endpoint command\n",
++				timeleft == 0 ? "Timeout" : "Signal");
++		spin_lock_irqsave(&xhci->lock, flags);
++		/* The timeout might have raced with the event ring handler, so
++		 * only delete from the list if the item isn't poisoned.
++		 */
++		if (cmd->cmd_list.next != LIST_POISON1)
++			list_del(&cmd->cmd_list);
++		spin_unlock_irqrestore(&xhci->lock, flags);
++		ret = -ETIME;
++		goto command_cleanup;
++	}
++
++command_cleanup:
++	xhci_free_command(xhci, cmd);
++	return ret;
++}
++
++/*
++ * Ring device, it rings the all doorbells unconditionally.
++ */
++void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
++{
++	int i;
++
++	for (i = 0; i < LAST_EP_INDEX + 1; i++)
++		if (xhci->devs[slot_id]->eps[i].ring &&
++		    xhci->devs[slot_id]->eps[i].ring->dequeue)
++			xhci_ring_ep_doorbell(xhci, slot_id, i, 0);
++
++	return;
++}
++
+ static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
+ 		u32 __iomem *addr, u32 port_status)
+ {
+@@ -162,6 +259,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
+ 		status = PORT_PEC;
+ 		port_change_bit = "enable/disable";
+ 		break;
++	case USB_PORT_FEAT_C_SUSPEND:
++		status = PORT_PLC;
++		port_change_bit = "suspend/resume";
++		break;
+ 	default:
+ 		/* Should never happen */
+ 		return;
+@@ -179,9 +280,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ 	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+ 	int ports;
+ 	unsigned long flags;
+-	u32 temp, status;
++	u32 temp, temp1, status;
+ 	int retval = 0;
+ 	u32 __iomem *addr;
++	int slot_id;
+ 
+ 	ports = HCS_MAX_PORTS(xhci->hcs_params1);
+ 
+@@ -211,9 +313,49 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ 		if ((temp & PORT_OCC))
+ 			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+ 		/*
+-		 * FIXME ignoring suspend, reset, and USB 2.1/3.0 specific
++		 * FIXME ignoring reset and USB 2.1/3.0 specific
+ 		 * changes
+ 		 */
++		if ((temp & PORT_PLS_MASK) == XDEV_U3
++			&& (temp & PORT_POWER))
++			status |= 1 << USB_PORT_FEAT_SUSPEND;
++		if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
++			if ((temp & PORT_RESET) || !(temp & PORT_PE))
++				goto error;
++			if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies,
++						xhci->resume_done[wIndex])) {
++				xhci_dbg(xhci, "Resume USB2 port %d\n",
++					wIndex + 1);
++				xhci->resume_done[wIndex] = 0;
++				temp1 = xhci_port_state_to_neutral(temp);
++				temp1 &= ~PORT_PLS_MASK;
++				temp1 |= PORT_LINK_STROBE | XDEV_U0;
++				xhci_writel(xhci, temp1, addr);
++
++				xhci_dbg(xhci, "set port %d resume\n",
++					wIndex + 1);
++				slot_id = xhci_find_slot_id_by_port(xhci,
++								 wIndex + 1);
++				if (!slot_id) {
++					xhci_dbg(xhci, "slot_id is zero\n");
++					goto error;
++				}
++				xhci_ring_device(xhci, slot_id);
++				xhci->port_c_suspend[wIndex >> 5] |=
++						1 << (wIndex & 31);
++				xhci->suspended_ports[wIndex >> 5] &=
++						~(1 << (wIndex & 31));
++			}
++		}
++		if ((temp & PORT_PLS_MASK) == XDEV_U0
++			&& (temp & PORT_POWER)
++			&& (xhci->suspended_ports[wIndex >> 5] &
++			    (1 << (wIndex & 31)))) {
++			xhci->suspended_ports[wIndex >> 5] &=
++					~(1 << (wIndex & 31));
++			xhci->port_c_suspend[wIndex >> 5] |=
++					1 << (wIndex & 31);
++		}
+ 		if (temp & PORT_CONNECT) {
+ 			status |= USB_PORT_STAT_CONNECTION;
+ 			status |= xhci_port_speed(temp);
+@@ -226,6 +368,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ 			status |= USB_PORT_STAT_RESET;
+ 		if (temp & PORT_POWER)
+ 			status |= USB_PORT_STAT_POWER;
++		if (xhci->port_c_suspend[wIndex >> 5] & (1 << (wIndex & 31)))
++			status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ 		xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
+ 		put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+ 		break;
+@@ -238,6 +382,42 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ 		temp = xhci_readl(xhci, addr);
+ 		temp = xhci_port_state_to_neutral(temp);
+ 		switch (wValue) {
++		case USB_PORT_FEAT_SUSPEND:
++			temp = xhci_readl(xhci, addr);
++			/* In spec software should not attempt to suspend
++			 * a port unless the port reports that it is in the
++			 * enabled (PED = ‘1’,PLS < ‘3’) state.
++			 */
++			if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
++				|| (temp & PORT_PLS_MASK) >= XDEV_U3) {
++				xhci_warn(xhci, "USB core suspending device "
++					  "not in U0/U1/U2.\n");
++				goto error;
++			}
++
++			slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1);
++			if (!slot_id) {
++				xhci_warn(xhci, "slot_id is zero\n");
++				goto error;
++			}
++			/* unlock to execute stop endpoint commands */
++			spin_unlock_irqrestore(&xhci->lock, flags);
++			xhci_stop_device(xhci, slot_id, 1);
++			spin_lock_irqsave(&xhci->lock, flags);
++
++			temp = xhci_port_state_to_neutral(temp);
++			temp &= ~PORT_PLS_MASK;
++			temp |= PORT_LINK_STROBE | XDEV_U3;
++			xhci_writel(xhci, temp, addr);
++
++			spin_unlock_irqrestore(&xhci->lock, flags);
++			msleep(10); /* wait device to enter */
++			spin_lock_irqsave(&xhci->lock, flags);
++
++			temp = xhci_readl(xhci, addr);
++			xhci->suspended_ports[wIndex >> 5] |=
++					1 << (wIndex & (31));
++			break;
+ 		case USB_PORT_FEAT_POWER:
+ 			/*
+ 			 * Turn on ports, even if there isn't per-port switching.
+@@ -271,6 +451,52 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ 		temp = xhci_readl(xhci, addr);
+ 		temp = xhci_port_state_to_neutral(temp);
+ 		switch (wValue) {
++		case USB_PORT_FEAT_SUSPEND:
++			temp = xhci_readl(xhci, addr);
++			xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
++			xhci_dbg(xhci, "PORTSC %04x\n", temp);
++			if (temp & PORT_RESET)
++				goto error;
++			if (temp & XDEV_U3) {
++				if ((temp & PORT_PE) == 0)
++					goto error;
++				if (DEV_SUPERSPEED(temp)) {
++					temp = xhci_port_state_to_neutral(temp);
++					temp &= ~PORT_PLS_MASK;
++					temp |= PORT_LINK_STROBE | XDEV_U0;
++					xhci_writel(xhci, temp, addr);
++					xhci_readl(xhci, addr);
++				} else {
++					temp = xhci_port_state_to_neutral(temp);
++					temp &= ~PORT_PLS_MASK;
++					temp |= PORT_LINK_STROBE | XDEV_RESUME;
++					xhci_writel(xhci, temp, addr);
++
++					spin_unlock_irqrestore(&xhci->lock,
++							       flags);
++					msleep(20);
++					spin_lock_irqsave(&xhci->lock, flags);
++
++					temp = xhci_readl(xhci, addr);
++					temp = xhci_port_state_to_neutral(temp);
++					temp &= ~PORT_PLS_MASK;
++					temp |= PORT_LINK_STROBE | XDEV_U0;
++					xhci_writel(xhci, temp, addr);
++				}
++				xhci->port_c_suspend[wIndex >> 5] |=
++						1 << (wIndex & 31);
++			}
++
++			slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1);
++			if (!slot_id) {
++				xhci_dbg(xhci, "slot_id is zero\n");
++				goto error;
++			}
++			xhci_ring_device(xhci, slot_id);
++			break;
++		case USB_PORT_FEAT_C_SUSPEND:
++			xhci->port_c_suspend[wIndex >> 5] &=
++					~(1 << (wIndex & 31));
+ 		case USB_PORT_FEAT_C_RESET:
+ 		case USB_PORT_FEAT_C_CONNECTION:
+ 		case USB_PORT_FEAT_C_OVER_CURRENT:
+@@ -306,6 +532,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+ {
+ 	unsigned long flags;
+ 	u32 temp, status;
++	u32 mask;
+ 	int i, retval;
+ 	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+ 	int ports;
+@@ -318,13 +545,18 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+ 	memset(buf, 0, retval);
+ 	status = 0;
+ 
++	mask = PORT_CSC | PORT_PEC | PORT_OCC;
++
+ 	spin_lock_irqsave(&xhci->lock, flags);
+ 	/* For each port, did anything change?  If so, set that bit in buf. */
+ 	for (i = 0; i < ports; i++) {
+ 		addr = &xhci->op_regs->port_status_base +
+ 			NUM_PORT_REGS*i;
+ 		temp = xhci_readl(xhci, addr);
+-		if (temp & (PORT_CSC | PORT_PEC | PORT_OCC)) {
++		if ((temp & mask) != 0 ||
++			(xhci->port_c_suspend[i >> 5] &	1 << (i & 31)) ||
++			(xhci->resume_done[i] && time_after_eq(
++			    jiffies, xhci->resume_done[i]))) {
+ 			buf[(i + 1) / 8] |= 1 << (i + 1) % 8;
+ 			status = 1;
+ 		}
+@@ -332,3 +564,187 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+ 	spin_unlock_irqrestore(&xhci->lock, flags);
+ 	return status ? retval : 0;
+ }
++
++#ifdef CONFIG_PM
++
++int xhci_bus_suspend(struct usb_hcd *hcd)
++{
++	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
++	int port;
++	unsigned long flags;
++
++	xhci_dbg(xhci, "suspend root hub\n");
++
++	spin_lock_irqsave(&xhci->lock, flags);
++
++	if (hcd->self.root_hub->do_remote_wakeup) {
++		port = HCS_MAX_PORTS(xhci->hcs_params1);
++		while (port--) {
++			if (xhci->resume_done[port] != 0) {
++				spin_unlock_irqrestore(&xhci->lock, flags);
++				xhci_dbg(xhci, "suspend failed because "
++						"port %d is resuming\n",
++						port + 1);
++				return -EBUSY;
++			}
++		}
++	}
++
++	port = HCS_MAX_PORTS(xhci->hcs_params1);
++	xhci->bus_suspended = 0;
++	while (port--) {
++		/* suspend the port if the port is not suspended */
++		u32 __iomem *addr;
++		u32 t1, t2;
++		int slot_id;
++
++		addr = &xhci->op_regs->port_status_base +
++			NUM_PORT_REGS * (port & 0xff);
++		t1 = xhci_readl(xhci, addr);
++		t2 = xhci_port_state_to_neutral(t1);
++
++		if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) {
++			xhci_dbg(xhci, "port %d not suspended\n", port);
++			slot_id = xhci_find_slot_id_by_port(xhci, port + 1);
++			if (slot_id) {
++				spin_unlock_irqrestore(&xhci->lock, flags);
++				xhci_stop_device(xhci, slot_id, 1);
++				spin_lock_irqsave(&xhci->lock, flags);
++			}
++			t2 &= ~PORT_PLS_MASK;
++			t2 |= PORT_LINK_STROBE | XDEV_U3;
++			set_bit(port, &xhci->bus_suspended);
++		}
++		if (hcd->self.root_hub->do_remote_wakeup) {
++			if (t1 & PORT_CONNECT) {
++				t2 |= PORT_WKOC_E | PORT_WKDISC_E;
++				t2 &= ~PORT_WKCONN_E;
++			} else {
++				t2 |= PORT_WKOC_E | PORT_WKCONN_E;
++				t2 &= ~PORT_WKDISC_E;
++			}
++		} else
++			t2 &= ~PORT_WAKE_BITS;
++
++		t1 = xhci_port_state_to_neutral(t1);
++		if (t1 != t2)
++			xhci_writel(xhci, t2, addr);
++
++		if (DEV_HIGHSPEED(t1)) {
++			/* enable remote wake up for USB 2.0 */
++			u32 __iomem *addr;
++			u32 tmp;
++
++			addr = &xhci->op_regs->port_power_base +
++				NUM_PORT_REGS * (port & 0xff);
++			tmp = xhci_readl(xhci, addr);
++			tmp |= PORT_RWE;
++			xhci_writel(xhci, tmp, addr);
++		}
++	}
++	hcd->state = HC_STATE_SUSPENDED;
++	xhci->next_statechange = jiffies + msecs_to_jiffies(10);
++	spin_unlock_irqrestore(&xhci->lock, flags);
++	return 0;
++}
++
++int xhci_bus_resume(struct usb_hcd *hcd)
++{
++	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
++	int port;
++	u32 temp;
++	unsigned long flags;
++
++	xhci_dbg(xhci, "resume root hub\n");
++
++	if (time_before(jiffies, xhci->next_statechange))
++		msleep(5);
++
++	spin_lock_irqsave(&xhci->lock, flags);
++	if (!HCD_HW_ACCESSIBLE(hcd)) {
++		spin_unlock_irqrestore(&xhci->lock, flags);
++		return -ESHUTDOWN;
++	}
++
++	/* delay the irqs */
++	temp = xhci_readl(xhci, &xhci->op_regs->command);
++	temp &= ~CMD_EIE;
++	xhci_writel(xhci, temp, &xhci->op_regs->command);
++
++	port = HCS_MAX_PORTS(xhci->hcs_params1);
++	while (port--) {
++		/* Check whether need resume ports. If needed
++		   resume port and disable remote wakeup */
++		u32 __iomem *addr;
++		u32 temp;
++		int slot_id;
++
++		addr = &xhci->op_regs->port_status_base +
++			NUM_PORT_REGS * (port & 0xff);
++		temp = xhci_readl(xhci, addr);
++		if (DEV_SUPERSPEED(temp))
++			temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
++		else
++			temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
++		if (test_bit(port, &xhci->bus_suspended) &&
++		    (temp & PORT_PLS_MASK)) {
++			if (DEV_SUPERSPEED(temp)) {
++				temp = xhci_port_state_to_neutral(temp);
++				temp &= ~PORT_PLS_MASK;
++				temp |= PORT_LINK_STROBE | XDEV_U0;
++				xhci_writel(xhci, temp, addr);
++			} else {
++				temp = xhci_port_state_to_neutral(temp);
++				temp &= ~PORT_PLS_MASK;
++				temp |= PORT_LINK_STROBE | XDEV_RESUME;
++				xhci_writel(xhci, temp, addr);
++
++				spin_unlock_irqrestore(&xhci->lock, flags);
++				msleep(20);
++				spin_lock_irqsave(&xhci->lock, flags);
++
++				temp = xhci_readl(xhci, addr);
++				temp = xhci_port_state_to_neutral(temp);
++				temp &= ~PORT_PLS_MASK;
++				temp |= PORT_LINK_STROBE | XDEV_U0;
++				xhci_writel(xhci, temp, addr);
++			}
++			slot_id = xhci_find_slot_id_by_port(xhci, port + 1);
++			if (slot_id)
++				xhci_ring_device(xhci, slot_id);
++		} else
++			xhci_writel(xhci, temp, addr);
++
++		if (DEV_HIGHSPEED(temp)) {
++			/* disable remote wake up for USB 2.0 */
++			u32 __iomem *addr;
++			u32 tmp;
++
++			addr = &xhci->op_regs->port_power_base +
++				NUM_PORT_REGS * (port & 0xff);
++			tmp = xhci_readl(xhci, addr);
++			tmp &= ~PORT_RWE;
++			xhci_writel(xhci, tmp, addr);
++		}
++	}
++
++	(void) xhci_readl(xhci, &xhci->op_regs->command);
++
++	xhci->next_statechange = jiffies + msecs_to_jiffies(5);
++	hcd->state = HC_STATE_RUNNING;
++	/* re-enable irqs */
++	temp = xhci_readl(xhci, &xhci->op_regs->command);
++	temp |= CMD_EIE;
++	xhci_writel(xhci, temp, &xhci->op_regs->command);
++	temp = xhci_readl(xhci, &xhci->op_regs->command);
++
++	spin_unlock_irqrestore(&xhci->lock, flags);
++	return 0;
++}
++
++#else
++
++#define	xhci_bus_suspend	NULL
++#define	xhci_bus_resume		NULL
++
++#endif
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 4e51343..cef8d81 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -866,6 +866,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
+ 			top_dev = top_dev->parent)
+ 		/* Found device below root hub */;
+ 	slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);
++	dev->port = top_dev->portnum;
+ 	xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum);
+ 
+ 	/* Is this a LS/FS device under a HS hub? */
+@@ -1443,6 +1444,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+ 	scratchpad_free(xhci);
+ 	xhci->page_size = 0;
+ 	xhci->page_shift = 0;
++	xhci->bus_suspended = 0;
+ }
+ 
+ static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
+@@ -1801,6 +1803,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+ 	init_completion(&xhci->addr_dev);
+ 	for (i = 0; i < MAX_HC_SLOTS; ++i)
+ 		xhci->devs[i] = NULL;
++	for (i = 0; i < MAX_HC_PORTS; ++i)
++		xhci->resume_done[i] = 0;
+ 
+ 	if (scratchpad_alloc(xhci, flags))
+ 		goto fail;
+diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
+index f7efe02..e3a5924 100644
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -116,6 +116,30 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
+ 	return xhci_pci_reinit(xhci, pdev);
+ }
+ 
++#ifdef CONFIG_PM
++static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
++{
++	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
++	int	retval = 0;
++
++	if (hcd->state != HC_STATE_SUSPENDED)
++		return -EINVAL;
++
++	retval = xhci_suspend(xhci);
++
++	return retval;
++}
++
++static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
++{
++	struct xhci_hcd		*xhci = hcd_to_xhci(hcd);
++	int			retval = 0;
++
++	retval = xhci_resume(xhci, hibernated);
++	return retval;
++}
++#endif /* CONFIG_PM */
++
+ static const struct hc_driver xhci_pci_hc_driver = {
+ 	.description =		hcd_name,
+ 	.product_desc =		"xHCI Host Controller",
+@@ -132,7 +156,10 @@ static const struct hc_driver xhci_pci_hc_driver = {
+ 	 */
+ 	.reset =		xhci_pci_setup,
+ 	.start =		xhci_run,
+-	/* suspend and resume implemented later */
++#ifdef CONFIG_PM
++	.pci_suspend =          xhci_pci_suspend,
++	.pci_resume =           xhci_pci_resume,
++#endif
+ 	.stop =			xhci_stop,
+ 	.shutdown =		xhci_shutdown,
+ 
+@@ -162,6 +189,8 @@ static const struct hc_driver xhci_pci_hc_driver = {
+ 	/* Root hub support */
+ 	.hub_control =		xhci_hub_control,
+ 	.hub_status_data =	xhci_hub_status_data,
++	.bus_suspend =		xhci_bus_suspend,
++	.bus_resume =		xhci_bus_resume,
+ };
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -186,6 +215,11 @@ static struct pci_driver xhci_pci_driver = {
+ 	/* suspend and resume implemented later */
+ 
+ 	.shutdown = 	usb_hcd_pci_shutdown,
++#ifdef CONFIG_PM_SLEEP
++	.driver = {
++		.pm = &usb_hcd_pci_pm_ops
++	},
++#endif
+ };
+ 
+ int xhci_register_pci(void)
+diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
+index 48e60d1..9f3115e 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -68,6 +68,10 @@
+ #include <linux/slab.h>
+ #include "xhci.h"
+ 
++static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
++		struct xhci_virt_device *virt_dev,
++		struct xhci_event_cmd *event);
++
+ /*
+  * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
+  * address of the TRB.
+@@ -313,7 +317,7 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
+ 	xhci_readl(xhci, &xhci->dba->doorbell[0]);
+ }
+ 
+-static void ring_ep_doorbell(struct xhci_hcd *xhci,
++void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
+ 		unsigned int slot_id,
+ 		unsigned int ep_index,
+ 		unsigned int stream_id)
+@@ -353,7 +357,7 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
+ 	/* A ring has pending URBs if its TD list is not empty */
+ 	if (!(ep->ep_state & EP_HAS_STREAMS)) {
+ 		if (!(list_empty(&ep->ring->td_list)))
+-			ring_ep_doorbell(xhci, slot_id, ep_index, 0);
++			xhci_ring_ep_doorbell(xhci, slot_id, ep_index, 0);
+ 		return;
+ 	}
+ 
+@@ -361,7 +365,8 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
+ 			stream_id++) {
+ 		struct xhci_stream_info *stream_info = ep->stream_info;
+ 		if (!list_empty(&stream_info->stream_rings[stream_id]->td_list))
+-			ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
++			xhci_ring_ep_doorbell(xhci, slot_id, ep_index,
++						stream_id);
+ 	}
+ }
+ 
+@@ -626,10 +631,11 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
+  *     bit cleared) so that the HW will skip over them.
+  */
+ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
+-		union xhci_trb *trb)
++		union xhci_trb *trb, struct xhci_event_cmd *event)
+ {
+ 	unsigned int slot_id;
+ 	unsigned int ep_index;
++	struct xhci_virt_device *virt_dev;
+ 	struct xhci_ring *ep_ring;
+ 	struct xhci_virt_ep *ep;
+ 	struct list_head *entry;
+@@ -638,6 +644,21 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
+ 
+ 	struct xhci_dequeue_state deq_state;
+ 
++	if (unlikely(TRB_TO_SUSPEND_PORT(
++			xhci->cmd_ring->dequeue->generic.field[3]))) {
++		slot_id = TRB_TO_SLOT_ID(
++			xhci->cmd_ring->dequeue->generic.field[3]);
++		virt_dev = xhci->devs[slot_id];
++		if (virt_dev)
++			handle_cmd_in_cmd_wait_list(xhci, virt_dev,
++				event);
++		else
++			xhci_warn(xhci, "Stop endpoint command "
++				"completion for disabled slot %u\n",
++				slot_id);
++		return;
++	}
++
+ 	memset(&deq_state, 0, sizeof(deq_state));
+ 	slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
+ 	ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
+@@ -1091,7 +1112,7 @@ bandwidth_change:
+ 		complete(&xhci->addr_dev);
+ 		break;
+ 	case TRB_TYPE(TRB_STOP_RING):
+-		handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue);
++		handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue, event);
+ 		break;
+ 	case TRB_TYPE(TRB_SET_DEQ):
+ 		handle_set_deq_completion(xhci, event, xhci->cmd_ring->dequeue);
+@@ -1144,17 +1165,72 @@ static void handle_vendor_event(struct xhci_hcd *xhci,
+ static void handle_port_status(struct xhci_hcd *xhci,
+ 		union xhci_trb *event)
+ {
++	struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ 	u32 port_id;
++	u32 temp, temp1;
++	u32 __iomem *addr;
++	int ports;
++	int slot_id;
+ 
+ 	/* Port status change events always have a successful completion code */
+ 	if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
+ 		xhci_warn(xhci, "WARN: xHC returned failed port status event\n");
+ 		xhci->error_bitmask |= 1 << 8;
+ 	}
+-	/* FIXME: core doesn't care about all port link state changes yet */
+ 	port_id = GET_PORT_ID(event->generic.field[0]);
+ 	xhci_dbg(xhci, "Port Status Change Event for port %d\n", port_id);
+ 
++	ports = HCS_MAX_PORTS(xhci->hcs_params1);
++	if ((port_id <= 0) || (port_id > ports)) {
++		xhci_warn(xhci, "Invalid port id %d\n", port_id);
++		goto cleanup;
++	}
++
++	addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS * (port_id - 1);
++	temp = xhci_readl(xhci, addr);
++	if ((temp & PORT_CONNECT) && (hcd->state == HC_STATE_SUSPENDED)) {
++		xhci_dbg(xhci, "resume root hub\n");
++		usb_hcd_resume_root_hub(hcd);
++	}
++
++	if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
++		xhci_dbg(xhci, "port resume event for port %d\n", port_id);
++
++		temp1 = xhci_readl(xhci, &xhci->op_regs->command);
++		if (!(temp1 & CMD_RUN)) {
++			xhci_warn(xhci, "xHC is not running.\n");
++			goto cleanup;
++		}
++
++		if (DEV_SUPERSPEED(temp)) {
++			xhci_dbg(xhci, "resume SS port %d\n", port_id);
++			temp = xhci_port_state_to_neutral(temp);
++			temp &= ~PORT_PLS_MASK;
++			temp |= PORT_LINK_STROBE | XDEV_U0;
++			xhci_writel(xhci, temp, addr);
++			slot_id = xhci_find_slot_id_by_port(xhci, port_id);
++			if (!slot_id) {
++				xhci_dbg(xhci, "slot_id is zero\n");
++				goto cleanup;
++			}
++			xhci_ring_device(xhci, slot_id);
++			xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
++			/* Clear PORT_PLC */
++			temp = xhci_readl(xhci, addr);
++			temp = xhci_port_state_to_neutral(temp);
++			temp |= PORT_PLC;
++			xhci_writel(xhci, temp, addr);
++		} else {
++			xhci_dbg(xhci, "resume HS port %d\n", port_id);
++			xhci->resume_done[port_id - 1] = jiffies +
++				msecs_to_jiffies(20);
++			mod_timer(&hcd->rh_timer,
++				  xhci->resume_done[port_id - 1]);
++			/* Do the rest in GetPortStatus */
++		}
++	}
++
++cleanup:
+ 	/* Update event ring dequeue pointer before dropping the lock */
+ 	inc_deq(xhci, xhci->event_ring, true);
+ 
+@@ -2347,7 +2423,7 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
+ 	 */
+ 	wmb();
+ 	start_trb->field[3] |= start_cycle;
+-	ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
++	xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
+ }
+ 
+ /*
+@@ -2931,7 +3007,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
+ 	wmb();
+ 	start_trb->field[3] |= start_cycle;
+ 
+-	ring_ep_doorbell(xhci, slot_id, ep_index, urb->stream_id);
++	xhci_ring_ep_doorbell(xhci, slot_id, ep_index, urb->stream_id);
+ 	return 0;
+ }
+ 
+@@ -3108,15 +3184,20 @@ int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
+ 			false);
+ }
+ 
++/*
++ * Suspend is set to indicate "Stop Endpoint Command" is being issued to stop
++ * activity on an endpoint that is about to be suspended.
++ */
+ int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
+-		unsigned int ep_index)
++		unsigned int ep_index, int suspend)
+ {
+ 	u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
+ 	u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
+ 	u32 type = TRB_TYPE(TRB_STOP_RING);
++	u32 trb_suspend = SUSPEND_PORT_FOR_TRB(suspend);
+ 
+ 	return queue_command(xhci, 0, 0, 0,
+-			trb_slot_id | trb_ep_index | type, false);
++			trb_slot_id | trb_ep_index | type | trb_suspend, false);
+ }
+ 
+ /* Set Transfer Ring Dequeue Pointer command.
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index d5c550e..34f1b3b 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -551,6 +551,216 @@ void xhci_shutdown(struct usb_hcd *hcd)
+ 		    xhci_readl(xhci, &xhci->op_regs->status));
+ }
+ 
++static void xhci_save_registers(struct xhci_hcd *xhci)
++{
++	xhci->s3.command = xhci_readl(xhci, &xhci->op_regs->command);
++	xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification);
++	xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
++	xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg);
++	xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
++	xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control);
++	xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size);
++	xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
++	xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++}
++
++static void xhci_restore_registers(struct xhci_hcd *xhci)
++{
++	xhci_writel(xhci, xhci->s3.command, &xhci->op_regs->command);
++	xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
++	xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
++	xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg);
++	xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
++	xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control);
++	xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size);
++	xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
++}
++
++/*
++ * Stop HC (not bus-specific)
++ *
++ * This is called when the machine transition into S3/S4 mode.
++ *
++ */
++int xhci_suspend(struct xhci_hcd *xhci)
++{
++	int			rc = 0;
++	struct usb_hcd		*hcd = xhci_to_hcd(xhci);
++	u32			command;
++
++	spin_lock_irq(&xhci->lock);
++	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++	/* step 1: stop endpoint */
++	/* skipped assuming that port suspend has done */
++
++	/* step 2: clear Run/Stop bit */
++	command = xhci_readl(xhci, &xhci->op_regs->command);
++	command &= ~CMD_RUN;
++	xhci_writel(xhci, command, &xhci->op_regs->command);
++	if (handshake(xhci, &xhci->op_regs->status,
++		      STS_HALT, STS_HALT, 100*100)) {
++		xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
++		spin_unlock_irq(&xhci->lock);
++		return -ETIMEDOUT;
++	}
++
++	/* step 3: save registers */
++	xhci_save_registers(xhci);
++
++	/* step 4: set CSS flag */
++	command = xhci_readl(xhci, &xhci->op_regs->command);
++	command |= CMD_CSS;
++	xhci_writel(xhci, command, &xhci->op_regs->command);
++	if (handshake(xhci, &xhci->op_regs->status, STS_SAVE, 0, 10*100)) {
++		xhci_warn(xhci, "WARN: xHC CMD_CSS timeout\n");
++		spin_unlock_irq(&xhci->lock);
++		return -ETIMEDOUT;
++	}
++	/* step 5: remove core well power */
++	xhci_cleanup_msix(xhci);
++	spin_unlock_irq(&xhci->lock);
++
++	return rc;
++}
++
++/*
++ * start xHC (not bus-specific)
++ *
++ * This is called when the machine transition from S3/S4 mode.
++ *
++ */
++int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
++{
++	u32			command, temp = 0;
++	struct usb_hcd		*hcd = xhci_to_hcd(xhci);
++	struct pci_dev		*pdev = to_pci_dev(hcd->self.controller);
++	u64	val_64;
++	int	old_state, retval;
++
++	old_state = hcd->state;
++	if (time_before(jiffies, xhci->next_statechange))
++		msleep(100);
++
++	spin_lock_irq(&xhci->lock);
++
++	if (!hibernated) {
++		/* step 1: restore register */
++		xhci_restore_registers(xhci);
++		/* step 2: initialize command ring buffer */
++		val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
++		val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
++			 (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
++					       xhci->cmd_ring->dequeue) &
++			 (u64) ~CMD_RING_RSVD_BITS) |
++			 xhci->cmd_ring->cycle_state;
++		xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
++				(long unsigned long) val_64);
++		xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
++		/* step 3: restore state and start state*/
++		/* step 3: set CRS flag */
++		command = xhci_readl(xhci, &xhci->op_regs->command);
++		command |= CMD_CRS;
++		xhci_writel(xhci, command, &xhci->op_regs->command);
++		if (handshake(xhci, &xhci->op_regs->status,
++			      STS_RESTORE, 0, 10*100)) {
++			xhci_dbg(xhci, "WARN: xHC CMD_CSS timeout\n");
++			spin_unlock_irq(&xhci->lock);
++			return -ETIMEDOUT;
++		}
++		temp = xhci_readl(xhci, &xhci->op_regs->status);
++	}
++
++	/* If restore operation fails, re-initialize the HC during resume */
++	if ((temp & STS_SRE) || hibernated) {
++		usb_root_hub_lost_power(hcd->self.root_hub);
++
++		xhci_dbg(xhci, "Stop HCD\n");
++		xhci_halt(xhci);
++		xhci_reset(xhci);
++		if (hibernated)
++			xhci_cleanup_msix(xhci);
++		spin_unlock_irq(&xhci->lock);
++
++#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
++		/* Tell the event ring poll function not to reschedule */
++		xhci->zombie = 1;
++		del_timer_sync(&xhci->event_ring_timer);
++#endif
++
++		xhci_dbg(xhci, "// Disabling event ring interrupts\n");
++		temp = xhci_readl(xhci, &xhci->op_regs->status);
++		xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
++		temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
++		xhci_writel(xhci, ER_IRQ_DISABLE(temp),
++				&xhci->ir_set->irq_pending);
++		xhci_print_ir_set(xhci, xhci->ir_set, 0);
++
++		xhci_dbg(xhci, "cleaning up memory\n");
++		xhci_mem_cleanup(xhci);
++		xhci_dbg(xhci, "xhci_stop completed - status = %x\n",
++			    xhci_readl(xhci, &xhci->op_regs->status));
++
++		xhci_dbg(xhci, "Initialize the HCD\n");
++		retval = xhci_init(hcd);
++		if (retval)
++			return retval;
++
++		xhci_dbg(xhci, "Start the HCD\n");
++		retval = xhci_run(hcd);
++		if (!retval)
++			set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++		hcd->state = HC_STATE_SUSPENDED;
++		return retval;
++	}
++
++	/* Re-setup MSI-X */
++	if (hcd->irq)
++		free_irq(hcd->irq, hcd);
++	hcd->irq = -1;
++
++	retval = xhci_setup_msix(xhci);
++	if (retval)
++		/* fall back to msi*/
++		retval = xhci_setup_msi(xhci);
++
++	if (retval) {
++		/* fall back to legacy interrupt*/
++		retval = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
++					hcd->irq_descr, hcd);
++		if (retval) {
++			xhci_err(xhci, "request interrupt %d failed\n",
++					pdev->irq);
++			return retval;
++		}
++		hcd->irq = pdev->irq;
++	}
++
++	/* step 4: set Run/Stop bit */
++	command = xhci_readl(xhci, &xhci->op_regs->command);
++	command |= CMD_RUN;
++	xhci_writel(xhci, command, &xhci->op_regs->command);
++	handshake(xhci, &xhci->op_regs->status, STS_HALT,
++		  0, 250 * 1000);
++
++	/* step 5: walk topology and initialize portsc,
++	 * portpmsc and portli
++	 */
++	/* this is done in bus_resume */
++
++	/* step 6: restart each of the previously
++	 * Running endpoints by ringing their doorbells
++	 */
++
++	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++	if (!hibernated)
++		hcd->state = old_state;
++	else
++		hcd->state = HC_STATE_SUSPENDED;
++
++	spin_unlock_irq(&xhci->lock);
++	return 0;
++}
++
+ /*-------------------------------------------------------------------------*/
+ 
+ /**
+@@ -956,7 +1166,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+ 		ep->stop_cmd_timer.expires = jiffies +
+ 			XHCI_STOP_EP_CMD_TIMEOUT * HZ;
+ 		add_timer(&ep->stop_cmd_timer);
+-		xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index);
++		xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index, 0);
+ 		xhci_ring_cmd_db(xhci);
+ 	}
+ done:
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 34a60d9..b6d8033 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -191,7 +191,7 @@ struct xhci_op_regs {
+ /* bits 4:6 are reserved (and should be preserved on writes). */
+ /* light reset (port status stays unchanged) - reset completed when this is 0 */
+ #define CMD_LRESET	(1 << 7)
+-/* FIXME: ignoring host controller save/restore state for now. */
++/* host controller save/restore state. */
+ #define CMD_CSS		(1 << 8)
+ #define CMD_CRS		(1 << 9)
+ /* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */
+@@ -269,6 +269,10 @@ struct xhci_op_regs {
+  * A read gives the current link PM state of the port,
+  * a write with Link State Write Strobe set sets the link state.
+  */
++#define PORT_PLS_MASK	(0xf << 5)
++#define XDEV_U0		(0x0 << 5)
++#define XDEV_U3		(0x3 << 5)
++#define XDEV_RESUME	(0xf << 5)
+ /* true: port has power (see HCC_PPC) */
+ #define PORT_POWER	(1 << 9)
+ /* bits 10:13 indicate device speed:
+@@ -353,6 +357,8 @@ struct xhci_op_regs {
+ #define PORT_U2_TIMEOUT(p)	(((p) & 0xff) << 8)
+ /* Bits 24:31 for port testing */
+ 
++/* USB2 Protocol PORTSPMSC */
++#define PORT_RWE	(1 << 0x3)
+ 
+ /**
+  * struct xhci_intr_reg - Interrupt Register Set
+@@ -510,6 +516,7 @@ struct xhci_slot_ctx {
+ #define MAX_EXIT	(0xffff)
+ /* Root hub port number that is needed to access the USB device */
+ #define ROOT_HUB_PORT(p)	(((p) & 0xff) << 16)
++#define DEVINFO_TO_ROOT_HUB_PORT(p)	(((p) >> 16) & 0xff)
+ /* Maximum number of ports under a hub device */
+ #define XHCI_MAX_PORTS(p)	(((p) & 0xff) << 24)
+ 
+@@ -751,6 +758,7 @@ struct xhci_virt_device {
+ 	/* Status of the last command issued for this device */
+ 	u32				cmd_status;
+ 	struct list_head		cmd_list;
++	u8				port;
+ };
+ 
+ 
+@@ -881,6 +889,10 @@ struct xhci_event_cmd {
+ #define TRB_TO_EP_INDEX(p)		((((p) & (0x1f << 16)) >> 16) - 1)
+ #define	EP_ID_FOR_TRB(p)		((((p) + 1) & 0x1f) << 16)
+ 
++#define SUSPEND_PORT_FOR_TRB(p)		(((p) & 1) << 23)
++#define TRB_TO_SUSPEND_PORT(p)		(((p) & (1 << 23)) >> 23)
++#define LAST_EP_INDEX			30
++
+ /* Set TR Dequeue Pointer command TRB fields */
+ #define TRB_TO_STREAM_ID(p)		((((p) & (0xffff << 16)) >> 16))
+ #define STREAM_ID_FOR_TRB(p)		((((p)) & 0xffff) << 16)
+@@ -1115,6 +1127,17 @@ struct urb_priv {
+ #define XHCI_STOP_EP_CMD_TIMEOUT	5
+ /* XXX: Make these module parameters */
+ 
++struct s3_save {
++	u32	command;
++	u32	dev_nt;
++	u64	dcbaa_ptr;
++	u32	config_reg;
++	u32	irq_pending;
++	u32	irq_control;
++	u32	erst_size;
++	u64	erst_base;
++	u64	erst_dequeue;
++};
+ 
+ /* There is one ehci_hci structure per controller */
+ struct xhci_hcd {
+@@ -1178,6 +1201,12 @@ struct xhci_hcd {
+ #endif
+ 	/* Host controller watchdog timer structures */
+ 	unsigned int		xhc_state;
++
++	unsigned long		bus_suspended;
++	unsigned long		next_statechange;
++
++	u32			command;
++	struct s3_save		s3;
+ /* Host controller is dying - not responding to commands. "I'm not dead yet!"
+  *
+  * xHC interrupts have been disabled and a watchdog timer will (or has already)
+@@ -1199,6 +1228,10 @@ struct xhci_hcd {
+ #define	XHCI_LINK_TRB_QUIRK	(1 << 0)
+ #define XHCI_RESET_EP_QUIRK	(1 << 1)
+ #define XHCI_NEC_HOST		(1 << 2)
++	u32			port_c_suspend[8];	/* port suspend change*/
++	u32			suspended_ports[8];	/* which ports are
++							   suspended */
++	unsigned long		resume_done[MAX_HC_PORTS];
+ };
+ 
+ /* For testing purposes */
+@@ -1369,6 +1402,8 @@ int xhci_init(struct usb_hcd *hcd);
+ int xhci_run(struct usb_hcd *hcd);
+ void xhci_stop(struct usb_hcd *hcd);
+ void xhci_shutdown(struct usb_hcd *hcd);
++int xhci_suspend(struct xhci_hcd *xhci);
++int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
+ int xhci_get_frame(struct usb_hcd *hcd);
+ irqreturn_t xhci_irq(struct usb_hcd *hcd);
+ irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd);
+@@ -1406,7 +1441,7 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
+ int xhci_queue_vendor_command(struct xhci_hcd *xhci,
+ 		u32 field1, u32 field2, u32 field3, u32 field4);
+ int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
+-		unsigned int ep_index);
++		unsigned int ep_index, int suspend);
+ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
+ 		int slot_id, unsigned int ep_index);
+ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
+@@ -1436,11 +1471,18 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
+ 		unsigned int slot_id, unsigned int ep_index,
+ 		struct xhci_dequeue_state *deq_state);
+ void xhci_stop_endpoint_command_watchdog(unsigned long arg);
++void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
++		unsigned int ep_index, unsigned int stream_id);
+ 
+ /* xHCI roothub code */
+ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
+ 		char *buf, u16 wLength);
+ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
++int xhci_bus_suspend(struct usb_hcd *hcd);
++int xhci_bus_resume(struct usb_hcd *hcd);
++u32 xhci_port_state_to_neutral(u32 state);
++int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port);
++void xhci_ring_device(struct xhci_hcd *xhci, int slot_id);
+ 
+ /* xHCI contexts */
+ struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);


More information about the scm-commits mailing list