]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
more .31 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Sat, 5 Dec 2009 19:41:07 +0000 (11:41 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Sat, 5 Dec 2009 19:41:07 +0000 (11:41 -0800)
12 files changed:
queue-2.6.31/md-revert-incorrect-fix-for-read-error-handling-in-raid1.patch [new file with mode: 0644]
queue-2.6.31/modules-don-t-export-section-names-of-empty-sections-via-sysfs.patch [new file with mode: 0644]
queue-2.6.31/param-don-t-complain-about-unused-module-parameters.patch [new file with mode: 0644]
queue-2.6.31/pxamci-call-mmc_remove_host-before-freeing-resources.patch [new file with mode: 0644]
queue-2.6.31/series
queue-2.6.31/speedstep-ich-fix-error-caused-by-394122ab144dae4b276d74644a2f11c44a60ac5c.patch [new file with mode: 0644]
queue-2.6.31/tty_port-handle-the-nonblocking-open-of-a-dead-port-corner-case.patch [new file with mode: 0644]
queue-2.6.31/usb-amd5536udc-fixed-shared-interrupt-bug-and-warning-oops.patch [new file with mode: 0644]
queue-2.6.31/usb-ehci-don-t-send-clear-tt-buffer-following-a-stall.patch [new file with mode: 0644]
queue-2.6.31/usb-ftdi_sio-keep-going-when-write-errors-are-encountered.patch [new file with mode: 0644]
queue-2.6.31/usb-musb_gadget-fix-stall-handling.patch [new file with mode: 0644]
queue-2.6.31/usb-work-around-for-ehci-with-quirky-periodic-schedules.patch [new file with mode: 0644]

diff --git a/queue-2.6.31/md-revert-incorrect-fix-for-read-error-handling-in-raid1.patch b/queue-2.6.31/md-revert-incorrect-fix-for-read-error-handling-in-raid1.patch
new file mode 100644 (file)
index 0000000..9f18a33
--- /dev/null
@@ -0,0 +1,50 @@
+From d0e260782c3702a009645c3caa02e381dab8798b Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Tue, 1 Dec 2009 17:30:59 +1100
+Subject: md: revert incorrect fix for read error handling in raid1.
+
+From: NeilBrown <neilb@suse.de>
+
+commit d0e260782c3702a009645c3caa02e381dab8798b upstream.
+
+commit 4706b349f was a forward port of a fix that was needed
+for SLES10.  But in fact it is not needed in mainline because
+the earlier commit dd00a99e7a fixes the same problem in a
+better way.
+Further, this commit introduces a bug in the way it interacts with
+the automatic read-error-correction.  If, after a read error is
+successfully corrected, the same disk is chosen to re-read - the
+re-read won't be attempted but an error will be returned instead.
+
+After reverting that commit, there is the possibility that a
+read error on a read-only array (where read errors cannot
+be corrected as that requires a write) will repeatedly read the same
+device and continue to get an error.
+So in the "Array is readonly" case, fail the drive immediately on
+a read error.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/raid1.c |    7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/md/raid1.c
++++ b/drivers/md/raid1.c
+@@ -1643,11 +1643,12 @@ static void raid1d(mddev_t *mddev)
+                                              r1_bio->sector,
+                                              r1_bio->sectors);
+                               unfreeze_array(conf);
+-                      }
++                      } else
++                              md_error(mddev,
++                                       conf->mirrors[r1_bio->read_disk].rdev);
+                       bio = r1_bio->bios[r1_bio->read_disk];
+-                      if ((disk=read_balance(conf, r1_bio)) == -1 ||
+-                          disk == r1_bio->read_disk) {
++                      if ((disk=read_balance(conf, r1_bio)) == -1) {
+                               printk(KERN_ALERT "raid1: %s: unrecoverable I/O"
+                                      " read error for block %llu\n",
+                                      bdevname(bio->bi_bdev,b),
diff --git a/queue-2.6.31/modules-don-t-export-section-names-of-empty-sections-via-sysfs.patch b/queue-2.6.31/modules-don-t-export-section-names-of-empty-sections-via-sysfs.patch
new file mode 100644 (file)
index 0000000..b007c84
--- /dev/null
@@ -0,0 +1,74 @@
+From 35dead4235e2b67da7275b4122fed37099c2f462 Mon Sep 17 00:00:00 2001
+From: Helge Deller <deller@gmx.de>
+Date: Thu, 3 Dec 2009 00:29:15 +0100
+Subject: modules: don't export section names of empty sections via sysfs
+
+From: Helge Deller <deller@gmx.de>
+
+commit 35dead4235e2b67da7275b4122fed37099c2f462 upstream.
+
+On the parisc architecture we face for each and every loaded kernel module
+this kernel "badness warning":
+  sysfs: cannot create duplicate filename '/module/ac97_bus/sections/.text'
+  Badness at fs/sysfs/dir.c:487
+
+Reason for that is, that on parisc all kernel modules do have multiple
+.text sections due to the usage of the -ffunction-sections compiler flag
+which is needed to reach all jump targets on this platform.
+
+An objdump on such a kernel module gives:
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  0 .note.gnu.build-id 00000024  00000000  00000000  00000034  2**2
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+  1 .text         00000000  00000000  00000000  00000058  2**0
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE
+  2 .text.ac97_bus_match 0000001c  00000000  00000000  00000058  2**2
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE
+  3 .text         00000000  00000000  00000000  000000d4  2**0
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE
+...
+Since the .text sections are empty (size of 0 bytes) and won't be
+loaded by the kernel module loader anyway, I don't see a reason
+why such sections need to be listed under
+/sys/module/<module_name>/sections/<section_name> either.
+
+The attached patch does solve this issue by not exporting section
+names which are empty.
+
+This fixes bugzilla http://bugzilla.kernel.org/show_bug.cgi?id=14703
+
+Signed-off-by: Helge Deller <deller@gmx.de>
+CC: rusty@rustcorp.com.au
+CC: akpm@linux-foundation.org
+CC: James.Bottomley@HansenPartnership.com
+CC: roland@redhat.com
+CC: dave@hiauly1.hia.nrc.ca
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ kernel/module.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -1179,7 +1179,8 @@ static void add_sect_attrs(struct module
+       /* Count loaded sections and allocate structures */
+       for (i = 0; i < nsect; i++)
+-              if (sechdrs[i].sh_flags & SHF_ALLOC)
++              if (sechdrs[i].sh_flags & SHF_ALLOC
++                  && sechdrs[i].sh_size)
+                       nloaded++;
+       size[0] = ALIGN(sizeof(*sect_attrs)
+                       + nloaded * sizeof(sect_attrs->attrs[0]),
+@@ -1199,6 +1200,8 @@ static void add_sect_attrs(struct module
+       for (i = 0; i < nsect; i++) {
+               if (! (sechdrs[i].sh_flags & SHF_ALLOC))
+                       continue;
++              if (!sechdrs[i].sh_size)
++                      continue;
+               sattr->address = sechdrs[i].sh_addr;
+               sattr->name = kstrdup(secstrings + sechdrs[i].sh_name,
+                                       GFP_KERNEL);
diff --git a/queue-2.6.31/param-don-t-complain-about-unused-module-parameters.patch b/queue-2.6.31/param-don-t-complain-about-unused-module-parameters.patch
new file mode 100644 (file)
index 0000000..f55370b
--- /dev/null
@@ -0,0 +1,51 @@
+From f066a4f6df68f03b565dfe867dde54dfeb26576e Mon Sep 17 00:00:00 2001
+From: Rusty Russell <rusty@rustcorp.com.au>
+Date: Tue, 1 Dec 2009 14:56:44 +1030
+Subject: param: don't complain about unused module parameters.
+
+From: Rusty Russell <rusty@rustcorp.com.au>
+
+commit f066a4f6df68f03b565dfe867dde54dfeb26576e upstream.
+
+Jon confirms that recent modprobe will look in /proc/cmdline, so these
+cmdline options can still be used.
+
+See http://bugzilla.kernel.org/show_bug.cgi?id=14164
+
+Reported-by: Adam Williamson <awilliam@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ init/main.c |   11 +++--------
+ 1 file changed, 3 insertions(+), 8 deletions(-)
+
+--- a/init/main.c
++++ b/init/main.c
+@@ -250,7 +250,7 @@ early_param("loglevel", loglevel);
+ /*
+  * Unknown boot options get handed to init, unless they look like
+- * failed parameters
++ * unused parameters (modprobe will find them in /proc/cmdline).
+  */
+ static int __init unknown_bootoption(char *param, char *val)
+ {
+@@ -271,14 +271,9 @@ static int __init unknown_bootoption(cha
+       if (obsolete_checksetup(param))
+               return 0;
+-      /*
+-       * Preemptive maintenance for "why didn't my misspelled command
+-       * line work?"
+-       */
+-      if (strchr(param, '.') && (!val || strchr(param, '.') < val)) {
+-              printk(KERN_ERR "Unknown boot option `%s': ignoring\n", param);
++      /* Unused module parameter. */
++      if (strchr(param, '.') && (!val || strchr(param, '.') < val))
+               return 0;
+-      }
+       if (panic_later)
+               return 0;
diff --git a/queue-2.6.31/pxamci-call-mmc_remove_host-before-freeing-resources.patch b/queue-2.6.31/pxamci-call-mmc_remove_host-before-freeing-resources.patch
new file mode 100644 (file)
index 0000000..dded178
--- /dev/null
@@ -0,0 +1,93 @@
+From 5d6b1edf8ccc4b7e4e77dff3fc80882833d6186e Mon Sep 17 00:00:00 2001
+From: Daniel Mack <daniel@caiaq.de>
+Date: Tue, 1 Dec 2009 18:17:18 +0100
+Subject: [ARM] pxamci: call mmc_remove_host() before freeing resources
+
+From: Daniel Mack <daniel@caiaq.de>
+
+commit 5d6b1edf8ccc4b7e4e77dff3fc80882833d6186e upstream.
+
+mmc_remove_host() will cause the mmc core to switch off the bus power by
+eventually calling pxamci_set_ios(). This function uses the regulator or
+the GPIO which have been freed already.
+
+This causes the following Oops on module unload.
+
+[   49.519649] Unable to handle kernel paging request at virtual address 30303a70
+[   49.526878] pgd = c7084000
+[   49.529563] [30303a70] *pgd=00000000
+[   49.533136] Internal error: Oops: 5 [#1]
+[   49.537025] last sysfs file: /sys/devices/platform/pxa27x-ohci/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/scsi_level
+[   49.547471] Modules linked in: pxamci(-) eeti_ts
+[   49.552061] CPU: 0    Not tainted  (2.6.32-rc8 #322)
+[   49.557001] PC is at regulator_is_enabled+0x3c/0xbc
+[   49.561846] LR is at regulator_is_enabled+0x30/0xbc
+[   49.566691] pc : [<c01a2448>]    lr : [<c01a243c>]    psr: 60000013
+[   49.566702] sp : c7083e70  ip : 30303a30  fp : 00000000
+[   49.578093] r10: c705e200  r9 : c7082000  r8 : c705e2e0
+[   49.583280] r7 : c7061340  r6 : c7061340  r5 : c7083e70  r4 : 00000000
+[   49.589759] r3 : c04dc434  r2 : c04dc434  r1 : c03eecea  r0 : 00000047
+[   49.596241] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
+[   49.603329] Control: 0000397f  Table: a7084018  DAC: 00000015
+[   49.609031] Process rmmod (pid: 1101, stack limit = 0xc7082278)
+[   49.614908] Stack: (0xc7083e70 to 0xc7084000)
+[   49.619238] 3e60:                                     c7082000 c703c4f8 c705ea00 c04f4074
+[   49.627366] 3e80: 00000000 c705e3a0 ffffffff c0247ddc c70361a0 00000000 c705e3a0 ffffffff
+[   49.635499] 3ea0: c705e200 bf006400 c78c4f00 c705e200 c705e3a0 ffffffff c705e200 ffffffff
+[   49.643633] 3ec0: c04d8ac8 c02476d0 ffffffff c0247c60 c705e200 c0248678 c705e200 c0249064
+[   49.651765] 3ee0: ffffffff bf006204 c04d8ad0 c04d8ad0 c04d8ac8 bf007490 00000880 c00440c4
+[   49.659898] 3f00: 0000b748 c01c5708 bf007490 c01c44c8 c04d8ac8 c04d8afc bf007490 c01c4570
+[   49.668031] 3f20: bf007490 bf00750c c04f4258 c01c37a4 00000000 bf00750c c7083f44 c007b014
+[   49.676162] 3f40: 4000d000 6d617870 08006963 00000001 00000000 c7085000 00000001 00000000
+[   49.684287] 3f60: 4000d000 c7083f8c 00000001 bea01a54 00005401 c7ab1400 c00440c4 00082000
+[   49.692420] 3f80: bf00750c 00000880 c7083f8c 00000000 4000cfa8 00000000 00000880 bea01cc8
+[   49.700552] 3fa0: 00000081 c0043f40 00000000 00000880 bea01cc8 00000880 00000006 00000000
+[   49.708677] 3fc0: 00000000 00000880 bea01cc8 00000081 00000097 0000cca4 0000b748 00000000
+[   49.716802] 3fe0: 4001a4f0 bea01cc0 00018bf4 4001a4fc 20000010 bea01cc8 a063e021 a063e421
+[   49.724958] [<c01a2448>] (regulator_is_enabled+0x3c/0xbc) from [<c0247ddc>] (mmc_regulator_set_ocr+0x14/0xd8)
+[   49.734836] [<c0247ddc>] (mmc_regulator_set_ocr+0x14/0xd8) from [<bf006400>] (pxamci_set_ios+0xd8/0x17c [pxamci])
+[   49.745044] [<bf006400>] (pxamci_set_ios+0xd8/0x17c [pxamci]) from [<c02476d0>] (mmc_power_off+0x50/0x58)
+[   49.754555] [<c02476d0>] (mmc_power_off+0x50/0x58) from [<c0247c60>] (mmc_detach_bus+0x68/0xc4)
+[   49.763207] [<c0247c60>] (mmc_detach_bus+0x68/0xc4) from [<c0248678>] (mmc_stop_host+0xd4/0x1bc)
+[   49.771944] [<c0248678>] (mmc_stop_host+0xd4/0x1bc) from [<c0249064>] (mmc_remove_host+0xc/0x20)
+[   49.780681] [<c0249064>] (mmc_remove_host+0xc/0x20) from [<bf006204>] (pxamci_remove+0xc8/0x174 [pxamci])
+[   49.790211] [<bf006204>] (pxamci_remove+0xc8/0x174 [pxamci]) from [<c01c5708>] (platform_drv_remove+0x1c/0x24)
+[   49.800164] [<c01c5708>] (platform_drv_remove+0x1c/0x24) from [<c01c44c8>] (__device_release_driver+0x7c/0xc4)
+[   49.810110] [<c01c44c8>] (__device_release_driver+0x7c/0xc4) from [<c01c4570>] (driver_detach+0x60/0x8c)
+[   49.819535] [<c01c4570>] (driver_detach+0x60/0x8c) from [<c01c37a4>] (bus_remove_driver+0x90/0xcc)
+[   49.828452] [<c01c37a4>] (bus_remove_driver+0x90/0xcc) from [<c007b014>] (sys_delete_module+0x1d8/0x254)
+[   49.837891] [<c007b014>] (sys_delete_module+0x1d8/0x254) from [<c0043f40>] (ret_fast_syscall+0x0/0x28)
+[   49.847145] Code: eb06c53a e596c030 e1a0500d e59f106c (e59c0040)
+[   49.853566] ---[ end trace b5fa66a00cea142f ]---
+
+Signed-off-by: Daniel Mack <daniel@caiaq.de>
+Reported-by: Sven Neumann <s.neumann@raumfeld.com>
+Cc: Pierre Ossman <pierre@ossman.eu>
+Cc: linux-mmc@vger.kernel.org
+Cc: linux-arm-kernel@lists.infradead.org
+Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/mmc/host/pxamci.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/mmc/host/pxamci.c
++++ b/drivers/mmc/host/pxamci.c
+@@ -694,14 +694,14 @@ static int pxamci_remove(struct platform
+       if (mmc) {
+               struct pxamci_host *host = mmc_priv(mmc);
++              mmc_remove_host(mmc);
++
+               if (host->vcc)
+                       regulator_put(host->vcc);
+               if (host->pdata && host->pdata->exit)
+                       host->pdata->exit(&pdev->dev, mmc);
+-              mmc_remove_host(mmc);
+-
+               pxamci_stop_clock(host);
+               writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
+                      END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
index 7a7120137156caa2d51f4dd1284de6c67a061945..e7cad40dbd1745c8452cec18b5360f5c3d352d75 100644 (file)
@@ -82,3 +82,14 @@ v4l-dvb-13202-smsusb-add-autodetection-support-for-three-additional-hauppauge-us
 v4l-dvb-13313-saa7134-add-support-for-force_ts_valid-mode-for-mpeg-ts-input.patch
 v4l-dvb-13314-saa7134-set-ts_force_val-for-the-hauppauge-wintv-hvr-1150.patch
 ipv4-additional-update-of-dev_net-dev-to-struct-net-in-ip_fragment.c-null-ptr-oops.patch
+speedstep-ich-fix-error-caused-by-394122ab144dae4b276d74644a2f11c44a60ac5c.patch
+usb-ehci-don-t-send-clear-tt-buffer-following-a-stall.patch
+usb-musb_gadget-fix-stall-handling.patch
+usb-amd5536udc-fixed-shared-interrupt-bug-and-warning-oops.patch
+usb-ftdi_sio-keep-going-when-write-errors-are-encountered.patch
+usb-work-around-for-ehci-with-quirky-periodic-schedules.patch
+tty_port-handle-the-nonblocking-open-of-a-dead-port-corner-case.patch
+pxamci-call-mmc_remove_host-before-freeing-resources.patch
+param-don-t-complain-about-unused-module-parameters.patch
+modules-don-t-export-section-names-of-empty-sections-via-sysfs.patch
+md-revert-incorrect-fix-for-read-error-handling-in-raid1.patch
diff --git a/queue-2.6.31/speedstep-ich-fix-error-caused-by-394122ab144dae4b276d74644a2f11c44a60ac5c.patch b/queue-2.6.31/speedstep-ich-fix-error-caused-by-394122ab144dae4b276d74644a2f11c44a60ac5c.patch
new file mode 100644 (file)
index 0000000..34e8549
--- /dev/null
@@ -0,0 +1,67 @@
+From 8dca15e40889e5d5e9655b03ba79c26200f760ce Mon Sep 17 00:00:00 2001
+From: Rusty Russell <rusty@rustcorp.com.au>
+Date: Mon, 2 Nov 2009 23:35:30 -0800
+Subject: [CPUFREQ] speedstep-ich: fix error caused by 394122ab144dae4b276d74644a2f11c44a60ac5c
+
+From: Rusty Russell <rusty@rustcorp.com.au>
+
+commit 8dca15e40889e5d5e9655b03ba79c26200f760ce upstream.
+
+"[CPUFREQ] cpumask: avoid playing with cpus_allowed in speedstep-ich.c"
+changed the code to mistakenly pass the current cpu as the "processor"
+argument of speedstep_get_frequency(), whereas it should be the type of
+the processor.
+
+Addresses http://bugzilla.kernel.org/show_bug.cgi?id=14340
+
+Based on a patch by Dave Mueller.
+
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+Acked-by: Dominik Brodowski <linux@brodo.de>
+Reported-by: Dave Mueller <dave.mueller@gmx.ch>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Dave Jones <davej@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/kernel/cpu/cpufreq/speedstep-ich.c |   19 +++++++------------
+ 1 file changed, 7 insertions(+), 12 deletions(-)
+
+--- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
++++ b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
+@@ -232,28 +232,23 @@ static unsigned int speedstep_detect_chi
+       return 0;
+ }
+-struct get_freq_data {
+-      unsigned int speed;
+-      unsigned int processor;
+-};
+-
+-static void get_freq_data(void *_data)
++static void get_freq_data(void *_speed)
+ {
+-      struct get_freq_data *data = _data;
++      unsigned int *speed = _speed;
+-      data->speed = speedstep_get_frequency(data->processor);
++      *speed = speedstep_get_frequency(speedstep_processor);
+ }
+ static unsigned int speedstep_get(unsigned int cpu)
+ {
+-      struct get_freq_data data = { .processor = cpu };
++      unsigned int speed;
+       /* You're supposed to ensure CPU is online. */
+-      if (smp_call_function_single(cpu, get_freq_data, &data, 1) != 0)
++      if (smp_call_function_single(cpu, get_freq_data, &speed, 1) != 0)
+               BUG();
+-      dprintk("detected %u kHz as current frequency\n", data.speed);
+-      return data.speed;
++      dprintk("detected %u kHz as current frequency\n", speed);
++      return speed;
+ }
+ /**
diff --git a/queue-2.6.31/tty_port-handle-the-nonblocking-open-of-a-dead-port-corner-case.patch b/queue-2.6.31/tty_port-handle-the-nonblocking-open-of-a-dead-port-corner-case.patch
new file mode 100644 (file)
index 0000000..4d13771
--- /dev/null
@@ -0,0 +1,35 @@
+From 8627b96dd80dca440d91fbb1ec733be25912d0dd Mon Sep 17 00:00:00 2001
+From: Alan Cox <alan@linux.intel.com>
+Date: Wed, 18 Nov 2009 14:12:58 +0000
+Subject: tty_port: handle the nonblocking open of a dead port corner case
+
+From: Alan Cox <alan@linux.intel.com>
+
+commit 8627b96dd80dca440d91fbb1ec733be25912d0dd upstream.
+
+Some drivers allow O_NDELAY of a dead port (eg for setserial to work). In that
+situation we must not try to raise the carrier.
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/tty_port.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/char/tty_port.c
++++ b/drivers/char/tty_port.c
+@@ -217,8 +217,11 @@ int tty_port_block_til_ready(struct tty_
+       /* if non-blocking mode is set we can pass directly to open unless
+          the port has just hung up or is in another error state */
+-      if ((filp->f_flags & O_NONBLOCK) ||
+-                      (tty->flags & (1 << TTY_IO_ERROR))) {
++      if (tty->flags & (1 << TTY_IO_ERROR)) {
++              port->flags |= ASYNC_NORMAL_ACTIVE;
++              return 0;
++      }
++      if (filp->f_flags & O_NONBLOCK) {
+               /* Indicate we are open */
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
diff --git a/queue-2.6.31/usb-amd5536udc-fixed-shared-interrupt-bug-and-warning-oops.patch b/queue-2.6.31/usb-amd5536udc-fixed-shared-interrupt-bug-and-warning-oops.patch
new file mode 100644 (file)
index 0000000..e0e1798
--- /dev/null
@@ -0,0 +1,122 @@
+From c5deb832d7a3f9618b09e6eeaa91a1a845c90c65 Mon Sep 17 00:00:00 2001
+From: Thomas Dahlmann <dahlmann.thomas@arcor.de>
+Date: Tue, 17 Nov 2009 14:18:27 -0800
+Subject: usb: amd5536udc: fixed shared interrupt bug and warning oops
+
+From: Thomas Dahlmann <dahlmann.thomas@arcor.de>
+
+commit c5deb832d7a3f9618b09e6eeaa91a1a845c90c65 upstream.
+
+- fixed shared interrupt bug reported by Vadim Lobanov
+ - fixed possible warning oops on driver unload when connected
+ - prevent interrupt flood in PIO mode ("modprobe amd5536udc use_dma=0")
+   when using gadget ether
+
+Signed-off-by: Thomas Dahlmann <dahlmann.thomas@arcor.de>
+Cc: Robert Richter <robert.richter@amd.com>
+Cc: David Brownell <david-b@pacbell.net>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/amd5536udc.c |   49 ++++++++++++++++++++++++----------------
+ 1 file changed, 30 insertions(+), 19 deletions(-)
+
+--- a/drivers/usb/gadget/amd5536udc.c
++++ b/drivers/usb/gadget/amd5536udc.c
+@@ -1213,7 +1213,12 @@ udc_queue(struct usb_ep *usbep, struct u
+                               tmp &= AMD_UNMASK_BIT(ep->num);
+                               writel(tmp, &dev->regs->ep_irqmsk);
+                       }
+-              }
++              } else if (ep->in) {
++                              /* enable ep irq */
++                              tmp = readl(&dev->regs->ep_irqmsk);
++                              tmp &= AMD_UNMASK_BIT(ep->num);
++                              writel(tmp, &dev->regs->ep_irqmsk);
++                      }
+       } else if (ep->dma) {
+@@ -2005,18 +2010,17 @@ __acquires(dev->lock)
+ {
+       int tmp;
+-      /* empty queues and init hardware */
+-      udc_basic_init(dev);
+-      for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+-              empty_req_queue(&dev->ep[tmp]);
+-      }
+-
+       if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+               spin_unlock(&dev->lock);
+               driver->disconnect(&dev->gadget);
+               spin_lock(&dev->lock);
+       }
+-      /* init */
++
++      /* empty queues and init hardware */
++      udc_basic_init(dev);
++      for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
++              empty_req_queue(&dev->ep[tmp]);
++
+       udc_setup_endpoints(dev);
+ }
+@@ -2478,6 +2482,13 @@ static irqreturn_t udc_data_in_isr(struc
+                               }
+                       }
++              } else if (!use_dma && ep->in) {
++                      /* disable interrupt */
++                      tmp = readl(
++                              &dev->regs->ep_irqmsk);
++                      tmp |= AMD_BIT(ep->num);
++                      writel(tmp,
++                              &dev->regs->ep_irqmsk);
+               }
+       }
+       /* clear status bits */
+@@ -3285,6 +3296,17 @@ static int udc_pci_probe(
+               goto finished;
+       }
++      spin_lock_init(&dev->lock);
++      /* udc csr registers base */
++      dev->csr = dev->virt_addr + UDC_CSR_ADDR;
++      /* dev registers base */
++      dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
++      /* ep registers base */
++      dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
++      /* fifo's base */
++      dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
++      dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
++
+       if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+               dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+               kfree(dev);
+@@ -3337,7 +3359,6 @@ static int udc_probe(struct udc *dev)
+       udc_pollstall_timer.data = 0;
+       /* device struct setup */
+-      spin_lock_init(&dev->lock);
+       dev->gadget.ops = &udc_ops;
+       dev_set_name(&dev->gadget.dev, "gadget");
+@@ -3346,16 +3367,6 @@ static int udc_probe(struct udc *dev)
+       dev->gadget.name = name;
+       dev->gadget.is_dualspeed = 1;
+-      /* udc csr registers base */
+-      dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+-      /* dev registers base */
+-      dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+-      /* ep registers base */
+-      dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+-      /* fifo's base */
+-      dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+-      dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+-
+       /* init registers, interrupts, ... */
+       startup_registers(dev);
diff --git a/queue-2.6.31/usb-ehci-don-t-send-clear-tt-buffer-following-a-stall.patch b/queue-2.6.31/usb-ehci-don-t-send-clear-tt-buffer-following-a-stall.patch
new file mode 100644 (file)
index 0000000..3f46596
--- /dev/null
@@ -0,0 +1,71 @@
+From c2f6595fbdb408d3d6850cfae590c8fa93e27399 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Wed, 18 Nov 2009 11:37:15 -0500
+Subject: USB: EHCI: don't send Clear-TT-Buffer following a STALL
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit c2f6595fbdb408d3d6850cfae590c8fa93e27399 upstream.
+
+This patch (as1304) fixes a regression in ehci-hcd.  Evidently some
+hubs don't handle Clear-TT-Buffer requests correctly, so we should
+avoid sending them when they don't appear to be absolutely necessary.
+The reported symptom is that output on a downstream audio device cuts
+out because the hub stops relaying isochronous packets.
+
+The patch prevents Clear-TT-Buffer requests from being sent following
+a STALL handshake.  In theory a STALL indicates either that the
+downstream device sent a STALL or that no matching TT buffer could be
+found.  In either case, the transfer is completed and the TT buffer
+does not remain busy, so it doesn't need to be cleared.
+
+Also, the patch fixes a minor flaw in the code that actually sends the
+Clear-TT-Buffer requests.  Although the pipe direction isn't really
+used for control transfers, it should be a Send rather than a Receive.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Reported-by: Javier Kohen <jkohen@users.sourceforge.net>
+CC: David Brownell <david-b@pacbell.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/hub.c    |    2 +-
+ drivers/usb/host/ehci-q.c |   16 ++++++++++++++--
+ 2 files changed, 15 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -439,7 +439,7 @@ resubmit:
+ static inline int
+ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
+ {
+-      return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
++      return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
+                              HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo,
+                              tt, NULL, 0, 1000);
+ }
+--- a/drivers/usb/host/ehci-q.c
++++ b/drivers/usb/host/ehci-q.c
+@@ -475,8 +475,20 @@ halt:
+                        * we must clear the TT buffer (11.17.5).
+                        */
+                       if (unlikely(last_status != -EINPROGRESS &&
+-                                      last_status != -EREMOTEIO))
+-                              ehci_clear_tt_buffer(ehci, qh, urb, token);
++                                      last_status != -EREMOTEIO)) {
++                              /* The TT's in some hubs malfunction when they
++                               * receive this request following a STALL (they
++                               * stop sending isochronous packets).  Since a
++                               * STALL can't leave the TT buffer in a busy
++                               * state (if you believe Figures 11-48 - 11-51
++                               * in the USB 2.0 spec), we won't clear the TT
++                               * buffer in this case.  Strictly speaking this
++                               * is a violation of the spec.
++                               */
++                              if (last_status != -EPIPE)
++                                      ehci_clear_tt_buffer(ehci, qh, urb,
++                                                      token);
++                      }
+               }
+               /* if we're removing something not at the queue head,
diff --git a/queue-2.6.31/usb-ftdi_sio-keep-going-when-write-errors-are-encountered.patch b/queue-2.6.31/usb-ftdi_sio-keep-going-when-write-errors-are-encountered.patch
new file mode 100644 (file)
index 0000000..9d8c794
--- /dev/null
@@ -0,0 +1,45 @@
+From 0de6ab8b91f2e1e8e7fc66a8b5c5e8ca82ea16b7 Mon Sep 17 00:00:00 2001
+From: Eric W. Biederman <ebiederm@xmission.com>
+Date: Tue, 17 Nov 2009 19:10:48 -0800
+Subject: USB: ftdi_sio: Keep going when write errors are encountered.
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+commit 0de6ab8b91f2e1e8e7fc66a8b5c5e8ca82ea16b7 upstream.
+
+The use of urb->actual_length to update tx_outstanding_bytes
+implicitly assumes that the number of bytes actually written is the
+same as the number of bytes we tried to write.  On error that
+assumption is violated so just use transfer_buffer_length the number
+of bytes we intended to write to the device.
+
+If an error occurs we need to fall through and call
+usb_serial_port_softint to wake up processes waiting in
+tty_wait_until_sent.
+
+Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/ftdi_sio.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -1939,7 +1939,7 @@ static void ftdi_write_bulk_callback(str
+               return;
+       }
+       /* account for transferred data */
+-      countback = urb->actual_length;
++      countback = urb->transfer_buffer_length;
+       data_offset = priv->write_offset;
+       if (data_offset > 0) {
+               /* Subtract the control bytes */
+@@ -1952,7 +1952,6 @@ static void ftdi_write_bulk_callback(str
+       if (status) {
+               dbg("nonzero write bulk status received: %d", status);
+-              return;
+       }
+       usb_serial_port_softint(port);
diff --git a/queue-2.6.31/usb-musb_gadget-fix-stall-handling.patch b/queue-2.6.31/usb-musb_gadget-fix-stall-handling.patch
new file mode 100644 (file)
index 0000000..4e5efe8
--- /dev/null
@@ -0,0 +1,223 @@
+From cea83241b3a84499c4f9b12f8288f787e7aa6383 Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Date: Wed, 18 Nov 2009 22:51:18 +0300
+Subject: USB: musb_gadget: fix STALL handling
+
+From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+
+commit cea83241b3a84499c4f9b12f8288f787e7aa6383 upstream.
+
+The driver incorrectly cancels the mass-storage device CSW request
+(which leads to device reset) due to giving back URB at the head of
+endpoint's queue after sending each STALL handshake; stop doing that
+and start checking for the queue being non-empty before stalling an
+endpoint and disallowing stall in such case in musb_gadget_set_halt()
+like the other gadget drivers do.
+
+Moreover, the driver starts Rx request despite of the endpoint being
+halted -- fix this by moving the SendStall bit check from musb_g_rx()
+to rxstate().  And we also sometimes get into rxstate() with DMA still
+active after clearing an endpoint's halt (not clear why), so bail out
+in this case, similarly to what txstate() does...
+
+While at it, also do the following changes :
+
+- in musb_gadget_set_halt(), remove pointless Tx FIFO flushing (the
+  driver does not allow stalling with non-empty Tx FIFO anyway);
+
+- in rxstate(), stop pointlessly zeroing the 'csr' variable;
+
+- in musb_gadget_set_halt(), move the 'done' label to a more proper
+  place;
+
+- in musb_g_rx(), eliminate the 'done' label completely...
+
+Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musb_gadget.c |   79 +++++++++++++++++------------------------
+ 1 file changed, 34 insertions(+), 45 deletions(-)
+
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -4,6 +4,7 @@
+  * Copyright 2005 Mentor Graphics Corporation
+  * Copyright (C) 2005-2006 by Texas Instruments
+  * Copyright (C) 2006-2007 Nokia Corporation
++ * Copyright (C) 2009 MontaVista Software, Inc. <source@mvista.com>
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+@@ -436,14 +437,6 @@ void musb_g_tx(struct musb *musb, u8 epn
+                       csr |= MUSB_TXCSR_P_WZC_BITS;
+                       csr &= ~MUSB_TXCSR_P_SENTSTALL;
+                       musb_writew(epio, MUSB_TXCSR, csr);
+-                      if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+-                              dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+-                              musb->dma_controller->channel_abort(dma);
+-                      }
+-
+-                      if (request)
+-                              musb_g_giveback(musb_ep, request, -EPIPE);
+-
+                       break;
+               }
+@@ -582,15 +575,25 @@ void musb_g_tx(struct musb *musb, u8 epn
+  */
+ static void rxstate(struct musb *musb, struct musb_request *req)
+ {
+-      u16                     csr = 0;
+       const u8                epnum = req->epnum;
+       struct usb_request      *request = &req->request;
+       struct musb_ep          *musb_ep = &musb->endpoints[epnum].ep_out;
+       void __iomem            *epio = musb->endpoints[epnum].regs;
+       unsigned                fifo_count = 0;
+       u16                     len = musb_ep->packet_sz;
++      u16                     csr = musb_readw(epio, MUSB_RXCSR);
+-      csr = musb_readw(epio, MUSB_RXCSR);
++      /* We shouldn't get here while DMA is active, but we do... */
++      if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
++              DBG(4, "DMA pending...\n");
++              return;
++      }
++
++      if (csr & MUSB_RXCSR_P_SENDSTALL) {
++              DBG(5, "%s stalling, RXCSR %04x\n",
++                  musb_ep->end_point.name, csr);
++              return;
++      }
+       if (is_cppi_enabled() && musb_ep->dma) {
+               struct dma_controller   *c = musb->dma_controller;
+@@ -761,19 +764,10 @@ void musb_g_rx(struct musb *musb, u8 epn
+                       csr, dma ? " (dma)" : "", request);
+       if (csr & MUSB_RXCSR_P_SENTSTALL) {
+-              if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+-                      dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+-                      (void) musb->dma_controller->channel_abort(dma);
+-                      request->actual += musb_ep->dma->actual_len;
+-              }
+-
+               csr |= MUSB_RXCSR_P_WZC_BITS;
+               csr &= ~MUSB_RXCSR_P_SENTSTALL;
+               musb_writew(epio, MUSB_RXCSR, csr);
+-
+-              if (request)
+-                      musb_g_giveback(musb_ep, request, -EPIPE);
+-              goto done;
++              return;
+       }
+       if (csr & MUSB_RXCSR_P_OVERRUN) {
+@@ -795,7 +789,7 @@ void musb_g_rx(struct musb *musb, u8 epn
+               DBG((csr & MUSB_RXCSR_DMAENAB) ? 4 : 1,
+                       "%s busy, csr %04x\n",
+                       musb_ep->end_point.name, csr);
+-              goto done;
++              return;
+       }
+       if (dma && (csr & MUSB_RXCSR_DMAENAB)) {
+@@ -826,22 +820,15 @@ void musb_g_rx(struct musb *musb, u8 epn
+               if ((request->actual < request->length)
+                               && (musb_ep->dma->actual_len
+                                       == musb_ep->packet_sz))
+-                      goto done;
++                      return;
+ #endif
+               musb_g_giveback(musb_ep, request, 0);
+               request = next_request(musb_ep);
+               if (!request)
+-                      goto done;
+-
+-              /* don't start more i/o till the stall clears */
+-              musb_ep_select(mbase, epnum);
+-              csr = musb_readw(epio, MUSB_RXCSR);
+-              if (csr & MUSB_RXCSR_P_SENDSTALL)
+-                      goto done;
++                      return;
+       }
+-
+       /* analyze request if the ep is hot */
+       if (request)
+               rxstate(musb, to_musb_request(request));
+@@ -849,8 +836,6 @@ void musb_g_rx(struct musb *musb, u8 epn
+               DBG(3, "packet waiting for %s%s request\n",
+                               musb_ep->desc ? "" : "inactive ",
+                               musb_ep->end_point.name);
+-
+-done:
+       return;
+ }
+@@ -1244,7 +1229,7 @@ int musb_gadget_set_halt(struct usb_ep *
+       void __iomem            *mbase;
+       unsigned long           flags;
+       u16                     csr;
+-      struct musb_request     *request = NULL;
++      struct musb_request     *request;
+       int                     status = 0;
+       if (!ep)
+@@ -1260,24 +1245,29 @@ int musb_gadget_set_halt(struct usb_ep *
+       musb_ep_select(mbase, epnum);
+-      /* cannot portably stall with non-empty FIFO */
+       request = to_musb_request(next_request(musb_ep));
+-      if (value && musb_ep->is_in) {
+-              csr = musb_readw(epio, MUSB_TXCSR);
+-              if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
+-                      DBG(3, "%s fifo busy, cannot halt\n", ep->name);
+-                      spin_unlock_irqrestore(&musb->lock, flags);
+-                      return -EAGAIN;
++      if (value) {
++              if (request) {
++                      DBG(3, "request in progress, cannot halt %s\n",
++                          ep->name);
++                      status = -EAGAIN;
++                      goto done;
++              }
++              /* Cannot portably stall with non-empty FIFO */
++              if (musb_ep->is_in) {
++                      csr = musb_readw(epio, MUSB_TXCSR);
++                      if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
++                              DBG(3, "FIFO busy, cannot halt %s\n", ep->name);
++                              status = -EAGAIN;
++                              goto done;
++                      }
+               }
+-
+       }
+       /* set/clear the stall and toggle bits */
+       DBG(2, "%s: %s stall\n", ep->name, value ? "set" : "clear");
+       if (musb_ep->is_in) {
+               csr = musb_readw(epio, MUSB_TXCSR);
+-              if (csr & MUSB_TXCSR_FIFONOTEMPTY)
+-                      csr |= MUSB_TXCSR_FLUSHFIFO;
+               csr |= MUSB_TXCSR_P_WZC_BITS
+                       | MUSB_TXCSR_CLRDATATOG;
+               if (value)
+@@ -1300,14 +1290,13 @@ int musb_gadget_set_halt(struct usb_ep *
+               musb_writew(epio, MUSB_RXCSR, csr);
+       }
+-done:
+-
+       /* maybe start the first request in the queue */
+       if (!musb_ep->busy && !value && request) {
+               DBG(3, "restarting the request\n");
+               musb_ep_restart(musb, request);
+       }
++done:
+       spin_unlock_irqrestore(&musb->lock, flags);
+       return status;
+ }
diff --git a/queue-2.6.31/usb-work-around-for-ehci-with-quirky-periodic-schedules.patch b/queue-2.6.31/usb-work-around-for-ehci-with-quirky-periodic-schedules.patch
new file mode 100644 (file)
index 0000000..ee99c1d
--- /dev/null
@@ -0,0 +1,102 @@
+From ee4ecb8ac63a5792bec448037d4b82ec4144f94b Mon Sep 17 00:00:00 2001
+From: Oliver Neukum <oliver@neukum.org>
+Date: Fri, 27 Nov 2009 15:17:59 +0100
+Subject: USB: work around for EHCI with quirky periodic schedules
+
+From: Oliver Neukum <oliver@neukum.org>
+
+commit ee4ecb8ac63a5792bec448037d4b82ec4144f94b upstream.
+
+a quirky chipset needs periodic schedules to run for a minimum
+time before they can be disabled again. This enforces the requirement
+with a time stamp and a calculated delay
+
+Signed-off-by: Oliver Neukum <oliver@neukum.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ehci-hcd.c   |    2 ++
+ drivers/usb/host/ehci-pci.c   |    6 ++++++
+ drivers/usb/host/ehci-sched.c |   12 ++++++++++++
+ drivers/usb/host/ehci.h       |    2 ++
+ 4 files changed, 22 insertions(+)
+
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -118,6 +118,7 @@ struct ehci_hcd {                  /* one per controlle
+       unsigned                stamp;
+       unsigned                random_frame;
+       unsigned long           next_statechange;
++      ktime_t                 last_periodic_enable;
+       u32                     command;
+       /* SILICON QUIRKS */
+@@ -126,6 +127,7 @@ struct ehci_hcd {                  /* one per controlle
+       unsigned                big_endian_mmio:1;
+       unsigned                big_endian_desc:1;
+       unsigned                has_amcc_usb23:1;
++      unsigned                broken_periodic:1;
+       /* required for usb32 quirk */
+       #define OHCI_CTRL_HCFS          (3 << 6)
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -28,6 +28,7 @@
+ #include <linux/errno.h>
+ #include <linux/init.h>
+ #include <linux/timer.h>
++#include <linux/ktime.h>
+ #include <linux/list.h>
+ #include <linux/interrupt.h>
+ #include <linux/reboot.h>
+@@ -655,6 +656,7 @@ static int ehci_run (struct usb_hcd *hcd
+       ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+       msleep(5);
+       up_write(&ehci_cf_port_reset_rwsem);
++      ehci->last_periodic_enable = ktime_get_real();
+       temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
+       ehci_info (ehci,
+--- a/drivers/usb/host/ehci-pci.c
++++ b/drivers/usb/host/ehci-pci.c
+@@ -72,6 +72,12 @@ static int ehci_pci_setup(struct usb_hcd
+       int                     retval;
+       switch (pdev->vendor) {
++      case PCI_VENDOR_ID_INTEL:
++              if (pdev->device == 0x27cc) {
++                      ehci->broken_periodic = 1;
++                      ehci_info(ehci, "using broken periodic workaround\n");
++              }
++              break;
+       case PCI_VENDOR_ID_TOSHIBA_2:
+               /* celleb's companion chip */
+               if (pdev->device == 0x01b5) {
+--- a/drivers/usb/host/ehci-sched.c
++++ b/drivers/usb/host/ehci-sched.c
+@@ -456,6 +456,8 @@ static int enable_periodic (struct ehci_
+       /* make sure ehci_work scans these */
+       ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+               % (ehci->periodic_size << 3);
++      if (unlikely(ehci->broken_periodic))
++              ehci->last_periodic_enable = ktime_get_real();
+       return 0;
+ }
+@@ -467,6 +469,16 @@ static int disable_periodic (struct ehci
+       if (--ehci->periodic_sched)
+               return 0;
++      if (unlikely(ehci->broken_periodic)) {
++              /* delay experimentally determined */
++              ktime_t safe = ktime_add_us(ehci->last_periodic_enable, 1000);
++              ktime_t now = ktime_get_real();
++              s64 delay = ktime_us_delta(safe, now);
++
++              if (unlikely(delay > 0))
++                      udelay(delay);
++      }
++
+       /* did setting PSE not take effect yet?
+        * takes effect only at frame boundaries...
+        */