From: Greg Kroah-Hartman Date: Wed, 11 Jul 2012 20:58:07 +0000 (-0700) Subject: 3.4-stable patches X-Git-Tag: v3.0.37~17 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8e3c0ccf1e8aad7c7b41d1a7e6356a223a464a1f;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches added patches: acpi-pm-leave-bus-master-arbitration-enabled-for-suspend-resume.patch pci-ehci-fix-crash-during-suspend-on-asus-computers.patch scsi-fix-null-dereferences-in-scsi_cmd_to_driver.patch scsi-libsas-fix-taskfile-corruption-in-sas_ata_qc_fill_rtf.patch usb-add-support-for-root-hub-port-status-cas.patch usb-cdc-wdm-fix-lockup-on-error-in-wdm_read.patch usb-metro-usb-fix-tty_flip_buffer_push-use.patch usb-option-add-mediatek-product-ids.patch usb-option-add-zte-mf60.patch xhci-fix-hang-on-back-to-back-set-tr-deq-ptr-commands.patch --- diff --git a/queue-3.4/acpi-pm-leave-bus-master-arbitration-enabled-for-suspend-resume.patch b/queue-3.4/acpi-pm-leave-bus-master-arbitration-enabled-for-suspend-resume.patch new file mode 100644 index 00000000000..d93974b4657 --- /dev/null +++ b/queue-3.4/acpi-pm-leave-bus-master-arbitration-enabled-for-suspend-resume.patch @@ -0,0 +1,82 @@ +From dc332fdf9f373a87b1e2f423b5b004b2a3c37e1a Mon Sep 17 00:00:00 2001 +From: Jonathan Nieder +Date: Sun, 8 Jul 2012 21:55:14 +0200 +Subject: ACPI / PM: Leave Bus Master Arbitration enabled for suspend/resume + +From: Jonathan Nieder + +commit dc332fdf9f373a87b1e2f423b5b004b2a3c37e1a upstream. + +This is an old suspend/resume lockup fix: + + commit 2780cc4660e1 + Author: Len Brown + Date: Thu Dec 23 13:43:30 2004 -0500 + + [ACPI] Fix suspend/resume lockup issue + by leaving Bus Master Arbitration enabled. + The ACPI spec mandates it be disabled only for C3. + + http://bugzilla.kernel.org/show_bug.cgi?id=3599 + + Signed-off-by: David Shaohua Li + Signed-off-by: Len Brown + +The bug snuck back in in commit 2feec47d4c5f (ACPICA: ACPI 5: Support +for new FADT SleepStatus, SleepControl registers, 2012-02-14), +presumably by copy/pasting a copy of the code without that fix for the +legacy case. + +On affected machines, after that commit, the machine locks up hard on +resume from suspend. The same fix as seven years ago still works. + +Addresses . + +Reported-bisected-and-tested-by: Octavio Alvarez +Reported-by: Adrian Knoth +Signed-off-by: Jonathan Nieder +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/acpica/hwsleep.c | 22 ---------------------- + 1 file changed, 22 deletions(-) + +--- a/drivers/acpi/acpica/hwsleep.c ++++ b/drivers/acpi/acpica/hwsleep.c +@@ -95,18 +95,6 @@ acpi_status acpi_hw_legacy_sleep(u8 slee + return_ACPI_STATUS(status); + } + +- if (sleep_state != ACPI_STATE_S5) { +- /* +- * Disable BM arbitration. This feature is contained within an +- * optional register (PM2 Control), so ignore a BAD_ADDRESS +- * exception. +- */ +- status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); +- if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) { +- return_ACPI_STATUS(status); +- } +- } +- + /* + * 1) Disable/Clear all GPEs + * 2) Enable all wakeup GPEs +@@ -364,16 +352,6 @@ acpi_status acpi_hw_legacy_wake(u8 sleep + [ACPI_EVENT_POWER_BUTTON]. + status_register_id, ACPI_CLEAR_STATUS); + +- /* +- * Enable BM arbitration. This feature is contained within an +- * optional register (PM2 Control), so ignore a BAD_ADDRESS +- * exception. +- */ +- status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0); +- if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) { +- return_ACPI_STATUS(status); +- } +- + acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING); + return_ACPI_STATUS(status); + } diff --git a/queue-3.4/pci-ehci-fix-crash-during-suspend-on-asus-computers.patch b/queue-3.4/pci-ehci-fix-crash-during-suspend-on-asus-computers.patch new file mode 100644 index 00000000000..28937b0bce3 --- /dev/null +++ b/queue-3.4/pci-ehci-fix-crash-during-suspend-on-asus-computers.patch @@ -0,0 +1,156 @@ +From dbf0e4c7257f8d684ec1a3c919853464293de66e Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Mon, 9 Jul 2012 11:09:21 -0400 +Subject: PCI: EHCI: fix crash during suspend on ASUS computers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alan Stern + +commit dbf0e4c7257f8d684ec1a3c919853464293de66e upstream. + +Quite a few ASUS computers experience a nasty problem, related to the +EHCI controllers, when going into system suspend. It was observed +that the problem didn't occur if the controllers were not put into the +D3 power state before starting the suspend, and commit +151b61284776be2d6f02d48c23c3625678960b97 (USB: EHCI: fix crash during +suspend on ASUS computers) was created to do this. + +It turned out this approach messed up other computers that didn't have +the problem -- it prevented USB wakeup from working. Consequently +commit c2fb8a3fa25513de8fedb38509b1f15a5bbee47b (USB: add +NO_D3_DURING_SLEEP flag and revert 151b61284776be2) was merged; it +reverted the earlier commit and added a whitelist of known good board +names. + +Now we know the actual cause of the problem. Thanks to AceLan Kao for +tracking it down. + +According to him, an engineer at ASUS explained that some of their +BIOSes contain a bug that was added in an attempt to work around a +problem in early versions of Windows. When the computer goes into S3 +suspend, the BIOS tries to verify that the EHCI controllers were first +quiesced by the OS. Nothing's wrong with this, but the BIOS does it +by checking that the PCI COMMAND registers contain 0 without checking +the controllers' power state. If the register isn't 0, the BIOS +assumes the controller needs to be quiesced and tries to do so. This +involves making various MMIO accesses to the controller, which don't +work very well if the controller is already in D3. The end result is +a system hang or memory corruption. + +Since the value in the PCI COMMAND register doesn't matter once the +controller has been suspended, and since the value will be restored +anyway when the controller is resumed, we can work around the BIOS bug +simply by setting the register to 0 during system suspend. This patch +(as1590) does so and also reverts the second commit mentioned above, +which is now unnecessary. + +In theory we could do this for every PCI device. However to avoid +introducing new problems, the patch restricts itself to EHCI host +controllers. + +Finally the affected systems can suspend with USB wakeup working +properly. + +Reference: https://bugzilla.kernel.org/show_bug.cgi?id=37632 +Reference: https://bugzilla.kernel.org/show_bug.cgi?id=42728 +Based-on-patch-by: AceLan Kao +Signed-off-by: Alan Stern +Tested-by: Dâniel Fraga +Tested-by: Javier Marcet +Tested-by: Andrey Rahmatullin +Tested-by: Oleksij Rempel +Tested-by: Pavel Pisa +Acked-by: Bjorn Helgaas +Acked-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/pci-driver.c | 12 ++++++++++++ + drivers/pci/pci.c | 5 ----- + drivers/pci/quirks.c | 26 -------------------------- + include/linux/pci.h | 2 -- + 4 files changed, 12 insertions(+), 33 deletions(-) + +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -742,6 +742,18 @@ static int pci_pm_suspend_noirq(struct d + + pci_pm_set_unknown_state(pci_dev); + ++ /* ++ * Some BIOSes from ASUS have a bug: If a USB EHCI host controller's ++ * PCI COMMAND register isn't 0, the BIOS assumes that the controller ++ * hasn't been quiesced and tries to turn it off. If the controller ++ * is already in D3, this can hang or cause memory corruption. ++ * ++ * Since the value of the COMMAND register doesn't matter once the ++ * device has been suspended, we can safely set it to 0 here. ++ */ ++ if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI) ++ pci_write_config_word(pci_dev, PCI_COMMAND, 0); ++ + return 0; + } + +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -1743,11 +1743,6 @@ int pci_prepare_to_sleep(struct pci_dev + if (target_state == PCI_POWER_ERROR) + return -EIO; + +- /* Some devices mustn't be in D3 during system sleep */ +- if (target_state == PCI_D3hot && +- (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP)) +- return 0; +- + pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev)); + + error = pci_set_power_state(dev, target_state); +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -2917,32 +2917,6 @@ static void __devinit disable_igfx_irq(s + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); + +-/* +- * The Intel 6 Series/C200 Series chipset's EHCI controllers on many +- * ASUS motherboards will cause memory corruption or a system crash +- * if they are in D3 while the system is put into S3 sleep. +- */ +-static void __devinit asus_ehci_no_d3(struct pci_dev *dev) +-{ +- const char *sys_info; +- static const char good_Asus_board[] = "P8Z68-V"; +- +- if (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP) +- return; +- if (dev->subsystem_vendor != PCI_VENDOR_ID_ASUSTEK) +- return; +- sys_info = dmi_get_system_info(DMI_BOARD_NAME); +- if (sys_info && memcmp(sys_info, good_Asus_board, +- sizeof(good_Asus_board) - 1) == 0) +- return; +- +- dev_info(&dev->dev, "broken D3 during system sleep on ASUS\n"); +- dev->dev_flags |= PCI_DEV_FLAGS_NO_D3_DURING_SLEEP; +- device_set_wakeup_capable(&dev->dev, false); +-} +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3); +- + static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, + struct pci_fixup *end) + { +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -176,8 +176,6 @@ enum pci_dev_flags { + PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2, + /* Provide indication device is assigned by a Virtual Machine Manager */ + PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4, +- /* Device causes system crash if in D3 during S3 sleep */ +- PCI_DEV_FLAGS_NO_D3_DURING_SLEEP = (__force pci_dev_flags_t) 8, + }; + + enum pci_irq_reroute_variant { diff --git a/queue-3.4/scsi-fix-null-dereferences-in-scsi_cmd_to_driver.patch b/queue-3.4/scsi-fix-null-dereferences-in-scsi_cmd_to_driver.patch new file mode 100644 index 00000000000..801e413fa20 --- /dev/null +++ b/queue-3.4/scsi-fix-null-dereferences-in-scsi_cmd_to_driver.patch @@ -0,0 +1,72 @@ +From 222a806af830fda34ad1f6bc991cd226916de060 Mon Sep 17 00:00:00 2001 +From: Mark Rustad +Date: Thu, 21 Jun 2012 12:23:42 -0700 +Subject: SCSI: Fix NULL dereferences in scsi_cmd_to_driver + +From: Mark Rustad + +commit 222a806af830fda34ad1f6bc991cd226916de060 upstream. + +Avoid crashing if the private_data pointer happens to be NULL. This has +been seen sometimes when a host reset happens, notably when there are +many LUNs: + +host3: Assigned Port ID 0c1601 +scsi host3: libfc: Host reset succeeded on port (0c1601) +BUG: unable to handle kernel NULL pointer dereference at 0000000000000350 +IP: [] scsi_send_eh_cmnd+0x58/0x3a0 + +Process scsi_eh_3 (pid: 4144, threadinfo ffff88030920c000, task ffff880326b160c0) +Stack: + 000000010372e6ba 0000000000000282 000027100920dca0 ffffffffa0038ee0 + 0000000000000000 0000000000030003 ffff88030920dc80 ffff88030920dc80 + 00000002000e0000 0000000a00004000 ffff8803242f7760 ffff88031326ed80 +Call Trace: + [] ? lock_timer_base+0x70/0x70 + [] scsi_eh_tur+0x3e/0xc0 + [] scsi_eh_test_devices+0x76/0x170 + [] scsi_eh_host_reset+0x85/0x160 + [] scsi_eh_ready_devs+0x91/0x110 + [] scsi_unjam_host+0xed/0x1f0 + [] scsi_error_handler+0x1a8/0x200 + [] ? scsi_unjam_host+0x1f0/0x1f0 + [] kthread+0x9e/0xb0 + [] kernel_thread_helper+0x4/0x10 + [] ? kthread_freezable_should_stop+0x70/0x70 + [] ? gs_change+0x13/0x13 +Code: 25 28 00 00 00 48 89 45 c8 31 c0 48 8b 87 80 00 00 00 48 8d b5 60 ff ff ff 89 d1 48 89 fb 41 89 d6 4c 89 fa 48 8b 80 b8 00 00 00 + <48> 8b 80 50 03 00 00 48 8b 00 48 89 85 38 ff ff ff 48 8b 07 4c +RIP [] scsi_send_eh_cmnd+0x58/0x3a0 + RSP +CR2: 0000000000000350 + + +Signed-off-by: Mark Rustad +Tested-by: Marcus Dennis +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + include/scsi/scsi_cmnd.h | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/include/scsi/scsi_cmnd.h ++++ b/include/scsi/scsi_cmnd.h +@@ -134,10 +134,16 @@ struct scsi_cmnd { + + static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) + { ++ struct scsi_driver **sdp; ++ + if (!cmd->request->rq_disk) + return NULL; + +- return *(struct scsi_driver **)cmd->request->rq_disk->private_data; ++ sdp = (struct scsi_driver **)cmd->request->rq_disk->private_data; ++ if (!sdp) ++ return NULL; ++ ++ return *sdp; + } + + extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); diff --git a/queue-3.4/scsi-libsas-fix-taskfile-corruption-in-sas_ata_qc_fill_rtf.patch b/queue-3.4/scsi-libsas-fix-taskfile-corruption-in-sas_ata_qc_fill_rtf.patch new file mode 100644 index 00000000000..b983fd455a2 --- /dev/null +++ b/queue-3.4/scsi-libsas-fix-taskfile-corruption-in-sas_ata_qc_fill_rtf.patch @@ -0,0 +1,108 @@ +From 6ef1b512f4e6f936d89aa20be3d97a7ec7c290ac Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Fri, 22 Jun 2012 10:52:34 -0700 +Subject: SCSI: libsas: fix taskfile corruption in sas_ata_qc_fill_rtf + +From: Dan Williams + +commit 6ef1b512f4e6f936d89aa20be3d97a7ec7c290ac upstream. + +fill_result_tf() grabs the taskfile flags from the originating qc which +sas_ata_qc_fill_rtf() promptly overwrites. The presence of an +ata_taskfile in the sata_device makes it tempting to just copy the full +contents in sas_ata_qc_fill_rtf(). However, libata really only wants +the fis contents and expects the other portions of the taskfile to not +be touched by ->qc_fill_rtf. To that end store a fis buffer in the +sata_device and use ata_tf_from_fis() like every other ->qc_fill_rtf() +implementation. + +Reported-by: Praveen Murali +Tested-by: Praveen Murali +Signed-off-by: Dan Williams +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/aic94xx/aic94xx_task.c | 2 +- + drivers/scsi/libsas/sas_ata.c | 12 ++++++------ + include/scsi/libsas.h | 6 ++++-- + 3 files changed, 11 insertions(+), 9 deletions(-) + +--- a/drivers/scsi/aic94xx/aic94xx_task.c ++++ b/drivers/scsi/aic94xx/aic94xx_task.c +@@ -201,7 +201,7 @@ static void asd_get_response_tasklet(str + + if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { + resp->frame_len = le16_to_cpu(*(__le16 *)(r+6)); +- memcpy(&resp->ending_fis[0], r+16, 24); ++ memcpy(&resp->ending_fis[0], r+16, ATA_RESP_FIS_SIZE); + ts->buf_valid_size = sizeof(*resp); + } + } +--- a/drivers/scsi/libsas/sas_ata.c ++++ b/drivers/scsi/libsas/sas_ata.c +@@ -139,12 +139,12 @@ static void sas_ata_task_done(struct sas + if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || + ((stat->stat == SAM_STAT_CHECK_CONDITION && + dev->sata_dev.command_set == ATAPI_COMMAND_SET))) { +- ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf); ++ memcpy(dev->sata_dev.fis, resp->ending_fis, ATA_RESP_FIS_SIZE); + + if (!link->sactive) { +- qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command); ++ qc->err_mask |= ac_err_mask(dev->sata_dev.fis[2]); + } else { +- link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.tf.command); ++ link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]); + if (unlikely(link->eh_info.err_mask)) + qc->flags |= ATA_QCFLAG_FAILED; + } +@@ -161,8 +161,8 @@ static void sas_ata_task_done(struct sas + qc->flags |= ATA_QCFLAG_FAILED; + } + +- dev->sata_dev.tf.feature = 0x04; /* status err */ +- dev->sata_dev.tf.command = ATA_ERR; ++ dev->sata_dev.fis[3] = 0x04; /* status err */ ++ dev->sata_dev.fis[2] = ATA_ERR; + } + } + +@@ -269,7 +269,7 @@ static bool sas_ata_qc_fill_rtf(struct a + { + struct domain_device *dev = qc->ap->private_data; + +- memcpy(&qc->result_tf, &dev->sata_dev.tf, sizeof(qc->result_tf)); ++ ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf); + return true; + } + +--- a/include/scsi/libsas.h ++++ b/include/scsi/libsas.h +@@ -163,6 +163,8 @@ enum ata_command_set { + ATAPI_COMMAND_SET = 1, + }; + ++#define ATA_RESP_FIS_SIZE 24 ++ + struct sata_device { + enum ata_command_set command_set; + struct smp_resp rps_resp; /* report_phy_sata_resp */ +@@ -171,7 +173,7 @@ struct sata_device { + + struct ata_port *ap; + struct ata_host ata_host; +- struct ata_taskfile tf; ++ u8 fis[ATA_RESP_FIS_SIZE]; + }; + + enum { +@@ -537,7 +539,7 @@ enum exec_status { + */ + struct ata_task_resp { + u16 frame_len; +- u8 ending_fis[24]; /* dev to host or data-in */ ++ u8 ending_fis[ATA_RESP_FIS_SIZE]; /* dev to host or data-in */ + }; + + #define SAS_STATUS_BUF_SIZE 96 diff --git a/queue-3.4/series b/queue-3.4/series index 487289fa53d..ab6203ba97f 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -143,3 +143,13 @@ omapdss-use-dsi_fifo_bug-workaround-only-for-manual-update-displays.patch e1000e-test-for-valid-check_reset_block-function-pointer.patch hid-hid-multitouch-fix-wrong-protocol-detection.patch acpi-pm-make-acpi_pm_device_sleep_state-follow-the-specification.patch +scsi-fix-null-dereferences-in-scsi_cmd_to_driver.patch +scsi-libsas-fix-taskfile-corruption-in-sas_ata_qc_fill_rtf.patch +acpi-pm-leave-bus-master-arbitration-enabled-for-suspend-resume.patch +usb-metro-usb-fix-tty_flip_buffer_push-use.patch +usb-cdc-wdm-fix-lockup-on-error-in-wdm_read.patch +usb-option-add-zte-mf60.patch +usb-option-add-mediatek-product-ids.patch +usb-add-support-for-root-hub-port-status-cas.patch +xhci-fix-hang-on-back-to-back-set-tr-deq-ptr-commands.patch +pci-ehci-fix-crash-during-suspend-on-asus-computers.patch diff --git a/queue-3.4/usb-add-support-for-root-hub-port-status-cas.patch b/queue-3.4/usb-add-support-for-root-hub-port-status-cas.patch new file mode 100644 index 00000000000..f1c318eccc4 --- /dev/null +++ b/queue-3.4/usb-add-support-for-root-hub-port-status-cas.patch @@ -0,0 +1,164 @@ +From 8bea2bd37df08aaa599aa361a9f8b836ba98e554 Mon Sep 17 00:00:00 2001 +From: Stanislaw Ledwon +Date: Mon, 18 Jun 2012 15:20:00 +0200 +Subject: usb: Add support for root hub port status CAS + +From: Stanislaw Ledwon + +commit 8bea2bd37df08aaa599aa361a9f8b836ba98e554 upstream. + +The host controller port status register supports CAS (Cold Attach +Status) bit. This bit could be set when USB3.0 device is connected +when system is in Sx state. When the system wakes to S0 this port +status with CAS bit is reported and this port can't be used by any +device. + +When CAS bit is set the port should be reset by warm reset. This +was not supported by xhci driver. + +The issue was found when pendrive was connected to suspended +platform. The link state of "Compliance Mode" was reported together +with CAS bit. This link state was also not supported by xhci and +core/hub.c. + +The CAS bit is defined only for xhci root hub port and it is +not supported on regular hubs. The link status is used to force +warm reset on port. Make the USB core issue a warm reset when port +is in ether the 'inactive' or 'compliance mode'. Change the xHCI driver +to report 'compliance mode' when the CAS is set. This force warm reset +on the root hub port. + +This patch should be backported to stable kernels as old as 3.2, that +contain the commit 10d674a82e553cb8a1f41027bb3c3e309b3f6804 "USB: When +hot reset for USB3 fails, try warm reset." + +Signed-off-by: Stanislaw Ledwon +Signed-off-by: Sarah Sharp +Acked-by: Andiry Xu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/hub.c | 18 ++++++++++-------- + drivers/usb/host/xhci-hub.c | 44 ++++++++++++++++++++++++++++++++++++++------ + drivers/usb/host/xhci.h | 6 +++++- + 3 files changed, 53 insertions(+), 15 deletions(-) + +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -2102,12 +2102,16 @@ static unsigned hub_is_wusb(struct usb_h + static int hub_port_reset(struct usb_hub *hub, int port1, + struct usb_device *udev, unsigned int delay, bool warm); + +-/* Is a USB 3.0 port in the Inactive state? */ +-static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus) ++/* Is a USB 3.0 port in the Inactive or Complinance Mode state? ++ * Port worm reset is required to recover ++ */ ++static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus) + { + return hub_is_superspeed(hub->hdev) && +- (portstatus & USB_PORT_STAT_LINK_STATE) == +- USB_SS_PORT_LS_SS_INACTIVE; ++ (((portstatus & USB_PORT_STAT_LINK_STATE) == ++ USB_SS_PORT_LS_SS_INACTIVE) || ++ ((portstatus & USB_PORT_STAT_LINK_STATE) == ++ USB_SS_PORT_LS_COMP_MOD)) ; + } + + static int hub_port_wait_reset(struct usb_hub *hub, int port1, +@@ -2143,7 +2147,7 @@ static int hub_port_wait_reset(struct us + * + * See https://bugzilla.kernel.org/show_bug.cgi?id=41752 + */ +- if (hub_port_inactive(hub, portstatus)) { ++ if (hub_port_warm_reset_required(hub, portstatus)) { + int ret; + + if ((portchange & USB_PORT_STAT_C_CONNECTION)) +@@ -3757,9 +3761,7 @@ static void hub_events(void) + /* Warm reset a USB3 protocol port if it's in + * SS.Inactive state. + */ +- if (hub_is_superspeed(hub->hdev) && +- (portstatus & USB_PORT_STAT_LINK_STATE) +- == USB_SS_PORT_LS_SS_INACTIVE) { ++ if (hub_port_warm_reset_required(hub, portstatus)) { + dev_dbg(hub_dev, "warm reset port %d\n", i); + hub_port_reset(hub, i, NULL, + HUB_BH_RESET_TIME, true); +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -462,6 +462,42 @@ void xhci_test_and_clear_bit(struct xhci + } + } + ++/* Updates Link Status for super Speed port */ ++static void xhci_hub_report_link_state(u32 *status, u32 status_reg) ++{ ++ u32 pls = status_reg & PORT_PLS_MASK; ++ ++ /* resume state is a xHCI internal state. ++ * Do not report it to usb core. ++ */ ++ if (pls == XDEV_RESUME) ++ return; ++ ++ /* When the CAS bit is set then warm reset ++ * should be performed on port ++ */ ++ if (status_reg & PORT_CAS) { ++ /* The CAS bit can be set while the port is ++ * in any link state. ++ * Only roothubs have CAS bit, so we ++ * pretend to be in compliance mode ++ * unless we're already in compliance ++ * or the inactive state. ++ */ ++ if (pls != USB_SS_PORT_LS_COMP_MOD && ++ pls != USB_SS_PORT_LS_SS_INACTIVE) { ++ pls = USB_SS_PORT_LS_COMP_MOD; ++ } ++ /* Return also connection bit - ++ * hub state machine resets port ++ * when this bit is set. ++ */ ++ pls |= USB_PORT_STAT_CONNECTION; ++ } ++ /* update status field */ ++ *status |= pls; ++} ++ + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength) + { +@@ -605,13 +641,9 @@ int xhci_hub_control(struct usb_hcd *hcd + else + status |= USB_PORT_STAT_POWER; + } +- /* Port Link State */ ++ /* Update Port Link State for super speed ports*/ + if (hcd->speed == HCD_USB3) { +- /* resume state is a xHCI internal state. +- * Do not report it to usb core. +- */ +- if ((temp & PORT_PLS_MASK) != XDEV_RESUME) +- status |= (temp & PORT_PLS_MASK); ++ xhci_hub_report_link_state(&status, temp); + } + if (bus_state->port_c_suspend & (1 << wIndex)) + status |= 1 << USB_PORT_FEAT_C_SUSPEND; +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -341,7 +341,11 @@ struct xhci_op_regs { + #define PORT_PLC (1 << 22) + /* port configure error change - port failed to configure its link partner */ + #define PORT_CEC (1 << 23) +-/* bit 24 reserved */ ++/* Cold Attach Status - xHC can set this bit to report device attached during ++ * Sx state. Warm port reset should be perfomed to clear this bit and move port ++ * to connected state. ++ */ ++#define PORT_CAS (1 << 24) + /* wake on connect (enable) */ + #define PORT_WKCONN_E (1 << 25) + /* wake on disconnect (enable) */ diff --git a/queue-3.4/usb-cdc-wdm-fix-lockup-on-error-in-wdm_read.patch b/queue-3.4/usb-cdc-wdm-fix-lockup-on-error-in-wdm_read.patch new file mode 100644 index 00000000000..5b2d62d007a --- /dev/null +++ b/queue-3.4/usb-cdc-wdm-fix-lockup-on-error-in-wdm_read.patch @@ -0,0 +1,75 @@ +From b086b6b10d9f182cd8d2f0dcfd7fd11edba93fc9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Mon, 2 Jul 2012 10:33:14 +0200 +Subject: USB: cdc-wdm: fix lockup on error in wdm_read +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= + +commit b086b6b10d9f182cd8d2f0dcfd7fd11edba93fc9 upstream. + +Clear the WDM_READ flag on empty reads to avoid running +forever in an infinite tight loop, causing lockups: + +Jul 1 21:58:11 nemi kernel: [ 3658.898647] qmi_wwan 2-1:1.2: Unexpected error -71 +Jul 1 21:58:36 nemi kernel: [ 3684.072021] BUG: soft lockup - CPU#0 stuck for 23s! [qmi.pl:12235] +Jul 1 21:58:36 nemi kernel: [ 3684.072212] CPU 0 +Jul 1 21:58:36 nemi kernel: [ 3684.072355] +Jul 1 21:58:36 nemi kernel: [ 3684.072367] Pid: 12235, comm: qmi.pl Tainted: P O 3.5.0-rc2+ #13 LENOVO 2776LEG/2776LEG +Jul 1 21:58:36 nemi kernel: [ 3684.072383] RIP: 0010:[] [] spin_unlock_irq+0x8/0xc [cdc_wdm] +Jul 1 21:58:36 nemi kernel: [ 3684.072388] RSP: 0018:ffff88022dca1e70 EFLAGS: 00000282 +Jul 1 21:58:36 nemi kernel: [ 3684.072393] RAX: ffff88022fc3f650 RBX: ffffffff811c56f7 RCX: 00000001000ce8c1 +Jul 1 21:58:36 nemi kernel: [ 3684.072398] RDX: 0000000000000010 RSI: 000000000267d810 RDI: ffff88022fc3f650 +Jul 1 21:58:36 nemi kernel: [ 3684.072403] RBP: ffff88022dca1eb0 R08: ffffffffa063578e R09: 0000000000000000 +Jul 1 21:58:36 nemi kernel: [ 3684.072407] R10: 0000000000000008 R11: 0000000000000246 R12: 0000000000000002 +Jul 1 21:58:36 nemi kernel: [ 3684.072412] R13: 0000000000000246 R14: ffffffff00000002 R15: ffff8802281d8c88 +Jul 1 21:58:36 nemi kernel: [ 3684.072418] FS: 00007f666a260700(0000) GS:ffff88023bc00000(0000) knlGS:0000000000000000 +Jul 1 21:58:36 nemi kernel: [ 3684.072423] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +Jul 1 21:58:36 nemi kernel: [ 3684.072428] CR2: 000000000270d9d8 CR3: 000000022e865000 CR4: 00000000000007f0 +Jul 1 21:58:36 nemi kernel: [ 3684.072433] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +Jul 1 21:58:36 nemi kernel: [ 3684.072438] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 +Jul 1 21:58:36 nemi kernel: [ 3684.072444] Process qmi.pl (pid: 12235, threadinfo ffff88022dca0000, task ffff88022ff76380) +Jul 1 21:58:36 nemi kernel: [ 3684.072448] Stack: +Jul 1 21:58:36 nemi kernel: [ 3684.072458] ffffffffa063592e 0000000100020000 ffff88022fc3f650 ffff88022fc3f6a8 +Jul 1 21:58:36 nemi kernel: [ 3684.072466] 0000000000000200 0000000100000000 000000000267d810 0000000000000000 +Jul 1 21:58:36 nemi kernel: [ 3684.072475] 0000000000000000 ffff880212cfb6d0 0000000000000200 ffff880212cfb6c0 +Jul 1 21:58:36 nemi kernel: [ 3684.072479] Call Trace: +Jul 1 21:58:36 nemi kernel: [ 3684.072489] [] ? wdm_read+0x1a0/0x263 [cdc_wdm] +Jul 1 21:58:36 nemi kernel: [ 3684.072500] [] ? vfs_read+0xa1/0xfb +Jul 1 21:58:36 nemi kernel: [ 3684.072509] [] ? alarm_setitimer+0x35/0x64 +Jul 1 21:58:36 nemi kernel: [ 3684.072517] [] ? sys_read+0x45/0x6e +Jul 1 21:58:36 nemi kernel: [ 3684.072525] [] ? system_call_fastpath+0x16/0x1b +Jul 1 21:58:36 nemi kernel: [ 3684.072557] Code: <66> 66 90 c3 83 ff ed 89 f8 74 16 7f 06 83 ff a1 75 0a c3 83 ff f4 + +The WDM_READ flag is normally cleared by wdm_int_callback +before resubmitting the read urb, and set by wdm_in_callback +when this urb returns with data or an error. But a crashing +device may cause both a read error and cancelling all urbs. +Make sure that the flag is cleared by wdm_read if the buffer +is empty. + +We don't clear the flag on errors, as there may be pending +data in the buffer which should be processed. The flag will +instead be cleared on the next wdm_read call. + +Signed-off-by: Bjørn Mork +Acked-by: Oliver Neukum +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/class/cdc-wdm.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/class/cdc-wdm.c ++++ b/drivers/usb/class/cdc-wdm.c +@@ -497,6 +497,8 @@ retry: + goto retry; + } + if (!desc->reslength) { /* zero length read */ ++ dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); ++ clear_bit(WDM_READ, &desc->flags); + spin_unlock_irq(&desc->iuspin); + goto retry; + } diff --git a/queue-3.4/usb-metro-usb-fix-tty_flip_buffer_push-use.patch b/queue-3.4/usb-metro-usb-fix-tty_flip_buffer_push-use.patch new file mode 100644 index 00000000000..c8c3920ba67 --- /dev/null +++ b/queue-3.4/usb-metro-usb-fix-tty_flip_buffer_push-use.patch @@ -0,0 +1,36 @@ +From b7d28e32c93801d60c1a7a817f774a02b7bdde43 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 2 Jul 2012 12:34:24 +0200 +Subject: USB: metro-usb: fix tty_flip_buffer_push use + +From: Johan Hovold + +commit b7d28e32c93801d60c1a7a817f774a02b7bdde43 upstream. + +Do not set low_latency flag at open as tty_flip_buffer_push must not be +called in IRQ context with low_latency set. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/metro-usb.c | 8 -------- + 1 file changed, 8 deletions(-) + +--- a/drivers/usb/serial/metro-usb.c ++++ b/drivers/usb/serial/metro-usb.c +@@ -171,14 +171,6 @@ static int metrousb_open(struct tty_stru + metro_priv->throttled = 0; + spin_unlock_irqrestore(&metro_priv->lock, flags); + +- /* +- * Force low_latency on so that our tty_push actually forces the data +- * through, otherwise it is scheduled, and with high data rates (like +- * with OHCI) data can get lost. +- */ +- if (tty) +- tty->low_latency = 1; +- + /* Clear the urb pipe. */ + usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe); + diff --git a/queue-3.4/usb-option-add-mediatek-product-ids.patch b/queue-3.4/usb-option-add-mediatek-product-ids.patch new file mode 100644 index 00000000000..a3edc9db24e --- /dev/null +++ b/queue-3.4/usb-option-add-mediatek-product-ids.patch @@ -0,0 +1,52 @@ +From aacef9c561a693341566a6850c451ce3df68cb9a Mon Sep 17 00:00:00 2001 +From: Gaosen Zhang +Date: Thu, 5 Jul 2012 21:49:00 +0800 +Subject: USB: option: Add MEDIATEK product ids + +From: Gaosen Zhang + +commit aacef9c561a693341566a6850c451ce3df68cb9a upstream. + +Signed-off-by: Gaosen Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/option.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -497,6 +497,15 @@ static void option_instat_callback(struc + + /* MediaTek products */ + #define MEDIATEK_VENDOR_ID 0x0e8d ++#define MEDIATEK_PRODUCT_DC_1COM 0x00a0 ++#define MEDIATEK_PRODUCT_DC_4COM 0x00a5 ++#define MEDIATEK_PRODUCT_DC_5COM 0x00a4 ++#define MEDIATEK_PRODUCT_7208_1COM 0x7101 ++#define MEDIATEK_PRODUCT_7208_2COM 0x7102 ++#define MEDIATEK_PRODUCT_FP_1COM 0x0003 ++#define MEDIATEK_PRODUCT_FP_2COM 0x0023 ++#define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 ++#define MEDIATEK_PRODUCT_FPDC_2COM 0x0033 + + /* Cellient products */ + #define CELLIENT_VENDOR_ID 0x2692 +@@ -1246,6 +1255,17 @@ static const struct usb_device_id option + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */ ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_1COM, 0x0a, 0x00, 0x00) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x02, 0x01) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x00, 0x00) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x02, 0x01) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x00, 0x00) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_1COM, 0x02, 0x00, 0x00) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_2COM, 0x02, 0x02, 0x01) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_1COM, 0x0a, 0x00, 0x00) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, + { } /* Terminating entry */ + }; diff --git a/queue-3.4/usb-option-add-zte-mf60.patch b/queue-3.4/usb-option-add-zte-mf60.patch new file mode 100644 index 00000000000..22d3cee3708 --- /dev/null +++ b/queue-3.4/usb-option-add-zte-mf60.patch @@ -0,0 +1,67 @@ +From 8e16e33c168a6efd0c9f7fa9dd4c1e1db9a74553 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Mon, 2 Jul 2012 19:53:55 +0200 +Subject: USB: option: add ZTE MF60 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= + +commit 8e16e33c168a6efd0c9f7fa9dd4c1e1db9a74553 upstream. + +Switches into a composite device by ejecting the initial +driver CD. The four interfaces are: QCDM, AT, QMI/wwan +and mass storage. Let this driver manage the two serial +interfaces: + +T: Bus=02 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 28 Spd=480 MxCh= 0 +D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 +P: Vendor=19d2 ProdID=1402 Rev= 0.00 +S: Manufacturer=ZTE,Incorporated +S: Product=ZTE WCDMA Technologies MSM +S: SerialNumber=xxxxx +C:* #Ifs= 4 Cfg#= 1 Atr=c0 MxPwr=500mA +I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option +E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms +I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan +E: Ad=83(I) Atr=03(Int.) MxPS= 64 Ivl=2ms +E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms +I:* If#= 3 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage +E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms + +Signed-off-by: Bjørn Mork +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/option.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -554,6 +554,10 @@ static const struct option_blacklist_inf + .reserved = BIT(1), + }; + ++static const struct option_blacklist_info net_intf2_blacklist = { ++ .reserved = BIT(2), ++}; ++ + static const struct option_blacklist_info net_intf3_blacklist = { + .reserved = BIT(3), + }; +@@ -1099,6 +1103,8 @@ static const struct usb_device_id option + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, + 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, diff --git a/queue-3.4/xhci-fix-hang-on-back-to-back-set-tr-deq-ptr-commands.patch b/queue-3.4/xhci-fix-hang-on-back-to-back-set-tr-deq-ptr-commands.patch new file mode 100644 index 00000000000..a4c66441307 --- /dev/null +++ b/queue-3.4/xhci-fix-hang-on-back-to-back-set-tr-deq-ptr-commands.patch @@ -0,0 +1,107 @@ +From 0d9f78a92ef5e97d9fe51d9215ebe22f6f0d289d Mon Sep 17 00:00:00 2001 +From: Sarah Sharp +Date: Thu, 21 Jun 2012 16:28:30 -0700 +Subject: xhci: Fix hang on back-to-back Set TR Deq Ptr commands. + +From: Sarah Sharp + +commit 0d9f78a92ef5e97d9fe51d9215ebe22f6f0d289d upstream. + +The Microsoft LifeChat 3000 USB headset was causing a very reproducible +hang whenever it was plugged in. At first, I thought the host +controller was producing bad transfer events, because the log was filled +with errors like: + +xhci_hcd 0000:00:14.0: ERROR Transfer event TRB DMA ptr not part of current TD + +However, it turned out to be an xHCI driver bug in the ring expansion +patches. The bug is triggered When there are two ring segments, and a +TD that ends just before a link TRB, like so: + + ______________ _____________ +| | ---> | setup TRB B | + ______________ | _____________ +| | | | data TRB B | + ______________ | _____________ +| setup TRB A | <-- deq | | data TRB B | + ______________ | _____________ +| data TRB A | | | | <-- enq, deq'' + ______________ | _____________ +| status TRB A | | | | + ______________ | _____________ +| link TRB |--------------- | link TRB | + _____________ <--- deq' _____________ + +TD A (the first control transfer) stalls on the data phase. That halts +the ring. The xHCI driver moves the hardware dequeue pointer to the +first TRB after the stalled transfer, which happens to be the link TRB. + +Once the Set TR dequeue pointer command completes, the function +update_ring_for_set_deq_completion runs. That function is supposed to +update the xHCI driver's dequeue pointer to match the internal hardware +dequeue pointer. On the first call this would work fine, and the +software dequeue pointer would move to deq'. + +However, if the transfer immediately after that stalled (TD B in this +case), another Set TR Dequeue command would be issued. That would move +the hardware dequeue pointer to deq''. Once that command completed, +update_ring_for_set_deq_completion would run again. + +The original code would unconditionally increment the software dequeue +pointer, which moved the pointer off the ring segment into la-la-land. +The while loop would happy increment the dequeue pointer (possibly +wrapping it) until it matched the hardware pointer value. + +The while loop would also access all the memory in between the first +ring segment and the second ring segment to determine if it was a link +TRB. This could cause general protection faults, although it was +unlikely because the ring segments came from a DMA pool, and would often +have consecutive memory addresses. + +If nothing in that space looked like a link TRB, the deq_seg pointer for +the ring would remain on the first segment. Thus, the deq_seg and the +software dequeue pointer would get out of sync. + +When the next transfer event came in after the stalled transfer, the +xHCI driver code would attempt to convert the software dequeue pointer +into a DMA address in order to compare the DMA address for the completed +transfer. Since the deq_seg and the dequeue pointer were out of sync, +xhci_trb_virt_to_dma would return NULL. + +The transfer event would get ignored, the transfer would eventually +timeout, and we would mistakenly convert the finished transfer to no-op +TRBs. Some kernel driver (maybe xHCI?) would then get stuck in an +infinite loop in interrupt context, and the whole machine would hang. + +This patch should be backported to kernels as old as 3.4, that contain +the commit b008df60c6369ba0290fa7daa177375407a12e07 "xHCI: count free +TRBs on transfer ring" + +Signed-off-by: Sarah Sharp +Cc: Andiry Xu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-ring.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -885,6 +885,17 @@ static void update_ring_for_set_deq_comp + num_trbs_free_temp = ep_ring->num_trbs_free; + dequeue_temp = ep_ring->dequeue; + ++ /* If we get two back-to-back stalls, and the first stalled transfer ++ * ends just before a link TRB, the dequeue pointer will be left on ++ * the link TRB by the code in the while loop. So we have to update ++ * the dequeue pointer one segment further, or we'll jump off ++ * the segment into la-la-land. ++ */ ++ if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) { ++ ep_ring->deq_seg = ep_ring->deq_seg->next; ++ ep_ring->dequeue = ep_ring->deq_seg->trbs; ++ } ++ + while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) { + /* We have more usable TRBs */ + ep_ring->num_trbs_free++;