aboutsummaryrefslogtreecommitdiffstats
path: root/usb
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2010-08-02 16:47:04 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-02 16:47:04 -0700
commit24ec1fda011aeaad77e34172651892e704c1076e (patch)
tree9ffb519b3af6b32842a59ce2ef10051426b2aeb1 /usb
parent3e04eb00f19d12ec07922e9a32f049e046f3db4b (diff)
downloadpatches-24ec1fda011aeaad77e34172651892e704c1076e.tar.gz
more patches
Diffstat (limited to 'usb')
-rw-r--r--usb/usb-accept-rndis-configs-if-there-s-no-alternative.patch40
-rw-r--r--usb/usb-add-of_platform-glue-driver-for-fsl-usb-dr-controller.patch261
-rw-r--r--usb/usb-add-usb-2.0-to-ssb-ohci-driver.patch99
-rw-r--r--usb/usb-add-usb-ehci-support-for-mpc5121-soc.patch503
-rw-r--r--usb/usb-add-usb-serial-ssu100-driver.patch749
-rw-r--r--usb/usb-cp210x-add-four-new-device-ids.patch33
-rw-r--r--usb/usb-ehci-fix-remove-of-ehci-debugfs-dir.patch118
-rw-r--r--usb/usb-fix-linux-usb.h-kernel-doc-warnings.patch40
-rw-r--r--usb/usb-fix-stuck-usb-generic-serial-driver.patch62
-rw-r--r--usb/usb-ftdi_sio-device-id-for-navitator.patch53
-rw-r--r--usb/usb-powerpc-fsl_soc.c-remove-fsl-usb-platform-code.patch198
-rw-r--r--usb/usb-usb-storage-implement-autosuspend.patch67
-rw-r--r--usb/usb-usbtest-avoid-to-free-coherent-buffer-in-atomic-context.patch84
-rw-r--r--usb/usb-usbtest-support-test-device-with-only-one-iso-in-or-iso-out-endpoint.patch42
-rw-r--r--usb/usb-xhci-don-t-flush-doorbell-writes.patch39
-rw-r--r--usb/usb-xhci-make-xhci_handle_event-static.patch41
-rw-r--r--usb/usb-xhci-make-xhci_set_hc_event_deq-static.patch96
-rw-r--r--usb/usb-xhci-minimize-hw-event-ring-dequeue-pointer-writes.patch128
-rw-r--r--usb/usb-xhci-performance-move-functions-that-find-ep-ring.patch204
-rw-r--r--usb/usb-xhci-performance-move-interrupt-handlers-into-xhci-ring.c.patch268
-rw-r--r--usb/usb-xhci-performance-move-xhci_work-into-xhci_irq.patch115
-rw-r--r--usb/usb-xhci-reduce-reads-and-writes-of-interrupter-registers.patch83
-rw-r--r--usb/usb-xhci-remove-unnecessary-reads-of-irq_pending-register.patch95
-rw-r--r--usb/usb-xhci-set-dma-mask-for-host.patch49
24 files changed, 2505 insertions, 962 deletions
diff --git a/usb/usb-accept-rndis-configs-if-there-s-no-alternative.patch b/usb/usb-accept-rndis-configs-if-there-s-no-alternative.patch
new file mode 100644
index 00000000000000..bf94191771ec64
--- /dev/null
+++ b/usb/usb-accept-rndis-configs-if-there-s-no-alternative.patch
@@ -0,0 +1,40 @@
+From stern+4c5c36d6@rowland.harvard.edu Tue Jul 27 10:13:11 2010
+Date: Tue, 27 Jul 2010 11:28:42 -0400 (EDT)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: Greg KH <greg@kroah.com>
+cc: Adam Kropelin <akropel1@rochester.rr.com>
+Subject: USB: accept RNDIS configs if there's no alternative
+Message-ID: <Pine.LNX.4.44L0.1007271126520.1768-100000@iolanthe.rowland.org>
+
+This patch (as1410) makes a slight change to the strategy used for
+choosing a default configuration. Currently we skip configs whose
+first interface is RNDIS, if the kernel wasn't built with the
+corresponding driver. This risks losing access to the other
+interfaces in those configs. In addition, if there is only one config
+then we will end up not configuring the device at all.
+
+This changes the logic; now such configurations will be skipped only
+if there is at least one other config.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Tested-by: Adam Kropelin <akropel1@rochester.rr.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/generic.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/core/generic.c
++++ b/drivers/usb/core/generic.c
+@@ -105,8 +105,10 @@ int usb_choose_configuration(struct usb_
+ /* When the first config's first interface is one of Microsoft's
+ * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+ * this kernel has enabled the necessary host side driver.
++ * But: Don't ignore it if it's the only config.
+ */
+- if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
++ if (i == 0 && num_configs > 1 && desc &&
++ (is_rndis(desc) || is_activesync(desc))) {
+ #if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+ continue;
+ #else
diff --git a/usb/usb-add-of_platform-glue-driver-for-fsl-usb-dr-controller.patch b/usb/usb-add-of_platform-glue-driver-for-fsl-usb-dr-controller.patch
deleted file mode 100644
index 0f12d9a906c03e..00000000000000
--- a/usb/usb-add-of_platform-glue-driver-for-fsl-usb-dr-controller.patch
+++ /dev/null
@@ -1,261 +0,0 @@
-From agust@denx.de Thu Jul 22 16:54:08 2010
-From: Anatolij Gustschin <agust@denx.de>
-To: linux-usb@vger.kernel.org
-Cc: linuxppc-dev@ozlabs.org, Greg Kroah-Hartman <gregkh@suse.de>,
- David Brownell <dbrownell@users.sourceforge.net>,
- Grant Likely <grant.likely@secretlab.ca>,
- Detlev Zundel <dzu@denx.de>, Wolfgang Denk <wd@denx.de>,
- Anatolij Gustschin <agust@denx.de>,
- Kumar Gala <galak@kernel.crashing.org>
-Subject: USB: add of_platform glue driver for FSL USB DR controller
-Date: Thu, 22 Jul 2010 18:25:21 +0200
-Message-Id: <1279815922-27198-3-git-send-email-agust@denx.de>
-
-The driver creates platform devices based on the information
-from USB nodes in the flat device tree. This is the replacement
-for old arch fsl_soc usb code removed by the previous patch.
-It uses usual of-style binding, available EHCI-HCD and UDC
-drivers can be bound to the created devices. The new of-style
-driver additionaly instantiates USB OTG platform device, as the
-appropriate USB OTG driver will be added soon.
-
-Signed-off-by: Anatolij Gustschin <agust@denx.de>
-Cc: Kumar Gala <galak@kernel.crashing.org>
-Cc: Grant Likely <grant.likely@secretlab.ca>
-Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-
----
- drivers/usb/gadget/Kconfig | 1
- drivers/usb/host/Kconfig | 5 +
- drivers/usb/host/Makefile | 1
- drivers/usb/host/fsl-mph-dr-of.c | 189 +++++++++++++++++++++++++++++++++++++++
- 4 files changed, 196 insertions(+)
-
---- a/drivers/usb/gadget/Kconfig
-+++ b/drivers/usb/gadget/Kconfig
-@@ -158,6 +158,7 @@ config USB_GADGET_FSL_USB2
- boolean "Freescale Highspeed USB DR Peripheral Controller"
- depends on FSL_SOC || ARCH_MXC
- select USB_GADGET_DUALSPEED
-+ select USB_FSL_MPH_DR_OF
- help
- Some of Freescale PowerPC processors have a High Speed
- Dual-Role(DR) USB controller, which supports device mode.
---- a/drivers/usb/host/Kconfig
-+++ b/drivers/usb/host/Kconfig
-@@ -112,10 +112,15 @@ config XPS_USB_HCD_XILINX
- support both high speed and full speed devices, or high speed
- devices only.
-
-+config USB_FSL_MPH_DR_OF
-+ bool
-+ depends on PPC_OF
-+
- config USB_EHCI_FSL
- bool "Support for Freescale on-chip EHCI USB controller"
- depends on USB_EHCI_HCD && FSL_SOC
- select USB_EHCI_ROOT_HUB_TT
-+ select USB_FSL_MPH_DR_OF
- ---help---
- Variation of ARC USB block used in some Freescale chips.
-
---- a/drivers/usb/host/Makefile
-+++ b/drivers/usb/host/Makefile
-@@ -33,4 +33,5 @@ obj-$(CONFIG_USB_R8A66597_HCD) += r8a665
- obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
- obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
- obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
-+obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
-
---- /dev/null
-+++ b/drivers/usb/host/fsl-mph-dr-of.c
-@@ -0,0 +1,189 @@
-+/*
-+ * Setup platform devices needed by the Freescale multi-port host
-+ * and/or dual-role USB controller modules based on the description
-+ * in flat device tree.
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/fsl_devices.h>
-+#include <linux/io.h>
-+#include <linux/of_platform.h>
-+
-+struct fsl_usb2_dev_data {
-+ char *dr_mode; /* controller mode */
-+ char *drivers[3]; /* drivers to instantiate for this mode */
-+ enum fsl_usb2_operating_modes op_mode; /* operating mode */
-+};
-+
-+struct fsl_usb2_dev_data dr_mode_data[] __devinitdata = {
-+ {
-+ "host",
-+ { "fsl-ehci", NULL, NULL, },
-+ FSL_USB2_DR_HOST,
-+ },
-+ {
-+ "otg",
-+ { "fsl-ehci", "fsl-usb2-udc", "fsl-usb2-otg", },
-+ FSL_USB2_DR_OTG,
-+ },
-+ {
-+ "periferal",
-+ { "fsl-usb2-udc", NULL, NULL, },
-+ FSL_USB2_DR_DEVICE,
-+ },
-+};
-+
-+struct fsl_usb2_dev_data * __devinit get_dr_mode_data(struct device_node *np)
-+{
-+ const unsigned char *prop;
-+ int i;
-+
-+ prop = of_get_property(np, "dr_mode", NULL);
-+ if (prop) {
-+ for (i = 0; i < ARRAY_SIZE(dr_mode_data); i++) {
-+ if (!strcmp(prop, dr_mode_data[i].dr_mode))
-+ return &dr_mode_data[i];
-+ }
-+ }
-+ return &dr_mode_data[0]; /* mode not specified, use host */
-+}
-+
-+static enum fsl_usb2_phy_modes __devinit determine_usb_phy(const char *phy_type)
-+{
-+ if (!phy_type)
-+ return FSL_USB2_PHY_NONE;
-+ if (!strcasecmp(phy_type, "ulpi"))
-+ return FSL_USB2_PHY_ULPI;
-+ if (!strcasecmp(phy_type, "utmi"))
-+ return FSL_USB2_PHY_UTMI;
-+ if (!strcasecmp(phy_type, "utmi_wide"))
-+ return FSL_USB2_PHY_UTMI_WIDE;
-+ if (!strcasecmp(phy_type, "serial"))
-+ return FSL_USB2_PHY_SERIAL;
-+
-+ return FSL_USB2_PHY_NONE;
-+}
-+
-+struct platform_device * __devinit
-+fsl_usb2_device_register(struct of_device *ofdev,
-+ struct fsl_usb2_platform_data *pdata,
-+ const char *name, int id)
-+{
-+ struct platform_device *pdev;
-+ const struct resource *res = ofdev->resource;
-+ unsigned int num = ofdev->num_resources;
-+ int retval;
-+
-+ pdev = platform_device_alloc(name, id);
-+ if (!pdev) {
-+ retval = -ENOMEM;
-+ goto error;
-+ }
-+
-+ pdev->dev.parent = &ofdev->dev;
-+
-+ pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
-+ pdev->dev.dma_mask = &pdev->archdata.dma_mask;
-+ *pdev->dev.dma_mask = *ofdev->dev.dma_mask;
-+
-+ retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
-+ if (retval)
-+ goto error;
-+
-+ if (num) {
-+ retval = platform_device_add_resources(pdev, res, num);
-+ if (retval)
-+ goto error;
-+ }
-+
-+ retval = platform_device_add(pdev);
-+ if (retval)
-+ goto error;
-+
-+ return pdev;
-+
-+error:
-+ platform_device_put(pdev);
-+ return ERR_PTR(retval);
-+}
-+
-+static int __devinit fsl_usb2_mph_dr_of_probe(struct of_device *ofdev,
-+ const struct of_device_id *match)
-+{
-+ struct device_node *np = ofdev->dev.of_node;
-+ struct platform_device *usb_dev;
-+ struct fsl_usb2_platform_data data, *pdata;
-+ struct fsl_usb2_dev_data *dev_data;
-+ const unsigned char *prop;
-+ static unsigned int idx;
-+ int i;
-+
-+ if (!of_device_is_available(np))
-+ return -ENODEV;
-+
-+ pdata = match->data;
-+ if (!pdata) {
-+ memset(&data, 0, sizeof(data));
-+ pdata = &data;
-+ }
-+
-+ dev_data = get_dr_mode_data(np);
-+
-+ if (of_device_is_compatible(np, "fsl-usb2-mph")) {
-+ prop = of_get_property(np, "port0", NULL);
-+ if (prop)
-+ pdata->port_enables |= FSL_USB2_PORT0_ENABLED;
-+
-+ prop = of_get_property(np, "port1", NULL);
-+ if (prop)
-+ pdata->port_enables |= FSL_USB2_PORT1_ENABLED;
-+
-+ pdata->operating_mode = FSL_USB2_MPH_HOST;
-+ } else {
-+ /* setup mode selected in the device tree */
-+ pdata->operating_mode = dev_data->op_mode;
-+ }
-+
-+ prop = of_get_property(np, "phy_type", NULL);
-+ pdata->phy_mode = determine_usb_phy(prop);
-+
-+ for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
-+ if (!dev_data->drivers[i])
-+ continue;
-+ usb_dev = fsl_usb2_device_register(ofdev, pdata,
-+ dev_data->drivers[i], idx);
-+ if (IS_ERR(usb_dev)) {
-+ dev_err(&ofdev->dev, "Can't register usb device\n");
-+ return PTR_ERR(usb_dev);
-+ }
-+ }
-+ idx++;
-+ return 0;
-+}
-+
-+static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
-+ { .compatible = "fsl-usb2-mph", },
-+ { .compatible = "fsl-usb2-dr", },
-+ {},
-+};
-+
-+static struct of_platform_driver fsl_usb2_mph_dr_driver = {
-+ .driver = {
-+ .name = "fsl-usb2-mph-dr",
-+ .owner = THIS_MODULE,
-+ .of_match_table = fsl_usb2_mph_dr_of_match,
-+ },
-+ .probe = fsl_usb2_mph_dr_of_probe,
-+};
-+
-+static int __init fsl_usb2_mph_dr_init(void)
-+{
-+ return of_register_platform_driver(&fsl_usb2_mph_dr_driver);
-+}
-+fs_initcall(fsl_usb2_mph_dr_init);
diff --git a/usb/usb-add-usb-2.0-to-ssb-ohci-driver.patch b/usb/usb-add-usb-2.0-to-ssb-ohci-driver.patch
new file mode 100644
index 00000000000000..915151b6f379aa
--- /dev/null
+++ b/usb/usb-add-usb-2.0-to-ssb-ohci-driver.patch
@@ -0,0 +1,99 @@
+From linux-usb-owner@vger.kernel.org Mon Aug 2 15:58:15 2010
+From: Hauke Mehrtens <hauke@hauke-m.de>
+To: sshtylyov@mvista.com
+Cc: linux-usb@vger.kernel.org, gregkh@suse.de,
+ Hauke Mehrtens <hauke@hauke-m.de>,
+ Steve Brown <sbrown@cortland.com>
+Subject: USB: Add USB 2.0 to ssb ohci driver
+Date: Wed, 28 Jul 2010 22:11:35 +0200
+Message-Id: <1280347895-4885-1-git-send-email-hauke@hauke-m.de>
+
+This adds USB 2.0 support to ssb ohci driver.
+This patch was used in OpenWRT for a long time now.
+
+CC: Steve Brown <sbrown@cortland.com>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ohci-ssb.c | 52 +++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 49 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/ohci-ssb.c
++++ b/drivers/usb/host/ohci-ssb.c
+@@ -93,8 +93,11 @@ static void ssb_ohci_detach(struct ssb_d
+ {
+ struct usb_hcd *hcd = ssb_get_drvdata(dev);
+
++ if (hcd->driver->shutdown)
++ hcd->driver->shutdown(hcd);
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ ssb_device_disable(dev, 0);
+ }
+@@ -106,10 +109,52 @@ static int ssb_ohci_attach(struct ssb_de
+ int err = -ENOMEM;
+ u32 tmp, flags = 0;
+
+- if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+- flags |= SSB_OHCI_TMSLOW_HOSTMODE;
++ if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
++ dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
++ return -EOPNOTSUPP;
+
+- ssb_device_enable(dev, flags);
++ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
++ /* Put the device into host-mode. */
++ flags |= SSB_OHCI_TMSLOW_HOSTMODE;
++ ssb_device_enable(dev, flags);
++ } else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
++ /*
++ * USB 2.0 special considerations:
++ *
++ * In addition to the standard SSB reset sequence, the Host
++ * Control Register must be programmed to bring the USB core
++ * and various phy components out of reset.
++ */
++ ssb_device_enable(dev, 0);
++ ssb_write32(dev, 0x200, 0x7ff);
++
++ /* Change Flush control reg */
++ tmp = ssb_read32(dev, 0x400);
++ tmp &= ~8;
++ ssb_write32(dev, 0x400, tmp);
++ tmp = ssb_read32(dev, 0x400);
++
++ /* Change Shim control reg */
++ tmp = ssb_read32(dev, 0x304);
++ tmp &= ~0x100;
++ ssb_write32(dev, 0x304, tmp);
++ tmp = ssb_read32(dev, 0x304);
++
++ udelay(1);
++
++ /* Work around for 5354 failures */
++ if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
++ /* Change syn01 reg */
++ tmp = 0x00fe00fe;
++ ssb_write32(dev, 0x894, tmp);
++
++ /* Change syn03 reg */
++ tmp = ssb_read32(dev, 0x89c);
++ tmp |= 0x1;
++ ssb_write32(dev, 0x89c, tmp);
++ }
++ } else
++ ssb_device_enable(dev, 0);
+
+ hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
+ dev_name(dev->dev));
+@@ -200,6 +245,7 @@ static int ssb_ohci_resume(struct ssb_de
+ static const struct ssb_device_id ssb_ohci_table[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
++ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
+ SSB_DEVTABLE_END
+ };
+ MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
diff --git a/usb/usb-add-usb-ehci-support-for-mpc5121-soc.patch b/usb/usb-add-usb-ehci-support-for-mpc5121-soc.patch
deleted file mode 100644
index 6fa814f54f40e8..00000000000000
--- a/usb/usb-add-usb-ehci-support-for-mpc5121-soc.patch
+++ /dev/null
@@ -1,503 +0,0 @@
-From agust@denx.de Thu Jul 22 16:54:48 2010
-From: Anatolij Gustschin <agust@denx.de>
-To: linux-usb@vger.kernel.org
-Cc: linuxppc-dev@ozlabs.org, Greg Kroah-Hartman <gregkh@suse.de>,
- David Brownell <dbrownell@users.sourceforge.net>,
- Grant Likely <grant.likely@secretlab.ca>,
- Detlev Zundel <dzu@denx.de>, Wolfgang Denk <wd@denx.de>,
- Anatolij Gustschin <agust@denx.de>
-Subject: USB: add USB EHCI support for MPC5121 SoC
-Date: Thu, 22 Jul 2010 18:25:22 +0200
-Message-Id: <1279815922-27198-4-git-send-email-agust@denx.de>
-
-Extends FSL EHCI platform driver glue layer to support
-MPC5121 USB controllers. MPC5121 Rev 2.0 silicon EHCI
-registers are in big endian format. The appropriate flags
-are set using the information in the platform data structure.
-MPC83xx system interface registers are not available on
-MPC512x, so the access to these registers is isolated in
-MPC512x case. Furthermore the USB controller clocks
-must be enabled before 512x register accesses which is
-done by providing platform specific init callback.
-
-The MPC512x internal USB PHY doesn't provide supply voltage.
-For boards using different power switches allow specifying
-DRVVBUS and PWR_FAULT signal polarity of the MPC5121 internal
-PHY using "fsl,invert-drvvbus" and "fsl,invert-pwr-fault"
-properties in the device tree USB nodes. Adds documentation
-for this new device tree bindings.
-
-Signed-off-by: Anatolij Gustschin <agust@denx.de>
-Cc: Grant Likely <grant.likely@secretlab.ca>
-Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-
----
- Documentation/powerpc/dts-bindings/fsl/usb.txt | 22 +++++
- drivers/usb/Kconfig | 1
- drivers/usb/host/Kconfig | 6 -
- drivers/usb/host/ehci-fsl.c | 107 ++++++++++++++++++-------
- drivers/usb/host/ehci-fsl.h | 19 ++++
- drivers/usb/host/ehci-mem.c | 2
- drivers/usb/host/fsl-mph-dr-of.c | 89 ++++++++++++++++++++
- include/linux/fsl_devices.h | 15 +++
- 8 files changed, 229 insertions(+), 32 deletions(-)
-
---- a/Documentation/powerpc/dts-bindings/fsl/usb.txt
-+++ b/Documentation/powerpc/dts-bindings/fsl/usb.txt
-@@ -8,6 +8,7 @@ and additions :
- Required properties :
- - compatible : Should be "fsl-usb2-mph" for multi port host USB
- controllers, or "fsl-usb2-dr" for dual role USB controllers
-+ or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
- - phy_type : For multi port host USB controllers, should be one of
- "ulpi", or "serial". For dual role USB controllers, should be
- one of "ulpi", "utmi", "utmi_wide", or "serial".
-@@ -33,6 +34,12 @@ Recommended properties :
- - interrupt-parent : the phandle for the interrupt controller that
- services interrupts for this device.
-
-+Optional properties :
-+ - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the
-+ port power polarity of internal PHY signal DRVVBUS is inverted.
-+ - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates
-+ the PWR_FAULT signal polarity is inverted.
-+
- Example multi port host USB controller device node :
- usb@22000 {
- compatible = "fsl-usb2-mph";
-@@ -57,3 +64,18 @@ Example dual role USB controller device
- dr_mode = "otg";
- phy = "ulpi";
- };
-+
-+Example dual role USB controller device node for MPC5121ADS:
-+
-+ usb@4000 {
-+ compatible = "fsl,mpc5121-usb2-dr";
-+ reg = <0x4000 0x1000>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ interrupt-parent = < &ipic >;
-+ interrupts = <44 0x8>;
-+ dr_mode = "otg";
-+ phy_type = "utmi_wide";
-+ fsl,invert-drvvbus;
-+ fsl,invert-pwr-fault;
-+ };
---- a/drivers/usb/Kconfig
-+++ b/drivers/usb/Kconfig
-@@ -58,6 +58,7 @@ config USB_ARCH_HAS_OHCI
- config USB_ARCH_HAS_EHCI
- boolean
- default y if PPC_83xx
-+ default y if PPC_MPC512x
- default y if SOC_AU1200
- default y if ARCH_IXP4XX
- default y if ARCH_W90X900
---- a/drivers/usb/host/Kconfig
-+++ b/drivers/usb/host/Kconfig
-@@ -93,12 +93,14 @@ config USB_EHCI_TT_NEWSCHED
-
- config USB_EHCI_BIG_ENDIAN_MMIO
- bool
-- depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX)
-+ depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || \
-+ XPS_USB_HCD_XILINX || PPC_MPC512x)
- default y
-
- config USB_EHCI_BIG_ENDIAN_DESC
- bool
-- depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX)
-+ depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
-+ PPC_MPC512x)
- default y
-
- config XPS_USB_HCD_XILINX
---- a/drivers/usb/host/ehci-fsl.c
-+++ b/drivers/usb/host/ehci-fsl.c
-@@ -116,13 +116,39 @@ static int usb_hcd_fsl_probe(const struc
- goto err3;
- }
-
-- /* Enable USB controller */
-- temp = in_be32(hcd->regs + 0x500);
-- out_be32(hcd->regs + 0x500, temp | 0x4);
-+ pdata->regs = hcd->regs;
-+
-+ /*
-+ * do platform specific init: check the clock, grab/config pins, etc.
-+ */
-+ if (pdata->init && pdata->init(pdev)) {
-+ retval = -ENODEV;
-+ goto err3;
-+ }
-+
-+ /*
-+ * Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs
-+ * flag for 83xx or 8536 system interface registers.
-+ */
-+ if (pdata->big_endian_mmio)
-+ temp = in_be32(hcd->regs + FSL_SOC_USB_ID);
-+ else
-+ temp = in_le32(hcd->regs + FSL_SOC_USB_ID);
-+
-+ if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK))
-+ pdata->have_sysif_regs = 1;
-+
-+ /* Enable USB controller, 83xx or 8536 */
-+ if (pdata->have_sysif_regs)
-+ setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
-
- /* Set to Host mode */
-- temp = in_le32(hcd->regs + 0x1a8);
-- out_le32(hcd->regs + 0x1a8, temp | 0x3);
-+ if (pdata->big_endian_mmio) {
-+ setbits32(hcd->regs + FSL_SOC_USB_USBMODE, USBMODE_CM_HOST);
-+ } else {
-+ clrsetbits_le32(hcd->regs + FSL_SOC_USB_USBMODE,
-+ USBMODE_CM_MASK, USBMODE_CM_HOST);
-+ }
-
- retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
- if (retval != 0)
-@@ -137,6 +163,8 @@ static int usb_hcd_fsl_probe(const struc
- usb_put_hcd(hcd);
- err1:
- dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
-+ if (pdata->exit)
-+ pdata->exit(pdev);
- return retval;
- }
-
-@@ -154,17 +182,30 @@ static int usb_hcd_fsl_probe(const struc
- static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
- struct platform_device *pdev)
- {
-+ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-+
- usb_remove_hcd(hcd);
-+
-+ /*
-+ * do platform specific un-initialization:
-+ * release iomux pins, disable clock, etc.
-+ */
-+ if (pdata->exit)
-+ pdata->exit(pdev);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
- }
-
--static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
-- enum fsl_usb2_phy_modes phy_mode,
-- unsigned int port_offset)
-+static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
-+ enum fsl_usb2_phy_modes phy_mode,
-+ unsigned int port_offset)
- {
-- u32 portsc = 0;
-+ u32 portsc;
-+
-+ portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
-+ portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
-+
- switch (phy_mode) {
- case FSL_USB2_PHY_ULPI:
- portsc |= PORT_PTS_ULPI;
-@@ -184,20 +225,21 @@ static void mpc83xx_setup_phy(struct ehc
- ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
- }
-
--static void mpc83xx_usb_setup(struct usb_hcd *hcd)
-+static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
- {
-- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-+ struct usb_hcd *hcd = ehci_to_hcd(ehci);
- struct fsl_usb2_platform_data *pdata;
- void __iomem *non_ehci = hcd->regs;
- u32 temp;
-
-- pdata =
-- (struct fsl_usb2_platform_data *)hcd->self.controller->
-- platform_data;
-+ pdata = hcd->self.controller->platform_data;
-+
- /* Enable PHY interface in the control reg. */
-- temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-- out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
-- out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
-+ if (pdata->have_sysif_regs) {
-+ temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-+ out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
-+ out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
-+ }
-
- #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- /*
-@@ -214,7 +256,7 @@ static void mpc83xx_usb_setup(struct usb
-
- if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
- (pdata->operating_mode == FSL_USB2_DR_OTG))
-- mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
-+ ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
-
- if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
- unsigned int chip, rev, svr;
-@@ -228,27 +270,31 @@ static void mpc83xx_usb_setup(struct usb
- ehci->has_fsl_port_bug = 1;
-
- if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
-- mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
-+ ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
- if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
-- mpc83xx_setup_phy(ehci, pdata->phy_mode, 1);
-+ ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
- }
-
- /* put controller in host mode. */
-- ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
-+ temp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
-+ ehci_writel(ehci, temp, non_ehci + FSL_SOC_USB_USBMODE);
-+
-+ if (pdata->have_sysif_regs) {
- #ifdef CONFIG_PPC_85xx
-- out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
-- out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
-+ out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
-+ out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
- #else
-- out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
-- out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
-+ out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
-+ out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
- #endif
-- out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
-+ out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
-+ }
- }
-
- /* called after powerup, by probe or system-pm "wakeup" */
- static int ehci_fsl_reinit(struct ehci_hcd *ehci)
- {
-- mpc83xx_usb_setup(ehci_to_hcd(ehci));
-+ ehci_fsl_usb_setup(ehci);
- ehci_port_power(ehci, 0);
-
- return 0;
-@@ -259,6 +305,11 @@ static int ehci_fsl_setup(struct usb_hcd
- {
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int retval;
-+ struct fsl_usb2_platform_data *pdata;
-+
-+ pdata = hcd->self.controller->platform_data;
-+ ehci->big_endian_desc = pdata->big_endian_desc;
-+ ehci->big_endian_mmio = pdata->big_endian_mmio;
-
- /* EHCI registers start at offset 0x100 */
- ehci->caps = hcd->regs + 0x100;
-@@ -372,7 +423,7 @@ static const struct hc_driver ehci_fsl_h
- * generic hardware linkage
- */
- .irq = ehci_irq,
-- .flags = HCD_USB2,
-+ .flags = HCD_USB2 | HCD_MEMORY,
-
- /*
- * basic lifecycle operations
---- a/drivers/usb/host/ehci-fsl.h
-+++ b/drivers/usb/host/ehci-fsl.h
-@@ -1,4 +1,4 @@
--/* Copyright (c) 2005 freescale semiconductor
-+/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc.
- * Copyright (c) 2005 MontaVista Software
- *
- * This program is free software; you can redistribute it and/or modify it
-@@ -19,6 +19,11 @@
- #define _EHCI_FSL_H
-
- /* offsets for the non-ehci registers in the FSL SOC USB controller */
-+#define FSL_SOC_USB_ID 0x0
-+#define ID_MSK 0x3f
-+#define NID_MSK 0x3f00
-+#define FSL_SOC_USB_SBUSCFG 0x90
-+#define FSL_SOC_USB_BURSTSIZE 0x160
- #define FSL_SOC_USB_ULPIVP 0x170
- #define FSL_SOC_USB_PORTSC1 0x184
- #define PORT_PTS_MSK (3<<30)
-@@ -26,8 +31,20 @@
- #define PORT_PTS_ULPI (2<<30)
- #define PORT_PTS_SERIAL (3<<30)
- #define PORT_PTS_PTW (1<<28)
-+#define PORT_PTS_PHCD (1<<23)
- #define FSL_SOC_USB_PORTSC2 0x188
- #define FSL_SOC_USB_USBMODE 0x1a8
-+#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */
-+#define USBMODE_CM_HOST (3 << 0) /* controller mode: host */
-+#define USBMODE_ES (1 << 2) /* (Big) Endian Select */
-+
-+#define FSL_SOC_USB_USBGENCTRL 0x200
-+#define USBGENCTRL_PPP (1 << 3)
-+#define USBGENCTRL_PFP (1 << 2)
-+#define FSL_SOC_USB_ISIPHYCTRL 0x204
-+#define ISIPHYCTRL_PXE (1)
-+#define ISIPHYCTRL_PHYE (1 << 4)
-+
- #define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */
- #define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */
- #define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */
---- a/drivers/usb/host/ehci-mem.c
-+++ b/drivers/usb/host/ehci-mem.c
-@@ -40,7 +40,7 @@ static inline void ehci_qtd_init(struct
- {
- memset (qtd, 0, sizeof *qtd);
- qtd->qtd_dma = dma;
-- qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
-+ qtd->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
- qtd->hw_next = EHCI_LIST_END(ehci);
- qtd->hw_alt_next = EHCI_LIST_END(ehci);
- INIT_LIST_HEAD (&qtd->qtd_list);
---- a/drivers/usb/host/fsl-mph-dr-of.c
-+++ b/drivers/usb/host/fsl-mph-dr-of.c
-@@ -14,6 +14,7 @@
- #include <linux/fsl_devices.h>
- #include <linux/io.h>
- #include <linux/of_platform.h>
-+#include <linux/clk.h>
-
- struct fsl_usb2_dev_data {
- char *dr_mode; /* controller mode */
-@@ -146,6 +147,12 @@ static int __devinit fsl_usb2_mph_dr_of_
-
- pdata->operating_mode = FSL_USB2_MPH_HOST;
- } else {
-+ if (of_get_property(np, "fsl,invert-drvvbus", NULL))
-+ pdata->invert_drvvbus = 1;
-+
-+ if (of_get_property(np, "fsl,invert-pwr-fault", NULL))
-+ pdata->invert_pwr_fault = 1;
-+
- /* setup mode selected in the device tree */
- pdata->operating_mode = dev_data->op_mode;
- }
-@@ -167,9 +174,91 @@ static int __devinit fsl_usb2_mph_dr_of_
- return 0;
- }
-
-+#ifdef CONFIG_PPC_MPC512x
-+
-+#define USBGENCTRL 0x200 /* NOTE: big endian */
-+#define GC_WU_INT_CLR (1 << 5) /* Wakeup int clear */
-+#define GC_ULPI_SEL (1 << 4) /* ULPI i/f select (usb0 only)*/
-+#define GC_PPP (1 << 3) /* Inv. Port Power Polarity */
-+#define GC_PFP (1 << 2) /* Inv. Power Fault Polarity */
-+#define GC_WU_ULPI_EN (1 << 1) /* Wakeup on ULPI event */
-+#define GC_WU_IE (1 << 1) /* Wakeup interrupt enable */
-+
-+#define ISIPHYCTRL 0x204 /* NOTE: big endian */
-+#define PHYCTRL_PHYE (1 << 4) /* On-chip UTMI PHY enable */
-+#define PHYCTRL_BSENH (1 << 3) /* Bit Stuff Enable High */
-+#define PHYCTRL_BSEN (1 << 2) /* Bit Stuff Enable */
-+#define PHYCTRL_LSFE (1 << 1) /* Line State Filter Enable */
-+#define PHYCTRL_PXE (1 << 0) /* PHY oscillator enable */
-+
-+int fsl_usb2_mpc5121_init(struct platform_device *pdev)
-+{
-+ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-+ struct clk *clk;
-+ char clk_name[10];
-+ int base, clk_num;
-+
-+ base = pdev->resource->start & 0xf000;
-+ if (base == 0x3000)
-+ clk_num = 1;
-+ else if (base == 0x4000)
-+ clk_num = 2;
-+ else
-+ return -ENODEV;
-+
-+ snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
-+ clk = clk_get(&pdev->dev, clk_name);
-+ if (IS_ERR(clk)) {
-+ dev_err(&pdev->dev, "failed to get clk\n");
-+ return PTR_ERR(clk);
-+ }
-+
-+ clk_enable(clk);
-+ pdata->clk = clk;
-+
-+ if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
-+ u32 reg = 0;
-+
-+ if (pdata->invert_drvvbus)
-+ reg |= GC_PPP;
-+
-+ if (pdata->invert_pwr_fault)
-+ reg |= GC_PFP;
-+
-+ out_be32(pdata->regs + ISIPHYCTRL, PHYCTRL_PHYE | PHYCTRL_PXE);
-+ out_be32(pdata->regs + USBGENCTRL, reg);
-+ }
-+ return 0;
-+}
-+
-+static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
-+{
-+ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-+
-+ pdata->regs = NULL;
-+
-+ if (pdata->clk) {
-+ clk_disable(pdata->clk);
-+ clk_put(pdata->clk);
-+ }
-+}
-+
-+struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = {
-+ .big_endian_desc = 1,
-+ .big_endian_mmio = 1,
-+ .es = 1,
-+ .le_setup_buf = 1,
-+ .init = fsl_usb2_mpc5121_init,
-+ .exit = fsl_usb2_mpc5121_exit,
-+};
-+#endif /* CONFIG_PPC_MPC512x */
-+
- static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
- { .compatible = "fsl-usb2-mph", },
- { .compatible = "fsl-usb2-dr", },
-+#ifdef CONFIG_PPC_MPC512x
-+ { .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, },
-+#endif
- {},
- };
-
---- a/include/linux/fsl_devices.h
-+++ b/include/linux/fsl_devices.h
-@@ -58,11 +58,26 @@ enum fsl_usb2_phy_modes {
- FSL_USB2_PHY_SERIAL,
- };
-
-+struct clk;
-+struct platform_device;
-+
- struct fsl_usb2_platform_data {
- /* board specific information */
- enum fsl_usb2_operating_modes operating_mode;
- enum fsl_usb2_phy_modes phy_mode;
- unsigned int port_enables;
-+
-+ int (*init)(struct platform_device *);
-+ void (*exit)(struct platform_device *);
-+ void __iomem *regs; /* ioremap'd register base */
-+ struct clk *clk;
-+ unsigned big_endian_mmio:1;
-+ unsigned big_endian_desc:1;
-+ unsigned es:1; /* need USBMODE:ES */
-+ unsigned le_setup_buf:1;
-+ unsigned have_sysif_regs:1;
-+ unsigned invert_drvvbus:1;
-+ unsigned invert_pwr_fault:1;
- };
-
- /* Flags in fsl_usb2_mph_platform_data */
diff --git a/usb/usb-add-usb-serial-ssu100-driver.patch b/usb/usb-add-usb-serial-ssu100-driver.patch
new file mode 100644
index 00000000000000..730854de6a9568
--- /dev/null
+++ b/usb/usb-add-usb-serial-ssu100-driver.patch
@@ -0,0 +1,749 @@
+From linux-usb-owner@vger.kernel.org Mon Aug 2 16:03:42 2010
+From: Bill Pemberton <wfp5p@virginia.edu>
+To: linux-usb@vger.kernel.org
+Subject: [PATCH] USB: add USB serial ssu100 driver
+Date: Thu, 29 Jul 2010 11:05:41 -0400
+Message-Id: <1280415941-21770-1-git-send-email-wfp5p@virginia.edu>
+
+Add support for the Quatech SSU-100 single port usb to serial device.
+This driver is based on the ftdi_sio.c driver and the original
+serqt_usb driver from Quatech.
+
+Signed-off-by: Bill Pemberton <wfp5p@virginia.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/Kconfig | 9
+ drivers/usb/serial/Makefile | 1
+ drivers/usb/serial/ssu100.c | 698 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 708 insertions(+)
+
+--- a/drivers/usb/serial/Kconfig
++++ b/drivers/usb/serial/Kconfig
+@@ -642,6 +642,15 @@ config USB_SERIAL_ZIO
+ To compile this driver as a module, choose M here: the
+ module will be called zio.
+
++config USB_SERIAL_SSU100
++ tristate "USB Quatech SSU-100 Single Port Serial Driver"
++ help
++ Say Y here if you want to use the Quatech SSU-100 single
++ port usb to serial adapter.
++
++ To compile this driver as a module, choose M here: the
++ module will be called ssu100.
++
+ config USB_SERIAL_DEBUG
+ tristate "USB Debugging Device"
+ help
+--- a/drivers/usb/serial/Makefile
++++ b/drivers/usb/serial/Makefile
+@@ -51,6 +51,7 @@ obj-$(CONFIG_USB_SERIAL_SAFE) += safe_
+ obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o
+ obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
+ obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o
++obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o
+ obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o
+ obj-$(CONFIG_USB_SERIAL_WWAN) += usb_wwan.o
+ obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o
+--- /dev/null
++++ b/drivers/usb/serial/ssu100.c
+@@ -0,0 +1,698 @@
++/*
++ * usb-serial driver for Quatech SSU-100
++ *
++ * based on ftdi_sio.c and the original serqt_usb.c from Quatech
++ *
++ */
++
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++#include <linux/module.h>
++#include <linux/serial.h>
++#include <linux/usb.h>
++#include <linux/usb/serial.h>
++#include <linux/uaccess.h>
++
++#define QT_OPEN_CLOSE_CHANNEL 0xca
++#define QT_SET_GET_DEVICE 0xc2
++#define QT_SET_GET_REGISTER 0xc0
++#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc
++#define QT_SET_ATF 0xcd
++#define QT_GET_SET_UART 0xc1
++#define QT_TRANSFER_IN 0xc0
++#define QT_HW_FLOW_CONTROL_MASK 0xc5
++#define QT_SW_FLOW_CONTROL_MASK 0xc6
++
++#define MODEM_CTL_REGISTER 0x04
++#define MODEM_STATUS_REGISTER 0x06
++
++
++#define SERIAL_LSR_OE 0x02
++#define SERIAL_LSR_PE 0x04
++#define SERIAL_LSR_FE 0x08
++#define SERIAL_LSR_BI 0x10
++
++#define SERIAL_LSR_TEMT 0x40
++
++#define SERIAL_MCR_DTR 0x01
++#define SERIAL_MCR_RTS 0x02
++#define SERIAL_MCR_LOOP 0x10
++
++#define SERIAL_MSR_CTS 0x10
++#define SERIAL_MSR_CD 0x80
++#define SERIAL_MSR_RI 0x40
++#define SERIAL_MSR_DSR 0x20
++#define SERIAL_MSR_MASK 0xf0
++
++#define SERIAL_CRTSCTS ((SERIAL_MCR_RTS << 8) | SERIAL_MSR_CTS)
++
++#define SERIAL_8_DATA 0x03
++#define SERIAL_7_DATA 0x02
++#define SERIAL_6_DATA 0x01
++#define SERIAL_5_DATA 0x00
++
++#define SERIAL_ODD_PARITY 0X08
++#define SERIAL_EVEN_PARITY 0X18
++
++#define MAX_BAUD_RATE 460800
++
++#define ATC_DISABLED 0x00
++#define DUPMODE_BITS 0xc0
++#define RR_BITS 0x03
++#define LOOPMODE_BITS 0x41
++#define RS232_MODE 0x00
++#define RTSCTS_TO_CONNECTOR 0x40
++#define CLKS_X4 0x02
++#define FULLPWRBIT 0x00000080
++#define NEXT_BOARD_POWER_BIT 0x00000004
++
++static int debug = 1;
++
++/* Version Information */
++#define DRIVER_VERSION "v0.1"
++#define DRIVER_DESC "Quatech SSU-100 USB to Serial Driver"
++
++#define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */
++#define QUATECH_SSU100 0xC020 /* SSU100 */
++
++static const struct usb_device_id id_table[] = {
++ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)},
++ {} /* Terminating entry */
++};
++
++MODULE_DEVICE_TABLE(usb, id_table);
++
++
++static struct usb_driver ssu100_driver = {
++ .name = "ssu100",
++ .probe = usb_serial_probe,
++ .disconnect = usb_serial_disconnect,
++ .id_table = id_table,
++ .suspend = usb_serial_suspend,
++ .resume = usb_serial_resume,
++ .no_dynamic_id = 1,
++ .supports_autosuspend = 1,
++};
++
++struct ssu100_port_private {
++ u8 shadowLSR;
++ u8 shadowMSR;
++ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
++ unsigned short max_packet_size;
++};
++
++static void ssu100_release(struct usb_serial *serial)
++{
++ struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port);
++
++ dbg("%s", __func__);
++ kfree(priv);
++}
++
++static inline int ssu100_control_msg(struct usb_device *dev,
++ u8 request, u16 data, u16 index)
++{
++ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
++ request, 0x40, data, index,
++ NULL, 0, 300);
++}
++
++static inline int ssu100_setdevice(struct usb_device *dev, u8 *data)
++{
++ u16 x = ((u16)(data[1] << 8) | (u16)(data[0]));
++
++ return ssu100_control_msg(dev, QT_SET_GET_DEVICE, x, 0);
++}
++
++
++static inline int ssu100_getdevice(struct usb_device *dev, u8 *data)
++{
++ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
++ QT_SET_GET_DEVICE, 0xc0, 0, 0,
++ data, 3, 300);
++}
++
++static inline int ssu100_getregister(struct usb_device *dev,
++ unsigned short uart,
++ unsigned short reg,
++ u8 *data)
++{
++ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
++ QT_SET_GET_REGISTER, 0xc0, reg,
++ uart, data, sizeof(*data), 300);
++
++}
++
++
++static inline int ssu100_setregister(struct usb_device *dev,
++ unsigned short uart,
++ u16 data)
++{
++ u16 value = (data << 8) | MODEM_CTL_REGISTER;
++
++ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
++ QT_SET_GET_REGISTER, 0x40, value, uart,
++ NULL, 0, 300);
++
++}
++
++#define set_mctrl(dev, set) update_mctrl((dev), (set), 0)
++#define clear_mctrl(dev, clear) update_mctrl((dev), 0, (clear))
++
++/* these do not deal with device that have more than 1 port */
++static inline int update_mctrl(struct usb_device *dev, unsigned int set,
++ unsigned int clear)
++{
++ unsigned urb_value;
++ int result;
++
++ if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
++ dbg("%s - DTR|RTS not being set|cleared", __func__);
++ return 0; /* no change */
++ }
++
++ clear &= ~set; /* 'set' takes precedence over 'clear' */
++ urb_value = 0;
++ if (set & TIOCM_DTR)
++ urb_value |= SERIAL_MCR_DTR;
++ if (set & TIOCM_RTS)
++ urb_value |= SERIAL_MCR_RTS;
++
++ result = ssu100_setregister(dev, 0, urb_value);
++ if (result < 0)
++ dbg("%s Error from MODEM_CTRL urb", __func__);
++
++ return result;
++}
++
++static int ssu100_initdevice(struct usb_device *dev)
++{
++ u8 *data;
++ int result = 0;
++
++ dbg("%s", __func__);
++
++ data = kzalloc(3, GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ result = ssu100_getdevice(dev, data);
++ if (result < 0) {
++ dbg("%s - get_device failed %i", __func__, result);
++ goto out;
++ }
++
++ data[1] &= ~FULLPWRBIT;
++
++ result = ssu100_setdevice(dev, data);
++ if (result < 0) {
++ dbg("%s - setdevice failed %i", __func__, result);
++ goto out;
++ }
++
++ result = ssu100_control_msg(dev, QT_GET_SET_PREBUF_TRIG_LVL, 128, 0);
++ if (result < 0) {
++ dbg("%s - set prebuffer level failed %i", __func__, result);
++ goto out;
++ }
++
++ result = ssu100_control_msg(dev, QT_SET_ATF, ATC_DISABLED, 0);
++ if (result < 0) {
++ dbg("%s - set ATFprebuffer level failed %i", __func__, result);
++ goto out;
++ }
++
++ result = ssu100_getdevice(dev, data);
++ if (result < 0) {
++ dbg("%s - get_device failed %i", __func__, result);
++ goto out;
++ }
++
++ data[0] &= ~(RR_BITS | DUPMODE_BITS);
++ data[0] |= CLKS_X4;
++ data[1] &= ~(LOOPMODE_BITS);
++ data[1] |= RS232_MODE;
++
++ result = ssu100_setdevice(dev, data);
++ if (result < 0) {
++ dbg("%s - setdevice failed %i", __func__, result);
++ goto out;
++ }
++
++out: kfree(data);
++ return result;
++
++}
++
++
++static void ssu100_set_termios(struct tty_struct *tty,
++ struct usb_serial_port *port,
++ struct ktermios *old_termios)
++{
++ struct usb_device *dev = port->serial->dev;
++ struct ktermios *termios = tty->termios;
++ u16 baud, divisor, remainder;
++ unsigned int cflag = termios->c_cflag;
++ u16 urb_value = 0; /* will hold the new flags */
++ int result;
++
++ dbg("%s", __func__);
++
++ if (cflag & PARENB) {
++ if (cflag & PARODD)
++ urb_value |= SERIAL_ODD_PARITY;
++ else
++ urb_value |= SERIAL_EVEN_PARITY;
++ }
++
++ switch (cflag & CSIZE) {
++ case CS5:
++ urb_value |= SERIAL_5_DATA;
++ break;
++ case CS6:
++ urb_value |= SERIAL_6_DATA;
++ break;
++ case CS7:
++ urb_value |= SERIAL_7_DATA;
++ break;
++ default:
++ case CS8:
++ urb_value |= SERIAL_8_DATA;
++ break;
++ }
++
++ baud = tty_get_baud_rate(tty);
++ if (!baud)
++ baud = 9600;
++
++ dbg("%s - got baud = %d\n", __func__, baud);
++
++
++ divisor = MAX_BAUD_RATE / baud;
++ remainder = MAX_BAUD_RATE % baud;
++ if (((remainder * 2) >= baud) && (baud != 110))
++ divisor++;
++
++ urb_value = urb_value << 8;
++
++ result = ssu100_control_msg(dev, QT_GET_SET_UART, divisor, urb_value);
++ if (result < 0)
++ dbg("%s - set uart failed", __func__);
++
++ if (cflag & CRTSCTS)
++ result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
++ SERIAL_CRTSCTS, 0);
++ else
++ result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
++ 0, 0);
++ if (result < 0)
++ dbg("%s - set HW flow control failed", __func__);
++
++ if (I_IXOFF(tty) || I_IXON(tty)) {
++ u16 x = ((u16)(START_CHAR(tty) << 8) | (u16)(STOP_CHAR(tty)));
++
++ result = ssu100_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
++ x, 0);
++ } else
++ result = ssu100_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
++ 0, 0);
++
++ if (result < 0)
++ dbg("%s - set SW flow control failed", __func__);
++
++}
++
++
++static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
++{
++ struct usb_device *dev = port->serial->dev;
++ struct ssu100_port_private *priv = usb_get_serial_port_data(port);
++ u8 *data;
++ int result;
++
++ dbg("%s - port %d", __func__, port->number);
++
++ data = kzalloc(2, GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
++ QT_OPEN_CLOSE_CHANNEL,
++ QT_TRANSFER_IN, 0x01,
++ 0, data, 2, 300);
++ if (result < 0) {
++ dbg("%s - open failed %i", __func__, result);
++ kfree(data);
++ return result;
++ }
++
++ priv->shadowLSR = data[0] & (SERIAL_LSR_OE | SERIAL_LSR_PE |
++ SERIAL_LSR_FE | SERIAL_LSR_BI);
++
++ priv->shadowMSR = data[1] & (SERIAL_MSR_CTS | SERIAL_MSR_DSR |
++ SERIAL_MSR_RI | SERIAL_MSR_CD);
++
++ kfree(data);
++
++/* set to 9600 */
++ result = ssu100_control_msg(dev, QT_GET_SET_UART, 0x30, 0x0300);
++ if (result < 0)
++ dbg("%s - set uart failed", __func__);
++
++ if (tty)
++ ssu100_set_termios(tty, port, tty->termios);
++
++ return usb_serial_generic_open(tty, port);
++}
++
++static void ssu100_close(struct usb_serial_port *port)
++{
++ dbg("%s", __func__);
++ usb_serial_generic_close(port);
++}
++
++static int get_serial_info(struct usb_serial_port *port,
++ struct serial_struct __user *retinfo)
++{
++ struct serial_struct tmp;
++
++ if (!retinfo)
++ return -EFAULT;
++
++ memset(&tmp, 0, sizeof(tmp));
++ tmp.line = port->serial->minor;
++ tmp.port = 0;
++ tmp.irq = 0;
++ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
++ tmp.xmit_fifo_size = port->bulk_out_size;
++ tmp.baud_base = 9600;
++ tmp.close_delay = 5*HZ;
++ tmp.closing_wait = 30*HZ;
++
++ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
++ return -EFAULT;
++ return 0;
++}
++
++static int ssu100_ioctl(struct tty_struct *tty, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ struct usb_serial_port *port = tty->driver_data;
++ struct ssu100_port_private *priv = usb_get_serial_port_data(port);
++
++ dbg("%s cmd 0x%04x", __func__, cmd);
++
++ switch (cmd) {
++ case TIOCGSERIAL:
++ return get_serial_info(port,
++ (struct serial_struct __user *) arg);
++
++ case TIOCMIWAIT:
++ while (priv != NULL) {
++ u8 prevMSR = priv->shadowMSR & SERIAL_MSR_MASK;
++ interruptible_sleep_on(&priv->delta_msr_wait);
++ /* see if a signal did it */
++ if (signal_pending(current))
++ return -ERESTARTSYS;
++ else {
++ u8 diff = (priv->shadowMSR & SERIAL_MSR_MASK) ^ prevMSR;
++ if (!diff)
++ return -EIO; /* no change => error */
++
++ /* Return 0 if caller wanted to know about
++ these bits */
++
++ if (((arg & TIOCM_RNG) && (diff & SERIAL_MSR_RI)) ||
++ ((arg & TIOCM_DSR) && (diff & SERIAL_MSR_DSR)) ||
++ ((arg & TIOCM_CD) && (diff & SERIAL_MSR_CD)) ||
++ ((arg & TIOCM_CTS) && (diff & SERIAL_MSR_CTS)))
++ return 0;
++ }
++ }
++ return 0;
++
++ default:
++ break;
++ }
++
++ dbg("%s arg not supported", __func__);
++
++ return -ENOIOCTLCMD;
++}
++
++static void ssu100_set_max_packet_size(struct usb_serial_port *port)
++{
++ struct ssu100_port_private *priv = usb_get_serial_port_data(port);
++ struct usb_serial *serial = port->serial;
++ struct usb_device *udev = serial->dev;
++
++ struct usb_interface *interface = serial->interface;
++ struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
++
++ unsigned num_endpoints;
++ int i;
++
++ num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
++ dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
++
++ for (i = 0; i < num_endpoints; i++) {
++ dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1,
++ interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
++ ep_desc = &interface->cur_altsetting->endpoint[i].desc;
++ }
++
++ /* set max packet size based on descriptor */
++ priv->max_packet_size = ep_desc->wMaxPacketSize;
++
++ dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
++}
++
++static int ssu100_attach(struct usb_serial *serial)
++{
++ struct ssu100_port_private *priv;
++ struct usb_serial_port *port = *serial->port;
++
++ dbg("%s", __func__);
++
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ if (!priv) {
++ dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
++ sizeof(*priv));
++ return -ENOMEM;
++ }
++
++ init_waitqueue_head(&priv->delta_msr_wait);
++ usb_set_serial_port_data(port, priv);
++
++ ssu100_set_max_packet_size(port);
++
++ return ssu100_initdevice(serial->dev);
++}
++
++static int ssu100_tiocmget(struct tty_struct *tty, struct file *file)
++{
++ struct usb_serial_port *port = tty->driver_data;
++ struct usb_device *dev = port->serial->dev;
++ u8 *d;
++ int r;
++
++ dbg("%s\n", __func__);
++
++ d = kzalloc(2, GFP_KERNEL);
++ if (!d)
++ return -ENOMEM;
++
++ r = ssu100_getregister(dev, 0, MODEM_CTL_REGISTER, d);
++ if (r < 0)
++ goto mget_out;
++
++ r = ssu100_getregister(dev, 0, MODEM_STATUS_REGISTER, d+1);
++ if (r < 0)
++ goto mget_out;
++
++ r = (d[0] & SERIAL_MCR_DTR ? TIOCM_DTR : 0) |
++ (d[0] & SERIAL_MCR_RTS ? TIOCM_RTS : 0) |
++ (d[1] & SERIAL_MSR_CTS ? TIOCM_CTS : 0) |
++ (d[1] & SERIAL_MSR_CD ? TIOCM_CAR : 0) |
++ (d[1] & SERIAL_MSR_RI ? TIOCM_RI : 0) |
++ (d[1] & SERIAL_MSR_DSR ? TIOCM_DSR : 0);
++
++mget_out:
++ kfree(d);
++ return r;
++}
++
++static int ssu100_tiocmset(struct tty_struct *tty, struct file *file,
++ unsigned int set, unsigned int clear)
++{
++ struct usb_serial_port *port = tty->driver_data;
++ struct usb_device *dev = port->serial->dev;
++
++ dbg("%s\n", __func__);
++ return update_mctrl(dev, set, clear);
++}
++
++static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
++{
++ struct usb_device *dev = port->serial->dev;
++
++ dbg("%s\n", __func__);
++
++ mutex_lock(&port->serial->disc_mutex);
++ if (!port->serial->disconnected) {
++ /* Disable flow control */
++ if (!on &&
++ ssu100_setregister(dev, 0, 0) < 0)
++ dev_err(&port->dev, "error from flowcontrol urb\n");
++ /* drop RTS and DTR */
++ if (on)
++ set_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
++ else
++ clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
++ }
++ mutex_unlock(&port->serial->disc_mutex);
++}
++
++static int ssu100_process_packet(struct tty_struct *tty,
++ struct usb_serial_port *port,
++ struct ssu100_port_private *priv,
++ char *packet, int len)
++{
++ int i;
++ char flag;
++ char *ch;
++
++ dbg("%s - port %d", __func__, port->number);
++
++ if (len < 4) {
++ dbg("%s - malformed packet", __func__);
++ return 0;
++ }
++
++ if ((packet[0] == 0x1b) && (packet[1] == 0x1b) &&
++ ((packet[2] == 0x00) || (packet[2] == 0x01))) {
++ if (packet[2] == 0x00)
++ priv->shadowLSR = packet[3] & (SERIAL_LSR_OE |
++ SERIAL_LSR_PE |
++ SERIAL_LSR_FE |
++ SERIAL_LSR_BI);
++
++ if (packet[2] == 0x01) {
++ priv->shadowMSR = packet[3];
++ wake_up_interruptible(&priv->delta_msr_wait);
++ }
++
++ len -= 4;
++ ch = packet + 4;
++ } else
++ ch = packet;
++
++ if (!len)
++ return 0; /* status only */
++
++ if (port->port.console && port->sysrq) {
++ for (i = 0; i < len; i++, ch++) {
++ if (!usb_serial_handle_sysrq_char(tty, port, *ch))
++ tty_insert_flip_char(tty, *ch, flag);
++ }
++ } else
++ tty_insert_flip_string_fixed_flag(tty, ch, flag, len);
++
++ return len;
++}
++
++static void ssu100_process_read_urb(struct urb *urb)
++{
++ struct usb_serial_port *port = urb->context;
++ struct ssu100_port_private *priv = usb_get_serial_port_data(port);
++ char *data = (char *)urb->transfer_buffer;
++ struct tty_struct *tty;
++ int count = 0;
++ int i;
++ int len;
++
++ dbg("%s", __func__);
++
++ tty = tty_port_tty_get(&port->port);
++ if (!tty)
++ return;
++
++ for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
++ len = min_t(int, urb->actual_length - i, priv->max_packet_size);
++ count += ssu100_process_packet(tty, port, priv, &data[i], len);
++ }
++
++ if (count)
++ tty_flip_buffer_push(tty);
++ tty_kref_put(tty);
++}
++
++
++static struct usb_serial_driver ssu100_device = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "ssu100",
++ },
++ .description = DRIVER_DESC,
++ .id_table = id_table,
++ .usb_driver = &ssu100_driver,
++ .num_ports = 1,
++ .bulk_in_size = 256,
++ .bulk_out_size = 256,
++ .open = ssu100_open,
++ .close = ssu100_close,
++ .attach = ssu100_attach,
++ .release = ssu100_release,
++ .dtr_rts = ssu100_dtr_rts,
++ .process_read_urb = ssu100_process_read_urb,
++ .tiocmget = ssu100_tiocmget,
++ .tiocmset = ssu100_tiocmset,
++ .ioctl = ssu100_ioctl,
++ .set_termios = ssu100_set_termios,
++};
++
++static int __init ssu100_init(void)
++{
++ int retval;
++
++ dbg("%s", __func__);
++
++ /* register with usb-serial */
++ retval = usb_serial_register(&ssu100_device);
++
++ if (retval)
++ goto failed_usb_sio_register;
++
++ retval = usb_register(&ssu100_driver);
++ if (retval)
++ goto failed_usb_register;
++
++ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
++ DRIVER_DESC "\n");
++
++ return 0;
++
++failed_usb_register:
++ usb_serial_deregister(&ssu100_device);
++failed_usb_sio_register:
++ return retval;
++}
++
++static void __exit ssu100_exit(void)
++{
++ usb_deregister(&ssu100_driver);
++ usb_serial_deregister(&ssu100_device);
++}
++
++module_init(ssu100_init);
++module_exit(ssu100_exit);
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
++
++module_param(debug, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/usb/usb-cp210x-add-four-new-device-ids.patch b/usb/usb-cp210x-add-four-new-device-ids.patch
new file mode 100644
index 00000000000000..268f70a2fdee4f
--- /dev/null
+++ b/usb/usb-cp210x-add-four-new-device-ids.patch
@@ -0,0 +1,33 @@
+From alessioigorbogani@gmail.com Mon Aug 2 15:57:57 2010
+From: Alessio Igor Bogani <abogani@texware.it>
+To: Greg Kroah-Hartman <gregkh@suse.de>,
+ Craig Shelley <craig@microtron.org.uk>,
+ Johan Hovold <jhovold@gmail.com>, Alan Cox <alan@linux.intel.com>,
+ Michael Brunner <mibru@gmx.de>
+Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
+ Alessio Igor Bogani <abogani@texware.it>
+Subject: USB: cp210x: Add four new device IDs
+Date: Tue, 27 Jul 2010 23:05:14 +0200
+Message-Id: <1280264714-17175-1-git-send-email-abogani@texware.it>
+
+Signed-off-by: Alessio Igor Bogani <abogani@texware.it>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/cp210x.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/usb/serial/cp210x.c
++++ b/drivers/usb/serial/cp210x.c
+@@ -126,6 +126,10 @@ static const struct usb_device_id id_tab
+ { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
+ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
+ { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
++ { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
++ { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
++ { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */
++ { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */
+ { } /* Terminating Entry */
+ };
+
diff --git a/usb/usb-ehci-fix-remove-of-ehci-debugfs-dir.patch b/usb/usb-ehci-fix-remove-of-ehci-debugfs-dir.patch
new file mode 100644
index 00000000000000..0e1e8dcd96e44c
--- /dev/null
+++ b/usb/usb-ehci-fix-remove-of-ehci-debugfs-dir.patch
@@ -0,0 +1,118 @@
+From tom.leiming@gmail.com Mon Aug 2 16:01:50 2010
+From: tom.leiming@gmail.com
+To: greg@kroah.com,
+ stern@rowland.harvard.edu
+Cc: linux-usb@vger.kernel.org, david-b@pacbell.net, alek.du@intel.com, Ming Lei <tom.leiming@gmail.com>
+Subject: USB: ehci: fix remove of ehci debugfs dir
+Date: Wed, 28 Jul 2010 22:33:28 +0800
+Message-Id: <1280327608-4376-1-git-send-email-tom.leiming@gmail.com>
+
+From: Ming Lei <tom.leiming@gmail.com>
+
+The patch below on gregkh tree only creates 'lpm' file under
+ehci->debug_dir, but not removes it when unloading module,
+
+ USB: EHCI: EHCI 1.1 addendum: preparation
+
+which can make loading of ehci-hcd module failed after unloading it.
+
+This patch replaces debugfs_remove with debugfs_remove_recursive
+to remove ehci debugfs dir and files. It does fix the bug above,
+and may simplify the removing procedure.
+
+Also, remove the debug_registers, debug_async and debug_periodic
+field from ehci_hcd struct since they are useless now.
+
+Signed-off-by: Ming Lei <tom.leiming@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ehci-dbg.c | 56 +++++++++++++++-----------------------------
+ drivers/usb/host/ehci.h | 4 ---
+ 2 files changed, 20 insertions(+), 40 deletions(-)
+
+--- a/drivers/usb/host/ehci-dbg.c
++++ b/drivers/usb/host/ehci-dbg.c
+@@ -1049,49 +1049,33 @@ static inline void create_debug_files (s
+
+ ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root);
+ if (!ehci->debug_dir)
+- goto dir_error;
++ return;
++
++ if (!debugfs_create_file("async", S_IRUGO, ehci->debug_dir, bus,
++ &debug_async_fops))
++ goto file_error;
++
++ if (!debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus,
++ &debug_periodic_fops))
++ goto file_error;
++
++ if (!debugfs_create_file("registers", S_IRUGO, ehci->debug_dir, bus,
++ &debug_registers_fops))
++ goto file_error;
++
++ if (!debugfs_create_file("lpm", S_IRUGO|S_IWUGO, ehci->debug_dir, bus,
++ &debug_lpm_fops))
++ goto file_error;
+
+- ehci->debug_async = debugfs_create_file("async", S_IRUGO,
+- ehci->debug_dir, bus,
+- &debug_async_fops);
+- if (!ehci->debug_async)
+- goto async_error;
+-
+- ehci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
+- ehci->debug_dir, bus,
+- &debug_periodic_fops);
+- if (!ehci->debug_periodic)
+- goto periodic_error;
+-
+- ehci->debug_registers = debugfs_create_file("registers", S_IRUGO,
+- ehci->debug_dir, bus,
+- &debug_registers_fops);
+-
+- ehci->debug_registers = debugfs_create_file("lpm", S_IRUGO|S_IWUGO,
+- ehci->debug_dir, bus,
+- &debug_lpm_fops);
+- if (!ehci->debug_registers)
+- goto registers_error;
+ return;
+
+-registers_error:
+- debugfs_remove(ehci->debug_periodic);
+-periodic_error:
+- debugfs_remove(ehci->debug_async);
+-async_error:
+- debugfs_remove(ehci->debug_dir);
+-dir_error:
+- ehci->debug_periodic = NULL;
+- ehci->debug_async = NULL;
+- ehci->debug_dir = NULL;
++file_error:
++ debugfs_remove_recursive(ehci->debug_dir);
+ }
+
+ static inline void remove_debug_files (struct ehci_hcd *ehci)
+ {
+- debugfs_remove(ehci->debug_registers);
+- debugfs_remove(ehci->debug_periodic);
+- debugfs_remove(ehci->debug_async);
+- debugfs_remove(ehci->debug_dir);
++ debugfs_remove_recursive(ehci->debug_dir);
+ }
+
+ #endif /* STUB_DEBUG_FILES */
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -156,10 +156,6 @@ struct ehci_hcd { /* one per controlle
+ /* debug files */
+ #ifdef DEBUG
+ struct dentry *debug_dir;
+- struct dentry *debug_async;
+- struct dentry *debug_periodic;
+- struct dentry *debug_registers;
+- struct dentry *debug_lpm;
+ #endif
+ };
+
diff --git a/usb/usb-fix-linux-usb.h-kernel-doc-warnings.patch b/usb/usb-fix-linux-usb.h-kernel-doc-warnings.patch
new file mode 100644
index 00000000000000..a3652d87fa661e
--- /dev/null
+++ b/usb/usb-fix-linux-usb.h-kernel-doc-warnings.patch
@@ -0,0 +1,40 @@
+From linux-usb-owner@vger.kernel.org Mon Aug 2 16:04:48 2010
+Date: Thu, 29 Jul 2010 15:54:38 -0700
+From: Randy Dunlap <randy.dunlap@oracle.com>
+Cc: gregkh@suse.de
+Subject: USB:: fix linux/usb.h kernel-doc warnings
+Message-Id: <20100729155438.d3a02177.randy.dunlap@oracle.com>
+
+From: Randy Dunlap <randy.dunlap@oracle.com>
+
+Fix kernel-doc warnings in linux/usb.h:
+
+Warning(include/linux/usb.h:185): No description found for parameter 'resetting_device'
+Warning(include/linux/usb.h:1212): No description found for parameter 'stream_id'
+
+Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/usb.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -127,6 +127,8 @@ enum usb_interface_condition {
+ * queued reset so that usb_cancel_queued_reset() doesn't try to
+ * remove from the workqueue when running inside the worker
+ * thread. See __usb_queue_reset_device().
++ * @resetting_device: USB core reset the device, so use alt setting 0 as
++ * current; needs bandwidth alloc after reset.
+ *
+ * USB device drivers attach to interfaces on a physical device. Each
+ * interface encapsulates a single high level function, such as feeding
+@@ -1015,6 +1017,7 @@ typedef void (*usb_complete_t)(struct ur
+ * is a different endpoint (and pipe) from "out" endpoint two.
+ * The current configuration controls the existence, type, and
+ * maximum packet size of any given endpoint.
++ * @stream_id: the endpoint's stream ID for bulk streams
+ * @dev: Identifies the USB device to perform the request.
+ * @status: This is read in non-iso completion functions to get the
+ * status of the particular request. ISO requests only use it
diff --git a/usb/usb-fix-stuck-usb-generic-serial-driver.patch b/usb/usb-fix-stuck-usb-generic-serial-driver.patch
new file mode 100644
index 00000000000000..5beecacc94c3bc
--- /dev/null
+++ b/usb/usb-fix-stuck-usb-generic-serial-driver.patch
@@ -0,0 +1,62 @@
+From dvomlehn@cisco.com Mon Aug 2 16:13:11 2010
+Date: Mon, 2 Aug 2010 10:46:00 -0700
+From: David VomLehn <dvomlehn@cisco.com>
+To: linux-usb@vger.kernel.org
+Cc: greg@kroah.com
+Subject: USB: Fix stuck USB generic serial driver
+Message-ID: <20100802174600.GA6845@dvomlehn-lnx2.corp.sa.net>
+Content-Disposition: inline
+
+Fix USB console hang due to non-atomic URB allocation
+
+This is intended to fix a problem seen with the Amtel sam-ba tool by
+Alexander Stein (alexander.stein@systec-electronic.com). It appears
+when using an A91 controller. He bisected it to commit:
+
+ 8e8dce065088833fc418bfa5fbf035cb0726c04c: USB: use kfifo to buffer usb-generic serial writes
+
+The current patch fixes a problem when using a USB serial device as the
+kernel console and as /dev/console. The URB allocation is not atomic and
+an URB can be doubly allocated, leading to a continual rejection of URB
+submissions. The fix puts all pieces of the URB allocation in the same
+spinlock-protected section of code.
+
+Having said that...
+
+This fix was developed because, after Alexander's email, I took a look
+at my USB console and found that it, too, was experiencing a hang. I
+assumed that this hang was the same as the one Alexander is seeing and
+developed this fix. It's a good fix for *a* hang, but after thinking
+about this a bit, I'm not sure this is a fix for *Alexander's* hang.
+
+Signed-off-by: David VomLehn <dvomlehn@cisco.com>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/generic.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/generic.c
++++ b/drivers/usb/serial/generic.c
+@@ -199,6 +199,9 @@ retry:
+ }
+ i = (int)find_first_bit(&port->write_urbs_free,
+ ARRAY_SIZE(port->write_urbs));
++ if (i == ARRAY_SIZE(port->write_urbs))
++ return 0;
++ clear_bit(i, &port->write_urbs_free);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ urb = port->write_urbs[i];
+@@ -213,9 +216,9 @@ retry:
+ dev_err(&port->dev, "%s - error submitting urb: %d\n",
+ __func__, result);
+ clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
++ set_bit(i, &port->write_urbs_free);
+ return result;
+ }
+- clear_bit(i, &port->write_urbs_free);
+
+ spin_lock_irqsave(&port->lock, flags);
+ port->tx_bytes += count;
diff --git a/usb/usb-ftdi_sio-device-id-for-navitator.patch b/usb/usb-ftdi_sio-device-id-for-navitator.patch
new file mode 100644
index 00000000000000..0ca149c5391db9
--- /dev/null
+++ b/usb/usb-ftdi_sio-device-id-for-navitator.patch
@@ -0,0 +1,53 @@
+From dranch@trinnet.net Tue Jul 27 10:14:22 2010
+Date: Mon, 26 Jul 2010 19:44:33 -0700
+From: dranch@trinnet.net
+To: greg@kroah.com, gregkh@suse.de, linux-kernel@vger.kernel.org
+Cc: dranch@trinnet.net
+Subject: USB: ftdi_sio: device id for Navitator
+Message-ID: <20100727024433.GA29758@trinity4.trinnet.net>
+Content-Disposition: inline
+
+This patch is to add a US Interface, Inc. "Navigator" USB device.
+Specifically, it's a HAM Radio USB sound modem that also
+incorporates three pairs of unique FTDI serial ports. The standard
+Linux FTDI serial driver will only recognize the first two serial
+ports of an unknown FDTI derived device and this patch adds in
+recognition to these specific new IDs.
+
+Signed-off-by: David A. Ranch <dranch@trinnet.net>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+
+---
+ drivers/usb/serial/ftdi_sio.c | 3 +++
+ drivers/usb/serial/ftdi_sio_ids.h | 5 +++++
+ 2 files changed, 8 insertions(+)
+
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -157,6 +157,9 @@ static struct usb_device_id id_table_com
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) },
++ { USB_DEVICE(FTDI_VID, FTDI_USINT_CAT_PID) },
++ { USB_DEVICE(FTDI_VID, FTDI_USINT_WKEY_PID) },
++ { USB_DEVICE(FTDI_VID, FTDI_USINT_RS232_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
+--- a/drivers/usb/serial/ftdi_sio_ids.h
++++ b/drivers/usb/serial/ftdi_sio_ids.h
+@@ -40,6 +40,11 @@
+
+ #define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */
+
++/* US Interface Navigator (http://www.usinterface.com/) */
++#define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */
++#define FTDI_USINT_WKEY_PID 0xb811 /* Navigator WKEY and FSK lines */
++#define FTDI_USINT_RS232_PID 0xb812 /* Navigator RS232 and CONFIG lines */
++
+ /* OOCDlink by Joern Kaipf <joernk@web.de>
+ * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */
+ #define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */
diff --git a/usb/usb-powerpc-fsl_soc.c-remove-fsl-usb-platform-code.patch b/usb/usb-powerpc-fsl_soc.c-remove-fsl-usb-platform-code.patch
deleted file mode 100644
index a8fd3e68c83ae2..00000000000000
--- a/usb/usb-powerpc-fsl_soc.c-remove-fsl-usb-platform-code.patch
+++ /dev/null
@@ -1,198 +0,0 @@
-From agust@denx.de Thu Jul 22 16:53:55 2010
-From: Anatolij Gustschin <agust@denx.de>
-To: linux-usb@vger.kernel.org
-Cc: linuxppc-dev@ozlabs.org, Greg Kroah-Hartman <gregkh@suse.de>,
- David Brownell <dbrownell@users.sourceforge.net>,
- Grant Likely <grant.likely@secretlab.ca>,
- Detlev Zundel <dzu@denx.de>, Wolfgang Denk <wd@denx.de>,
- Anatolij Gustschin <agust@denx.de>,
- Kumar Gala <galak@kernel.crashing.org>
-Subject: USB: powerpc/fsl_soc.c: remove FSL USB platform code
-Date: Thu, 22 Jul 2010 18:25:20 +0200
-Message-Id: <1279815922-27198-2-git-send-email-agust@denx.de>
-
-This removed code will be replaced by simple of_platform
-driver for creation of FSL USB platform devices which is
-added by next patch of the series.
-
-Signed-off-by: Anatolij Gustschin <agust@denx.de>
-Cc: Kumar Gala <galak@kernel.crashing.org>
-Cc: Grant Likely <grant.likely@secretlab.ca>
-Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-
----
- arch/powerpc/sysdev/fsl_soc.c | 163 ------------------------------------------
- 1 file changed, 163 deletions(-)
-
---- a/arch/powerpc/sysdev/fsl_soc.c
-+++ b/arch/powerpc/sysdev/fsl_soc.c
-@@ -209,169 +209,6 @@ static int __init of_add_fixed_phys(void
- arch_initcall(of_add_fixed_phys);
- #endif /* CONFIG_FIXED_PHY */
-
--static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
--{
-- if (!phy_type)
-- return FSL_USB2_PHY_NONE;
-- if (!strcasecmp(phy_type, "ulpi"))
-- return FSL_USB2_PHY_ULPI;
-- if (!strcasecmp(phy_type, "utmi"))
-- return FSL_USB2_PHY_UTMI;
-- if (!strcasecmp(phy_type, "utmi_wide"))
-- return FSL_USB2_PHY_UTMI_WIDE;
-- if (!strcasecmp(phy_type, "serial"))
-- return FSL_USB2_PHY_SERIAL;
--
-- return FSL_USB2_PHY_NONE;
--}
--
--static int __init fsl_usb_of_init(void)
--{
-- struct device_node *np;
-- unsigned int i = 0;
-- struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL,
-- *usb_dev_dr_client = NULL;
-- int ret;
--
-- for_each_compatible_node(np, NULL, "fsl-usb2-mph") {
-- struct resource r[2];
-- struct fsl_usb2_platform_data usb_data;
-- const unsigned char *prop = NULL;
--
-- memset(&r, 0, sizeof(r));
-- memset(&usb_data, 0, sizeof(usb_data));
--
-- ret = of_address_to_resource(np, 0, &r[0]);
-- if (ret)
-- goto err;
--
-- of_irq_to_resource(np, 0, &r[1]);
--
-- usb_dev_mph =
-- platform_device_register_simple("fsl-ehci", i, r, 2);
-- if (IS_ERR(usb_dev_mph)) {
-- ret = PTR_ERR(usb_dev_mph);
-- goto err;
-- }
--
-- usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL;
-- usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask;
--
-- usb_data.operating_mode = FSL_USB2_MPH_HOST;
--
-- prop = of_get_property(np, "port0", NULL);
-- if (prop)
-- usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
--
-- prop = of_get_property(np, "port1", NULL);
-- if (prop)
-- usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
--
-- prop = of_get_property(np, "phy_type", NULL);
-- usb_data.phy_mode = determine_usb_phy(prop);
--
-- ret =
-- platform_device_add_data(usb_dev_mph, &usb_data,
-- sizeof(struct
-- fsl_usb2_platform_data));
-- if (ret)
-- goto unreg_mph;
-- i++;
-- }
--
-- for_each_compatible_node(np, NULL, "fsl-usb2-dr") {
-- struct resource r[2];
-- struct fsl_usb2_platform_data usb_data;
-- const unsigned char *prop = NULL;
--
-- if (!of_device_is_available(np))
-- continue;
--
-- memset(&r, 0, sizeof(r));
-- memset(&usb_data, 0, sizeof(usb_data));
--
-- ret = of_address_to_resource(np, 0, &r[0]);
-- if (ret)
-- goto unreg_mph;
--
-- of_irq_to_resource(np, 0, &r[1]);
--
-- prop = of_get_property(np, "dr_mode", NULL);
--
-- if (!prop || !strcmp(prop, "host")) {
-- usb_data.operating_mode = FSL_USB2_DR_HOST;
-- usb_dev_dr_host = platform_device_register_simple(
-- "fsl-ehci", i, r, 2);
-- if (IS_ERR(usb_dev_dr_host)) {
-- ret = PTR_ERR(usb_dev_dr_host);
-- goto err;
-- }
-- } else if (prop && !strcmp(prop, "peripheral")) {
-- usb_data.operating_mode = FSL_USB2_DR_DEVICE;
-- usb_dev_dr_client = platform_device_register_simple(
-- "fsl-usb2-udc", i, r, 2);
-- if (IS_ERR(usb_dev_dr_client)) {
-- ret = PTR_ERR(usb_dev_dr_client);
-- goto err;
-- }
-- } else if (prop && !strcmp(prop, "otg")) {
-- usb_data.operating_mode = FSL_USB2_DR_OTG;
-- usb_dev_dr_host = platform_device_register_simple(
-- "fsl-ehci", i, r, 2);
-- if (IS_ERR(usb_dev_dr_host)) {
-- ret = PTR_ERR(usb_dev_dr_host);
-- goto err;
-- }
-- usb_dev_dr_client = platform_device_register_simple(
-- "fsl-usb2-udc", i, r, 2);
-- if (IS_ERR(usb_dev_dr_client)) {
-- ret = PTR_ERR(usb_dev_dr_client);
-- goto err;
-- }
-- } else {
-- ret = -EINVAL;
-- goto err;
-- }
--
-- prop = of_get_property(np, "phy_type", NULL);
-- usb_data.phy_mode = determine_usb_phy(prop);
--
-- if (usb_dev_dr_host) {
-- usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL;
-- usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host->
-- dev.coherent_dma_mask;
-- if ((ret = platform_device_add_data(usb_dev_dr_host,
-- &usb_data, sizeof(struct
-- fsl_usb2_platform_data))))
-- goto unreg_dr;
-- }
-- if (usb_dev_dr_client) {
-- usb_dev_dr_client->dev.coherent_dma_mask = 0xffffffffUL;
-- usb_dev_dr_client->dev.dma_mask = &usb_dev_dr_client->
-- dev.coherent_dma_mask;
-- if ((ret = platform_device_add_data(usb_dev_dr_client,
-- &usb_data, sizeof(struct
-- fsl_usb2_platform_data))))
-- goto unreg_dr;
-- }
-- i++;
-- }
-- return 0;
--
--unreg_dr:
-- if (usb_dev_dr_host)
-- platform_device_unregister(usb_dev_dr_host);
-- if (usb_dev_dr_client)
-- platform_device_unregister(usb_dev_dr_client);
--unreg_mph:
-- if (usb_dev_mph)
-- platform_device_unregister(usb_dev_mph);
--err:
-- return ret;
--}
--
--arch_initcall(fsl_usb_of_init);
--
- #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
- static __be32 __iomem *rstcr;
-
diff --git a/usb/usb-usb-storage-implement-autosuspend.patch b/usb/usb-usb-storage-implement-autosuspend.patch
new file mode 100644
index 00000000000000..ff1920e71d3102
--- /dev/null
+++ b/usb/usb-usb-storage-implement-autosuspend.patch
@@ -0,0 +1,67 @@
+From stern+4c5c36d6@rowland.harvard.edu Mon Aug 2 16:02:08 2010
+Date: Wed, 28 Jul 2010 17:12:39 -0400 (EDT)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: James Bottomley <James.Bottomley@suse.de>, Greg KH <greg@kroah.com>
+cc: Matthew Dharm <mdharm-usb@one-eyed-alien.net>,
+ Oliver Neukum <oliver@neukum.org>,
+ SCSI development list <linux-scsi@vger.kernel.org>,
+ USB Storage list <usb-storage@lists.one-eyed-alien.net>
+Subject: USB: usb-storage: implement autosuspend
+Message-ID: <Pine.LNX.4.44L0.1007281702030.1744-100000@iolanthe.rowland.org>
+
+This patch (as1400) adds runtime-PM support to usb-storage. It
+utilizes the SCSI layer's runtime-PM implementation, so its scope is
+limited. Currently the only effect is that disk-like devices (such as
+card readers or flash drives) will be autosuspended if they aren't
+mounted and their device files aren't open. This would apply, for
+example, to card readers that don't contain a memory card.
+
+Unfortunately this won't interact very well with the removable-media
+polling normally carried out by hal or DeviceKit. Maybe those
+programs can be changed to use a longer polling interval, or maybe the
+default autosuspend time for usb-storage should be set to something
+below 1 second.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Cc: James Bottomley <James.Bottomley@suse.de>
+Cc: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/storage/usb.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/usb/storage/usb.c
++++ b/drivers/usb/storage/usb.c
+@@ -336,6 +336,7 @@ static int usb_stor_control_thread(void
+ else {
+ US_DEBUG(usb_stor_show_command(us->srb));
+ us->proto_handler(us->srb, us);
++ usb_mark_last_busy(us->pusb_dev);
+ }
+
+ /* lock access to the state */
+@@ -845,6 +846,7 @@ static int usb_stor_scan_thread(void * _
+ /* Should we unbind if no devices were detected? */
+ }
+
++ usb_autopm_put_interface(us->pusb_intf);
+ complete_and_exit(&us->scanning_done, 0);
+ }
+
+@@ -968,6 +970,7 @@ int usb_stor_probe2(struct us_data *us)
+ goto BadDevice;
+ }
+
++ usb_autopm_get_interface_no_resume(us->pusb_intf);
+ wake_up_process(th);
+
+ return 0;
+@@ -1040,6 +1043,7 @@ static struct usb_driver usb_storage_dri
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = usb_storage_usb_ids,
++ .supports_autosuspend = 1,
+ .soft_unbind = 1,
+ };
+
diff --git a/usb/usb-usbtest-avoid-to-free-coherent-buffer-in-atomic-context.patch b/usb/usb-usbtest-avoid-to-free-coherent-buffer-in-atomic-context.patch
new file mode 100644
index 00000000000000..78a9e7f0a8f998
--- /dev/null
+++ b/usb/usb-usbtest-avoid-to-free-coherent-buffer-in-atomic-context.patch
@@ -0,0 +1,84 @@
+From tom.leiming@gmail.com Mon Aug 2 16:12:38 2010
+From: tom.leiming@gmail.com
+To: greg@kroah.com,
+ stern@rowland.harvard.edu,
+ dbrownell@users.sourceforge.net
+Cc: linux-usb@vger.kernel.org, Ming Lei <tom.leiming@gmail.com>, stable <stable@kernel.org>
+Subject: USB: usbtest: avoid to free coherent buffer in atomic context
+Date: Mon, 2 Aug 2010 22:09:01 +0800
+Message-Id: <1280758141-3035-1-git-send-email-tom.leiming@gmail.com>
+
+From: Ming Lei <tom.leiming@gmail.com>
+
+This patch fixes the warning below:
+[30753.755998] ------------[ cut here ]------------
+[30753.755998] WARNING: at /home/tom/git/linux-2.6/linux-2.6-next/arch/x86/include/asm/dma-mapping.h:155 hcd_buffer_free+0xb1/0xd4 [usbcore]()
+[30753.755998] Hardware name: 6475EK2
+[30753.755998] Modules linked in: uvcvideo ehci_hcd usbtest cdc_ether usbnet vfat fat usb_storage nfsd lockd nfs_acl auth_rpcgss exportfs mii tun videodev v4l1_compat v4l2_compat_ioctl32 fuse bridge stp llc sunrpc ipv6 cpufreq_ondemand acpi_cpufreq freq_table mperf kvm_intel kvm arc4 ecb ath5k usbhid mac80211 snd_hda_codec_conexant ch341 usbserial ath cfg80211 thinkpad_acpi snd_hda_intel pcspkr wmi hwmon yenta_socket iTCO_wdt iTCO_vendor_support i2c_i801 e1000e snd_hda_codec snd_hwdep snd_pcm snd_timer snd soundcore snd_page_alloc pata_acpi uhci_hcd ohci_hcd usbcore i915 drm_kms_helper drm i2c_algo_bit i2c_core video output [last unloaded: uvcvideo]
+[30753.755998] Pid: 0, comm: swapper Tainted: G W 2.6.35-rc6-gkh-wl+ #49
+[30753.755998] Call Trace:
+[30753.755998] <IRQ> [<ffffffff8104478a>] warn_slowpath_common+0x80/0x98
+[30753.755998] [<ffffffff810447b7>] warn_slowpath_null+0x15/0x17
+[30753.755998] [<ffffffffa00ce02d>] hcd_buffer_free+0xb1/0xd4 [usbcore]
+[30753.755998] [<ffffffffa00c1345>] usb_free_coherent+0x1c/0x1e [usbcore]
+[30753.755998] [<ffffffffa00b13e4>] simple_free_urb+0x23/0x2f [usbtest]
+[30753.755998] [<ffffffffa00b210b>] iso_callback+0xbb/0x10f [usbtest]
+[30753.755998] [<ffffffffa00c7390>] usb_hcd_giveback_urb+0x8c/0xc0 [usbcore]
+[30753.755998] [<ffffffffa0449b35>] ehci_urb_done+0x84/0x95 [ehci_hcd]
+[30753.755998] [<ffffffffa044b5a5>] ehci_work+0x41a/0x7dd [ehci_hcd]
+[30753.755998] [<ffffffffa044e298>] ehci_irq+0x33b/0x370 [ehci_hcd]
+[30753.755998] [<ffffffff8100fb05>] ? sched_clock+0x9/0xd
+[30753.755998] [<ffffffff8105e641>] ? sched_clock_local+0x1c/0x82
+[30753.755998] [<ffffffff8105e76a>] ? sched_clock_cpu+0xc3/0xce
+[30753.755998] [<ffffffff81067c7e>] ? trace_hardirqs_off+0xd/0xf
+[30753.755998] [<ffffffff8105e7b8>] ? cpu_clock+0x43/0x5e
+[30753.755998] [<ffffffffa00c6999>] usb_hcd_irq+0x45/0xa1 [usbcore]
+[30753.755998] [<ffffffff81092e02>] handle_IRQ_event+0x20/0xa5
+[30753.755998] [<ffffffff81094cea>] handle_fasteoi_irq+0x92/0xd2
+[30753.755998] [<ffffffff8100c0ed>] handle_irq+0x1f/0x2a
+[30753.755998] [<ffffffff8100b75d>] do_IRQ+0x57/0xbe
+[30753.755998] [<ffffffff8136a693>] ret_from_intr+0x0/0x16
+[30753.755998] <EOI> [<ffffffff81223baa>] ? acpi_idle_enter_bm+0x231/0x269
+[30753.755998] [<ffffffff81223ba3>] ? acpi_idle_enter_bm+0x22a/0x269
+[30753.755998] [<ffffffff812c4b6b>] cpuidle_idle_call+0x99/0xce
+[30753.755998] [<ffffffff81008dd5>] cpu_idle+0x61/0xaa
+[30753.755998] [<ffffffff8136374b>] start_secondary+0x1c2/0x1c6
+[30753.755998] ---[ end trace 904cfaf7ab4cb1a2 ]---
+
+Signed-off-by: Ming Lei <tom.leiming@gmail.com>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/usbtest.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/misc/usbtest.c
++++ b/drivers/usb/misc/usbtest.c
+@@ -1378,7 +1378,6 @@ static void iso_callback (struct urb *ur
+ break;
+ }
+ }
+- simple_free_urb (urb);
+
+ ctx->pending--;
+ if (ctx->pending == 0) {
+@@ -1495,6 +1494,7 @@ test_iso_queue (struct usbtest_dev *dev,
+ }
+
+ simple_free_urb (urbs [i]);
++ urbs[i] = NULL;
+ context.pending--;
+ context.submit_error = 1;
+ break;
+@@ -1504,6 +1504,10 @@ test_iso_queue (struct usbtest_dev *dev,
+
+ wait_for_completion (&context.done);
+
++ for (i = 0; i < param->sglen; i++) {
++ if (urbs[i])
++ simple_free_urb(urbs[i]);
++ }
+ /*
+ * Isochronous transfers are expected to fail sometimes. As an
+ * arbitrary limit, we will report an error if any submissions
diff --git a/usb/usb-usbtest-support-test-device-with-only-one-iso-in-or-iso-out-endpoint.patch b/usb/usb-usbtest-support-test-device-with-only-one-iso-in-or-iso-out-endpoint.patch
new file mode 100644
index 00000000000000..b25fd728bcbe5d
--- /dev/null
+++ b/usb/usb-usbtest-support-test-device-with-only-one-iso-in-or-iso-out-endpoint.patch
@@ -0,0 +1,42 @@
+From linux-usb-owner@vger.kernel.org Mon Aug 2 16:12:50 2010
+From: tom.leiming@gmail.com
+To: greg@kroah.com, stern@rowland.harvard.edu,
+ dbrownell@users.sourceforge.net
+Cc: linux-usb@vger.kernel.org, Ming Lei <tom.leiming@gmail.com>
+Subject: [PATCH] USB: usbtest: support test device with only one iso-in or iso-out endpoint
+Date: Mon, 2 Aug 2010 22:09:17 +0800
+Message-Id: <1280758157-3068-1-git-send-email-tom.leiming@gmail.com>
+
+From: Ming Lei <tom.leiming@gmail.com>
+
+It is very common that one altsetting may include only one iso-in or iso-out
+single endpoint, especially for high bandwidth endpoint, so support it.
+
+Signed-off-by: Ming Lei <tom.leiming@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/usbtest.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/misc/usbtest.c
++++ b/drivers/usb/misc/usbtest.c
+@@ -136,7 +136,7 @@ try_iso:
+ iso_out = e;
+ }
+ }
+- if ((in && out) || (iso_in && iso_out))
++ if ((in && out) || iso_in || iso_out)
+ goto found;
+ }
+ return -EINVAL;
+@@ -162,6 +162,9 @@ found:
+ dev->in_iso_pipe = usb_rcvisocpipe (udev,
+ iso_in->desc.bEndpointAddress
+ & USB_ENDPOINT_NUMBER_MASK);
++ }
++
++ if (iso_out) {
+ dev->iso_out = &iso_out->desc;
+ dev->out_iso_pipe = usb_sndisocpipe (udev,
+ iso_out->desc.bEndpointAddress
diff --git a/usb/usb-xhci-don-t-flush-doorbell-writes.patch b/usb/usb-xhci-don-t-flush-doorbell-writes.patch
new file mode 100644
index 00000000000000..22e67807046373
--- /dev/null
+++ b/usb/usb-xhci-don-t-flush-doorbell-writes.patch
@@ -0,0 +1,39 @@
+From sarah.a.sharp@linux.intel.com Mon Aug 2 16:07:09 2010
+Date: Thu, 29 Jul 2010 22:13:17 -0700
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Subject: USB: xhci: Don't flush doorbell writes.
+Message-ID: <20100730051317.GA7617@xanatos>
+Content-Disposition: inline
+
+To tell the host controller that there are transfers on the endpoint
+rings, we need to ring the endpoint doorbell. This is a PCI MMIO write,
+which can be delayed until another register read is queued.
+
+The previous code would flush the doorbell write by reading the doorbell
+register after the write. This may take time, and it's not necessary to
+force the host controller to know about the transfers right away. Don't
+flush the doorbell register writes.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -337,11 +337,6 @@ static void ring_ep_doorbell(struct xhci
+ field = xhci_readl(xhci, db_addr) & DB_MASK;
+ field |= EPI_TO_DB(ep_index) | STREAM_ID_TO_DB(stream_id);
+ xhci_writel(xhci, field, db_addr);
+- /* Flush PCI posted writes - FIXME Matthew Wilcox says this
+- * isn't time-critical and we shouldn't make the CPU wait for
+- * the flush.
+- */
+- xhci_readl(xhci, db_addr);
+ }
+ }
+
diff --git a/usb/usb-xhci-make-xhci_handle_event-static.patch b/usb/usb-xhci-make-xhci_handle_event-static.patch
new file mode 100644
index 00000000000000..3915dc0ac22395
--- /dev/null
+++ b/usb/usb-xhci-make-xhci_handle_event-static.patch
@@ -0,0 +1,41 @@
+From sarah.a.sharp@linux.intel.com Mon Aug 2 16:06:16 2010
+Date: Thu, 29 Jul 2010 22:12:46 -0700
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Subject: USB: xhci: Make xhci_handle_event() static.
+Message-ID: <20100730051246.GA7368@xanatos>
+Content-Disposition: inline
+
+xhci_handle_event() is now only called from within xhci-ring.c, so make it
+static.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 2 +-
+ drivers/usb/host/xhci.h | 1 -
+ 2 files changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1964,7 +1964,7 @@ cleanup:
+ * This function handles all OS-owned events on the event ring. It may drop
+ * xhci->lock between event processing (e.g. to pass up port status changes).
+ */
+-void xhci_handle_event(struct xhci_hcd *xhci)
++static void xhci_handle_event(struct xhci_hcd *xhci)
+ {
+ union xhci_trb *event;
+ int update_ptrs = 1;
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1400,7 +1400,6 @@ struct xhci_segment *trb_in_td(struct xh
+ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code);
+ void xhci_ring_cmd_db(struct xhci_hcd *xhci);
+ void *xhci_setup_one_noop(struct xhci_hcd *xhci);
+-void xhci_handle_event(struct xhci_hcd *xhci);
+ void xhci_set_hc_event_deq(struct xhci_hcd *xhci);
+ int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id);
+ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
diff --git a/usb/usb-xhci-make-xhci_set_hc_event_deq-static.patch b/usb/usb-xhci-make-xhci_set_hc_event_deq-static.patch
new file mode 100644
index 00000000000000..c3dcfaab180487
--- /dev/null
+++ b/usb/usb-xhci-make-xhci_set_hc_event_deq-static.patch
@@ -0,0 +1,96 @@
+From sarah.a.sharp@linux.intel.com Mon Aug 2 16:06:42 2010
+Date: Thu, 29 Jul 2010 22:12:56 -0700
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Subject: USB: xhci: Make xhci_set_hc_event_deq() static.
+Message-ID: <20100730051256.GA7471@xanatos>
+Content-Disposition: inline
+
+Now that the event handler functions no longer use xhci_set_hc_event_deq()
+to update the event ring dequeue pointer, that function is not used by
+anything in xhci-ring.c. Move that function into xhci-mem.c and make it
+static.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-mem.c | 23 +++++++++++++++++++++++
+ drivers/usb/host/xhci-ring.c | 22 ----------------------
+ drivers/usb/host/xhci.h | 1 -
+ 3 files changed, 23 insertions(+), 23 deletions(-)
+
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -1601,6 +1601,29 @@ static int xhci_check_trb_in_td_math(str
+ return 0;
+ }
+
++static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
++{
++ u64 temp;
++ dma_addr_t deq;
++
++ deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
++ xhci->event_ring->dequeue);
++ if (deq == 0 && !in_interrupt())
++ xhci_warn(xhci, "WARN something wrong with SW event ring "
++ "dequeue ptr.\n");
++ /* Update HC event ring dequeue pointer */
++ temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++ temp &= ERST_PTR_MASK;
++ /* Don't clear the EHB bit (which is RW1C) because
++ * there might be more events to service.
++ */
++ temp &= ~ERST_EHB;
++ xhci_dbg(xhci, "// Write event ring dequeue pointer, "
++ "preserving EHB bit\n");
++ xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
++ &xhci->ir_set->erst_dequeue);
++}
++
+
+ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+ {
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -301,28 +301,6 @@ static int room_on_ring(struct xhci_hcd
+ return 1;
+ }
+
+-void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
+-{
+- u64 temp;
+- dma_addr_t deq;
+-
+- deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
+- xhci->event_ring->dequeue);
+- if (deq == 0 && !in_interrupt())
+- xhci_warn(xhci, "WARN something wrong with SW event ring "
+- "dequeue ptr.\n");
+- /* Update HC event ring dequeue pointer */
+- temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+- temp &= ERST_PTR_MASK;
+- /* Don't clear the EHB bit (which is RW1C) because
+- * there might be more events to service.
+- */
+- temp &= ~ERST_EHB;
+- xhci_dbg(xhci, "// Write event ring dequeue pointer, preserving EHB bit\n");
+- xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
+- &xhci->ir_set->erst_dequeue);
+-}
+-
+ /* Ring the host controller doorbell after placing a command on the ring */
+ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
+ {
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1400,7 +1400,6 @@ struct xhci_segment *trb_in_td(struct xh
+ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code);
+ void xhci_ring_cmd_db(struct xhci_hcd *xhci);
+ void *xhci_setup_one_noop(struct xhci_hcd *xhci);
+-void xhci_set_hc_event_deq(struct xhci_hcd *xhci);
+ int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id);
+ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
+ u32 slot_id);
diff --git a/usb/usb-xhci-minimize-hw-event-ring-dequeue-pointer-writes.patch b/usb/usb-xhci-minimize-hw-event-ring-dequeue-pointer-writes.patch
new file mode 100644
index 00000000000000..0bfee1d67b0430
--- /dev/null
+++ b/usb/usb-xhci-minimize-hw-event-ring-dequeue-pointer-writes.patch
@@ -0,0 +1,128 @@
+From sarah.a.sharp@linux.intel.com Mon Aug 2 16:06:29 2010
+Date: Thu, 29 Jul 2010 22:12:49 -0700
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Andiry Xu <andiry.xu@amd.com>
+Subject: USB: xhci: Minimize HW event ring dequeue pointer writes.
+Message-ID: <20100730051249.GA7415@xanatos>
+Content-Disposition: inline
+
+The xHCI specification suggests that writing the hardware event ring dequeue
+pointer register too often can be an expensive operation for the xHCI hardware
+to manage. It suggests minimizing the number of writes to that register.
+
+Originally, the driver wrote the event ring dequeue pointer after each
+event was processed. Depending on how the event ring moderation register
+is set up and how fast the transfers are completing, there may be several
+events processed for each interrupt. This patch makes the hardware event
+ring dequeue pointer be written only once per interrupt.
+
+Make the transfer event handler and port status event handler only write
+the software event ring dequeue pointer. Move the updating of the
+hardware event ring dequeue pointer into the interrupt function. Move the
+contents of xhci_set_hc_event_deq() into the interrupt handler. The
+interrupt handler must clear the event handler busy flag, so it might as
+well also write the dequeue pointer to the same register. This eliminates
+two 32-bit PCI reads and two 32-bit PCI writes.
+
+Reported-by: Andiry Xu <andiry.xu@amd.com>
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 50 +++++++++++++++++++++++++++++++------------
+ 1 file changed, 37 insertions(+), 13 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1184,7 +1184,6 @@ static void handle_port_status(struct xh
+
+ /* Update event ring dequeue pointer before dropping the lock */
+ inc_deq(xhci, xhci->event_ring, true);
+- xhci_set_hc_event_deq(xhci);
+
+ spin_unlock(&xhci->lock);
+ /* Pass this up to the core */
+@@ -1924,7 +1923,6 @@ cleanup:
+ */
+ if (trb_comp_code == COMP_MISSED_INT || !ep->skip) {
+ inc_deq(xhci, xhci->event_ring, true);
+- xhci_set_hc_event_deq(xhci);
+ }
+
+ if (ret) {
+@@ -2022,11 +2020,10 @@ static void xhci_handle_event(struct xhc
+ return;
+ }
+
+- if (update_ptrs) {
+- /* Update SW and HC event ring dequeue pointer */
++ if (update_ptrs)
++ /* Update SW event ring dequeue pointer */
+ inc_deq(xhci, xhci->event_ring, true);
+- xhci_set_hc_event_deq(xhci);
+- }
++
+ /* Are there more items on the event ring? */
+ xhci_handle_event(xhci);
+ }
+@@ -2042,6 +2039,8 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd
+ u32 status, irq_pending;
+ union xhci_trb *trb;
+ u64 temp_64;
++ union xhci_trb *event_ring_deq;
++ dma_addr_t deq;
+
+ spin_lock(&xhci->lock);
+ trb = xhci->event_ring->dequeue;
+@@ -2090,18 +2089,43 @@ hw_died:
+ irq_pending |= 0x3;
+ xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
+
+- if (xhci->xhc_state & XHCI_STATE_DYING)
++ if (xhci->xhc_state & XHCI_STATE_DYING) {
+ xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
+ "Shouldn't IRQs be disabled?\n");
+- else
+- /* FIXME this should be a delayed service routine
+- * that clears the EHB.
++ /* Clear the event handler busy flag (RW1C);
++ * the event ring should be empty.
+ */
+- xhci_handle_event(xhci);
++ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++ xhci_write_64(xhci, temp_64 | ERST_EHB,
++ &xhci->ir_set->erst_dequeue);
++ spin_unlock(&xhci->lock);
++
++ return IRQ_HANDLED;
++ }
++
++ event_ring_deq = xhci->event_ring->dequeue;
++ /* FIXME this should be a delayed service routine
++ * that clears the EHB.
++ */
++ xhci_handle_event(xhci);
+
+- /* Clear the event handler busy flag (RW1C); event ring is empty. */
+ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+- xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
++ /* If necessary, update the HW's version of the event ring deq ptr. */
++ if (event_ring_deq != xhci->event_ring->dequeue) {
++ deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
++ xhci->event_ring->dequeue);
++ if (deq == 0)
++ xhci_warn(xhci, "WARN something wrong with SW event "
++ "ring dequeue ptr.\n");
++ /* Update HC event ring dequeue pointer */
++ temp_64 &= ERST_PTR_MASK;
++ temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
++ }
++
++ /* Clear the event handler busy flag (RW1C); event ring is empty. */
++ temp_64 |= ERST_EHB;
++ xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
++
+ spin_unlock(&xhci->lock);
+
+ return IRQ_HANDLED;
diff --git a/usb/usb-xhci-performance-move-functions-that-find-ep-ring.patch b/usb/usb-xhci-performance-move-functions-that-find-ep-ring.patch
new file mode 100644
index 00000000000000..de7968d3252e48
--- /dev/null
+++ b/usb/usb-xhci-performance-move-functions-that-find-ep-ring.patch
@@ -0,0 +1,204 @@
+From sarah.a.sharp@linux.intel.com Mon Aug 2 16:05:02 2010
+Date: Thu, 29 Jul 2010 22:12:20 -0700
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Subject: USB: xhci: Performance - move functions that find ep ring.
+Message-ID: <20100730051220.GA6410@xanatos>
+Content-Disposition: inline
+
+I've been using perf to measure the top symbols while transferring 1GB of data
+on a USB 3.0 drive with dd. This is using the raw disk with /dev/sdb, with a
+block size of 1K.
+
+During performance testing, the top symbol was xhci_triad_to_transfer_ring(), a
+function that should return immediately if streams are not enabled for an
+endpoint. It turned out that the functions to find the endpoint ring was
+defined in xhci-mem.c and used in xhci-ring.c and xhci-hcd.c. I moved a copy of
+xhci_triad_to_transfer_ring() and xhci_urb_to_transfer_ring() into xhci-ring.c
+and declared them static. I also made a static version of
+xhci_urb_to_transfer_ring() in xhci.c.
+
+This improved throughput on a 1GB read of the raw disk with dd from
+186MB/s to 195MB/s, and perf reported sampling the xhci_triad_to_transfer_ring()
+0.06% of the time, rather than 9.26% of the time.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-mem.c | 43 ------------------------------------------
+ drivers/usb/host/xhci-ring.c | 44 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/host/xhci.c | 41 ++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/host/xhci.h | 5 ----
+ 4 files changed, 85 insertions(+), 48 deletions(-)
+
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -391,49 +391,6 @@ struct xhci_ring *xhci_stream_id_to_ring
+ return ep->stream_info->stream_rings[stream_id];
+ }
+
+-struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
+- unsigned int slot_id, unsigned int ep_index,
+- unsigned int stream_id)
+-{
+- struct xhci_virt_ep *ep;
+-
+- ep = &xhci->devs[slot_id]->eps[ep_index];
+- /* Common case: no streams */
+- if (!(ep->ep_state & EP_HAS_STREAMS))
+- return ep->ring;
+-
+- if (stream_id == 0) {
+- xhci_warn(xhci,
+- "WARN: Slot ID %u, ep index %u has streams, "
+- "but URB has no stream ID.\n",
+- slot_id, ep_index);
+- return NULL;
+- }
+-
+- if (stream_id < ep->stream_info->num_streams)
+- return ep->stream_info->stream_rings[stream_id];
+-
+- xhci_warn(xhci,
+- "WARN: Slot ID %u, ep index %u has "
+- "stream IDs 1 to %u allocated, "
+- "but stream ID %u is requested.\n",
+- slot_id, ep_index,
+- ep->stream_info->num_streams - 1,
+- stream_id);
+- return NULL;
+-}
+-
+-/* Get the right ring for the given URB.
+- * If the endpoint supports streams, boundary check the URB's stream ID.
+- * If the endpoint doesn't support streams, return the singular endpoint ring.
+- */
+-struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
+- struct urb *urb)
+-{
+- return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
+- xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id);
+-}
+-
+ #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
+ static int xhci_test_radix_tree(struct xhci_hcd *xhci,
+ unsigned int num_streams,
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -419,6 +419,50 @@ static struct xhci_segment *find_trb_seg
+ return cur_seg;
+ }
+
++
++static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
++ unsigned int slot_id, unsigned int ep_index,
++ unsigned int stream_id)
++{
++ struct xhci_virt_ep *ep;
++
++ ep = &xhci->devs[slot_id]->eps[ep_index];
++ /* Common case: no streams */
++ if (!(ep->ep_state & EP_HAS_STREAMS))
++ return ep->ring;
++
++ if (stream_id == 0) {
++ xhci_warn(xhci,
++ "WARN: Slot ID %u, ep index %u has streams, "
++ "but URB has no stream ID.\n",
++ slot_id, ep_index);
++ return NULL;
++ }
++
++ if (stream_id < ep->stream_info->num_streams)
++ return ep->stream_info->stream_rings[stream_id];
++
++ xhci_warn(xhci,
++ "WARN: Slot ID %u, ep index %u has "
++ "stream IDs 1 to %u allocated, "
++ "but stream ID %u is requested.\n",
++ slot_id, ep_index,
++ ep->stream_info->num_streams - 1,
++ stream_id);
++ return NULL;
++}
++
++/* Get the right ring for the given URB.
++ * If the endpoint supports streams, boundary check the URB's stream ID.
++ * If the endpoint doesn't support streams, return the singular endpoint ring.
++ */
++static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
++ struct urb *urb)
++{
++ return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
++ xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id);
++}
++
+ /*
+ * Move the xHC's endpoint ring dequeue pointer past cur_td.
+ * Record the new state of the xHC's endpoint ring dequeue segment,
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -916,6 +916,47 @@ dying:
+ return -ESHUTDOWN;
+ }
+
++/* Get the right ring for the given URB.
++ * If the endpoint supports streams, boundary check the URB's stream ID.
++ * If the endpoint doesn't support streams, return the singular endpoint ring.
++ */
++static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
++ struct urb *urb)
++{
++ unsigned int slot_id;
++ unsigned int ep_index;
++ unsigned int stream_id;
++ struct xhci_virt_ep *ep;
++
++ slot_id = urb->dev->slot_id;
++ ep_index = xhci_get_endpoint_index(&urb->ep->desc);
++ stream_id = urb->stream_id;
++ ep = &xhci->devs[slot_id]->eps[ep_index];
++ /* Common case: no streams */
++ if (!(ep->ep_state & EP_HAS_STREAMS))
++ return ep->ring;
++
++ if (stream_id == 0) {
++ xhci_warn(xhci,
++ "WARN: Slot ID %u, ep index %u has streams, "
++ "but URB has no stream ID.\n",
++ slot_id, ep_index);
++ return NULL;
++ }
++
++ if (stream_id < ep->stream_info->num_streams)
++ return ep->stream_info->stream_rings[stream_id];
++
++ xhci_warn(xhci,
++ "WARN: Slot ID %u, ep index %u has "
++ "stream IDs 1 to %u allocated, "
++ "but stream ID %u is requested.\n",
++ slot_id, ep_index,
++ ep->stream_info->num_streams - 1,
++ stream_id);
++ return NULL;
++}
++
+ /*
+ * Remove the URB's TD from the endpoint ring. This may cause the HC to stop
+ * USB transfers, potentially stopping in the middle of a TRB buffer. The HC
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1344,11 +1344,6 @@ void xhci_setup_no_streams_ep_input_ctx(
+ struct xhci_ring *xhci_dma_to_transfer_ring(
+ struct xhci_virt_ep *ep,
+ u64 address);
+-struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
+- struct urb *urb);
+-struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
+- unsigned int slot_id, unsigned int ep_index,
+- unsigned int stream_id);
+ struct xhci_ring *xhci_stream_id_to_ring(
+ struct xhci_virt_device *dev,
+ unsigned int ep_index,
diff --git a/usb/usb-xhci-performance-move-interrupt-handlers-into-xhci-ring.c.patch b/usb/usb-xhci-performance-move-interrupt-handlers-into-xhci-ring.c.patch
new file mode 100644
index 00000000000000..42b94be8694697
--- /dev/null
+++ b/usb/usb-xhci-performance-move-interrupt-handlers-into-xhci-ring.c.patch
@@ -0,0 +1,268 @@
+From sarah.a.sharp@linux.intel.com Mon Aug 2 16:05:17 2010
+Date: Thu, 29 Jul 2010 22:12:29 -0700
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Subject: USB: xhci: Performance - move interrupt handlers into xhci-ring.c
+Message-ID: <20100730051229.GA7229@xanatos>
+Content-Disposition: inline
+
+Most of the work for interrupt handling is done in xhci-ring.c, so it makes
+sense to move the functions that are first called when an interrupt happens
+(xhci_irq() or xhci_msi_irq()) into xhci-ring.c, so that the compiler can better
+optimize them.
+
+Shorten some lines to make it pass checkpatch.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 103 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/host/xhci.c | 103 -------------------------------------------
+ drivers/usb/host/xhci.h | 1
+ 3 files changed, 104 insertions(+), 103 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -2030,6 +2030,109 @@ void xhci_handle_event(struct xhci_hcd *
+ /* Are there more items on the event ring? */
+ xhci_handle_event(xhci);
+ }
++/*
++ * Called in interrupt context when there might be work
++ * queued on the event ring
++ *
++ * xhci->lock must be held by caller.
++ */
++static void xhci_work(struct xhci_hcd *xhci)
++{
++ u32 temp;
++ u64 temp_64;
++
++ /*
++ * Clear the op reg interrupt status first,
++ * so we can receive interrupts from other MSI-X interrupters.
++ * Write 1 to clear the interrupt status.
++ */
++ temp = xhci_readl(xhci, &xhci->op_regs->status);
++ temp |= STS_EINT;
++ xhci_writel(xhci, temp, &xhci->op_regs->status);
++ /* FIXME when MSI-X is supported and there are multiple vectors */
++ /* Clear the MSI-X event interrupt status */
++
++ /* Acknowledge the interrupt */
++ temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
++ temp |= 0x3;
++ xhci_writel(xhci, temp, &xhci->ir_set->irq_pending);
++
++ if (xhci->xhc_state & XHCI_STATE_DYING)
++ xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
++ "Shouldn't IRQs be disabled?\n");
++ else
++ /* FIXME this should be a delayed service routine
++ * that clears the EHB.
++ */
++ xhci_handle_event(xhci);
++
++ /* Clear the event handler busy flag (RW1C); event ring is empty. */
++ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++ xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
++ /* Flush posted writes -- FIXME is this necessary? */
++ xhci_readl(xhci, &xhci->ir_set->irq_pending);
++}
++
++/*
++ * xHCI spec says we can get an interrupt, and if the HC has an error condition,
++ * we might get bad data out of the event ring. Section 4.10.2.7 has a list of
++ * indicators of an event TRB error, but we check the status *first* to be safe.
++ */
++irqreturn_t xhci_irq(struct usb_hcd *hcd)
++{
++ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++ u32 temp, temp2;
++ union xhci_trb *trb;
++
++ spin_lock(&xhci->lock);
++ trb = xhci->event_ring->dequeue;
++ /* Check if the xHC generated the interrupt, or the irq is shared */
++ temp = xhci_readl(xhci, &xhci->op_regs->status);
++ temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending);
++ if (temp == 0xffffffff && temp2 == 0xffffffff)
++ goto hw_died;
++
++ if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) {
++ spin_unlock(&xhci->lock);
++ xhci_warn(xhci, "Spurious interrupt.\n");
++ return IRQ_NONE;
++ }
++ xhci_dbg(xhci, "op reg status = %08x\n", temp);
++ xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2);
++ xhci_dbg(xhci, "Event ring dequeue ptr:\n");
++ xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
++ (unsigned long long)
++ xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb),
++ lower_32_bits(trb->link.segment_ptr),
++ upper_32_bits(trb->link.segment_ptr),
++ (unsigned int) trb->link.intr_target,
++ (unsigned int) trb->link.control);
++
++ if (temp & STS_FATAL) {
++ xhci_warn(xhci, "WARNING: Host System Error\n");
++ xhci_halt(xhci);
++hw_died:
++ xhci_to_hcd(xhci)->state = HC_STATE_HALT;
++ spin_unlock(&xhci->lock);
++ return -ESHUTDOWN;
++ }
++
++ xhci_work(xhci);
++ spin_unlock(&xhci->lock);
++
++ return IRQ_HANDLED;
++}
++
++irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)
++{
++ irqreturn_t ret;
++
++ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
++
++ ret = xhci_irq(hcd);
++
++ return ret;
++}
+
+ /**** Endpoint Ring Operations ****/
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -172,17 +172,6 @@ int xhci_reset(struct xhci_hcd *xhci)
+ return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
+ }
+
+-static irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)
+-{
+- irqreturn_t ret;
+-
+- set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+-
+- ret = xhci_irq(hcd);
+-
+- return ret;
+-}
+-
+ /*
+ * Free IRQs
+ * free all IRQs request
+@@ -332,100 +321,8 @@ int xhci_init(struct usb_hcd *hcd)
+ return retval;
+ }
+
+-/*
+- * Called in interrupt context when there might be work
+- * queued on the event ring
+- *
+- * xhci->lock must be held by caller.
+- */
+-static void xhci_work(struct xhci_hcd *xhci)
+-{
+- u32 temp;
+- u64 temp_64;
+-
+- /*
+- * Clear the op reg interrupt status first,
+- * so we can receive interrupts from other MSI-X interrupters.
+- * Write 1 to clear the interrupt status.
+- */
+- temp = xhci_readl(xhci, &xhci->op_regs->status);
+- temp |= STS_EINT;
+- xhci_writel(xhci, temp, &xhci->op_regs->status);
+- /* FIXME when MSI-X is supported and there are multiple vectors */
+- /* Clear the MSI-X event interrupt status */
+-
+- /* Acknowledge the interrupt */
+- temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+- temp |= 0x3;
+- xhci_writel(xhci, temp, &xhci->ir_set->irq_pending);
+- /* Flush posted writes */
+- xhci_readl(xhci, &xhci->ir_set->irq_pending);
+-
+- if (xhci->xhc_state & XHCI_STATE_DYING)
+- xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
+- "Shouldn't IRQs be disabled?\n");
+- else
+- /* FIXME this should be a delayed service routine
+- * that clears the EHB.
+- */
+- xhci_handle_event(xhci);
+-
+- /* Clear the event handler busy flag (RW1C); the event ring should be empty. */
+- temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+- xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
+- /* Flush posted writes -- FIXME is this necessary? */
+- xhci_readl(xhci, &xhci->ir_set->irq_pending);
+-}
+-
+ /*-------------------------------------------------------------------------*/
+
+-/*
+- * xHCI spec says we can get an interrupt, and if the HC has an error condition,
+- * we might get bad data out of the event ring. Section 4.10.2.7 has a list of
+- * indicators of an event TRB error, but we check the status *first* to be safe.
+- */
+-irqreturn_t xhci_irq(struct usb_hcd *hcd)
+-{
+- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+- u32 temp, temp2;
+- union xhci_trb *trb;
+-
+- spin_lock(&xhci->lock);
+- trb = xhci->event_ring->dequeue;
+- /* Check if the xHC generated the interrupt, or the irq is shared */
+- temp = xhci_readl(xhci, &xhci->op_regs->status);
+- temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+- if (temp == 0xffffffff && temp2 == 0xffffffff)
+- goto hw_died;
+-
+- if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) {
+- spin_unlock(&xhci->lock);
+- return IRQ_NONE;
+- }
+- xhci_dbg(xhci, "op reg status = %08x\n", temp);
+- xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2);
+- xhci_dbg(xhci, "Event ring dequeue ptr:\n");
+- xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
+- (unsigned long long)xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb),
+- lower_32_bits(trb->link.segment_ptr),
+- upper_32_bits(trb->link.segment_ptr),
+- (unsigned int) trb->link.intr_target,
+- (unsigned int) trb->link.control);
+-
+- if (temp & STS_FATAL) {
+- xhci_warn(xhci, "WARNING: Host System Error\n");
+- xhci_halt(xhci);
+-hw_died:
+- xhci_to_hcd(xhci)->state = HC_STATE_HALT;
+- spin_unlock(&xhci->lock);
+- return -ESHUTDOWN;
+- }
+-
+- xhci_work(xhci);
+- spin_unlock(&xhci->lock);
+-
+- return IRQ_HANDLED;
+-}
+
+ #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
+ void xhci_event_ring_work(unsigned long arg)
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1371,6 +1371,7 @@ void xhci_stop(struct usb_hcd *hcd);
+ void xhci_shutdown(struct usb_hcd *hcd);
+ 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);
+ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
+ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
+ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
diff --git a/usb/usb-xhci-performance-move-xhci_work-into-xhci_irq.patch b/usb/usb-xhci-performance-move-xhci_work-into-xhci_irq.patch
new file mode 100644
index 00000000000000..b50eb913faf020
--- /dev/null
+++ b/usb/usb-xhci-performance-move-xhci_work-into-xhci_irq.patch
@@ -0,0 +1,115 @@
+From sarah.a.sharp@linux.intel.com Mon Aug 2 16:05:41 2010
+Date: Thu, 29 Jul 2010 22:12:38 -0700
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Subject: USB: xhci: Performance - move xhci_work() into xhci_irq()
+Message-ID: <20100730051238.GA7256@xanatos>
+Content-Disposition: inline
+
+When we move xhci_work() into xhci_irq(), we don't need to read the operational
+register status field twice.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 73 +++++++++++++++++--------------------------
+ 1 file changed, 30 insertions(+), 43 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -2030,48 +2030,6 @@ void xhci_handle_event(struct xhci_hcd *
+ /* Are there more items on the event ring? */
+ xhci_handle_event(xhci);
+ }
+-/*
+- * Called in interrupt context when there might be work
+- * queued on the event ring
+- *
+- * xhci->lock must be held by caller.
+- */
+-static void xhci_work(struct xhci_hcd *xhci)
+-{
+- u32 temp;
+- u64 temp_64;
+-
+- /*
+- * Clear the op reg interrupt status first,
+- * so we can receive interrupts from other MSI-X interrupters.
+- * Write 1 to clear the interrupt status.
+- */
+- temp = xhci_readl(xhci, &xhci->op_regs->status);
+- temp |= STS_EINT;
+- xhci_writel(xhci, temp, &xhci->op_regs->status);
+- /* FIXME when MSI-X is supported and there are multiple vectors */
+- /* Clear the MSI-X event interrupt status */
+-
+- /* Acknowledge the interrupt */
+- temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+- temp |= 0x3;
+- xhci_writel(xhci, temp, &xhci->ir_set->irq_pending);
+-
+- if (xhci->xhc_state & XHCI_STATE_DYING)
+- xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
+- "Shouldn't IRQs be disabled?\n");
+- else
+- /* FIXME this should be a delayed service routine
+- * that clears the EHB.
+- */
+- xhci_handle_event(xhci);
+-
+- /* Clear the event handler busy flag (RW1C); event ring is empty. */
+- temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+- xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
+- /* Flush posted writes -- FIXME is this necessary? */
+- xhci_readl(xhci, &xhci->ir_set->irq_pending);
+-}
+
+ /*
+ * xHCI spec says we can get an interrupt, and if the HC has an error condition,
+@@ -2083,6 +2041,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ u32 temp, temp2;
+ union xhci_trb *trb;
++ u64 temp_64;
+
+ spin_lock(&xhci->lock);
+ trb = xhci->event_ring->dequeue;
+@@ -2117,7 +2076,35 @@ hw_died:
+ return -ESHUTDOWN;
+ }
+
+- xhci_work(xhci);
++ /*
++ * Clear the op reg interrupt status first,
++ * so we can receive interrupts from other MSI-X interrupters.
++ * Write 1 to clear the interrupt status.
++ */
++ temp |= STS_EINT;
++ xhci_writel(xhci, temp, &xhci->op_regs->status);
++ /* FIXME when MSI-X is supported and there are multiple vectors */
++ /* Clear the MSI-X event interrupt status */
++
++ /* Acknowledge the interrupt */
++ temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
++ temp |= 0x3;
++ xhci_writel(xhci, temp, &xhci->ir_set->irq_pending);
++
++ if (xhci->xhc_state & XHCI_STATE_DYING)
++ xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
++ "Shouldn't IRQs be disabled?\n");
++ else
++ /* FIXME this should be a delayed service routine
++ * that clears the EHB.
++ */
++ xhci_handle_event(xhci);
++
++ /* Clear the event handler busy flag (RW1C); event ring is empty. */
++ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++ xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
++ /* Flush posted writes -- FIXME is this necessary? */
++ xhci_readl(xhci, &xhci->ir_set->irq_pending);
+ spin_unlock(&xhci->lock);
+
+ return IRQ_HANDLED;
diff --git a/usb/usb-xhci-reduce-reads-and-writes-of-interrupter-registers.patch b/usb/usb-xhci-reduce-reads-and-writes-of-interrupter-registers.patch
new file mode 100644
index 00000000000000..d10c17408e181a
--- /dev/null
+++ b/usb/usb-xhci-reduce-reads-and-writes-of-interrupter-registers.patch
@@ -0,0 +1,83 @@
+From sarah.a.sharp@linux.intel.com Mon Aug 2 16:06:55 2010
+Date: Thu, 29 Jul 2010 22:13:00 -0700
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Subject: USB: xhci: Reduce reads and writes of interrupter registers.
+Message-ID: <20100730051300.GA7561@xanatos>
+Content-Disposition: inline
+
+The interrupter register set includes a register that says whether interrupts
+are pending for each event ring (the IP bit). Each MSI-X vector will get its
+own interrupter set with separate IP bits. The status register includes an
+"Event Interrupt (EINT)" bit that is set when an IP bit is set in any of the
+interrupters.
+
+When PCI interrupts are used, the EINT bit exactly mirrors the IP bit in the
+single interrupter set, and it is a waste of time to check both registers when
+trying to figure out if the xHC interrupted or another device on the shared IRQ
+line interrupted. Only check the IP bit to reduce register reads.
+
+The IP bit is automatically cleared by the xHC when MSI or MSI-X is enabled. It
+doesn't make sense to read that register to check for shared interrupts (since
+MSI and MSI-X aren't shared). It also doesn't make sense to write to that
+register to clear the IP bit, since it is cleared by the hardware.
+
+We can tell whether MSI or MSI-X is enabled by looking at the irq number in
+hcd->irq. If it's -1, we know MSI or MSI-X is enabled.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -2014,7 +2014,7 @@ static void xhci_handle_event(struct xhc
+ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+ {
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+- u32 status, irq_pending;
++ u32 status;
+ union xhci_trb *trb;
+ u64 temp_64;
+ union xhci_trb *event_ring_deq;
+@@ -2024,17 +2024,15 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd
+ trb = xhci->event_ring->dequeue;
+ /* Check if the xHC generated the interrupt, or the irq is shared */
+ status = xhci_readl(xhci, &xhci->op_regs->status);
+- irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+- if (status == 0xffffffff && irq_pending == 0xffffffff)
++ if (status == 0xffffffff)
+ goto hw_died;
+
+- if (!(status & STS_EINT) && !ER_IRQ_PENDING(irq_pending)) {
++ if (!(status & STS_EINT)) {
+ spin_unlock(&xhci->lock);
+ xhci_warn(xhci, "Spurious interrupt.\n");
+ return IRQ_NONE;
+ }
+ xhci_dbg(xhci, "op reg status = %08x\n", status);
+- xhci_dbg(xhci, "ir set irq_pending = %08x\n", irq_pending);
+ xhci_dbg(xhci, "Event ring dequeue ptr:\n");
+ xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
+ (unsigned long long)
+@@ -2063,9 +2061,13 @@ hw_died:
+ /* FIXME when MSI-X is supported and there are multiple vectors */
+ /* Clear the MSI-X event interrupt status */
+
+- /* Acknowledge the interrupt */
+- irq_pending |= 0x3;
+- xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
++ if (hcd->irq != -1) {
++ u32 irq_pending;
++ /* Acknowledge the PCI interrupt */
++ irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
++ irq_pending |= 0x3;
++ xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
++ }
+
+ if (xhci->xhc_state & XHCI_STATE_DYING) {
+ xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
diff --git a/usb/usb-xhci-remove-unnecessary-reads-of-irq_pending-register.patch b/usb/usb-xhci-remove-unnecessary-reads-of-irq_pending-register.patch
new file mode 100644
index 00000000000000..71d1c650a34c5a
--- /dev/null
+++ b/usb/usb-xhci-remove-unnecessary-reads-of-irq_pending-register.patch
@@ -0,0 +1,95 @@
+From sarah.a.sharp@linux.intel.com Mon Aug 2 16:06:01 2010
+Date: Thu, 29 Jul 2010 22:12:43 -0700
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Subject: USB: xhci: Remove unnecessary reads of IRQ_PENDING register.
+Message-ID: <20100730051243.GA7312@xanatos>
+Content-Disposition: inline
+
+Remove a duplicate register read of the interrupt pending register from
+xhci_irq(). Also, remove waiting on the posted write of that register.
+The host will see it eventually. It will probably read the register
+itself before deciding whether to interrupt the system again, forcing the
+posted write to complete.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-ring.c | 27 ++++++++++++---------------
+ 1 file changed, 12 insertions(+), 15 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -2039,25 +2039,25 @@ void xhci_handle_event(struct xhci_hcd *
+ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+ {
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+- u32 temp, temp2;
++ u32 status, irq_pending;
+ union xhci_trb *trb;
+ u64 temp_64;
+
+ spin_lock(&xhci->lock);
+ trb = xhci->event_ring->dequeue;
+ /* Check if the xHC generated the interrupt, or the irq is shared */
+- temp = xhci_readl(xhci, &xhci->op_regs->status);
+- temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+- if (temp == 0xffffffff && temp2 == 0xffffffff)
++ status = xhci_readl(xhci, &xhci->op_regs->status);
++ irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
++ if (status == 0xffffffff && irq_pending == 0xffffffff)
+ goto hw_died;
+
+- if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) {
++ if (!(status & STS_EINT) && !ER_IRQ_PENDING(irq_pending)) {
+ spin_unlock(&xhci->lock);
+ xhci_warn(xhci, "Spurious interrupt.\n");
+ return IRQ_NONE;
+ }
+- xhci_dbg(xhci, "op reg status = %08x\n", temp);
+- xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2);
++ xhci_dbg(xhci, "op reg status = %08x\n", status);
++ xhci_dbg(xhci, "ir set irq_pending = %08x\n", irq_pending);
+ xhci_dbg(xhci, "Event ring dequeue ptr:\n");
+ xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
+ (unsigned long long)
+@@ -2067,7 +2067,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd
+ (unsigned int) trb->link.intr_target,
+ (unsigned int) trb->link.control);
+
+- if (temp & STS_FATAL) {
++ if (status & STS_FATAL) {
+ xhci_warn(xhci, "WARNING: Host System Error\n");
+ xhci_halt(xhci);
+ hw_died:
+@@ -2081,15 +2081,14 @@ hw_died:
+ * so we can receive interrupts from other MSI-X interrupters.
+ * Write 1 to clear the interrupt status.
+ */
+- temp |= STS_EINT;
+- xhci_writel(xhci, temp, &xhci->op_regs->status);
++ status |= STS_EINT;
++ xhci_writel(xhci, status, &xhci->op_regs->status);
+ /* FIXME when MSI-X is supported and there are multiple vectors */
+ /* Clear the MSI-X event interrupt status */
+
+ /* Acknowledge the interrupt */
+- temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+- temp |= 0x3;
+- xhci_writel(xhci, temp, &xhci->ir_set->irq_pending);
++ irq_pending |= 0x3;
++ xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
+
+ if (xhci->xhc_state & XHCI_STATE_DYING)
+ xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
+@@ -2103,8 +2102,6 @@ hw_died:
+ /* Clear the event handler busy flag (RW1C); event ring is empty. */
+ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+ xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
+- /* Flush posted writes -- FIXME is this necessary? */
+- xhci_readl(xhci, &xhci->ir_set->irq_pending);
+ spin_unlock(&xhci->lock);
+
+ return IRQ_HANDLED;
diff --git a/usb/usb-xhci-set-dma-mask-for-host.patch b/usb/usb-xhci-set-dma-mask-for-host.patch
new file mode 100644
index 00000000000000..a00866b74aef92
--- /dev/null
+++ b/usb/usb-xhci-set-dma-mask-for-host.patch
@@ -0,0 +1,49 @@
+From sarah.a.sharp@linux.intel.com Mon Aug 2 16:07:23 2010
+Date: Thu, 29 Jul 2010 22:13:22 -0700
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org
+Subject: USB: xhci: Set DMA mask for host.
+Message-ID: <20100730051322.GA7664@xanatos>
+Content-Disposition: inline
+
+Tell the USB core that we can do DMA directly (instead of needing it to
+memory-map the buffers for PIO). If the xHCI host supports 64-bit addresses,
+set the DMA mask accordingly. Otherwise indicate the host can handle 32-bit DMA
+addresses.
+
+This improves performance because the USB core doesn't have to spend time
+remapping buffers in high memory into the 32-bit address range.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-pci.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -53,6 +53,7 @@ static int xhci_pci_setup(struct usb_hcd
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ int retval;
++ u32 temp;
+
+ hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
+
+@@ -93,6 +94,14 @@ static int xhci_pci_setup(struct usb_hcd
+ return retval;
+ xhci_dbg(xhci, "Reset complete\n");
+
++ temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
++ if (HCC_64BIT_ADDR(temp)) {
++ xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
++ dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
++ } else {
++ dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
++ }
++
+ xhci_dbg(xhci, "Calling HCD init\n");
+ /* Initialize HCD and host controller data structures. */
+ retval = xhci_init(hcd);