From: Greg Kroah-Hartman Date: Wed, 3 Oct 2012 23:50:25 +0000 (-0700) Subject: 3.6-stable patches X-Git-Tag: v3.0.45~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=095d214c4e7ca6a5806208103a2c0759304f1c7a;p=thirdparty%2Fkernel%2Fstable-queue.git 3.6-stable patches 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 --- 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 index 00000000000..8256eb3a1f7 --- /dev/null +++ b/queue-3.6/ath9k-disable-aspm-only-for-ar9285.patch @@ -0,0 +1,38 @@ +From 046b6802c8d3c8a57448485513bf7291633e0fa3 Mon Sep 17 00:00:00 2001 +From: Sujith Manoharan +Date: Sat, 22 Sep 2012 00:14:28 +0530 +Subject: ath9k: Disable ASPM only for AR9285 + +From: Sujith Manoharan + +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 +Tested-by: Paul Stewart +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..8a789f2d811 --- /dev/null +++ b/queue-3.6/b43legacy-fix-crash-on-unload-when-firmware-not-available.patch @@ -0,0 +1,75 @@ +From 2d838bb608e2d1f6cb4280e76748cb812dc822e7 Mon Sep 17 00:00:00 2001 +From: Larry Finger +Date: Wed, 26 Sep 2012 12:32:02 -0500 +Subject: b43legacy: Fix crash on unload when firmware not available + +From: Larry Finger + +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: [] 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:[] 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] [] ? skb_dequeue+0x49/0x60 +[ 214.333957] [] destroy_workqueue+0xd/0x150 +[ 214.333957] [] ieee80211_unregister_hw+0xc4/0x100 [mac80211] +[ 214.333957] [] b43legacy_remove+0x78/0x80 [b43legacy] +[ 214.333957] [] ssb_device_remove+0x1d/0x30 [ssb] +[ 214.333957] [] __device_release_driver+0x5a/0xb0 +[ 214.333957] [] driver_detach+0x87/0x90 +[ 214.333957] [] bus_remove_driver+0x6c/0xe0 +[ 214.333957] [] driver_unregister+0x40/0x70 +[ 214.333957] [] ssb_driver_unregister+0xb/0x10 [ssb] +[ 214.333957] [] b43legacy_exit+0xd/0xf [b43legacy] +[ 214.333957] [] sys_delete_module+0x14e/0x2b0 +[ 214.333957] [] ? vfs_write+0xf7/0x150 +[ 214.333957] [] ? tty_write_lock+0x50/0x50 +[ 214.333957] [] ? sys_write+0x38/0x70 +[ 214.333957] [] 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: [] 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 +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..998364d190e --- /dev/null +++ b/queue-3.6/coredump-prevent-double-free-on-an-error-path-in-core.patch @@ -0,0 +1,66 @@ +From f34f9d186df35e5c39163444c43b4fc6255e39c5 Mon Sep 17 00:00:00 2001 +From: Denys Vlasenko +Date: Wed, 26 Sep 2012 11:34:50 +1000 +Subject: coredump: prevent double-free on an error path in core + dumper + +From: Denys Vlasenko + +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 +Signed-off-by: Denys Vlasenko +Cc: Venu Byravarasu +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..f010f267601 --- /dev/null +++ b/queue-3.6/firmware-add-missing-attributes-to-efi-variable-attribute-print-out-from-sysfs.patch @@ -0,0 +1,52 @@ +From 7083909023bbe29b3176e92d2d089def1aa7aa1e Mon Sep 17 00:00:00 2001 +From: Khalid Aziz +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 + +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 +Reviewed-by: Kees Cook +Acked-by: Matthew Garrett +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..31cbd73381c --- /dev/null +++ b/queue-3.6/hid-keep-dev_rdesc-unmodified-and-use-it-for-comparisons.patch @@ -0,0 +1,93 @@ +From 86e6b77eb7cf9ca2e9c7092b4dfd588f0a3307b6 Mon Sep 17 00:00:00 2001 +From: Kevin Daughtridge +Date: Thu, 20 Sep 2012 12:00:32 -0700 +Subject: HID: keep dev_rdesc unmodified and use it for comparisons + +From: Kevin Daughtridge + +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 +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..29749b6d02d --- /dev/null +++ b/queue-3.6/increase-xhci-suspend-timeout-to-16ms.patch @@ -0,0 +1,38 @@ +From a6e097dfdfd189b6929af6efa1d289af61858386 Mon Sep 17 00:00:00 2001 +From: Michael Spang +Date: Fri, 14 Sep 2012 13:05:49 -0400 +Subject: Increase XHCI suspend timeout to 16ms + +From: Michael Spang + +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 +Signed-off-by: Sarah Sharp +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..a5aa122aecc --- /dev/null +++ b/queue-3.6/n_gsm-added-interlocking-for-gsm_data_lock-for-certain-code-paths.patch @@ -0,0 +1,64 @@ +From 5e44708f75b0f8712da715d6babb0c21089b2317 Mon Sep 17 00:00:00 2001 +From: Russ Gorby +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 + +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 +Tested-by: Yin, Fengwei +Signed-off-by: Alan Cox +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..4ba0f5c1786 --- /dev/null +++ b/queue-3.6/n_gsm-memory-leak-in-uplink-error-path.patch @@ -0,0 +1,50 @@ +From 88ed2a60610974443335c924d7cb8e5dcf9dbdc1 Mon Sep 17 00:00:00 2001 +From: Russ Gorby +Date: Mon, 13 Aug 2012 13:45:30 +0100 +Subject: n_gsm: memory leak in uplink error path + +From: Russ Gorby + +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 +Tested-by: Kappel, LaurentX +Signed-off-by: Alan Cox +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..e22e2d2f18a --- /dev/null +++ b/queue-3.6/n_gsm-uplink-skbs-accumulate-on-list.patch @@ -0,0 +1,50 @@ +From 192b6041e75bb4a2aae73834037038cea139a92d Mon Sep 17 00:00:00 2001 +From: Russ Gorby +Date: Mon, 13 Aug 2012 13:43:36 +0100 +Subject: n_gsm: uplink SKBs accumulate on list + +From: Russ Gorby + +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 +Tested-by: Kappel, LaurentX +Signed-off-by: Alan Cox +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..8ddbc2efca1 --- /dev/null +++ b/queue-3.6/n_gsm.c-implement-3gpp27.010-dlc-start-up-procedure-in-mux.patch @@ -0,0 +1,41 @@ +From 7e8ac7b23b67416700dfb8b4136a4e81ce675b48 Mon Sep 17 00:00:00 2001 +From: xiaojin +Date: Mon, 13 Aug 2012 13:43:15 +0100 +Subject: n_gsm.c: Implement 3GPP27.010 DLC start-up procedure in MUX + +From: xiaojin + +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 +Tested-by: Yin, Fengwei +[tweaked the order we check things and error code] +Signed-off-by: Alan Cox +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-3.6/series b/queue-3.6/series index adf0937520a..628f5f2a641 100644 --- a/queue-3.6/series +++ b/queue-3.6/series @@ -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 index 00000000000..0f274120b69 --- /dev/null +++ b/queue-3.6/tools-hv-check-for-read-write-errors.patch @@ -0,0 +1,76 @@ +From 436473bc2173499ae274d0f50111d1e355006caf Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Wed, 5 Sep 2012 14:37:37 -0700 +Subject: tools/hv: Check for read/write errors + +From: Ben Hutchings + +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 +Signed-off-by: K. Y. Srinivasan +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..7c6cb8cfce6 --- /dev/null +++ b/queue-3.6/tools-hv-fix-exit-error-code.patch @@ -0,0 +1,121 @@ +From 6bb22fea25624ab593eee376fa5fb82d1b13f45a Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Wed, 5 Sep 2012 14:37:36 -0700 +Subject: tools/hv: Fix exit() error code + +From: Ben Hutchings + +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 +Signed-off-by: K. Y. Srinivasan +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..ca31d6be01c --- /dev/null +++ b/queue-3.6/tools-hv-fix-file-handle-leak.patch @@ -0,0 +1,38 @@ +From d5ab482799e7c4c4b7c0aa67e8710dce28115d03 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Wed, 5 Sep 2012 14:37:35 -0700 +Subject: tools/hv: Fix file handle leak + +From: Ben Hutchings + +commit d5ab482799e7c4c4b7c0aa67e8710dce28115d03 upstream. + +Match up each fopen() with an fclose(). + +Signed-off-by: Ben Hutchings +Signed-off-by: K. Y. Srinivasan +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..97a43277995 --- /dev/null +++ b/queue-3.6/xen-pciback-restore-the-pci-config-space-after-an-flr.patch @@ -0,0 +1,54 @@ +From c341ca45ce56143804ef5a8f4db753e554e640b4 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Tue, 25 Sep 2012 16:48:24 -0400 +Subject: xen/pciback: Restore the PCI config space after an FLR. + +From: Konrad Rzeszutek Wilk + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..ba77c5ae5dd --- /dev/null +++ b/queue-3.6/xhci-add-aborting-command-ring-function.patch @@ -0,0 +1,241 @@ +From b92cc66c047ff7cf587b318fe377061a353c120f Mon Sep 17 00:00:00 2001 +From: Elric Fu +Date: Wed, 27 Jun 2012 16:31:12 +0800 +Subject: xHCI: add aborting command ring function + +From: Elric Fu + +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 +Signed-off-by: Sarah Sharp +Tested-by: Miroslav Sabljic +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..7d43d86b795 --- /dev/null +++ b/queue-3.6/xhci-add-cmd_ring_state.patch @@ -0,0 +1,80 @@ +From c181bc5b5d5c79b71203cd10cef97f802fb6f9c1 Mon Sep 17 00:00:00 2001 +From: Elric Fu +Date: Wed, 27 Jun 2012 16:30:57 +0800 +Subject: xHCI: add cmd_ring_state + +From: Elric Fu + +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 +Signed-off-by: Sarah Sharp +Tested-by: Miroslav Sabljic +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..23ea183ac97 --- /dev/null +++ b/queue-3.6/xhci-cancel-command-after-command-timeout.patch @@ -0,0 +1,142 @@ +From 6e4468b9a0793dfb53eb80d9fe52c739b13b27fd Mon Sep 17 00:00:00 2001 +From: Elric Fu +Date: Wed, 27 Jun 2012 16:31:52 +0800 +Subject: xHCI: cancel command after command timeout + +From: Elric Fu + +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 +Signed-off-by: Sarah Sharp +Tested-by: Miroslav Sabljic +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..6b4eace2cf4 --- /dev/null +++ b/queue-3.6/xhci-handle-command-after-aborting-the-command-ring.patch @@ -0,0 +1,238 @@ +From b63f4053cc8aa22a98e3f9a97845afe6c15d0a0d Mon Sep 17 00:00:00 2001 +From: Elric Fu +Date: Wed, 27 Jun 2012 16:55:43 +0800 +Subject: xHCI: handle command after aborting the command ring + +From: Elric Fu + +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 +Signed-off-by: Sarah Sharp +Tested-by: Miroslav Sabljic +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..4b07dc1c9f3 --- /dev/null +++ b/queue-3.6/xhci-intel-panther-point-bei-quirk.patch @@ -0,0 +1,82 @@ +From 80fab3b244a22e0ca539d2439bdda50e81e5666f Mon Sep 17 00:00:00 2001 +From: Sarah Sharp +Date: Wed, 19 Sep 2012 16:27:26 -0700 +Subject: xhci: Intel Panther Point BEI quirk. + +From: Sarah Sharp + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 */