]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Oct 2012 23:50:25 +0000 (16:50 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Oct 2012 23:50:25 +0000 (16:50 -0700)
added patches:
ath9k-disable-aspm-only-for-ar9285.patch
b43legacy-fix-crash-on-unload-when-firmware-not-available.patch
coredump-prevent-double-free-on-an-error-path-in-core.patch
firmware-add-missing-attributes-to-efi-variable-attribute-print-out-from-sysfs.patch
hid-keep-dev_rdesc-unmodified-and-use-it-for-comparisons.patch
increase-xhci-suspend-timeout-to-16ms.patch
n_gsm-added-interlocking-for-gsm_data_lock-for-certain-code-paths.patch
n_gsm.c-implement-3gpp27.010-dlc-start-up-procedure-in-mux.patch
n_gsm-memory-leak-in-uplink-error-path.patch
n_gsm-uplink-skbs-accumulate-on-list.patch
tools-hv-check-for-read-write-errors.patch
tools-hv-fix-exit-error-code.patch
tools-hv-fix-file-handle-leak.patch
xen-pciback-restore-the-pci-config-space-after-an-flr.patch
xhci-add-aborting-command-ring-function.patch
xhci-add-cmd_ring_state.patch
xhci-cancel-command-after-command-timeout.patch
xhci-handle-command-after-aborting-the-command-ring.patch
xhci-intel-panther-point-bei-quirk.patch

20 files changed:
queue-3.6/ath9k-disable-aspm-only-for-ar9285.patch [new file with mode: 0644]
queue-3.6/b43legacy-fix-crash-on-unload-when-firmware-not-available.patch [new file with mode: 0644]
queue-3.6/coredump-prevent-double-free-on-an-error-path-in-core.patch [new file with mode: 0644]
queue-3.6/firmware-add-missing-attributes-to-efi-variable-attribute-print-out-from-sysfs.patch [new file with mode: 0644]
queue-3.6/hid-keep-dev_rdesc-unmodified-and-use-it-for-comparisons.patch [new file with mode: 0644]
queue-3.6/increase-xhci-suspend-timeout-to-16ms.patch [new file with mode: 0644]
queue-3.6/n_gsm-added-interlocking-for-gsm_data_lock-for-certain-code-paths.patch [new file with mode: 0644]
queue-3.6/n_gsm-memory-leak-in-uplink-error-path.patch [new file with mode: 0644]
queue-3.6/n_gsm-uplink-skbs-accumulate-on-list.patch [new file with mode: 0644]
queue-3.6/n_gsm.c-implement-3gpp27.010-dlc-start-up-procedure-in-mux.patch [new file with mode: 0644]
queue-3.6/series
queue-3.6/tools-hv-check-for-read-write-errors.patch [new file with mode: 0644]
queue-3.6/tools-hv-fix-exit-error-code.patch [new file with mode: 0644]
queue-3.6/tools-hv-fix-file-handle-leak.patch [new file with mode: 0644]
queue-3.6/xen-pciback-restore-the-pci-config-space-after-an-flr.patch [new file with mode: 0644]
queue-3.6/xhci-add-aborting-command-ring-function.patch [new file with mode: 0644]
queue-3.6/xhci-add-cmd_ring_state.patch [new file with mode: 0644]
queue-3.6/xhci-cancel-command-after-command-timeout.patch [new file with mode: 0644]
queue-3.6/xhci-handle-command-after-aborting-the-command-ring.patch [new file with mode: 0644]
queue-3.6/xhci-intel-panther-point-bei-quirk.patch [new file with mode: 0644]

diff --git a/queue-3.6/ath9k-disable-aspm-only-for-ar9285.patch b/queue-3.6/ath9k-disable-aspm-only-for-ar9285.patch
new file mode 100644 (file)
index 0000000..8256eb3
--- /dev/null
@@ -0,0 +1,38 @@
+From 046b6802c8d3c8a57448485513bf7291633e0fa3 Mon Sep 17 00:00:00 2001
+From: Sujith Manoharan <c_manoha@qualcomm.com>
+Date: Sat, 22 Sep 2012 00:14:28 +0530
+Subject: ath9k: Disable ASPM only for AR9285
+
+From: Sujith Manoharan <c_manoha@qualcomm.com>
+
+commit 046b6802c8d3c8a57448485513bf7291633e0fa3 upstream.
+
+Currently, ASPM is disabled for all WLAN+BT combo chipsets
+when BTCOEX is enabled. This is incorrect since the workaround
+is required only for WB195, which is a AR9285+AR3011 combo
+solution. Fix this by checking for the HW version when enabling
+the workaround.
+
+Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Tested-by: Paul Stewart <pstew@chromium.org>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/ath/ath9k/pci.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/pci.c
++++ b/drivers/net/wireless/ath/ath9k/pci.c
+@@ -127,8 +127,9 @@ static void ath_pci_aspm_init(struct ath
+       if (!parent)
+               return;
+-      if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
+-              /* Bluetooth coexistance requires disabling ASPM. */
++      if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) &&
++          (AR_SREV_9285(ah))) {
++              /* Bluetooth coexistance requires disabling ASPM for AR9285. */
+               pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm);
+               aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
+               pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm);
diff --git a/queue-3.6/b43legacy-fix-crash-on-unload-when-firmware-not-available.patch b/queue-3.6/b43legacy-fix-crash-on-unload-when-firmware-not-available.patch
new file mode 100644 (file)
index 0000000..8a789f2
--- /dev/null
@@ -0,0 +1,75 @@
+From 2d838bb608e2d1f6cb4280e76748cb812dc822e7 Mon Sep 17 00:00:00 2001
+From: Larry Finger <Larry.Finger@lwfinger.net>
+Date: Wed, 26 Sep 2012 12:32:02 -0500
+Subject: b43legacy: Fix crash on unload when firmware not available
+
+From: Larry Finger <Larry.Finger@lwfinger.net>
+
+commit 2d838bb608e2d1f6cb4280e76748cb812dc822e7 upstream.
+
+When b43legacy is loaded without the firmware being available, a following
+unload generates a kernel NULL pointer dereference BUG as follows:
+
+[  214.330789] BUG: unable to handle kernel NULL pointer dereference at 0000004c
+[  214.330997] IP: [<c104c395>] drain_workqueue+0x15/0x170
+[  214.331179] *pde = 00000000
+[  214.331311] Oops: 0000 [#1] SMP
+[  214.331471] Modules linked in: b43legacy(-) ssb pcmcia mac80211 cfg80211 af_packet mperf arc4 ppdev sr_mod cdrom sg shpchp yenta_socket pcmcia_rsrc pci_hotplug pcmcia_core battery parport_pc parport floppy container ac button edd autofs4 ohci_hcd ehci_hcd usbcore usb_common thermal processor scsi_dh_rdac scsi_dh_hp_sw scsi_dh_emc scsi_dh_alua scsi_dh fan thermal_sys hwmon ata_generic pata_ali libata [last unloaded: cfg80211]
+[  214.333421] Pid: 3639, comm: modprobe Not tainted 3.6.0-rc6-wl+ #163 Source Technology VIC 9921/ALI Based Notebook
+[  214.333580] EIP: 0060:[<c104c395>] EFLAGS: 00010246 CPU: 0
+[  214.333687] EIP is at drain_workqueue+0x15/0x170
+[  214.333788] EAX: c162ac40 EBX: cdfb8360 ECX: 0000002a EDX: 00002a2a
+[  214.333890] ESI: 00000000 EDI: 00000000 EBP: cd767e7c ESP: cd767e5c
+[  214.333957]  DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
+[  214.333957] CR0: 8005003b CR2: 0000004c CR3: 0c96a000 CR4: 00000090
+[  214.333957] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
+[  214.333957] DR6: ffff0ff0 DR7: 00000400
+[  214.333957] Process modprobe (pid: 3639, ti=cd766000 task=cf802e90 task.ti=cd766000)
+[  214.333957] Stack:
+[  214.333957]  00000292 cd767e74 c12c5e09 00000296 00000296 cdfb8360 cdfb9220 00000000
+[  214.333957]  cd767e90 c104c4fd cdfb8360 cdfb9220 cd682800 cd767ea4 d0c10184 cd682800
+[  214.333957]  cd767ea4 cba31064 cd767eb8 d0867908 cba31064 d087e09c cd96f034 cd767ec4
+[  214.333957] Call Trace:
+[  214.333957]  [<c12c5e09>] ? skb_dequeue+0x49/0x60
+[  214.333957]  [<c104c4fd>] destroy_workqueue+0xd/0x150
+[  214.333957]  [<d0c10184>] ieee80211_unregister_hw+0xc4/0x100 [mac80211]
+[  214.333957]  [<d0867908>] b43legacy_remove+0x78/0x80 [b43legacy]
+[  214.333957]  [<d083654d>] ssb_device_remove+0x1d/0x30 [ssb]
+[  214.333957]  [<c126f15a>] __device_release_driver+0x5a/0xb0
+[  214.333957]  [<c126fb07>] driver_detach+0x87/0x90
+[  214.333957]  [<c126ef4c>] bus_remove_driver+0x6c/0xe0
+[  214.333957]  [<c1270120>] driver_unregister+0x40/0x70
+[  214.333957]  [<d083686b>] ssb_driver_unregister+0xb/0x10 [ssb]
+[  214.333957]  [<d087c488>] b43legacy_exit+0xd/0xf [b43legacy]
+[  214.333957]  [<c1089dde>] sys_delete_module+0x14e/0x2b0
+[  214.333957]  [<c110a4a7>] ? vfs_write+0xf7/0x150
+[  214.333957]  [<c1240050>] ? tty_write_lock+0x50/0x50
+[  214.333957]  [<c110a6f8>] ? sys_write+0x38/0x70
+[  214.333957]  [<c1397c55>] syscall_call+0x7/0xb
+[  214.333957] Code: bc 27 00 00 00 00 a1 74 61 56 c1 55 89 e5 e8 a3 fc ff ff 5d c3 90 55 89 e5 57 56 89 c6 53 b8 40 ac 62 c1 83 ec 14 e8 bb b7 34 00 <8b> 46 4c 8d 50 01 85 c0 89 56 4c 75 03 83 0e 40 80 05 40 ac 62
+[  214.333957] EIP: [<c104c395>] drain_workqueue+0x15/0x170 SS:ESP 0068:cd767e5c
+[  214.333957] CR2: 000000000000004c
+[  214.341110] ---[ end trace c7e90ec026d875a6 ]---Index: wireless-testing/drivers/net/wireless/b43legacy/main.c
+
+The problem is fixed by making certain that the ucode pointer is not NULL
+before deregistering the driver in mac80211.
+
+Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/b43legacy/main.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/wireless/b43legacy/main.c
++++ b/drivers/net/wireless/b43legacy/main.c
+@@ -3894,6 +3894,8 @@ static void b43legacy_remove(struct ssb_
+       cancel_work_sync(&wl->firmware_load);
+       B43legacy_WARN_ON(!wl);
++      if (!wldev->fw.ucode)
++              return;                 /* NULL if fw never loaded */
+       if (wl->current_dev == wldev)
+               ieee80211_unregister_hw(wl->hw);
diff --git a/queue-3.6/coredump-prevent-double-free-on-an-error-path-in-core.patch b/queue-3.6/coredump-prevent-double-free-on-an-error-path-in-core.patch
new file mode 100644 (file)
index 0000000..998364d
--- /dev/null
@@ -0,0 +1,66 @@
+From f34f9d186df35e5c39163444c43b4fc6255e39c5 Mon Sep 17 00:00:00 2001
+From: Denys Vlasenko <vda.linux@googlemail.com>
+Date: Wed, 26 Sep 2012 11:34:50 +1000
+Subject: coredump: prevent double-free on an error path in core
+ dumper
+
+From: Denys Vlasenko <vda.linux@googlemail.com>
+
+commit f34f9d186df35e5c39163444c43b4fc6255e39c5 upstream.
+
+In !CORE_DUMP_USE_REGSET case, if elf_note_info_init fails to allocate
+memory for info->fields, it frees already allocated stuff and returns
+error to its caller, fill_note_info.  Which in turn returns error to its
+caller, elf_core_dump.  Which jumps to cleanup label and calls
+free_note_info, which will happily try to free all info->fields again.
+BOOM.
+
+This is the fix.
+
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
+Cc: Venu Byravarasu <vbyravarasu@nvidia.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/binfmt_elf.c |   19 ++++---------------
+ 1 file changed, 4 insertions(+), 15 deletions(-)
+
+--- a/fs/binfmt_elf.c
++++ b/fs/binfmt_elf.c
+@@ -1696,30 +1696,19 @@ static int elf_note_info_init(struct elf
+               return 0;
+       info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL);
+       if (!info->psinfo)
+-              goto notes_free;
++              return 0;
+       info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL);
+       if (!info->prstatus)
+-              goto psinfo_free;
++              return 0;
+       info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL);
+       if (!info->fpu)
+-              goto prstatus_free;
++              return 0;
+ #ifdef ELF_CORE_COPY_XFPREGS
+       info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL);
+       if (!info->xfpu)
+-              goto fpu_free;
++              return 0;
+ #endif
+       return 1;
+-#ifdef ELF_CORE_COPY_XFPREGS
+- fpu_free:
+-      kfree(info->fpu);
+-#endif
+- prstatus_free:
+-      kfree(info->prstatus);
+- psinfo_free:
+-      kfree(info->psinfo);
+- notes_free:
+-      kfree(info->notes);
+-      return 0;
+ }
+ static int fill_note_info(struct elfhdr *elf, int phdrs,
diff --git a/queue-3.6/firmware-add-missing-attributes-to-efi-variable-attribute-print-out-from-sysfs.patch b/queue-3.6/firmware-add-missing-attributes-to-efi-variable-attribute-print-out-from-sysfs.patch
new file mode 100644 (file)
index 0000000..f010f26
--- /dev/null
@@ -0,0 +1,52 @@
+From 7083909023bbe29b3176e92d2d089def1aa7aa1e Mon Sep 17 00:00:00 2001
+From: Khalid Aziz <khalid.aziz@hp.com>
+Date: Mon, 10 Sep 2012 12:52:42 -0600
+Subject: firmware: Add missing attributes to EFI variable attribute print out from sysfs
+
+From: Khalid Aziz <khalid.aziz@hp.com>
+
+commit 7083909023bbe29b3176e92d2d089def1aa7aa1e upstream.
+
+Some of the EFI variable attributes are missing from print out from
+/sys/firmware/efi/vars/*/attributes. This patch adds those in. It also
+updates code to use pre-defined constants for masking current value
+of attributes.
+
+Signed-off-by: Khalid Aziz <khalid.aziz@hp.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Acked-by: Matthew Garrett <mjg@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/firmware/efivars.c |   17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+--- a/drivers/firmware/efivars.c
++++ b/drivers/firmware/efivars.c
+@@ -435,12 +435,23 @@ efivar_attr_read(struct efivar_entry *en
+       if (status != EFI_SUCCESS)
+               return -EIO;
+-      if (var->Attributes & 0x1)
++      if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
+               str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
+-      if (var->Attributes & 0x2)
++      if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
+               str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
+-      if (var->Attributes & 0x4)
++      if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
+               str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
++      if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
++              str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n");
++      if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
++              str += sprintf(str,
++                      "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n");
++      if (var->Attributes &
++                      EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
++              str += sprintf(str,
++                      "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n");
++      if (var->Attributes & EFI_VARIABLE_APPEND_WRITE)
++              str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n");
+       return str - buf;
+ }
diff --git a/queue-3.6/hid-keep-dev_rdesc-unmodified-and-use-it-for-comparisons.patch b/queue-3.6/hid-keep-dev_rdesc-unmodified-and-use-it-for-comparisons.patch
new file mode 100644 (file)
index 0000000..31cbd73
--- /dev/null
@@ -0,0 +1,93 @@
+From 86e6b77eb7cf9ca2e9c7092b4dfd588f0a3307b6 Mon Sep 17 00:00:00 2001
+From: Kevin Daughtridge <kevin@kdau.com>
+Date: Thu, 20 Sep 2012 12:00:32 -0700
+Subject: HID: keep dev_rdesc unmodified and use it for comparisons
+
+From: Kevin Daughtridge <kevin@kdau.com>
+
+commit 86e6b77eb7cf9ca2e9c7092b4dfd588f0a3307b6 upstream.
+
+The dev_rdesc member of the hid_device structure is meant to store the original
+report descriptor received from the device, but it is currently passed to any
+report_fixup method before it is copied to the rdesc member. This patch uses a
+temporary buffer to shield dev_rdesc from the side effects of many HID drivers'
+report_fixup implementations.
+
+usbhid's hid_post_reset checks the report descriptor currently returned by the
+device against a descriptor that may have been modified by a driver's
+report_fixup method. That leaves some devices nonfunctional after a resume, with
+a "reset_resume error 1" reported. This patch checks the new descriptor against
+the unmodified dev_rdesc instead and uses the original, instead of modified,
+report size.
+
+BugLink: http://bugs.launchpad.net/bugs/1049623
+Signed-off-by: Kevin Daughtridge <kevin@kdau.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-core.c        |   16 +++++++++++++---
+ drivers/hid/usbhid/hid-core.c |    6 +++---
+ 2 files changed, 16 insertions(+), 6 deletions(-)
+
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -757,6 +757,7 @@ int hid_open_report(struct hid_device *d
+       struct hid_item item;
+       unsigned int size;
+       __u8 *start;
++      __u8 *buf;
+       __u8 *end;
+       int ret;
+       static int (*dispatch_type[])(struct hid_parser *parser,
+@@ -775,12 +776,21 @@ int hid_open_report(struct hid_device *d
+               return -ENODEV;
+       size = device->dev_rsize;
++      buf = kmemdup(start, size, GFP_KERNEL);
++      if (buf == NULL)
++              return -ENOMEM;
++
+       if (device->driver->report_fixup)
+-              start = device->driver->report_fixup(device, start, &size);
++              start = device->driver->report_fixup(device, buf, &size);
++      else
++              start = buf;
+-      device->rdesc = kmemdup(start, size, GFP_KERNEL);
+-      if (device->rdesc == NULL)
++      start = kmemdup(start, size, GFP_KERNEL);
++      kfree(buf);
++      if (start == NULL)
+               return -ENOMEM;
++
++      device->rdesc = start;
+       device->rsize = size;
+       parser = vzalloc(sizeof(struct hid_parser));
+--- a/drivers/hid/usbhid/hid-core.c
++++ b/drivers/hid/usbhid/hid-core.c
+@@ -1415,20 +1415,20 @@ static int hid_post_reset(struct usb_int
+        * configuration descriptors passed, we already know that
+        * the size of the HID report descriptor has not changed.
+        */
+-      rdesc = kmalloc(hid->rsize, GFP_KERNEL);
++      rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL);
+       if (!rdesc) {
+               dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
+               return 1;
+       }
+       status = hid_get_class_descriptor(dev,
+                               interface->desc.bInterfaceNumber,
+-                              HID_DT_REPORT, rdesc, hid->rsize);
++                              HID_DT_REPORT, rdesc, hid->dev_rsize);
+       if (status < 0) {
+               dbg_hid("reading report descriptor failed (post_reset)\n");
+               kfree(rdesc);
+               return 1;
+       }
+-      status = memcmp(rdesc, hid->rdesc, hid->rsize);
++      status = memcmp(rdesc, hid->dev_rdesc, hid->dev_rsize);
+       kfree(rdesc);
+       if (status != 0) {
+               dbg_hid("report descriptor changed\n");
diff --git a/queue-3.6/increase-xhci-suspend-timeout-to-16ms.patch b/queue-3.6/increase-xhci-suspend-timeout-to-16ms.patch
new file mode 100644 (file)
index 0000000..29749b6
--- /dev/null
@@ -0,0 +1,38 @@
+From a6e097dfdfd189b6929af6efa1d289af61858386 Mon Sep 17 00:00:00 2001
+From: Michael Spang <spang@chromium.org>
+Date: Fri, 14 Sep 2012 13:05:49 -0400
+Subject: Increase XHCI suspend timeout to 16ms
+
+From: Michael Spang <spang@chromium.org>
+
+commit a6e097dfdfd189b6929af6efa1d289af61858386 upstream.
+
+The Intel XHCI specification says that after clearing the run/stop bit
+the controller may take up to 16ms to halt. We've seen a device take
+14ms, which with the current timeout of 10ms causes the kernel to
+abort the suspend. Increasing the timeout to the recommended value
+fixes the problem.
+
+This patch should be backported to kernels as old as 2.6.37, that
+contain the commit 5535b1d5f8885695c6ded783c692e3c0d0eda8ca "USB: xHCI:
+PCI power management implementation".
+
+Signed-off-by: Michael Spang <spang@chromium.org>
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/host/xhci.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -890,7 +890,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
+       command &= ~CMD_RUN;
+       xhci_writel(xhci, command, &xhci->op_regs->command);
+       if (handshake(xhci, &xhci->op_regs->status,
+-                    STS_HALT, STS_HALT, 100*100)) {
++                    STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) {
+               xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
+               spin_unlock_irq(&xhci->lock);
+               return -ETIMEDOUT;
diff --git a/queue-3.6/n_gsm-added-interlocking-for-gsm_data_lock-for-certain-code-paths.patch b/queue-3.6/n_gsm-added-interlocking-for-gsm_data_lock-for-certain-code-paths.patch
new file mode 100644 (file)
index 0000000..a5aa122
--- /dev/null
@@ -0,0 +1,64 @@
+From 5e44708f75b0f8712da715d6babb0c21089b2317 Mon Sep 17 00:00:00 2001
+From: Russ Gorby <russ.gorby@intel.com>
+Date: Mon, 13 Aug 2012 13:44:40 +0100
+Subject: n_gsm: added interlocking for gsm_data_lock for certain code paths
+
+From: Russ Gorby <russ.gorby@intel.com>
+
+commit 5e44708f75b0f8712da715d6babb0c21089b2317 upstream.
+
+There were some locking holes in the management of the MUX's
+message queue for 2 code paths:
+1) gsmld_write_wakeup
+2) receipt of CMD_FCON flow-control message
+In both cases gsm_data_kick is called w/o locking so it can collide
+with other other instances of gsm_data_kick (pulling messages tx_tail)
+or potentially other instances of __gsm_data_queu (adding messages to tx_head)
+
+Changed to take the tx_lock in these 2 cases
+
+Signed-off-by: Russ Gorby <russ.gorby@intel.com>
+Tested-by: Yin, Fengwei <fengwei.yin@intel.com>
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/n_gsm.c |    8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -1193,6 +1193,8 @@ static void gsm_control_message(struct g
+                                                       u8 *data, int clen)
+ {
+       u8 buf[1];
++      unsigned long flags;
++
+       switch (command) {
+       case CMD_CLD: {
+               struct gsm_dlci *dlci = gsm->dlci[0];
+@@ -1218,7 +1220,9 @@ static void gsm_control_message(struct g
+               gsm->constipated = 0;
+               gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
+               /* Kick the link in case it is idling */
++              spin_lock_irqsave(&gsm->tx_lock, flags);
+               gsm_data_kick(gsm);
++              spin_unlock_irqrestore(&gsm->tx_lock, flags);
+               break;
+       case CMD_MSC:
+               /* Out of band modem line change indicator for a DLCI */
+@@ -2380,12 +2384,12 @@ static void gsmld_write_wakeup(struct tt
+       /* Queue poll */
+       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
++      spin_lock_irqsave(&gsm->tx_lock, flags);
+       gsm_data_kick(gsm);
+       if (gsm->tx_bytes < TX_THRESH_LO) {
+-              spin_lock_irqsave(&gsm->tx_lock, flags);
+               gsm_dlci_data_sweep(gsm);
+-              spin_unlock_irqrestore(&gsm->tx_lock, flags);
+       }
++      spin_unlock_irqrestore(&gsm->tx_lock, flags);
+ }
+ /**
diff --git a/queue-3.6/n_gsm-memory-leak-in-uplink-error-path.patch b/queue-3.6/n_gsm-memory-leak-in-uplink-error-path.patch
new file mode 100644 (file)
index 0000000..4ba0f5c
--- /dev/null
@@ -0,0 +1,50 @@
+From 88ed2a60610974443335c924d7cb8e5dcf9dbdc1 Mon Sep 17 00:00:00 2001
+From: Russ Gorby <russ.gorby@intel.com>
+Date: Mon, 13 Aug 2012 13:45:30 +0100
+Subject: n_gsm: memory leak in uplink error path
+
+From: Russ Gorby <russ.gorby@intel.com>
+
+commit 88ed2a60610974443335c924d7cb8e5dcf9dbdc1 upstream.
+
+Uplink (TX) network data will go through gsm_dlci_data_output_framed
+there is a bug where if memory allocation fails, the skb which
+has already been pulled off the list will be lost.
+
+In addition TX skbs were being processed in LIFO order
+
+Fixed the memory leak, and changed to FIFO order processing
+
+Signed-off-by: Russ Gorby <russ.gorby@intel.com>
+Tested-by: Kappel, LaurentX <laurentx.kappel@intel.com>
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/n_gsm.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -875,7 +875,7 @@ static int gsm_dlci_data_output_framed(s
+       /* dlci->skb is locked by tx_lock */
+       if (dlci->skb == NULL) {
+-              dlci->skb = skb_dequeue(&dlci->skb_list);
++              dlci->skb = skb_dequeue_tail(&dlci->skb_list);
+               if (dlci->skb == NULL)
+                       return 0;
+               first = 1;
+@@ -899,8 +899,11 @@ static int gsm_dlci_data_output_framed(s
+       /* FIXME: need a timer or something to kick this so it can't
+          get stuck with no work outstanding and no buffer free */
+-      if (msg == NULL)
++      if (msg == NULL) {
++              skb_queue_tail(&dlci->skb_list, dlci->skb);
++              dlci->skb = NULL;
+               return -ENOMEM;
++      }
+       dp = msg->data;
+       if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
diff --git a/queue-3.6/n_gsm-uplink-skbs-accumulate-on-list.patch b/queue-3.6/n_gsm-uplink-skbs-accumulate-on-list.patch
new file mode 100644 (file)
index 0000000..e22e2d2
--- /dev/null
@@ -0,0 +1,50 @@
+From 192b6041e75bb4a2aae73834037038cea139a92d Mon Sep 17 00:00:00 2001
+From: Russ Gorby <russ.gorby@intel.com>
+Date: Mon, 13 Aug 2012 13:43:36 +0100
+Subject: n_gsm: uplink SKBs accumulate on list
+
+From: Russ Gorby <russ.gorby@intel.com>
+
+commit 192b6041e75bb4a2aae73834037038cea139a92d upstream.
+
+gsm_dlci_data_kick will not call any output function if tx_bytes > THRESH_LO
+furthermore it will call the output function only once if tx_bytes == 0
+If the size of the IP writes are on the order of THRESH_LO
+we can get into a situation where skbs accumulate on the outbound list
+being starved for events to call the output function.
+
+gsm_dlci_data_kick now calls the sweep function when tx_bytes==0
+
+Signed-off-by: Russ Gorby <russ.gorby@intel.com>
+Tested-by: Kappel, LaurentX <laurentx.kappel@intel.com>
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/n_gsm.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -971,16 +971,19 @@ static void gsm_dlci_data_sweep(struct g
+ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
+ {
+       unsigned long flags;
++      int sweep;
+       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
+       /* If we have nothing running then we need to fire up */
++      sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO);
+       if (dlci->gsm->tx_bytes == 0) {
+               if (dlci->net)
+                       gsm_dlci_data_output_framed(dlci->gsm, dlci);
+               else
+                       gsm_dlci_data_output(dlci->gsm, dlci);
+-      } else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
+-              gsm_dlci_data_sweep(dlci->gsm);
++      }
++      if (sweep)
++              gsm_dlci_data_sweep(dlci->gsm);
+       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
+ }
diff --git a/queue-3.6/n_gsm.c-implement-3gpp27.010-dlc-start-up-procedure-in-mux.patch b/queue-3.6/n_gsm.c-implement-3gpp27.010-dlc-start-up-procedure-in-mux.patch
new file mode 100644 (file)
index 0000000..8ddbc2e
--- /dev/null
@@ -0,0 +1,41 @@
+From 7e8ac7b23b67416700dfb8b4136a4e81ce675b48 Mon Sep 17 00:00:00 2001
+From: xiaojin <jin.xiao@intel.com>
+Date: Mon, 13 Aug 2012 13:43:15 +0100
+Subject: n_gsm.c: Implement 3GPP27.010 DLC start-up procedure in MUX
+
+From: xiaojin <jin.xiao@intel.com>
+
+commit 7e8ac7b23b67416700dfb8b4136a4e81ce675b48 upstream.
+
+In 3GPP27.010 5.8.1, it defined:
+The TE multiplexer initiates the establishment of the multiplexer control channel by sending a SABM frame on DLCI 0 using the procedures of clause 5.4.1.
+Once the multiplexer channel is established other DLCs may be established using the procedures of clause 5.4.1.
+This patch implement 5.8.1 in MUX level, it make sure DLC0 is the first channel to be setup.
+
+[or for those not familiar with the specification: it was possible to try
+ and open a data connection while the control channel was not yet fully
+ open, which is a spec violation and confuses some modems]
+
+Signed-off-by: xiaojin <jin.xiao@intel.com>
+Tested-by: Yin, Fengwei <fengwei.yin@intel.com>
+[tweaked the order we check things and error code]
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/n_gsm.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -2889,6 +2889,10 @@ static int gsmtty_open(struct tty_struct
+       gsm = gsm_mux[mux];
+       if (gsm->dead)
+               return -EL2HLT;
++      /* If DLCI 0 is not yet fully open return an error. This is ok from a locking
++         perspective as we don't have to worry about this if DLCI0 is lost */
++      if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN)
++              return -EL2NSYNC;
+       dlci = gsm->dlci[line];
+       if (dlci == NULL)
+               dlci = gsm_dlci_alloc(gsm, line);
index adf0937520aafa71ac2b86e50c1d88ce318c54c4..628f5f2a64184ec72810577c3bbfbb41d161a1ce 100644 (file)
@@ -19,3 +19,22 @@ tty-ttyprintk-don-t-touch-behind-tty-write_buf.patch
 serial-omap-fix-software-flow-control.patch
 serial-pl011-handle-corruption-at-high-clock-speeds.patch
 serial-set-correct-baud_base-for-exsys-ex-41092-dual-16950.patch
+tools-hv-fix-file-handle-leak.patch
+tools-hv-fix-exit-error-code.patch
+tools-hv-check-for-read-write-errors.patch
+b43legacy-fix-crash-on-unload-when-firmware-not-available.patch
+firmware-add-missing-attributes-to-efi-variable-attribute-print-out-from-sysfs.patch
+xhci-intel-panther-point-bei-quirk.patch
+xhci-add-cmd_ring_state.patch
+xhci-add-aborting-command-ring-function.patch
+xhci-cancel-command-after-command-timeout.patch
+xhci-handle-command-after-aborting-the-command-ring.patch
+increase-xhci-suspend-timeout-to-16ms.patch
+hid-keep-dev_rdesc-unmodified-and-use-it-for-comparisons.patch
+ath9k-disable-aspm-only-for-ar9285.patch
+xen-pciback-restore-the-pci-config-space-after-an-flr.patch
+coredump-prevent-double-free-on-an-error-path-in-core.patch
+n_gsm.c-implement-3gpp27.010-dlc-start-up-procedure-in-mux.patch
+n_gsm-uplink-skbs-accumulate-on-list.patch
+n_gsm-added-interlocking-for-gsm_data_lock-for-certain-code-paths.patch
+n_gsm-memory-leak-in-uplink-error-path.patch
diff --git a/queue-3.6/tools-hv-check-for-read-write-errors.patch b/queue-3.6/tools-hv-check-for-read-write-errors.patch
new file mode 100644 (file)
index 0000000..0f27412
--- /dev/null
@@ -0,0 +1,76 @@
+From 436473bc2173499ae274d0f50111d1e355006caf Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Wed, 5 Sep 2012 14:37:37 -0700
+Subject: tools/hv: Check for read/write errors
+
+From: Ben Hutchings <ben@decadent.org.uk>
+
+commit 436473bc2173499ae274d0f50111d1e355006caf upstream.
+
+hv_kvp_daemon currently does not check whether fread() or fwrite()
+succeed.  Add the necessary checks.  Also, remove the incorrect use of
+feof() before fread().
+
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/hv/hv_kvp_daemon.c |   22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+--- a/tools/hv/hv_kvp_daemon.c
++++ b/tools/hv/hv_kvp_daemon.c
+@@ -144,7 +144,12 @@ static void kvp_update_file(int pool)
+                               sizeof(struct kvp_record),
+                               kvp_file_info[pool].num_records, filep);
+-      fclose(filep);
++      if (ferror(filep) || fclose(filep)) {
++              kvp_release_lock(pool);
++              syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
++              exit(EXIT_FAILURE);
++      }
++
+       kvp_release_lock(pool);
+ }
+@@ -165,12 +170,17 @@ static void kvp_update_mem_state(int poo
+               syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
+               exit(EXIT_FAILURE);
+       }
+-      while (!feof(filep)) {
++      for (;;) {
+               readp = &record[records_read];
+               records_read += fread(readp, sizeof(struct kvp_record),
+                                       ENTRIES_PER_BLOCK * num_blocks,
+                                       filep);
++              if (ferror(filep)) {
++                      syslog(LOG_ERR, "Failed to read file, pool: %d", pool);
++                      exit(EXIT_FAILURE);
++              }
++
+               if (!feof(filep)) {
+                       /*
+                        * We have more data to read.
+@@ -233,12 +243,18 @@ static int kvp_file_init(void)
+                       fclose(filep);
+                       return 1;
+               }
+-              while (!feof(filep)) {
++              for (;;) {
+                       readp = &record[records_read];
+                       records_read += fread(readp, sizeof(struct kvp_record),
+                                       ENTRIES_PER_BLOCK,
+                                       filep);
++                      if (ferror(filep)) {
++                              syslog(LOG_ERR, "Failed to read file, pool: %d",
++                                     i);
++                              exit(EXIT_FAILURE);
++                      }
++
+                       if (!feof(filep)) {
+                               /*
+                                * We have more data to read.
diff --git a/queue-3.6/tools-hv-fix-exit-error-code.patch b/queue-3.6/tools-hv-fix-exit-error-code.patch
new file mode 100644 (file)
index 0000000..7c6cb8c
--- /dev/null
@@ -0,0 +1,121 @@
+From 6bb22fea25624ab593eee376fa5fb82d1b13f45a Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Wed, 5 Sep 2012 14:37:36 -0700
+Subject: tools/hv: Fix exit() error code
+
+From: Ben Hutchings <ben@decadent.org.uk>
+
+commit 6bb22fea25624ab593eee376fa5fb82d1b13f45a upstream.
+
+Linux native exit codes are 8-bit unsigned values.  exit(-1) results
+in an exit code of 255, which is usually reserved for shells reporting
+'command not found'.  Use the portable value EXIT_FAILURE.  (Not that
+this matters much for a daemon.)
+
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/hv/hv_kvp_daemon.c |   22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+--- a/tools/hv/hv_kvp_daemon.c
++++ b/tools/hv/hv_kvp_daemon.c
+@@ -106,7 +106,7 @@ static void kvp_acquire_lock(int pool)
+       if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
+               syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
+-              exit(-1);
++              exit(EXIT_FAILURE);
+       }
+ }
+@@ -118,7 +118,7 @@ static void kvp_release_lock(int pool)
+       if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
+               perror("fcntl");
+               syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
+-              exit(-1);
++              exit(EXIT_FAILURE);
+       }
+ }
+@@ -137,7 +137,7 @@ static void kvp_update_file(int pool)
+       if (!filep) {
+               kvp_release_lock(pool);
+               syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
+-              exit(-1);
++              exit(EXIT_FAILURE);
+       }
+       bytes_written = fwrite(kvp_file_info[pool].records,
+@@ -163,7 +163,7 @@ static void kvp_update_mem_state(int poo
+       if (!filep) {
+               kvp_release_lock(pool);
+               syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
+-              exit(-1);
++              exit(EXIT_FAILURE);
+       }
+       while (!feof(filep)) {
+               readp = &record[records_read];
+@@ -180,7 +180,7 @@ static void kvp_update_mem_state(int poo
+                       if (record == NULL) {
+                               syslog(LOG_ERR, "malloc failed");
+-                              exit(-1);
++                              exit(EXIT_FAILURE);
+                       }
+                       continue;
+               }
+@@ -209,7 +209,7 @@ static int kvp_file_init(void)
+       if (access("/var/opt/hyperv", F_OK)) {
+               if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
+                       syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
+-                      exit(-1);
++                      exit(EXIT_FAILURE);
+               }
+       }
+@@ -658,13 +658,13 @@ int main(void)
+       if (kvp_file_init()) {
+               syslog(LOG_ERR, "Failed to initialize the pools");
+-              exit(-1);
++              exit(EXIT_FAILURE);
+       }
+       fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+       if (fd < 0) {
+               syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
+-              exit(-1);
++              exit(EXIT_FAILURE);
+       }
+       addr.nl_family = AF_NETLINK;
+       addr.nl_pad = 0;
+@@ -676,7 +676,7 @@ int main(void)
+       if (error < 0) {
+               syslog(LOG_ERR, "bind failed; error:%d", error);
+               close(fd);
+-              exit(-1);
++              exit(EXIT_FAILURE);
+       }
+       sock_opt = addr.nl_groups;
+       setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
+@@ -696,7 +696,7 @@ int main(void)
+       if (len < 0) {
+               syslog(LOG_ERR, "netlink_send failed; error:%d", len);
+               close(fd);
+-              exit(-1);
++              exit(EXIT_FAILURE);
+       }
+       pfd.fd = fd;
+@@ -864,7 +864,7 @@ kvp_done:
+               len = netlink_send(fd, incoming_cn_msg);
+               if (len < 0) {
+                       syslog(LOG_ERR, "net_link send failed; error:%d", len);
+-                      exit(-1);
++                      exit(EXIT_FAILURE);
+               }
+       }
diff --git a/queue-3.6/tools-hv-fix-file-handle-leak.patch b/queue-3.6/tools-hv-fix-file-handle-leak.patch
new file mode 100644 (file)
index 0000000..ca31d6b
--- /dev/null
@@ -0,0 +1,38 @@
+From d5ab482799e7c4c4b7c0aa67e8710dce28115d03 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Wed, 5 Sep 2012 14:37:35 -0700
+Subject: tools/hv: Fix file handle leak
+
+From: Ben Hutchings <ben@decadent.org.uk>
+
+commit d5ab482799e7c4c4b7c0aa67e8710dce28115d03 upstream.
+
+Match up each fopen() with an fclose().
+
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/hv/hv_kvp_daemon.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/tools/hv/hv_kvp_daemon.c
++++ b/tools/hv/hv_kvp_daemon.c
+@@ -144,7 +144,7 @@ static void kvp_update_file(int pool)
+                               sizeof(struct kvp_record),
+                               kvp_file_info[pool].num_records, filep);
+-      fflush(filep);
++      fclose(filep);
+       kvp_release_lock(pool);
+ }
+@@ -191,6 +191,7 @@ static void kvp_update_mem_state(int poo
+       kvp_file_info[pool].records = record;
+       kvp_file_info[pool].num_records = records_read;
++      fclose(filep);
+       kvp_release_lock(pool);
+ }
+ static int kvp_file_init(void)
diff --git a/queue-3.6/xen-pciback-restore-the-pci-config-space-after-an-flr.patch b/queue-3.6/xen-pciback-restore-the-pci-config-space-after-an-flr.patch
new file mode 100644 (file)
index 0000000..97a4327
--- /dev/null
@@ -0,0 +1,54 @@
+From c341ca45ce56143804ef5a8f4db753e554e640b4 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Date: Tue, 25 Sep 2012 16:48:24 -0400
+Subject: xen/pciback: Restore the PCI config space after an FLR.
+
+From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+
+commit c341ca45ce56143804ef5a8f4db753e554e640b4 upstream.
+
+When we do an FLR, or D0->D3_hot we may lose the BARs as the
+device has turned itself off (and on). This means the device cannot
+function unless the pci_restore_state is called - which it is
+when the PCI device is unbound from the Xen PCI backend driver.
+For PV guests it ends up calling pci_enable_device / pci_enable_msi[x]
+which does the proper steps
+
+That however is not happening if a HVM guest is run as QEMU
+deals with PCI configuration space. QEMU also requires that the
+device be "parked"  under the ownership of a pci-stub driver to
+guarantee that the PCI device is not being used. Hence we
+follow the same incantation as pci_reset_function does - by
+doing an FLR, then restoring the PCI configuration space.
+
+The result of this patch is that when you run lspci, you get
+now this:
+
+-       Region 0: [virtual] Memory at fe8c0000 (32-bit, non-prefetchable) [size=128K]
+-       Region 1: [virtual] Memory at fe800000 (32-bit, non-prefetchable) [size=512K]
++       Region 0: Memory at fe8c0000 (32-bit, non-prefetchable) [size=128K]
++       Region 1: Memory at fe800000 (32-bit, non-prefetchable) [size=512K]
+        Region 2: I/O ports at c000 [size=32]
+-       Region 3: [virtual] Memory at fe8e0000 (32-bit, non-prefetchable) [size=16K]
++       Region 3: Memory at fe8e0000 (32-bit, non-prefetchable) [size=16K]
+
+The [virtual] means that lspci read those entries from SysFS but when
+it read them from the device it got a different value (0xfffffff).
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/xen/xen-pciback/pci_stub.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/xen/xen-pciback/pci_stub.c
++++ b/drivers/xen/xen-pciback/pci_stub.c
+@@ -362,6 +362,7 @@ static int __devinit pcistub_init_device
+       else {
+               dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n");
+               __pci_reset_function_locked(dev);
++              pci_restore_state(dev);
+       }
+       /* Now disable the device (this also ensures some private device
+        * data is setup before we export)
diff --git a/queue-3.6/xhci-add-aborting-command-ring-function.patch b/queue-3.6/xhci-add-aborting-command-ring-function.patch
new file mode 100644 (file)
index 0000000..ba77c5a
--- /dev/null
@@ -0,0 +1,241 @@
+From b92cc66c047ff7cf587b318fe377061a353c120f Mon Sep 17 00:00:00 2001
+From: Elric Fu <elricfu1@gmail.com>
+Date: Wed, 27 Jun 2012 16:31:12 +0800
+Subject: xHCI: add aborting command ring function
+
+From: Elric Fu <elricfu1@gmail.com>
+
+commit b92cc66c047ff7cf587b318fe377061a353c120f upstream.
+
+Software have to abort command ring and cancel command
+when a command is failed or hang. Otherwise, the command
+ring will hang up and can't handle the others. An example
+of a command that may hang is the Address Device Command,
+because waiting for a SET_ADDRESS request to be acknowledged
+by a USB device is outside of the xHC's ability to control.
+
+To cancel a command, software will initialize a command
+descriptor for the cancel command, and add it into a
+cancel_cmd_list of xhci.
+
+Sarah: Fixed missing newline on "Have the command ring been stopped?"
+debugging statement.
+
+This patch should be backported to kernels as old as 3.0, that contain
+the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an
+assertion to check for virt_dev=0 bug." That commit papers over a NULL
+pointer dereference, and this patch fixes the underlying issue that
+caused the NULL pointer dereference.
+
+Signed-off-by: Elric Fu <elricfu1@gmail.com>
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Tested-by: Miroslav Sabljic <miroslav.sabljic@avl.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/host/xhci-mem.c  |    7 ++
+ drivers/usb/host/xhci-ring.c |  108 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/host/xhci.c      |    2 
+ drivers/usb/host/xhci.h      |   12 ++++
+ 4 files changed, 128 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -1772,6 +1772,7 @@ void xhci_mem_cleanup(struct xhci_hcd *x
+ {
+       struct pci_dev  *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+       struct dev_info *dev_info, *next;
++      struct xhci_cd  *cur_cd, *next_cd;
+       unsigned long   flags;
+       int size;
+       int i, j, num_ports;
+@@ -1795,6 +1796,11 @@ void xhci_mem_cleanup(struct xhci_hcd *x
+               xhci_ring_free(xhci, xhci->cmd_ring);
+       xhci->cmd_ring = NULL;
+       xhci_dbg(xhci, "Freed command ring\n");
++      list_for_each_entry_safe(cur_cd, next_cd,
++                      &xhci->cancel_cmd_list, cancel_cmd_list) {
++              list_del(&cur_cd->cancel_cmd_list);
++              kfree(cur_cd);
++      }
+       for (i = 1; i < MAX_HC_SLOTS; ++i)
+               xhci_free_virt_device(xhci, i);
+@@ -2340,6 +2346,7 @@ int xhci_mem_init(struct xhci_hcd *xhci,
+       xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
+       if (!xhci->cmd_ring)
+               goto fail;
++      INIT_LIST_HEAD(&xhci->cancel_cmd_list);
+       xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
+       xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
+                       (unsigned long long)xhci->cmd_ring->first_seg->dma);
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -289,6 +289,114 @@ void xhci_ring_cmd_db(struct xhci_hcd *x
+       xhci_readl(xhci, &xhci->dba->doorbell[0]);
+ }
++static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
++{
++      u64 temp_64;
++      int ret;
++
++      xhci_dbg(xhci, "Abort command ring\n");
++
++      if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) {
++              xhci_dbg(xhci, "The command ring isn't running, "
++                              "Have the command ring been stopped?\n");
++              return 0;
++      }
++
++      temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
++      if (!(temp_64 & CMD_RING_RUNNING)) {
++              xhci_dbg(xhci, "Command ring had been stopped\n");
++              return 0;
++      }
++      xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
++      xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
++                      &xhci->op_regs->cmd_ring);
++
++      /* Section 4.6.1.2 of xHCI 1.0 spec says software should
++       * time the completion od all xHCI commands, including
++       * the Command Abort operation. If software doesn't see
++       * CRR negated in a timely manner (e.g. longer than 5
++       * seconds), then it should assume that the there are
++       * larger problems with the xHC and assert HCRST.
++       */
++      ret = handshake(xhci, &xhci->op_regs->cmd_ring,
++                      CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
++      if (ret < 0) {
++              xhci_err(xhci, "Stopped the command ring failed, "
++                              "maybe the host is dead\n");
++              xhci->xhc_state |= XHCI_STATE_DYING;
++              xhci_quiesce(xhci);
++              xhci_halt(xhci);
++              return -ESHUTDOWN;
++      }
++
++      return 0;
++}
++
++static int xhci_queue_cd(struct xhci_hcd *xhci,
++              struct xhci_command *command,
++              union xhci_trb *cmd_trb)
++{
++      struct xhci_cd *cd;
++      cd = kzalloc(sizeof(struct xhci_cd), GFP_ATOMIC);
++      if (!cd)
++              return -ENOMEM;
++      INIT_LIST_HEAD(&cd->cancel_cmd_list);
++
++      cd->command = command;
++      cd->cmd_trb = cmd_trb;
++      list_add_tail(&cd->cancel_cmd_list, &xhci->cancel_cmd_list);
++
++      return 0;
++}
++
++/*
++ * Cancel the command which has issue.
++ *
++ * Some commands may hang due to waiting for acknowledgement from
++ * usb device. It is outside of the xHC's ability to control and
++ * will cause the command ring is blocked. When it occurs software
++ * should intervene to recover the command ring.
++ * See Section 4.6.1.1 and 4.6.1.2
++ */
++int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
++              union xhci_trb *cmd_trb)
++{
++      int retval = 0;
++      unsigned long flags;
++
++      spin_lock_irqsave(&xhci->lock, flags);
++
++      if (xhci->xhc_state & XHCI_STATE_DYING) {
++              xhci_warn(xhci, "Abort the command ring,"
++                              " but the xHCI is dead.\n");
++              retval = -ESHUTDOWN;
++              goto fail;
++      }
++
++      /* queue the cmd desriptor to cancel_cmd_list */
++      retval = xhci_queue_cd(xhci, command, cmd_trb);
++      if (retval) {
++              xhci_warn(xhci, "Queuing command descriptor failed.\n");
++              goto fail;
++      }
++
++      /* abort command ring */
++      retval = xhci_abort_cmd_ring(xhci);
++      if (retval) {
++              xhci_err(xhci, "Abort command ring failed\n");
++              if (unlikely(retval == -ESHUTDOWN)) {
++                      spin_unlock_irqrestore(&xhci->lock, flags);
++                      usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
++                      xhci_dbg(xhci, "xHCI host controller is dead.\n");
++                      return retval;
++              }
++      }
++
++fail:
++      spin_unlock_irqrestore(&xhci->lock, flags);
++      return retval;
++}
++
+ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
+               unsigned int slot_id,
+               unsigned int ep_index,
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -52,7 +52,7 @@ MODULE_PARM_DESC(link_quirk, "Don't clea
+  * handshake done).  There are two failure modes:  "usec" have passed (major
+  * hardware flakeout), or the register reads as all-ones (hardware removed).
+  */
+-static int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
++int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
+                     u32 mask, u32 done, int usec)
+ {
+       u32     result;
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1256,6 +1256,13 @@ struct xhci_td {
+       union xhci_trb          *last_trb;
+ };
++/* command descriptor */
++struct xhci_cd {
++      struct list_head        cancel_cmd_list;
++      struct xhci_command     *command;
++      union xhci_trb          *cmd_trb;
++};
++
+ struct xhci_dequeue_state {
+       struct xhci_segment *new_deq_seg;
+       union xhci_trb *new_deq_ptr;
+@@ -1425,6 +1432,7 @@ struct xhci_hcd {
+ #define CMD_RING_STATE_RUNNING         (1 << 0)
+ #define CMD_RING_STATE_ABORTED         (1 << 1)
+ #define CMD_RING_STATE_STOPPED         (1 << 2)
++      struct list_head        cancel_cmd_list;
+       unsigned int            cmd_ring_reserved_trbs;
+       struct xhci_ring        *event_ring;
+       struct xhci_erst        erst;
+@@ -1709,6 +1717,8 @@ static inline void xhci_unregister_plat(
+ /* xHCI host controller glue */
+ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
++int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
++              u32 mask, u32 done, int usec);
+ void xhci_quiesce(struct xhci_hcd *xhci);
+ int xhci_halt(struct xhci_hcd *xhci);
+ int xhci_reset(struct xhci_hcd *xhci);
+@@ -1799,6 +1809,8 @@ void xhci_queue_config_ep_quirk(struct x
+               unsigned int slot_id, unsigned int ep_index,
+               struct xhci_dequeue_state *deq_state);
+ void xhci_stop_endpoint_command_watchdog(unsigned long arg);
++int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
++              union xhci_trb *cmd_trb);
+ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
+               unsigned int ep_index, unsigned int stream_id);
diff --git a/queue-3.6/xhci-add-cmd_ring_state.patch b/queue-3.6/xhci-add-cmd_ring_state.patch
new file mode 100644 (file)
index 0000000..7d43d86
--- /dev/null
@@ -0,0 +1,80 @@
+From c181bc5b5d5c79b71203cd10cef97f802fb6f9c1 Mon Sep 17 00:00:00 2001
+From: Elric Fu <elricfu1@gmail.com>
+Date: Wed, 27 Jun 2012 16:30:57 +0800
+Subject: xHCI: add cmd_ring_state
+
+From: Elric Fu <elricfu1@gmail.com>
+
+commit c181bc5b5d5c79b71203cd10cef97f802fb6f9c1 upstream.
+
+Adding cmd_ring_state for command ring. It helps to verify
+the current command ring state for controlling the command
+ring operations.
+
+This patch should be backported to kernels as old as 3.0.  The commit
+7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an assertion to
+check for virt_dev=0 bug." papers over the NULL pointer dereference that
+I now believe is related to a timed out Set Address command.  This (and
+the four patches that follow it) contain the real fix that also allows
+VIA USB 3.0 hubs to consistently re-enumerate during the plug/unplug
+stress tests.
+
+Signed-off-by: Elric Fu <elricfu1@gmail.com>
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Tested-by: Miroslav Sabljic <miroslav.sabljic@avl.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/host/xhci-ring.c |    3 +++
+ drivers/usb/host/xhci.c      |    6 ++++--
+ drivers/usb/host/xhci.h      |    4 ++++
+ 3 files changed, 11 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -280,6 +280,9 @@ static inline int room_on_ring(struct xh
+ /* Ring the host controller doorbell after placing a command on the ring */
+ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
+ {
++      if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING))
++              return;
++
+       xhci_dbg(xhci, "// Ding dong!\n");
+       xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]);
+       /* Flush PCI posted writes */
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -105,9 +105,10 @@ int xhci_halt(struct xhci_hcd *xhci)
+       ret = handshake(xhci, &xhci->op_regs->status,
+                       STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
+-      if (!ret)
++      if (!ret) {
+               xhci->xhc_state |= XHCI_STATE_HALTED;
+-      else
++              xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
++      } else
+               xhci_warn(xhci, "Host not halted after %u microseconds.\n",
+                               XHCI_MAX_HALT_USEC);
+       return ret;
+@@ -583,6 +584,7 @@ static int xhci_run_finished(struct xhci
+               return -ENODEV;
+       }
+       xhci->shared_hcd->state = HC_STATE_RUNNING;
++      xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
+       if (xhci->quirks & XHCI_NEC_HOST)
+               xhci_ring_cmd_db(xhci);
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1421,6 +1421,10 @@ struct xhci_hcd {
+       /* data structures */
+       struct xhci_device_context_array *dcbaa;
+       struct xhci_ring        *cmd_ring;
++      unsigned int            cmd_ring_state;
++#define CMD_RING_STATE_RUNNING         (1 << 0)
++#define CMD_RING_STATE_ABORTED         (1 << 1)
++#define CMD_RING_STATE_STOPPED         (1 << 2)
+       unsigned int            cmd_ring_reserved_trbs;
+       struct xhci_ring        *event_ring;
+       struct xhci_erst        erst;
diff --git a/queue-3.6/xhci-cancel-command-after-command-timeout.patch b/queue-3.6/xhci-cancel-command-after-command-timeout.patch
new file mode 100644 (file)
index 0000000..23ea183
--- /dev/null
@@ -0,0 +1,142 @@
+From 6e4468b9a0793dfb53eb80d9fe52c739b13b27fd Mon Sep 17 00:00:00 2001
+From: Elric Fu <elricfu1@gmail.com>
+Date: Wed, 27 Jun 2012 16:31:52 +0800
+Subject: xHCI: cancel command after command timeout
+
+From: Elric Fu <elricfu1@gmail.com>
+
+commit 6e4468b9a0793dfb53eb80d9fe52c739b13b27fd upstream.
+
+The patch is used to cancel command when the command isn't
+acknowledged and a timeout occurs.
+
+This patch should be backported to kernels as old as 3.0, that contain
+the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an
+assertion to check for virt_dev=0 bug." That commit papers over a NULL
+pointer dereference, and this patch fixes the underlying issue that
+caused the NULL pointer dereference.
+
+Signed-off-by: Elric Fu <elricfu1@gmail.com>
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Tested-by: Miroslav Sabljic <miroslav.sabljic@avl.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/host/xhci.c |   26 +++++++++++++++++++-------
+ drivers/usb/host/xhci.h |    3 +++
+ 2 files changed, 22 insertions(+), 7 deletions(-)
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -2525,6 +2525,7 @@ static int xhci_configure_endpoint(struc
+       struct completion *cmd_completion;
+       u32 *cmd_status;
+       struct xhci_virt_device *virt_dev;
++      union xhci_trb *cmd_trb;
+       spin_lock_irqsave(&xhci->lock, flags);
+       virt_dev = xhci->devs[udev->slot_id];
+@@ -2570,6 +2571,7 @@ static int xhci_configure_endpoint(struc
+       }
+       init_completion(cmd_completion);
++      cmd_trb = xhci->cmd_ring->dequeue;
+       if (!ctx_change)
+               ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma,
+                               udev->slot_id, must_succeed);
+@@ -2591,14 +2593,17 @@ static int xhci_configure_endpoint(struc
+       /* Wait for the configure endpoint command to complete */
+       timeleft = wait_for_completion_interruptible_timeout(
+                       cmd_completion,
+-                      USB_CTRL_SET_TIMEOUT);
++                      XHCI_CMD_DEFAULT_TIMEOUT);
+       if (timeleft <= 0) {
+               xhci_warn(xhci, "%s while waiting for %s command\n",
+                               timeleft == 0 ? "Timeout" : "Signal",
+                               ctx_change == 0 ?
+                                       "configure endpoint" :
+                                       "evaluate context");
+-              /* FIXME cancel the configure endpoint command */
++              /* cancel the configure endpoint command */
++              ret = xhci_cancel_cmd(xhci, command, cmd_trb);
++              if (ret < 0)
++                      return ret;
+               return -ETIME;
+       }
+@@ -3547,8 +3552,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd,
+       unsigned long flags;
+       int timeleft;
+       int ret;
++      union xhci_trb *cmd_trb;
+       spin_lock_irqsave(&xhci->lock, flags);
++      cmd_trb = xhci->cmd_ring->dequeue;
+       ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0);
+       if (ret) {
+               spin_unlock_irqrestore(&xhci->lock, flags);
+@@ -3560,12 +3567,12 @@ int xhci_alloc_dev(struct usb_hcd *hcd,
+       /* XXX: how much time for xHC slot assignment? */
+       timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
+-                      USB_CTRL_SET_TIMEOUT);
++                      XHCI_CMD_DEFAULT_TIMEOUT);
+       if (timeleft <= 0) {
+               xhci_warn(xhci, "%s while waiting for a slot\n",
+                               timeleft == 0 ? "Timeout" : "Signal");
+-              /* FIXME cancel the enable slot request */
+-              return 0;
++              /* cancel the enable slot request */
++              return xhci_cancel_cmd(xhci, NULL, cmd_trb);
+       }
+       if (!xhci->slot_id) {
+@@ -3626,6 +3633,7 @@ int xhci_address_device(struct usb_hcd *
+       struct xhci_slot_ctx *slot_ctx;
+       struct xhci_input_control_ctx *ctrl_ctx;
+       u64 temp_64;
++      union xhci_trb *cmd_trb;
+       if (!udev->slot_id) {
+               xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
+@@ -3664,6 +3672,7 @@ int xhci_address_device(struct usb_hcd *
+       xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
+       spin_lock_irqsave(&xhci->lock, flags);
++      cmd_trb = xhci->cmd_ring->dequeue;
+       ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
+                                       udev->slot_id);
+       if (ret) {
+@@ -3676,7 +3685,7 @@ int xhci_address_device(struct usb_hcd *
+       /* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */
+       timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
+-                      USB_CTRL_SET_TIMEOUT);
++                      XHCI_CMD_DEFAULT_TIMEOUT);
+       /* FIXME: From section 4.3.4: "Software shall be responsible for timing
+        * the SetAddress() "recovery interval" required by USB and aborting the
+        * command on a timeout.
+@@ -3684,7 +3693,10 @@ int xhci_address_device(struct usb_hcd *
+       if (timeleft <= 0) {
+               xhci_warn(xhci, "%s while waiting for address device command\n",
+                               timeleft == 0 ? "Timeout" : "Signal");
+-              /* FIXME cancel the address device command */
++              /* cancel the address device command */
++              ret = xhci_cancel_cmd(xhci, NULL, cmd_trb);
++              if (ret < 0)
++                      return ret;
+               return -ETIME;
+       }
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1256,6 +1256,9 @@ struct xhci_td {
+       union xhci_trb          *last_trb;
+ };
++/* xHCI command default timeout value */
++#define XHCI_CMD_DEFAULT_TIMEOUT      (5 * HZ)
++
+ /* command descriptor */
+ struct xhci_cd {
+       struct list_head        cancel_cmd_list;
diff --git a/queue-3.6/xhci-handle-command-after-aborting-the-command-ring.patch b/queue-3.6/xhci-handle-command-after-aborting-the-command-ring.patch
new file mode 100644 (file)
index 0000000..6b4eace
--- /dev/null
@@ -0,0 +1,238 @@
+From b63f4053cc8aa22a98e3f9a97845afe6c15d0a0d Mon Sep 17 00:00:00 2001
+From: Elric Fu <elricfu1@gmail.com>
+Date: Wed, 27 Jun 2012 16:55:43 +0800
+Subject: xHCI: handle command after aborting the command ring
+
+From: Elric Fu <elricfu1@gmail.com>
+
+commit b63f4053cc8aa22a98e3f9a97845afe6c15d0a0d upstream.
+
+According to xHCI spec section 4.6.1.1 and section 4.6.1.2,
+after aborting a command on the command ring, xHC will
+generate a command completion event with its completion
+code set to Command Ring Stopped at least. If a command is
+currently executing at the time of aborting a command, xHC
+also generate a command completion event with its completion
+code set to Command Abort. When the command ring is stopped,
+software may remove, add, or rearrage Command Descriptors.
+
+To cancel a command, software will initialize a command
+descriptor for the cancel command, and add it into a
+cancel_cmd_list of xhci. When the command ring is stopped,
+software will find the command trbs described by command
+descriptors in cancel_cmd_list and modify it to No Op
+command. If software can't find the matched trbs, we can
+think it had been finished.
+
+This patch should be backported to kernels as old as 3.0, that contain
+the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an
+assertion to check for virt_dev=0 bug." That commit papers over a NULL
+pointer dereference, and this patch fixes the underlying issue that
+caused the NULL pointer dereference.
+
+Signed-off-by: Elric Fu <elricfu1@gmail.com>
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Tested-by: Miroslav Sabljic <miroslav.sabljic@avl.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/host/xhci-ring.c |  171 +++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 165 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1170,6 +1170,20 @@ static void handle_reset_ep_completion(s
+       }
+ }
++/* Complete the command and detele it from the devcie's command queue.
++ */
++static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
++              struct xhci_command *command, u32 status)
++{
++      command->status = status;
++      list_del(&command->cmd_list);
++      if (command->completion)
++              complete(command->completion);
++      else
++              xhci_free_command(xhci, command);
++}
++
++
+ /* Check to see if a command in the device's command queue matches this one.
+  * Signal the completion or free the command, and return 1.  Return 0 if the
+  * completed command isn't at the head of the command list.
+@@ -1188,15 +1202,144 @@ static int handle_cmd_in_cmd_wait_list(s
+       if (xhci->cmd_ring->dequeue != command->command_trb)
+               return 0;
+-      command->status = GET_COMP_CODE(le32_to_cpu(event->status));
+-      list_del(&command->cmd_list);
+-      if (command->completion)
+-              complete(command->completion);
+-      else
+-              xhci_free_command(xhci, command);
++      xhci_complete_cmd_in_cmd_wait_list(xhci, command,
++                      GET_COMP_CODE(le32_to_cpu(event->status)));
+       return 1;
+ }
++/*
++ * Finding the command trb need to be cancelled and modifying it to
++ * NO OP command. And if the command is in device's command wait
++ * list, finishing and freeing it.
++ *
++ * If we can't find the command trb, we think it had already been
++ * executed.
++ */
++static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd)
++{
++      struct xhci_segment *cur_seg;
++      union xhci_trb *cmd_trb;
++      u32 cycle_state;
++
++      if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue)
++              return;
++
++      /* find the current segment of command ring */
++      cur_seg = find_trb_seg(xhci->cmd_ring->first_seg,
++                      xhci->cmd_ring->dequeue, &cycle_state);
++
++      /* find the command trb matched by cd from command ring */
++      for (cmd_trb = xhci->cmd_ring->dequeue;
++                      cmd_trb != xhci->cmd_ring->enqueue;
++                      next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) {
++              /* If the trb is link trb, continue */
++              if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3]))
++                      continue;
++
++              if (cur_cd->cmd_trb == cmd_trb) {
++
++                      /* If the command in device's command list, we should
++                       * finish it and free the command structure.
++                       */
++                      if (cur_cd->command)
++                              xhci_complete_cmd_in_cmd_wait_list(xhci,
++                                      cur_cd->command, COMP_CMD_STOP);
++
++                      /* get cycle state from the origin command trb */
++                      cycle_state = le32_to_cpu(cmd_trb->generic.field[3])
++                              & TRB_CYCLE;
++
++                      /* modify the command trb to NO OP command */
++                      cmd_trb->generic.field[0] = 0;
++                      cmd_trb->generic.field[1] = 0;
++                      cmd_trb->generic.field[2] = 0;
++                      cmd_trb->generic.field[3] = cpu_to_le32(
++                                      TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
++                      break;
++              }
++      }
++}
++
++static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci)
++{
++      struct xhci_cd *cur_cd, *next_cd;
++
++      if (list_empty(&xhci->cancel_cmd_list))
++              return;
++
++      list_for_each_entry_safe(cur_cd, next_cd,
++                      &xhci->cancel_cmd_list, cancel_cmd_list) {
++              xhci_cmd_to_noop(xhci, cur_cd);
++              list_del(&cur_cd->cancel_cmd_list);
++              kfree(cur_cd);
++      }
++}
++
++/*
++ * traversing the cancel_cmd_list. If the command descriptor according
++ * to cmd_trb is found, the function free it and return 1, otherwise
++ * return 0.
++ */
++static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci,
++              union xhci_trb *cmd_trb)
++{
++      struct xhci_cd *cur_cd, *next_cd;
++
++      if (list_empty(&xhci->cancel_cmd_list))
++              return 0;
++
++      list_for_each_entry_safe(cur_cd, next_cd,
++                      &xhci->cancel_cmd_list, cancel_cmd_list) {
++              if (cur_cd->cmd_trb == cmd_trb) {
++                      if (cur_cd->command)
++                              xhci_complete_cmd_in_cmd_wait_list(xhci,
++                                      cur_cd->command, COMP_CMD_STOP);
++                      list_del(&cur_cd->cancel_cmd_list);
++                      kfree(cur_cd);
++                      return 1;
++              }
++      }
++
++      return 0;
++}
++
++/*
++ * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the
++ * trb pointed by the command ring dequeue pointer is the trb we want to
++ * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will
++ * traverse the cancel_cmd_list to trun the all of the commands according
++ * to command descriptor to NO-OP trb.
++ */
++static int handle_stopped_cmd_ring(struct xhci_hcd *xhci,
++              int cmd_trb_comp_code)
++{
++      int cur_trb_is_good = 0;
++
++      /* Searching the cmd trb pointed by the command ring dequeue
++       * pointer in command descriptor list. If it is found, free it.
++       */
++      cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci,
++                      xhci->cmd_ring->dequeue);
++
++      if (cmd_trb_comp_code == COMP_CMD_ABORT)
++              xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
++      else if (cmd_trb_comp_code == COMP_CMD_STOP) {
++              /* traversing the cancel_cmd_list and canceling
++               * the command according to command descriptor
++               */
++              xhci_cancel_cmd_in_cd_list(xhci);
++
++              xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
++              /*
++               * ring command ring doorbell again to restart the
++               * command ring
++               */
++              if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue)
++                      xhci_ring_cmd_db(xhci);
++      }
++      return cur_trb_is_good;
++}
++
+ static void handle_cmd_completion(struct xhci_hcd *xhci,
+               struct xhci_event_cmd *event)
+ {
+@@ -1222,6 +1365,22 @@ static void handle_cmd_completion(struct
+               xhci->error_bitmask |= 1 << 5;
+               return;
+       }
++
++      if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) ||
++              (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) {
++              /* If the return value is 0, we think the trb pointed by
++               * command ring dequeue pointer is a good trb. The good
++               * trb means we don't want to cancel the trb, but it have
++               * been stopped by host. So we should handle it normally.
++               * Otherwise, driver should invoke inc_deq() and return.
++               */
++              if (handle_stopped_cmd_ring(xhci,
++                              GET_COMP_CODE(le32_to_cpu(event->status)))) {
++                      inc_deq(xhci, xhci->cmd_ring);
++                      return;
++              }
++      }
++
+       switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
+               & TRB_TYPE_BITMASK) {
+       case TRB_TYPE(TRB_ENABLE_SLOT):
diff --git a/queue-3.6/xhci-intel-panther-point-bei-quirk.patch b/queue-3.6/xhci-intel-panther-point-bei-quirk.patch
new file mode 100644 (file)
index 0000000..4b07dc1
--- /dev/null
@@ -0,0 +1,82 @@
+From 80fab3b244a22e0ca539d2439bdda50e81e5666f Mon Sep 17 00:00:00 2001
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Wed, 19 Sep 2012 16:27:26 -0700
+Subject: xhci: Intel Panther Point BEI quirk.
+
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+
+commit 80fab3b244a22e0ca539d2439bdda50e81e5666f upstream.
+
+When a device with an isochronous endpoint is behind a hub plugged into
+the Intel Panther Point xHCI host controller, and the driver submits
+multiple frames per URB, the xHCI driver will set the Block Event
+Interrupt (BEI) flag on all but the last TD for the URB.  This causes
+the host controller to place an event on the event ring, but not send an
+interrupt.  When the last TD for the URB completes, BEI is cleared, and
+we get an interrupt for the whole URB.
+
+However, under a Panther Point xHCI host controller, if the parent hub
+is unplugged when one or more events from transfers with BEI set are on
+the event ring, a port status change event is placed on the event ring,
+but no interrupt is generated.  This means URBs stop completing, and the
+USB device disconnect is not noticed.  Something like a USB headset will
+cause mplayer to hang when the device is disconnected.
+
+If another transfer is sent (such as running `sudo lsusb -v`), the next
+transfer event seems to "unstick" the event ring, the xHCI driver gets
+an interrupt, and the disconnect is reported to the USB core.
+
+The fix is not to use the BEI flag under the Panther Point xHCI host.
+This will impact power consumption and system responsiveness, because
+the xHCI driver will receive an interrupt for every frame in all
+isochronous URBs instead of once per URB.
+
+Intel chipset developers confirm that this bug will be hit if the BEI
+flag is used on any endpoint, not just ones that are behind a hub.
+
+This patch should be backported to kernels as old as 3.0, that contain
+the commit 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support
+EHCI/xHCI port switching."
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/host/xhci-pci.c  |    1 +
+ drivers/usb/host/xhci-ring.c |    4 +++-
+ drivers/usb/host/xhci.h      |    1 +
+ 3 files changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -103,6 +103,7 @@ static void xhci_pci_quirks(struct devic
+                * PPT chipsets.
+                */
+               xhci->quirks |= XHCI_SPURIOUS_REBOOT;
++              xhci->quirks |= XHCI_AVOID_BEI;
+       }
+       if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
+                       pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -3400,7 +3400,9 @@ static int xhci_queue_isoc_tx(struct xhc
+                       } else {
+                               td->last_trb = ep_ring->enqueue;
+                               field |= TRB_IOC;
+-                              if (xhci->hci_version == 0x100) {
++                              if (xhci->hci_version == 0x100 &&
++                                              !(xhci->quirks &
++                                                      XHCI_AVOID_BEI)) {
+                                       /* Set BEI bit except for the last td */
+                                       if (i < num_tds - 1)
+                                               field |= TRB_BEI;
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1496,6 +1496,7 @@ struct xhci_hcd {
+ #define XHCI_INTEL_HOST               (1 << 12)
+ #define XHCI_SPURIOUS_REBOOT  (1 << 13)
+ #define XHCI_COMP_MODE_QUIRK  (1 << 14)
++#define XHCI_AVOID_BEI                (1 << 15)
+       unsigned int            num_active_eps;
+       unsigned int            limit_active_eps;
+       /* There are two roothubs to keep track of bus suspend info for */