From: Greg Kroah-Hartman Date: Fri, 27 Jul 2018 09:27:15 +0000 (+0200) Subject: 4.17-stable patches X-Git-Tag: v3.18.117~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=301963b6c8e1beac0f43bb7bd72d859fe4623369;p=thirdparty%2Fkernel%2Fstable-queue.git 4.17-stable patches added patches: acpica-aml-parser-ignore-dispatcher-error-status-during-table-load.patch can-m_can-fix-runtime-resume-call.patch can-m_can.c-fix-setup-of-cccr-register-clear-cccr-niso-bit-before-checking-can.ctrlmode.patch can-peak_canfd-fix-firmware-v3.3.0-limit-allocation-to-32-bit-dma-addr-only.patch can-xilinx_can-fix-device-dropping-off-bus-on-rx-overrun.patch can-xilinx_can-fix-incorrect-clear-of-non-processed-interrupts.patch can-xilinx_can-fix-power-management-handling.patch can-xilinx_can-fix-recovery-from-error-states-not-being-propagated.patch can-xilinx_can-fix-rx-loop-if-rxnemp-is-asserted-without-rxok.patch can-xilinx_can-fix-rx-overflow-interrupt-not-being-enabled.patch can-xilinx_can-keep-only-1-2-frames-in-tx-fifo-to-fix-tx-accounting.patch driver-core-partially-revert-driver-core-correct-device-s-shutdown-order.patch revert-staging-r8188eu-use-lib80211-to-support-tkip.patch staging-speakup-fix-wraparound-in-uaccess-length-check.patch usb-cdc_acm-add-quirk-for-castles-vega3000.patch usb-core-handle-hub-c_port_over_current-condition.patch usb-dwc2-fix-dma-alignment-to-start-at-allocated-boundary.patch usb-gadget-f_fs-only-return-delayed-status-when-len-is-0.patch usb-gadget-fix-os-descriptors-support.patch usb-xhci-fix-memory-leak-in-xhci_endpoint_reset.patch --- diff --git a/queue-4.17/acpica-aml-parser-ignore-dispatcher-error-status-during-table-load.patch b/queue-4.17/acpica-aml-parser-ignore-dispatcher-error-status-during-table-load.patch new file mode 100644 index 00000000000..24fc688ce62 --- /dev/null +++ b/queue-4.17/acpica-aml-parser-ignore-dispatcher-error-status-during-table-load.patch @@ -0,0 +1,90 @@ +From 73c2a01c52b657f4a0ead6c95f64c5279efbd000 Mon Sep 17 00:00:00 2001 +From: "Schmauss, Erik" +Date: Thu, 19 Jul 2018 16:33:00 -0700 +Subject: ACPICA: AML Parser: ignore dispatcher error status during table load + +From: Schmauss, Erik + +commit 73c2a01c52b657f4a0ead6c95f64c5279efbd000 upstream. + +The dispatcher and the executer process the parse nodes During table +load. Error status from the evaluation confuses the AML parser. This +results in the parser failing to complete parsing of the current +scope op which becomes problematic. For the incorrect AML below, _ADR +never gets created. + +definition_block(...) +{ + Scope (\_SB) + { + Device (PCI0){...} + Name (OBJ1, 0x0) + OBJ1 = PCI0 + 5 // Results in an operand error. + } // \_SB not closed + + // parser looks for \_SB._SB.PCI0, results in AE_NOT_FOUND error + // Entire scope block gets skipped. + Scope (\_SB.PCI0) + { + Name (_ADR, 0x0) + } +} + +Fix the above error by properly completing the initial \_SB scope +after an error by clearing errors that occur during table load. In +the above case, this means that OBJ1 = PIC0 + 5 is skipped. + +Fixes: 5088814a6e93 (ACPICA: AML parser: attempt to continue loading table after error) +Link: https://bugzilla.kernel.org/show_bug.cgi?id=200363 +Tested-by: Bastien Nocera +Signed-off-by: Erik Schmauss +Cc: 4.17+ # 4.17+ +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/acpica/psloop.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +--- a/drivers/acpi/acpica/psloop.c ++++ b/drivers/acpi/acpica/psloop.c +@@ -497,6 +497,18 @@ acpi_status acpi_ps_parse_loop(struct ac + status = + acpi_ps_create_op(walk_state, aml_op_start, &op); + if (ACPI_FAILURE(status)) { ++ /* ++ * ACPI_PARSE_MODULE_LEVEL means that we are loading a table by ++ * executing it as a control method. However, if we encounter ++ * an error while loading the table, we need to keep trying to ++ * load the table rather than aborting the table load. Set the ++ * status to AE_OK to proceed with the table load. ++ */ ++ if ((walk_state-> ++ parse_flags & ACPI_PARSE_MODULE_LEVEL) ++ && status == AE_ALREADY_EXISTS) { ++ status = AE_OK; ++ } + if (status == AE_CTRL_PARSE_CONTINUE) { + continue; + } +@@ -694,6 +706,20 @@ acpi_status acpi_ps_parse_loop(struct ac + acpi_ps_next_parse_state(walk_state, op, status); + if (status == AE_CTRL_PENDING) { + status = AE_OK; ++ } else ++ if ((walk_state-> ++ parse_flags & ACPI_PARSE_MODULE_LEVEL) ++ && ACPI_FAILURE(status)) { ++ /* ++ * ACPI_PARSE_MODULE_LEVEL means that we are loading a table by ++ * executing it as a control method. However, if we encounter ++ * an error while loading the table, we need to keep trying to ++ * load the table rather than aborting the table load. Set the ++ * status to AE_OK to proceed with the table load. If we get a ++ * failure at this point, it means that the dispatcher got an ++ * error while processing Op (most likely an AML operand error. ++ */ ++ status = AE_OK; + } + } + diff --git a/queue-4.17/can-m_can-fix-runtime-resume-call.patch b/queue-4.17/can-m_can-fix-runtime-resume-call.patch new file mode 100644 index 00000000000..fa0ad556892 --- /dev/null +++ b/queue-4.17/can-m_can-fix-runtime-resume-call.patch @@ -0,0 +1,53 @@ +From 1675bee3e732c2449e792feed9caff804f3bd42c Mon Sep 17 00:00:00 2001 +From: Faiz Abbas +Date: Tue, 3 Jul 2018 16:41:02 +0530 +Subject: can: m_can: Fix runtime resume call + +From: Faiz Abbas + +commit 1675bee3e732c2449e792feed9caff804f3bd42c upstream. + +pm_runtime_get_sync() returns a 1 if the state of the device is already +'active'. This is not a failure case and should return a success. + +Therefore fix error handling for pm_runtime_get_sync() call such that +it returns success when the value is 1. + +Also cleanup the TODO for using runtime PM for sleep mode as that is +implemented. + +Signed-off-by: Faiz Abbas +Cc: +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/m_can/m_can.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/can/m_can/m_can.c ++++ b/drivers/net/can/m_can/m_can.c +@@ -634,10 +634,12 @@ static int m_can_clk_start(struct m_can_ + int err; + + err = pm_runtime_get_sync(priv->device); +- if (err) ++ if (err < 0) { + pm_runtime_put_noidle(priv->device); ++ return err; ++ } + +- return err; ++ return 0; + } + + static void m_can_clk_stop(struct m_can_priv *priv) +@@ -1687,8 +1689,6 @@ failed_ret: + return ret; + } + +-/* TODO: runtime PM with power down or sleep mode */ +- + static __maybe_unused int m_can_suspend(struct device *dev) + { + struct net_device *ndev = dev_get_drvdata(dev); diff --git a/queue-4.17/can-m_can.c-fix-setup-of-cccr-register-clear-cccr-niso-bit-before-checking-can.ctrlmode.patch b/queue-4.17/can-m_can.c-fix-setup-of-cccr-register-clear-cccr-niso-bit-before-checking-can.ctrlmode.patch new file mode 100644 index 00000000000..07710975f99 --- /dev/null +++ b/queue-4.17/can-m_can.c-fix-setup-of-cccr-register-clear-cccr-niso-bit-before-checking-can.ctrlmode.patch @@ -0,0 +1,41 @@ +From 393753b217f05474e714aea36c37501546ed1202 Mon Sep 17 00:00:00 2001 +From: Roman Fietze +Date: Wed, 11 Jul 2018 15:36:14 +0200 +Subject: can: m_can.c: fix setup of CCCR register: clear CCCR NISO bit before checking can.ctrlmode + +From: Roman Fietze + +commit 393753b217f05474e714aea36c37501546ed1202 upstream. + +Inside m_can_chip_config(), when setting up the new value of the CCCR, +the CCCR_NISO bit is not cleared like the others, CCCR_TEST, CCCR_MON, +CCCR_BRSE and CCCR_FDOE, before checking the can.ctrlmode bits for +CAN_CTRLMODE_FD_NON_ISO. + +This way once the controller was configured for CAN_CTRLMODE_FD_NON_ISO, +this mode could never be cleared again. + +This fix is only relevant for controllers with version 3.1.x or 3.2.x. +Older versions do not support NISO. + +Signed-off-by: Roman Fietze +Cc: linux-stable +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/m_can/m_can.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/can/m_can/m_can.c ++++ b/drivers/net/can/m_can/m_can.c +@@ -1111,7 +1111,8 @@ static void m_can_chip_config(struct net + + } else { + /* Version 3.1.x or 3.2.x */ +- cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE); ++ cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE | ++ CCCR_NISO); + + /* Only 3.2.x has NISO Bit implemented */ + if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) diff --git a/queue-4.17/can-peak_canfd-fix-firmware-v3.3.0-limit-allocation-to-32-bit-dma-addr-only.patch b/queue-4.17/can-peak_canfd-fix-firmware-v3.3.0-limit-allocation-to-32-bit-dma-addr-only.patch new file mode 100644 index 00000000000..5d00774d377 --- /dev/null +++ b/queue-4.17/can-peak_canfd-fix-firmware-v3.3.0-limit-allocation-to-32-bit-dma-addr-only.patch @@ -0,0 +1,64 @@ +From 5d4c94ed9f564224d7b37dbee13f7c5d4a8a01ac Mon Sep 17 00:00:00 2001 +From: Stephane Grosjean +Date: Thu, 21 Jun 2018 15:23:31 +0200 +Subject: can: peak_canfd: fix firmware < v3.3.0: limit allocation to 32-bit DMA addr only + +From: Stephane Grosjean + +commit 5d4c94ed9f564224d7b37dbee13f7c5d4a8a01ac upstream. + +The DMA logic in firmwares < v3.3.0 embedded in the PCAN-PCIe FD cards +family is not capable of handling a mix of 32-bit and 64-bit logical +addresses. If the board is equipped with 2 or 4 CAN ports, then such a +situation might lead to a PCIe Bus Error "Malformed TLP" packet +as well as "irq xx: nobody cared" issue. + +This patch adds a workaround that requests only 32-bit DMA addresses +when these might be allocated outside of the 4 GB area. + +This issue has been fixed in firmware v3.3.0 and next. + +Signed-off-by: Stephane Grosjean +Cc: linux-stable +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/peak_canfd/peak_pciefd_main.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +--- a/drivers/net/can/peak_canfd/peak_pciefd_main.c ++++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c +@@ -58,6 +58,10 @@ MODULE_LICENSE("GPL v2"); + #define PCIEFD_REG_SYS_VER1 0x0040 /* version reg #1 */ + #define PCIEFD_REG_SYS_VER2 0x0044 /* version reg #2 */ + ++#define PCIEFD_FW_VERSION(x, y, z) (((u32)(x) << 24) | \ ++ ((u32)(y) << 16) | \ ++ ((u32)(z) << 8)) ++ + /* System Control Registers Bits */ + #define PCIEFD_SYS_CTL_TS_RST 0x00000001 /* timestamp clock */ + #define PCIEFD_SYS_CTL_CLK_EN 0x00000002 /* system clock */ +@@ -783,6 +787,21 @@ static int peak_pciefd_probe(struct pci_ + "%ux CAN-FD PCAN-PCIe FPGA v%u.%u.%u:\n", can_count, + hw_ver_major, hw_ver_minor, hw_ver_sub); + ++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++ /* FW < v3.3.0 DMA logic doesn't handle correctly the mix of 32-bit and ++ * 64-bit logical addresses: this workaround forces usage of 32-bit ++ * DMA addresses only when such a fw is detected. ++ */ ++ if (PCIEFD_FW_VERSION(hw_ver_major, hw_ver_minor, hw_ver_sub) < ++ PCIEFD_FW_VERSION(3, 3, 0)) { ++ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); ++ if (err) ++ dev_warn(&pdev->dev, ++ "warning: can't set DMA mask %llxh (err %d)\n", ++ DMA_BIT_MASK(32), err); ++ } ++#endif ++ + /* stop system clock */ + pciefd_sys_writereg(pciefd, PCIEFD_SYS_CTL_CLK_EN, + PCIEFD_REG_SYS_CTL_CLR); diff --git a/queue-4.17/can-xilinx_can-fix-device-dropping-off-bus-on-rx-overrun.patch b/queue-4.17/can-xilinx_can-fix-device-dropping-off-bus-on-rx-overrun.patch new file mode 100644 index 00000000000..e5971db807c --- /dev/null +++ b/queue-4.17/can-xilinx_can-fix-device-dropping-off-bus-on-rx-overrun.patch @@ -0,0 +1,41 @@ +From 2574fe54515ed3487405de329e4e9f13d7098c10 Mon Sep 17 00:00:00 2001 +From: Anssi Hannula +Date: Tue, 7 Feb 2017 13:23:04 +0200 +Subject: can: xilinx_can: fix device dropping off bus on RX overrun + +From: Anssi Hannula + +commit 2574fe54515ed3487405de329e4e9f13d7098c10 upstream. + +The xilinx_can driver performs a software reset when an RX overrun is +detected. This causes the device to enter Configuration mode where no +messages are received or transmitted. + +The documentation does not mention any need to perform a reset on an RX +overrun, and testing by inducing an RX overflow also indicated that the +device continues to work just fine without a reset. + +Remove the software reset. + +Tested with the integrated CAN on Zynq-7000 SoC. + +Fixes: b1201e44f50b ("can: xilinx CAN controller support") +Signed-off-by: Anssi Hannula +Cc: +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/xilinx_can.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/can/xilinx_can.c ++++ b/drivers/net/can/xilinx_can.c +@@ -696,7 +696,6 @@ static void xcan_err_interrupt(struct ne + if (isr & XCAN_IXR_RXOFLW_MASK) { + stats->rx_over_errors++; + stats->rx_errors++; +- priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; diff --git a/queue-4.17/can-xilinx_can-fix-incorrect-clear-of-non-processed-interrupts.patch b/queue-4.17/can-xilinx_can-fix-incorrect-clear-of-non-processed-interrupts.patch new file mode 100644 index 00000000000..f6fd191e3a0 --- /dev/null +++ b/queue-4.17/can-xilinx_can-fix-incorrect-clear-of-non-processed-interrupts.patch @@ -0,0 +1,54 @@ +From 2f4f0f338cf453bfcdbcf089e177c16f35f023c8 Mon Sep 17 00:00:00 2001 +From: Anssi Hannula +Date: Mon, 26 Feb 2018 14:39:59 +0200 +Subject: can: xilinx_can: fix incorrect clear of non-processed interrupts + +From: Anssi Hannula + +commit 2f4f0f338cf453bfcdbcf089e177c16f35f023c8 upstream. + +xcan_interrupt() clears ERROR|RXOFLV|BSOFF|ARBLST interrupts if any of +them is asserted. This does not take into account that some of them +could have been asserted between interrupt status read and interrupt +clear, therefore clearing them without handling them. + +Fix the code to only clear those interrupts that it knows are asserted +and therefore going to be processed in xcan_err_interrupt(). + +Fixes: b1201e44f50b ("can: xilinx CAN controller support") +Signed-off-by: Anssi Hannula +Cc: Michal Simek +Cc: +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/xilinx_can.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/net/can/xilinx_can.c ++++ b/drivers/net/can/xilinx_can.c +@@ -938,6 +938,7 @@ static irqreturn_t xcan_interrupt(int ir + struct net_device *ndev = (struct net_device *)dev_id; + struct xcan_priv *priv = netdev_priv(ndev); + u32 isr, ier; ++ u32 isr_errors; + + /* Get the interrupt status from Xilinx CAN */ + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); +@@ -956,11 +957,10 @@ static irqreturn_t xcan_interrupt(int ir + xcan_tx_interrupt(ndev, isr); + + /* Check for the type of error interrupt and Processing it */ +- if (isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | +- XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK)) { +- priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_ERROR_MASK | +- XCAN_IXR_RXOFLW_MASK | XCAN_IXR_BSOFF_MASK | +- XCAN_IXR_ARBLST_MASK)); ++ isr_errors = isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | ++ XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK); ++ if (isr_errors) { ++ priv->write_reg(priv, XCAN_ICR_OFFSET, isr_errors); + xcan_err_interrupt(ndev, isr); + } + diff --git a/queue-4.17/can-xilinx_can-fix-power-management-handling.patch b/queue-4.17/can-xilinx_can-fix-power-management-handling.patch new file mode 100644 index 00000000000..e26106e04bb --- /dev/null +++ b/queue-4.17/can-xilinx_can-fix-power-management-handling.patch @@ -0,0 +1,178 @@ +From 8ebd83bdb027f29870d96649dba18b91581ea829 Mon Sep 17 00:00:00 2001 +From: Anssi Hannula +Date: Thu, 17 May 2018 15:41:19 +0300 +Subject: can: xilinx_can: fix power management handling + +From: Anssi Hannula + +commit 8ebd83bdb027f29870d96649dba18b91581ea829 upstream. + +There are several issues with the suspend/resume handling code of the +driver: + +- The device is attached and detached in the runtime_suspend() and + runtime_resume() callbacks if the interface is running. However, + during xcan_chip_start() the interface is considered running, + causing the resume handler to incorrectly call netif_start_queue() + at the beginning of xcan_chip_start(), and on xcan_chip_start() error + return the suspend handler detaches the device leaving the user + unable to bring-up the device anymore. + +- The device is not brought properly up on system resume. A reset is + done and the code tries to determine the bus state after that. + However, after reset the device is always in Configuration mode + (down), so the state checking code does not make sense and + communication will also not work. + +- The suspend callback tries to set the device to sleep mode (low-power + mode which monitors the bus and brings the device back to normal mode + on activity), but then immediately disables the clocks (possibly + before the device reaches the sleep mode), which does not make sense + to me. If a clean shutdown is wanted before disabling clocks, we can + just bring it down completely instead of only sleep mode. + +Reorganize the PM code so that only the clock logic remains in the +runtime PM callbacks and the system PM callbacks contain the device +bring-up/down logic. This makes calling the runtime PM callbacks during +e.g. xcan_chip_start() safe. + +The system PM callbacks now simply call common code to start/stop the +HW if the interface was running, replacing the broken code from before. + +xcan_chip_stop() is updated to use the common reset code so that it will +wait for the reset to complete. Reset also disables all interrupts so do +not do that separately. + +Also, the device_may_wakeup() checks are removed as the driver does not +have wakeup support. + +Tested on Zynq-7000 integrated CAN. + +Signed-off-by: Anssi Hannula +Cc: Michal Simek +Cc: +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/xilinx_can.c | 69 +++++++++++++++++-------------------------- + 1 file changed, 28 insertions(+), 41 deletions(-) + +--- a/drivers/net/can/xilinx_can.c ++++ b/drivers/net/can/xilinx_can.c +@@ -811,13 +811,9 @@ static irqreturn_t xcan_interrupt(int ir + static void xcan_chip_stop(struct net_device *ndev) + { + struct xcan_priv *priv = netdev_priv(ndev); +- u32 ier; + + /* Disable interrupts and leave the can in configuration mode */ +- ier = priv->read_reg(priv, XCAN_IER_OFFSET); +- ier &= ~XCAN_INTR_ALL; +- priv->write_reg(priv, XCAN_IER_OFFSET, ier); +- priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); ++ set_reset_mode(ndev); + priv->can.state = CAN_STATE_STOPPED; + } + +@@ -950,10 +946,15 @@ static const struct net_device_ops xcan_ + */ + static int __maybe_unused xcan_suspend(struct device *dev) + { +- if (!device_may_wakeup(dev)) +- return pm_runtime_force_suspend(dev); ++ struct net_device *ndev = dev_get_drvdata(dev); + +- return 0; ++ if (netif_running(ndev)) { ++ netif_stop_queue(ndev); ++ netif_device_detach(ndev); ++ xcan_chip_stop(ndev); ++ } ++ ++ return pm_runtime_force_suspend(dev); + } + + /** +@@ -965,11 +966,27 @@ static int __maybe_unused xcan_suspend(s + */ + static int __maybe_unused xcan_resume(struct device *dev) + { +- if (!device_may_wakeup(dev)) +- return pm_runtime_force_resume(dev); ++ struct net_device *ndev = dev_get_drvdata(dev); ++ int ret; + +- return 0; ++ ret = pm_runtime_force_resume(dev); ++ if (ret) { ++ dev_err(dev, "pm_runtime_force_resume failed on resume\n"); ++ return ret; ++ } ++ ++ if (netif_running(ndev)) { ++ ret = xcan_chip_start(ndev); ++ if (ret) { ++ dev_err(dev, "xcan_chip_start failed on resume\n"); ++ return ret; ++ } ++ ++ netif_device_attach(ndev); ++ netif_start_queue(ndev); ++ } + ++ return 0; + } + + /** +@@ -984,14 +1001,6 @@ static int __maybe_unused xcan_runtime_s + struct net_device *ndev = dev_get_drvdata(dev); + struct xcan_priv *priv = netdev_priv(ndev); + +- if (netif_running(ndev)) { +- netif_stop_queue(ndev); +- netif_device_detach(ndev); +- } +- +- priv->write_reg(priv, XCAN_MSR_OFFSET, XCAN_MSR_SLEEP_MASK); +- priv->can.state = CAN_STATE_SLEEPING; +- + clk_disable_unprepare(priv->bus_clk); + clk_disable_unprepare(priv->can_clk); + +@@ -1010,7 +1019,6 @@ static int __maybe_unused xcan_runtime_r + struct net_device *ndev = dev_get_drvdata(dev); + struct xcan_priv *priv = netdev_priv(ndev); + int ret; +- u32 isr, status; + + ret = clk_prepare_enable(priv->bus_clk); + if (ret) { +@@ -1024,27 +1032,6 @@ static int __maybe_unused xcan_runtime_r + return ret; + } + +- priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); +- isr = priv->read_reg(priv, XCAN_ISR_OFFSET); +- status = priv->read_reg(priv, XCAN_SR_OFFSET); +- +- if (netif_running(ndev)) { +- if (isr & XCAN_IXR_BSOFF_MASK) { +- priv->can.state = CAN_STATE_BUS_OFF; +- priv->write_reg(priv, XCAN_SRR_OFFSET, +- XCAN_SRR_RESET_MASK); +- } else if ((status & XCAN_SR_ESTAT_MASK) == +- XCAN_SR_ESTAT_MASK) { +- priv->can.state = CAN_STATE_ERROR_PASSIVE; +- } else if (status & XCAN_SR_ERRWRN_MASK) { +- priv->can.state = CAN_STATE_ERROR_WARNING; +- } else { +- priv->can.state = CAN_STATE_ERROR_ACTIVE; +- } +- netif_device_attach(ndev); +- netif_start_queue(ndev); +- } +- + return 0; + } + diff --git a/queue-4.17/can-xilinx_can-fix-recovery-from-error-states-not-being-propagated.patch b/queue-4.17/can-xilinx_can-fix-recovery-from-error-states-not-being-propagated.patch new file mode 100644 index 00000000000..c78c6cf709a --- /dev/null +++ b/queue-4.17/can-xilinx_can-fix-recovery-from-error-states-not-being-propagated.patch @@ -0,0 +1,234 @@ +From 877e0b75947e2c7acf5624331bb17ceb093c98ae Mon Sep 17 00:00:00 2001 +From: Anssi Hannula +Date: Wed, 8 Feb 2017 13:13:40 +0200 +Subject: can: xilinx_can: fix recovery from error states not being propagated + +From: Anssi Hannula + +commit 877e0b75947e2c7acf5624331bb17ceb093c98ae upstream. + +The xilinx_can driver contains no mechanism for propagating recovery +from CAN_STATE_ERROR_WARNING and CAN_STATE_ERROR_PASSIVE. + +Add such a mechanism by factoring the handling of +XCAN_STATE_ERROR_PASSIVE and XCAN_STATE_ERROR_WARNING out of +xcan_err_interrupt and checking for recovery after RX and TX if the +interface is in one of those states. + +Tested with the integrated CAN on Zynq-7000 SoC. + +Fixes: b1201e44f50b ("can: xilinx CAN controller support") +Signed-off-by: Anssi Hannula +Cc: +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/xilinx_can.c | 155 +++++++++++++++++++++++++++++++++++-------- + 1 file changed, 127 insertions(+), 28 deletions(-) + +--- a/drivers/net/can/xilinx_can.c ++++ b/drivers/net/can/xilinx_can.c +@@ -2,6 +2,7 @@ + * + * Copyright (C) 2012 - 2014 Xilinx, Inc. + * Copyright (C) 2009 PetaLogix. All rights reserved. ++ * Copyright (C) 2017 Sandvik Mining and Construction Oy + * + * Description: + * This driver is developed for Axi CAN IP and for Zynq CANPS Controller. +@@ -530,6 +531,123 @@ static int xcan_rx(struct net_device *nd + } + + /** ++ * xcan_current_error_state - Get current error state from HW ++ * @ndev: Pointer to net_device structure ++ * ++ * Checks the current CAN error state from the HW. Note that this ++ * only checks for ERROR_PASSIVE and ERROR_WARNING. ++ * ++ * Return: ++ * ERROR_PASSIVE or ERROR_WARNING if either is active, ERROR_ACTIVE ++ * otherwise. ++ */ ++static enum can_state xcan_current_error_state(struct net_device *ndev) ++{ ++ struct xcan_priv *priv = netdev_priv(ndev); ++ u32 status = priv->read_reg(priv, XCAN_SR_OFFSET); ++ ++ if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) ++ return CAN_STATE_ERROR_PASSIVE; ++ else if (status & XCAN_SR_ERRWRN_MASK) ++ return CAN_STATE_ERROR_WARNING; ++ else ++ return CAN_STATE_ERROR_ACTIVE; ++} ++ ++/** ++ * xcan_set_error_state - Set new CAN error state ++ * @ndev: Pointer to net_device structure ++ * @new_state: The new CAN state to be set ++ * @cf: Error frame to be populated or NULL ++ * ++ * Set new CAN error state for the device, updating statistics and ++ * populating the error frame if given. ++ */ ++static void xcan_set_error_state(struct net_device *ndev, ++ enum can_state new_state, ++ struct can_frame *cf) ++{ ++ struct xcan_priv *priv = netdev_priv(ndev); ++ u32 ecr = priv->read_reg(priv, XCAN_ECR_OFFSET); ++ u32 txerr = ecr & XCAN_ECR_TEC_MASK; ++ u32 rxerr = (ecr & XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT; ++ ++ priv->can.state = new_state; ++ ++ if (cf) { ++ cf->can_id |= CAN_ERR_CRTL; ++ cf->data[6] = txerr; ++ cf->data[7] = rxerr; ++ } ++ ++ switch (new_state) { ++ case CAN_STATE_ERROR_PASSIVE: ++ priv->can.can_stats.error_passive++; ++ if (cf) ++ cf->data[1] = (rxerr > 127) ? ++ CAN_ERR_CRTL_RX_PASSIVE : ++ CAN_ERR_CRTL_TX_PASSIVE; ++ break; ++ case CAN_STATE_ERROR_WARNING: ++ priv->can.can_stats.error_warning++; ++ if (cf) ++ cf->data[1] |= (txerr > rxerr) ? ++ CAN_ERR_CRTL_TX_WARNING : ++ CAN_ERR_CRTL_RX_WARNING; ++ break; ++ case CAN_STATE_ERROR_ACTIVE: ++ if (cf) ++ cf->data[1] |= CAN_ERR_CRTL_ACTIVE; ++ break; ++ default: ++ /* non-ERROR states are handled elsewhere */ ++ WARN_ON(1); ++ break; ++ } ++} ++ ++/** ++ * xcan_update_error_state_after_rxtx - Update CAN error state after RX/TX ++ * @ndev: Pointer to net_device structure ++ * ++ * If the device is in a ERROR-WARNING or ERROR-PASSIVE state, check if ++ * the performed RX/TX has caused it to drop to a lesser state and set ++ * the interface state accordingly. ++ */ ++static void xcan_update_error_state_after_rxtx(struct net_device *ndev) ++{ ++ struct xcan_priv *priv = netdev_priv(ndev); ++ enum can_state old_state = priv->can.state; ++ enum can_state new_state; ++ ++ /* changing error state due to successful frame RX/TX can only ++ * occur from these states ++ */ ++ if (old_state != CAN_STATE_ERROR_WARNING && ++ old_state != CAN_STATE_ERROR_PASSIVE) ++ return; ++ ++ new_state = xcan_current_error_state(ndev); ++ ++ if (new_state != old_state) { ++ struct sk_buff *skb; ++ struct can_frame *cf; ++ ++ skb = alloc_can_err_skb(ndev, &cf); ++ ++ xcan_set_error_state(ndev, new_state, skb ? cf : NULL); ++ ++ if (skb) { ++ struct net_device_stats *stats = &ndev->stats; ++ ++ stats->rx_packets++; ++ stats->rx_bytes += cf->can_dlc; ++ netif_rx(skb); ++ } ++ } ++} ++ ++/** + * xcan_err_interrupt - error frame Isr + * @ndev: net_device pointer + * @isr: interrupt status register value +@@ -544,16 +662,12 @@ static void xcan_err_interrupt(struct ne + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; +- u32 err_status, status, txerr = 0, rxerr = 0; ++ u32 err_status; + + skb = alloc_can_err_skb(ndev, &cf); + + err_status = priv->read_reg(priv, XCAN_ESR_OFFSET); + priv->write_reg(priv, XCAN_ESR_OFFSET, err_status); +- txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK; +- rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) & +- XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT); +- status = priv->read_reg(priv, XCAN_SR_OFFSET); + + if (isr & XCAN_IXR_BSOFF_MASK) { + priv->can.state = CAN_STATE_BUS_OFF; +@@ -563,28 +677,10 @@ static void xcan_err_interrupt(struct ne + can_bus_off(ndev); + if (skb) + cf->can_id |= CAN_ERR_BUSOFF; +- } else if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) { +- priv->can.state = CAN_STATE_ERROR_PASSIVE; +- priv->can.can_stats.error_passive++; +- if (skb) { +- cf->can_id |= CAN_ERR_CRTL; +- cf->data[1] = (rxerr > 127) ? +- CAN_ERR_CRTL_RX_PASSIVE : +- CAN_ERR_CRTL_TX_PASSIVE; +- cf->data[6] = txerr; +- cf->data[7] = rxerr; +- } +- } else if (status & XCAN_SR_ERRWRN_MASK) { +- priv->can.state = CAN_STATE_ERROR_WARNING; +- priv->can.can_stats.error_warning++; +- if (skb) { +- cf->can_id |= CAN_ERR_CRTL; +- cf->data[1] |= (txerr > rxerr) ? +- CAN_ERR_CRTL_TX_WARNING : +- CAN_ERR_CRTL_RX_WARNING; +- cf->data[6] = txerr; +- cf->data[7] = rxerr; +- } ++ } else { ++ enum can_state new_state = xcan_current_error_state(ndev); ++ ++ xcan_set_error_state(ndev, new_state, skb ? cf : NULL); + } + + /* Check for Arbitration lost interrupt */ +@@ -714,8 +810,10 @@ static int xcan_rx_poll(struct napi_stru + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + } + +- if (work_done) ++ if (work_done) { + can_led_event(ndev, CAN_LED_EVENT_RX); ++ xcan_update_error_state_after_rxtx(ndev); ++ } + + if (work_done < quota) { + napi_complete_done(napi, work_done); +@@ -746,6 +844,7 @@ static void xcan_tx_interrupt(struct net + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + } + can_led_event(ndev, CAN_LED_EVENT_TX); ++ xcan_update_error_state_after_rxtx(ndev); + netif_wake_queue(ndev); + } + diff --git a/queue-4.17/can-xilinx_can-fix-rx-loop-if-rxnemp-is-asserted-without-rxok.patch b/queue-4.17/can-xilinx_can-fix-rx-loop-if-rxnemp-is-asserted-without-rxok.patch new file mode 100644 index 00000000000..3e8a6b23e7e --- /dev/null +++ b/queue-4.17/can-xilinx_can-fix-rx-loop-if-rxnemp-is-asserted-without-rxok.patch @@ -0,0 +1,98 @@ +From 32852c561bffd613d4ed7ec464b1e03e1b7b6c5c Mon Sep 17 00:00:00 2001 +From: Anssi Hannula +Date: Tue, 7 Feb 2017 17:01:14 +0200 +Subject: can: xilinx_can: fix RX loop if RXNEMP is asserted without RXOK + +From: Anssi Hannula + +commit 32852c561bffd613d4ed7ec464b1e03e1b7b6c5c upstream. + +If the device gets into a state where RXNEMP (RX FIFO not empty) +interrupt is asserted without RXOK (new frame received successfully) +interrupt being asserted, xcan_rx_poll() will continue to try to clear +RXNEMP without actually reading frames from RX FIFO. If the RX FIFO is +not empty, the interrupt will not be cleared and napi_schedule() will +just be called again. + +This situation can occur when: + +(a) xcan_rx() returns without reading RX FIFO due to an error condition. +The code tries to clear both RXOK and RXNEMP but RXNEMP will not clear +due to a frame still being in the FIFO. The frame will never be read +from the FIFO as RXOK is no longer set. + +(b) A frame is received between xcan_rx_poll() reading interrupt status +and clearing RXOK. RXOK will be cleared, but RXNEMP will again remain +set as the new message is still in the FIFO. + +I'm able to trigger case (b) by flooding the bus with frames under load. + +There does not seem to be any benefit in using both RXNEMP and RXOK in +the way the driver does, and the polling example in the reference manual +(UG585 v1.10 18.3.7 Read Messages from RxFIFO) also says that either +RXOK or RXNEMP can be used for detecting incoming messages. + +Fix the issue and simplify the RX processing by only using RXNEMP +without RXOK. + +Tested with the integrated CAN on Zynq-7000 SoC. + +Fixes: b1201e44f50b ("can: xilinx CAN controller support") +Signed-off-by: Anssi Hannula +Cc: +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/xilinx_can.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +--- a/drivers/net/can/xilinx_can.c ++++ b/drivers/net/can/xilinx_can.c +@@ -101,7 +101,7 @@ enum xcan_reg { + #define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ + XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ + XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ +- XCAN_IXR_ARBLST_MASK | XCAN_IXR_RXOK_MASK) ++ XCAN_IXR_ARBLST_MASK) + + /* CAN register bit shift - XCAN___SHIFT */ + #define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ +@@ -709,15 +709,7 @@ static int xcan_rx_poll(struct napi_stru + + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) { +- if (isr & XCAN_IXR_RXOK_MASK) { +- priv->write_reg(priv, XCAN_ICR_OFFSET, +- XCAN_IXR_RXOK_MASK); +- work_done += xcan_rx(ndev); +- } else { +- priv->write_reg(priv, XCAN_ICR_OFFSET, +- XCAN_IXR_RXNEMP_MASK); +- break; +- } ++ work_done += xcan_rx(ndev); + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK); + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + } +@@ -728,7 +720,7 @@ static int xcan_rx_poll(struct napi_stru + if (work_done < quota) { + napi_complete_done(napi, work_done); + ier = priv->read_reg(priv, XCAN_IER_OFFSET); +- ier |= (XCAN_IXR_RXOK_MASK | XCAN_IXR_RXNEMP_MASK); ++ ier |= XCAN_IXR_RXNEMP_MASK; + priv->write_reg(priv, XCAN_IER_OFFSET, ier); + } + return work_done; +@@ -800,9 +792,9 @@ static irqreturn_t xcan_interrupt(int ir + } + + /* Check for the type of receive interrupt and Processing it */ +- if (isr & (XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK)) { ++ if (isr & XCAN_IXR_RXNEMP_MASK) { + ier = priv->read_reg(priv, XCAN_IER_OFFSET); +- ier &= ~(XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK); ++ ier &= ~XCAN_IXR_RXNEMP_MASK; + priv->write_reg(priv, XCAN_IER_OFFSET, ier); + napi_schedule(&priv->napi); + } diff --git a/queue-4.17/can-xilinx_can-fix-rx-overflow-interrupt-not-being-enabled.patch b/queue-4.17/can-xilinx_can-fix-rx-overflow-interrupt-not-being-enabled.patch new file mode 100644 index 00000000000..078010ad134 --- /dev/null +++ b/queue-4.17/can-xilinx_can-fix-rx-overflow-interrupt-not-being-enabled.patch @@ -0,0 +1,37 @@ +From 83997997252f5d3fc7f04abc24a89600c2b504ab Mon Sep 17 00:00:00 2001 +From: Anssi Hannula +Date: Mon, 26 Feb 2018 14:27:13 +0200 +Subject: can: xilinx_can: fix RX overflow interrupt not being enabled + +From: Anssi Hannula + +commit 83997997252f5d3fc7f04abc24a89600c2b504ab upstream. + +RX overflow interrupt (RXOFLW) is disabled even though xcan_interrupt() +processes it. This means that an RX overflow interrupt will only be +processed when another interrupt gets asserted (e.g. for RX/TX). + +Fix that by enabling the RXOFLW interrupt. + +Fixes: b1201e44f50b ("can: xilinx CAN controller support") +Signed-off-by: Anssi Hannula +Cc: Michal Simek +Cc: +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/xilinx_can.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/can/xilinx_can.c ++++ b/drivers/net/can/xilinx_can.c +@@ -104,7 +104,7 @@ enum xcan_reg { + #define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ + XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ + XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ +- XCAN_IXR_ARBLST_MASK) ++ XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK) + + /* CAN register bit shift - XCAN___SHIFT */ + #define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ diff --git a/queue-4.17/can-xilinx_can-keep-only-1-2-frames-in-tx-fifo-to-fix-tx-accounting.patch b/queue-4.17/can-xilinx_can-keep-only-1-2-frames-in-tx-fifo-to-fix-tx-accounting.patch new file mode 100644 index 00000000000..423dbece3b3 --- /dev/null +++ b/queue-4.17/can-xilinx_can-keep-only-1-2-frames-in-tx-fifo-to-fix-tx-accounting.patch @@ -0,0 +1,335 @@ +From 620050d9c2be15c47017ba95efe59e0832e99a56 Mon Sep 17 00:00:00 2001 +From: Anssi Hannula +Date: Thu, 23 Feb 2017 14:50:03 +0200 +Subject: can: xilinx_can: keep only 1-2 frames in TX FIFO to fix TX accounting + +From: Anssi Hannula + +commit 620050d9c2be15c47017ba95efe59e0832e99a56 upstream. + +The xilinx_can driver assumes that the TXOK interrupt only clears after +it has been acknowledged as many times as there have been successfully +sent frames. + +However, the documentation does not mention such behavior, instead +saying just that the interrupt is cleared when the clear bit is set. + +Similarly, testing seems to also suggest that it is immediately cleared +regardless of the amount of frames having been sent. Performing some +heavy TX load and then going back to idle has the tx_head drifting +further away from tx_tail over time, steadily reducing the amount of +frames the driver keeps in the TX FIFO (but not to zero, as the TXOK +interrupt always frees up space for 1 frame from the driver's +perspective, so frames continue to be sent) and delaying the local echo +frames. + +The TX FIFO tracking is also otherwise buggy as it does not account for +TX FIFO being cleared after software resets, causing + BUG!, TX FIFO full when queue awake! +messages to be output. + +There does not seem to be any way to accurately track the state of the +TX FIFO for local echo support while using the full TX FIFO. + +The Zynq version of the HW (but not the soft-AXI version) has watermark +programming support and with it an additional TX-FIFO-empty interrupt +bit. + +Modify the driver to only put 1 frame into TX FIFO at a time on soft-AXI +and 2 frames at a time on Zynq. On Zynq the TXFEMP interrupt bit is used +to detect whether 1 or 2 frames have been sent at interrupt processing +time. + +Tested with the integrated CAN on Zynq-7000 SoC. The 1-frame-FIFO mode +was also tested. + +An alternative way to solve this would be to drop local echo support but +keep using the full TX FIFO. + +v2: Add FIFO space check before TX queue wake with locking to +synchronize with queue stop. This avoids waking the queue when xmit() +had just filled it. + +v3: Keep local echo support and reduce the amount of frames in FIFO +instead as suggested by Marc Kleine-Budde. + +Fixes: b1201e44f50b ("can: xilinx CAN controller support") +Signed-off-by: Anssi Hannula +Cc: +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/xilinx_can.c | 139 ++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 123 insertions(+), 16 deletions(-) + +--- a/drivers/net/can/xilinx_can.c ++++ b/drivers/net/can/xilinx_can.c +@@ -26,8 +26,10 @@ + #include + #include + #include ++#include + #include + #include ++#include + #include + #include + #include +@@ -119,6 +121,7 @@ enum xcan_reg { + /** + * struct xcan_priv - This definition define CAN driver instance + * @can: CAN private data structure. ++ * @tx_lock: Lock for synchronizing TX interrupt handling + * @tx_head: Tx CAN packets ready to send on the queue + * @tx_tail: Tx CAN packets successfully sended on the queue + * @tx_max: Maximum number packets the driver can send +@@ -133,6 +136,7 @@ enum xcan_reg { + */ + struct xcan_priv { + struct can_priv can; ++ spinlock_t tx_lock; + unsigned int tx_head; + unsigned int tx_tail; + unsigned int tx_max; +@@ -160,6 +164,11 @@ static const struct can_bittiming_const + .brp_inc = 1, + }; + ++#define XCAN_CAP_WATERMARK 0x0001 ++struct xcan_devtype_data { ++ unsigned int caps; ++}; ++ + /** + * xcan_write_reg_le - Write a value to the device register little endian + * @priv: Driver private data structure +@@ -239,6 +248,10 @@ static int set_reset_mode(struct net_dev + usleep_range(500, 10000); + } + ++ /* reset clears FIFOs */ ++ priv->tx_head = 0; ++ priv->tx_tail = 0; ++ + return 0; + } + +@@ -393,6 +406,7 @@ static int xcan_start_xmit(struct sk_buf + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf = (struct can_frame *)skb->data; + u32 id, dlc, data[2] = {0, 0}; ++ unsigned long flags; + + if (can_dropped_invalid_skb(ndev, skb)) + return NETDEV_TX_OK; +@@ -440,6 +454,9 @@ static int xcan_start_xmit(struct sk_buf + data[1] = be32_to_cpup((__be32 *)(cf->data + 4)); + + can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max); ++ ++ spin_lock_irqsave(&priv->tx_lock, flags); ++ + priv->tx_head++; + + /* Write the Frame to Xilinx CAN TX FIFO */ +@@ -455,10 +472,16 @@ static int xcan_start_xmit(struct sk_buf + stats->tx_bytes += cf->can_dlc; + } + ++ /* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */ ++ if (priv->tx_max > 1) ++ priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXFEMP_MASK); ++ + /* Check if the TX buffer is full */ + if ((priv->tx_head - priv->tx_tail) == priv->tx_max) + netif_stop_queue(ndev); + ++ spin_unlock_irqrestore(&priv->tx_lock, flags); ++ + return NETDEV_TX_OK; + } + +@@ -832,19 +855,71 @@ static void xcan_tx_interrupt(struct net + { + struct xcan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; ++ unsigned int frames_in_fifo; ++ int frames_sent = 1; /* TXOK => at least 1 frame was sent */ ++ unsigned long flags; ++ int retries = 0; ++ ++ /* Synchronize with xmit as we need to know the exact number ++ * of frames in the FIFO to stay in sync due to the TXFEMP ++ * handling. ++ * This also prevents a race between netif_wake_queue() and ++ * netif_stop_queue(). ++ */ ++ spin_lock_irqsave(&priv->tx_lock, flags); ++ ++ frames_in_fifo = priv->tx_head - priv->tx_tail; ++ ++ if (WARN_ON_ONCE(frames_in_fifo == 0)) { ++ /* clear TXOK anyway to avoid getting back here */ ++ priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); ++ spin_unlock_irqrestore(&priv->tx_lock, flags); ++ return; ++ } ++ ++ /* Check if 2 frames were sent (TXOK only means that at least 1 ++ * frame was sent). ++ */ ++ if (frames_in_fifo > 1) { ++ WARN_ON(frames_in_fifo > priv->tx_max); ++ ++ /* Synchronize TXOK and isr so that after the loop: ++ * (1) isr variable is up-to-date at least up to TXOK clear ++ * time. This avoids us clearing a TXOK of a second frame ++ * but not noticing that the FIFO is now empty and thus ++ * marking only a single frame as sent. ++ * (2) No TXOK is left. Having one could mean leaving a ++ * stray TXOK as we might process the associated frame ++ * via TXFEMP handling as we read TXFEMP *after* TXOK ++ * clear to satisfy (1). ++ */ ++ while ((isr & XCAN_IXR_TXOK_MASK) && !WARN_ON(++retries == 100)) { ++ priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); ++ isr = priv->read_reg(priv, XCAN_ISR_OFFSET); ++ } + +- while ((priv->tx_head - priv->tx_tail > 0) && +- (isr & XCAN_IXR_TXOK_MASK)) { ++ if (isr & XCAN_IXR_TXFEMP_MASK) { ++ /* nothing in FIFO anymore */ ++ frames_sent = frames_in_fifo; ++ } ++ } else { ++ /* single frame in fifo, just clear TXOK */ + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); ++ } ++ ++ while (frames_sent--) { + can_get_echo_skb(ndev, priv->tx_tail % + priv->tx_max); + priv->tx_tail++; + stats->tx_packets++; +- isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + } ++ ++ netif_wake_queue(ndev); ++ ++ spin_unlock_irqrestore(&priv->tx_lock, flags); ++ + can_led_event(ndev, CAN_LED_EVENT_TX); + xcan_update_error_state_after_rxtx(ndev); +- netif_wake_queue(ndev); + } + + /** +@@ -1138,6 +1213,18 @@ static const struct dev_pm_ops xcan_dev_ + SET_RUNTIME_PM_OPS(xcan_runtime_suspend, xcan_runtime_resume, NULL) + }; + ++static const struct xcan_devtype_data xcan_zynq_data = { ++ .caps = XCAN_CAP_WATERMARK, ++}; ++ ++/* Match table for OF platform binding */ ++static const struct of_device_id xcan_of_match[] = { ++ { .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data }, ++ { .compatible = "xlnx,axi-can-1.00.a", }, ++ { /* end of list */ }, ++}; ++MODULE_DEVICE_TABLE(of, xcan_of_match); ++ + /** + * xcan_probe - Platform registration call + * @pdev: Handle to the platform device structure +@@ -1152,8 +1239,10 @@ static int xcan_probe(struct platform_de + struct resource *res; /* IO mem resources */ + struct net_device *ndev; + struct xcan_priv *priv; ++ const struct of_device_id *of_id; ++ int caps = 0; + void __iomem *addr; +- int ret, rx_max, tx_max; ++ int ret, rx_max, tx_max, tx_fifo_depth; + + /* Get the virtual base address for the device */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -1163,7 +1252,8 @@ static int xcan_probe(struct platform_de + goto err; + } + +- ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", &tx_max); ++ ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", ++ &tx_fifo_depth); + if (ret < 0) + goto err; + +@@ -1171,6 +1261,30 @@ static int xcan_probe(struct platform_de + if (ret < 0) + goto err; + ++ of_id = of_match_device(xcan_of_match, &pdev->dev); ++ if (of_id) { ++ const struct xcan_devtype_data *devtype_data = of_id->data; ++ ++ if (devtype_data) ++ caps = devtype_data->caps; ++ } ++ ++ /* There is no way to directly figure out how many frames have been ++ * sent when the TXOK interrupt is processed. If watermark programming ++ * is supported, we can have 2 frames in the FIFO and use TXFEMP ++ * to determine if 1 or 2 frames have been sent. ++ * Theoretically we should be able to use TXFWMEMP to determine up ++ * to 3 frames, but it seems that after putting a second frame in the ++ * FIFO, with watermark at 2 frames, it can happen that TXFWMEMP (less ++ * than 2 frames in FIFO) is set anyway with no TXOK (a frame was ++ * sent), which is not a sensible state - possibly TXFWMEMP is not ++ * completely synchronized with the rest of the bits? ++ */ ++ if (caps & XCAN_CAP_WATERMARK) ++ tx_max = min(tx_fifo_depth, 2); ++ else ++ tx_max = 1; ++ + /* Create a CAN device instance */ + ndev = alloc_candev(sizeof(struct xcan_priv), tx_max); + if (!ndev) +@@ -1185,6 +1299,7 @@ static int xcan_probe(struct platform_de + CAN_CTRLMODE_BERR_REPORTING; + priv->reg_base = addr; + priv->tx_max = tx_max; ++ spin_lock_init(&priv->tx_lock); + + /* Get IRQ for the device */ + ndev->irq = platform_get_irq(pdev, 0); +@@ -1249,9 +1364,9 @@ static int xcan_probe(struct platform_de + + pm_runtime_put(&pdev->dev); + +- netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n", ++ netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth: actual %d, using %d\n", + priv->reg_base, ndev->irq, priv->can.clock.freq, +- priv->tx_max); ++ tx_fifo_depth, priv->tx_max); + + return 0; + +@@ -1285,14 +1400,6 @@ static int xcan_remove(struct platform_d + return 0; + } + +-/* Match table for OF platform binding */ +-static const struct of_device_id xcan_of_match[] = { +- { .compatible = "xlnx,zynq-can-1.0", }, +- { .compatible = "xlnx,axi-can-1.00.a", }, +- { /* end of list */ }, +-}; +-MODULE_DEVICE_TABLE(of, xcan_of_match); +- + static struct platform_driver xcan_driver = { + .probe = xcan_probe, + .remove = xcan_remove, diff --git a/queue-4.17/driver-core-partially-revert-driver-core-correct-device-s-shutdown-order.patch b/queue-4.17/driver-core-partially-revert-driver-core-correct-device-s-shutdown-order.patch new file mode 100644 index 00000000000..ca4cd9e2481 --- /dev/null +++ b/queue-4.17/driver-core-partially-revert-driver-core-correct-device-s-shutdown-order.patch @@ -0,0 +1,70 @@ +From 722e5f2b1eec7de61117b7c0a7914761e3da2eda Mon Sep 17 00:00:00 2001 +From: "Rafael J. Wysocki" +Date: Tue, 10 Jul 2018 14:51:33 +0200 +Subject: driver core: Partially revert "driver core: correct device's shutdown order" + +From: Rafael J. Wysocki + +commit 722e5f2b1eec7de61117b7c0a7914761e3da2eda upstream. + +Commit 52cdbdd49853 (driver core: correct device's shutdown order) +introduced a regression by breaking device shutdown on some systems. + +Namely, the devices_kset_move_last() call in really_probe() added by +that commit is a mistake as it may cause parents to follow children +in the devices_kset list which then causes shutdown to fail. For +example, if a device has children before really_probe() is called +for it (which is not uncommon), that call will cause it to be +reordered after the children in the devices_kset list and the +ordering of that list will not reflect the correct device shutdown +order any more. + +Also it causes the devices_kset list to be constantly reordered +until all drivers have been probed which is totally pointless +overhead in the majority of cases and it only covered an issue +with system shutdown, while system-wide suspend/resume potentially +had the same issue on the affected platforms (which was not covered). + +Moreover, the shutdown issue originally addressed by the change in +really_probe() made by commit 52cdbdd49853 is not present in 4.18-rc +any more, since dra7 started to use the sdhci-omap driver which +doesn't disable any regulators during shutdown, so the really_probe() +part of commit 52cdbdd49853 can be safely reverted. [The original +issue was related to the omap_hsmmc driver used by dra7 previously.] + +For the above reasons, revert the really_probe() modifications made +by commit 52cdbdd49853. + +The other code changes made by commit 52cdbdd49853 are useful and +they need not be reverted. + +Fixes: 52cdbdd49853 (driver core: correct device's shutdown order) +Link: https://lore.kernel.org/lkml/CAFgQCTt7VfqM=UyCnvNFxrSw8Z6cUtAi3HUwR4_xPAc03SgHjQ@mail.gmail.com/ +Reported-by: Pingfan Liu +Tested-by: Pingfan Liu +Reviewed-by: Kishon Vijay Abraham I +Signed-off-by: Rafael J. Wysocki +Cc: stable +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/base/dd.c | 8 -------- + 1 file changed, 8 deletions(-) + +--- a/drivers/base/dd.c ++++ b/drivers/base/dd.c +@@ -436,14 +436,6 @@ re_probe: + goto probe_failed; + } + +- /* +- * Ensure devices are listed in devices_kset in correct order +- * It's important to move Dev to the end of devices_kset before +- * calling .probe, because it could be recursive and parent Dev +- * should always go first +- */ +- devices_kset_move_last(dev); +- + if (dev->bus->probe) { + ret = dev->bus->probe(dev); + if (ret) diff --git a/queue-4.17/revert-staging-r8188eu-use-lib80211-to-support-tkip.patch b/queue-4.17/revert-staging-r8188eu-use-lib80211-to-support-tkip.patch new file mode 100644 index 00000000000..26a4c932eba --- /dev/null +++ b/queue-4.17/revert-staging-r8188eu-use-lib80211-to-support-tkip.patch @@ -0,0 +1,372 @@ +From 69a1d98c831ec64cbfd381f5dcb6697e1445d239 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sat, 14 Jul 2018 20:31:26 +0200 +Subject: Revert "staging:r8188eu: Use lib80211 to support TKIP" + +From: Hans de Goede + +commit 69a1d98c831ec64cbfd381f5dcb6697e1445d239 upstream. + +Commit b83b8b1881c4 ("staging:r8188eu: Use lib80211 to support TKIP") +is causing 2 problems for me: + +1) One boot the wifi on a laptop with a r8188eu wifi device would not + connect and dmesg contained an oops about scheduling while atomic + pointing to the tkip code. This went away after reverting the commit. + +2) I reverted the revert to try and get the oops from 1. again to be able + to add it to this commit message. But now the system did connect to the + wifi only to print a whole bunch of oopses, followed by a hardfreeze a + few seconds later. Subsequent reboots also all lead to scenario 2. Until + I reverted the commit again. + +Revert the commit fixes both issues making the laptop usable again. + +Fixes: b83b8b1881c4 ("staging:r8188eu: Use lib80211 to support TKIP") +Cc: stable@vger.kernel.org +Signed-off-by: Hans de Goede +Acked-by: Ivan Safonov +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/rtl8188eu/Kconfig | 1 + drivers/staging/rtl8188eu/core/rtw_recv.c | 163 ++++++++++++++++++-------- + drivers/staging/rtl8188eu/core/rtw_security.c | 94 +++++++------- + 3 files changed, 162 insertions(+), 96 deletions(-) + +--- a/drivers/staging/rtl8188eu/Kconfig ++++ b/drivers/staging/rtl8188eu/Kconfig +@@ -7,7 +7,6 @@ config R8188EU + select LIB80211 + select LIB80211_CRYPT_WEP + select LIB80211_CRYPT_CCMP +- select LIB80211_CRYPT_TKIP + ---help--- + This option adds the Realtek RTL8188EU USB device such as TP-Link TL-WN725N. + If built as a module, it will be called r8188eu. +--- a/drivers/staging/rtl8188eu/core/rtw_recv.c ++++ b/drivers/staging/rtl8188eu/core/rtw_recv.c +@@ -23,7 +23,6 @@ + #include + #include + #include +-#include + + #define ETHERNET_HEADER_SIZE 14 /* Ethernet Header Length */ + #define LLC_HEADER_SIZE 6 /* LLC Header Length */ +@@ -221,20 +220,31 @@ u32 rtw_free_uc_swdec_pending_queue(stru + static int recvframe_chkmic(struct adapter *adapter, + struct recv_frame *precvframe) + { +- int res = _SUCCESS; +- struct rx_pkt_attrib *prxattrib = &precvframe->attrib; +- struct sta_info *stainfo = rtw_get_stainfo(&adapter->stapriv, prxattrib->ta); ++ int i, res = _SUCCESS; ++ u32 datalen; ++ u8 miccode[8]; ++ u8 bmic_err = false, brpt_micerror = true; ++ u8 *pframe, *payload, *pframemic; ++ u8 *mickey; ++ struct sta_info *stainfo; ++ struct rx_pkt_attrib *prxattrib = &precvframe->attrib; ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]); + + if (prxattrib->encrypt == _TKIP_) { +- if (stainfo) { +- int key_idx; +- const int iv_len = 8, icv_len = 4, key_length = 32; +- struct sk_buff *skb = precvframe->pkt; +- u8 key[32], iv[8], icv[4], *pframe = skb->data; +- void *crypto_private = NULL; +- struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("TKIP"), "lib80211_crypt_tkip"); +- struct security_priv *psecuritypriv = &adapter->securitypriv; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ++ ("\n %s: prxattrib->encrypt==_TKIP_\n", __func__)); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ++ ("\n %s: da=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ __func__, prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], ++ prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5])); + ++ /* calculate mic code */ ++ if (stainfo) { + if (IS_MCAST(prxattrib->ra)) { + if (!psecuritypriv) { + res = _FAIL; +@@ -243,58 +253,115 @@ static int recvframe_chkmic(struct adapt + DBG_88E("\n %s: didn't install group key!!!!!!!!!!\n", __func__); + goto exit; + } +- key_idx = prxattrib->key_index; +- memcpy(key, psecuritypriv->dot118021XGrpKey[key_idx].skey, 16); +- memcpy(key + 16, psecuritypriv->dot118021XGrprxmickey[key_idx].skey, 16); ++ mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0]; ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ++ ("\n %s: bcmc key\n", __func__)); + } else { +- key_idx = 0; +- memcpy(key, stainfo->dot118021x_UncstKey.skey, 16); +- memcpy(key + 16, stainfo->dot11tkiprxmickey.skey, 16); ++ mickey = &stainfo->dot11tkiprxmickey.skey[0]; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ++ ("\n %s: unicast key\n", __func__)); + } + +- if (!crypto_ops) { +- res = _FAIL; +- goto exit_lib80211_tkip; +- } ++ /* icv_len included the mic code */ ++ datalen = precvframe->pkt->len-prxattrib->hdrlen - ++ prxattrib->iv_len-prxattrib->icv_len-8; ++ pframe = precvframe->pkt->data; ++ payload = pframe+prxattrib->hdrlen+prxattrib->iv_len; ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len)); ++ rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0], ++ (unsigned char)prxattrib->priority); /* care the length of the data */ + +- memcpy(iv, pframe + prxattrib->hdrlen, iv_len); +- memcpy(icv, pframe + skb->len - icv_len, icv_len); +- memmove(pframe + iv_len, pframe, prxattrib->hdrlen); ++ pframemic = payload+datalen; + +- skb_pull(skb, iv_len); +- skb_trim(skb, skb->len - icv_len); ++ bmic_err = false; + +- crypto_private = crypto_ops->init(key_idx); +- if (!crypto_private) { +- res = _FAIL; +- goto exit_lib80211_tkip; +- } +- if (crypto_ops->set_key(key, key_length, NULL, crypto_private) < 0) { +- res = _FAIL; +- goto exit_lib80211_tkip; ++ for (i = 0; i < 8; i++) { ++ if (miccode[i] != *(pframemic+i)) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ++ ("%s: miccode[%d](%02x)!=*(pframemic+%d)(%02x) ", ++ __func__, i, miccode[i], i, *(pframemic + i))); ++ bmic_err = true; ++ } + } +- if (crypto_ops->decrypt_msdu(skb, key_idx, prxattrib->hdrlen, crypto_private)) { ++ ++ if (bmic_err) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ++ ("\n *(pframemic-8)-*(pframemic-1)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ *(pframemic-8), *(pframemic-7), *(pframemic-6), ++ *(pframemic-5), *(pframemic-4), *(pframemic-3), ++ *(pframemic-2), *(pframemic-1))); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ++ ("\n *(pframemic-16)-*(pframemic-9)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ *(pframemic-16), *(pframemic-15), *(pframemic-14), ++ *(pframemic-13), *(pframemic-12), *(pframemic-11), ++ *(pframemic-10), *(pframemic-9))); ++ { ++ uint i; ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ++ ("\n ======demp packet (len=%d)======\n", ++ precvframe->pkt->len)); ++ for (i = 0; i < precvframe->pkt->len; i += 8) { ++ RT_TRACE(_module_rtl871x_recv_c_, ++ _drv_err_, ++ ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x", ++ *(precvframe->pkt->data+i), ++ *(precvframe->pkt->data+i+1), ++ *(precvframe->pkt->data+i+2), ++ *(precvframe->pkt->data+i+3), ++ *(precvframe->pkt->data+i+4), ++ *(precvframe->pkt->data+i+5), ++ *(precvframe->pkt->data+i+6), ++ *(precvframe->pkt->data+i+7))); ++ } ++ RT_TRACE(_module_rtl871x_recv_c_, ++ _drv_err_, ++ ("\n ====== demp packet end [len=%d]======\n", ++ precvframe->pkt->len)); ++ RT_TRACE(_module_rtl871x_recv_c_, ++ _drv_err_, ++ ("\n hrdlen=%d,\n", ++ prxattrib->hdrlen)); ++ } ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ++ ("ra=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey=%d ", ++ prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], ++ prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5], psecuritypriv->binstallGrpkey)); ++ ++ /* double check key_index for some timing issue , */ ++ /* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */ ++ if ((IS_MCAST(prxattrib->ra) == true) && (prxattrib->key_index != pmlmeinfo->key_index)) ++ brpt_micerror = false; ++ ++ if ((prxattrib->bdecrypted) && (brpt_micerror)) { ++ rtw_handle_tkip_mic_err(adapter, (u8)IS_MCAST(prxattrib->ra)); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted)); ++ DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); ++ } else { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted)); ++ DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); ++ } + res = _FAIL; +- goto exit_lib80211_tkip; ++ } else { ++ /* mic checked ok */ ++ if ((!psecuritypriv->bcheck_grpkey) && (IS_MCAST(prxattrib->ra))) { ++ psecuritypriv->bcheck_grpkey = true; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("psecuritypriv->bcheck_grpkey = true")); ++ } + } +- +- memmove(pframe, pframe + iv_len, prxattrib->hdrlen); +- skb_push(skb, iv_len); +- skb_put(skb, icv_len); +- +- memcpy(pframe + prxattrib->hdrlen, iv, iv_len); +- memcpy(pframe + skb->len - icv_len, icv, icv_len); +- +-exit_lib80211_tkip: +- if (crypto_ops && crypto_private) +- crypto_ops->deinit(crypto_private); + } else { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("%s: rtw_get_stainfo==NULL!!!\n", __func__)); + } ++ ++ skb_trim(precvframe->pkt, precvframe->pkt->len - 8); + } + + exit: ++ + return res; + } + +--- a/drivers/staging/rtl8188eu/core/rtw_security.c ++++ b/drivers/staging/rtl8188eu/core/rtw_security.c +@@ -650,71 +650,71 @@ u32 rtw_tkip_encrypt(struct adapter *pad + return res; + } + ++/* The hlen isn't include the IV */ + u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) +-{ +- struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; +- u32 res = _SUCCESS; ++{ /* exclude ICV */ ++ u16 pnl; ++ u32 pnh; ++ u8 rc4key[16]; ++ u8 ttkey[16]; ++ u8 crc[4]; ++ struct arc4context mycontext; ++ int length; ++ ++ u8 *pframe, *payload, *iv, *prwskey; ++ union pn48 dot11txpn; ++ struct sta_info *stainfo; ++ struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ u32 res = _SUCCESS; ++ ++ ++ pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data; + + /* 4 start to decrypt recvframe */ + if (prxattrib->encrypt == _TKIP_) { +- struct sta_info *stainfo = rtw_get_stainfo(&padapter->stapriv, prxattrib->ta); +- ++ stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); + if (stainfo) { +- int key_idx; +- const int iv_len = 8, icv_len = 4, key_length = 32; +- void *crypto_private = NULL; +- struct sk_buff *skb = ((struct recv_frame *)precvframe)->pkt; +- u8 key[32], iv[8], icv[4], *pframe = skb->data; +- struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("TKIP"), "lib80211_crypt_tkip"); +- struct security_priv *psecuritypriv = &padapter->securitypriv; +- + if (IS_MCAST(prxattrib->ra)) { + if (!psecuritypriv->binstallGrpkey) { + res = _FAIL; + DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__); + goto exit; + } +- key_idx = prxattrib->key_index; +- memcpy(key, psecuritypriv->dot118021XGrpKey[key_idx].skey, 16); +- memcpy(key + 16, psecuritypriv->dot118021XGrprxmickey[key_idx].skey, 16); ++ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; + } else { +- key_idx = 0; +- memcpy(key, stainfo->dot118021x_UncstKey.skey, 16); +- memcpy(key + 16, stainfo->dot11tkiprxmickey.skey, 16); ++ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__)); ++ prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + } + +- if (!crypto_ops) { +- res = _FAIL; +- goto exit_lib80211_tkip; +- } ++ iv = pframe+prxattrib->hdrlen; ++ payload = pframe+prxattrib->iv_len+prxattrib->hdrlen; ++ length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len; + +- memcpy(iv, pframe + prxattrib->hdrlen, iv_len); +- memcpy(icv, pframe + skb->len - icv_len, icv_len); ++ GET_TKIP_PN(iv, dot11txpn); + +- crypto_private = crypto_ops->init(key_idx); +- if (!crypto_private) { +- res = _FAIL; +- goto exit_lib80211_tkip; +- } +- if (crypto_ops->set_key(key, key_length, NULL, crypto_private) < 0) { +- res = _FAIL; +- goto exit_lib80211_tkip; +- } +- if (crypto_ops->decrypt_mpdu(skb, prxattrib->hdrlen, crypto_private)) { ++ pnl = (u16)(dot11txpn.val); ++ pnh = (u32)(dot11txpn.val>>16); ++ ++ phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], pnh); ++ phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl); ++ ++ /* 4 decrypt payload include icv */ ++ ++ arcfour_init(&mycontext, rc4key, 16); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ ++ *((__le32 *)crc) = getcrc32(payload, length-4); ++ ++ if (crc[3] != payload[length-1] || ++ crc[2] != payload[length-2] || ++ crc[1] != payload[length-3] || ++ crc[0] != payload[length-4]) { ++ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ++ ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n", ++ &crc, &payload[length-4])); + res = _FAIL; +- goto exit_lib80211_tkip; + } +- +- memmove(pframe, pframe + iv_len, prxattrib->hdrlen); +- skb_push(skb, iv_len); +- skb_put(skb, icv_len); +- +- memcpy(pframe + prxattrib->hdrlen, iv, iv_len); +- memcpy(pframe + skb->len - icv_len, icv, icv_len); +- +-exit_lib80211_tkip: +- if (crypto_ops && crypto_private) +- crypto_ops->deinit(crypto_private); + } else { + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo==NULL!!!\n")); + res = _FAIL; diff --git a/queue-4.17/series b/queue-4.17/series index 5bf12943b4f..c0de36dc5e6 100644 --- a/queue-4.17/series +++ b/queue-4.17/series @@ -44,3 +44,23 @@ tcp-avoid-collapses-in-tcp_prune_queue-if-possible.patch tcp-detect-malicious-patterns-in-tcp_collapse_ofo_queue.patch tcp-call-tcp_drop-from-tcp_data_queue_ofo.patch tcp-add-tcp_ooo_try_coalesce-helper.patch +revert-staging-r8188eu-use-lib80211-to-support-tkip.patch +staging-speakup-fix-wraparound-in-uaccess-length-check.patch +usb-cdc_acm-add-quirk-for-castles-vega3000.patch +usb-core-handle-hub-c_port_over_current-condition.patch +usb-dwc2-fix-dma-alignment-to-start-at-allocated-boundary.patch +usb-xhci-fix-memory-leak-in-xhci_endpoint_reset.patch +usb-gadget-fix-os-descriptors-support.patch +usb-gadget-f_fs-only-return-delayed-status-when-len-is-0.patch +acpica-aml-parser-ignore-dispatcher-error-status-during-table-load.patch +driver-core-partially-revert-driver-core-correct-device-s-shutdown-order.patch +can-xilinx_can-fix-rx-loop-if-rxnemp-is-asserted-without-rxok.patch +can-xilinx_can-fix-power-management-handling.patch +can-xilinx_can-fix-recovery-from-error-states-not-being-propagated.patch +can-xilinx_can-fix-device-dropping-off-bus-on-rx-overrun.patch +can-xilinx_can-keep-only-1-2-frames-in-tx-fifo-to-fix-tx-accounting.patch +can-xilinx_can-fix-incorrect-clear-of-non-processed-interrupts.patch +can-xilinx_can-fix-rx-overflow-interrupt-not-being-enabled.patch +can-peak_canfd-fix-firmware-v3.3.0-limit-allocation-to-32-bit-dma-addr-only.patch +can-m_can-fix-runtime-resume-call.patch +can-m_can.c-fix-setup-of-cccr-register-clear-cccr-niso-bit-before-checking-can.ctrlmode.patch diff --git a/queue-4.17/staging-speakup-fix-wraparound-in-uaccess-length-check.patch b/queue-4.17/staging-speakup-fix-wraparound-in-uaccess-length-check.patch new file mode 100644 index 00000000000..545fcdb5c09 --- /dev/null +++ b/queue-4.17/staging-speakup-fix-wraparound-in-uaccess-length-check.patch @@ -0,0 +1,52 @@ +From b96fba8d5855c3617adbfb43ca4723a808cac954 Mon Sep 17 00:00:00 2001 +From: Samuel Thibault +Date: Fri, 13 Jul 2018 00:29:36 +0200 +Subject: staging: speakup: fix wraparound in uaccess length check + +From: Samuel Thibault + +commit b96fba8d5855c3617adbfb43ca4723a808cac954 upstream. + +If softsynthx_read() is called with `count < 3`, `count - 3` wraps, causing +the loop to copy as much data as available to the provided buffer. If +softsynthx_read() is invoked through sys_splice(), this causes an +unbounded kernel write; but even when userspace just reads from it +normally, a small size could cause userspace crashes. + +Fixes: 425e586cf95b ("speakup: add unicode variant of /dev/softsynth") +Cc: stable@vger.kernel.org +Signed-off-by: Samuel Thibault +Signed-off-by: Jann Horn +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/speakup/speakup_soft.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/staging/speakup/speakup_soft.c ++++ b/drivers/staging/speakup/speakup_soft.c +@@ -197,11 +197,15 @@ static ssize_t softsynthx_read(struct fi + int chars_sent = 0; + char __user *cp; + char *init; ++ size_t bytes_per_ch = unicode ? 3 : 1; + u16 ch; + int empty; + unsigned long flags; + DEFINE_WAIT(wait); + ++ if (count < bytes_per_ch) ++ return -EINVAL; ++ + spin_lock_irqsave(&speakup_info.spinlock, flags); + while (1) { + prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE); +@@ -227,7 +231,7 @@ static ssize_t softsynthx_read(struct fi + init = get_initstring(); + + /* Keep 3 bytes available for a 16bit UTF-8-encoded character */ +- while (chars_sent <= count - 3) { ++ while (chars_sent <= count - bytes_per_ch) { + if (speakup_info.flushing) { + speakup_info.flushing = 0; + ch = '\x18'; diff --git a/queue-4.17/usb-cdc_acm-add-quirk-for-castles-vega3000.patch b/queue-4.17/usb-cdc_acm-add-quirk-for-castles-vega3000.patch new file mode 100644 index 00000000000..d749c67a990 --- /dev/null +++ b/queue-4.17/usb-cdc_acm-add-quirk-for-castles-vega3000.patch @@ -0,0 +1,33 @@ +From 1445cbe476fc3dd09c0b380b206526a49403c071 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Tue, 10 Jul 2018 08:28:49 +0200 +Subject: usb: cdc_acm: Add quirk for Castles VEGA3000 + +From: Lubomir Rintel + +commit 1445cbe476fc3dd09c0b380b206526a49403c071 upstream. + +The device (a POS terminal) implements CDC ACM, but has not union +descriptor. + +Signed-off-by: Lubomir Rintel +Acked-by: Oliver Neukum +Cc: stable +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/class/cdc-acm.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1831,6 +1831,9 @@ static const struct usb_device_id acm_id + { USB_DEVICE(0x09d8, 0x0320), /* Elatec GmbH TWN3 */ + .driver_info = NO_UNION_NORMAL, /* has misplaced union descriptor */ + }, ++ { USB_DEVICE(0x0ca6, 0xa050), /* Castles VEGA3000 */ ++ .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ ++ }, + + { USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */ + .driver_info = CLEAR_HALT_CONDITIONS, diff --git a/queue-4.17/usb-core-handle-hub-c_port_over_current-condition.patch b/queue-4.17/usb-core-handle-hub-c_port_over_current-condition.patch new file mode 100644 index 00000000000..a24647b4f3e --- /dev/null +++ b/queue-4.17/usb-core-handle-hub-c_port_over_current-condition.patch @@ -0,0 +1,49 @@ +From 249a32b7eeb3edb6897dd38f89651a62163ac4ed Mon Sep 17 00:00:00 2001 +From: Bin Liu +Date: Thu, 19 Jul 2018 14:39:37 -0500 +Subject: usb: core: handle hub C_PORT_OVER_CURRENT condition + +From: Bin Liu + +commit 249a32b7eeb3edb6897dd38f89651a62163ac4ed upstream. + +Based on USB2.0 Spec Section 11.12.5, + + "If a hub has per-port power switching and per-port current limiting, + an over-current on one port may still cause the power on another port + to fall below specific minimums. In this case, the affected port is + placed in the Power-Off state and C_PORT_OVER_CURRENT is set for the + port, but PORT_OVER_CURRENT is not set." + +so let's check C_PORT_OVER_CURRENT too for over current condition. + +Fixes: 08d1dec6f405 ("usb:hub set hub->change_bits when over-current happens") +Cc: +Tested-by: Alessandro Antenucci +Signed-off-by: Bin Liu +Acked-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/hub.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -1142,10 +1142,14 @@ static void hub_activate(struct usb_hub + + if (!udev || udev->state == USB_STATE_NOTATTACHED) { + /* Tell hub_wq to disconnect the device or +- * check for a new connection ++ * check for a new connection or over current condition. ++ * Based on USB2.0 Spec Section 11.12.5, ++ * C_PORT_OVER_CURRENT could be set while ++ * PORT_OVER_CURRENT is not. So check for any of them. + */ + if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || +- (portstatus & USB_PORT_STAT_OVERCURRENT)) ++ (portstatus & USB_PORT_STAT_OVERCURRENT) || ++ (portchange & USB_PORT_STAT_C_OVERCURRENT)) + set_bit(port1, hub->change_bits); + + } else if (portstatus & USB_PORT_STAT_ENABLE) { diff --git a/queue-4.17/usb-dwc2-fix-dma-alignment-to-start-at-allocated-boundary.patch b/queue-4.17/usb-dwc2-fix-dma-alignment-to-start-at-allocated-boundary.patch new file mode 100644 index 00000000000..1ebf57a2854 --- /dev/null +++ b/queue-4.17/usb-dwc2-fix-dma-alignment-to-start-at-allocated-boundary.patch @@ -0,0 +1,132 @@ +From 56406e017a883b54b339207b230f85599f4d70ae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Antti=20Sepp=C3=A4l=C3=A4?= +Date: Thu, 5 Jul 2018 17:31:53 +0300 +Subject: usb: dwc2: Fix DMA alignment to start at allocated boundary +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Antti Seppälä + +commit 56406e017a883b54b339207b230f85599f4d70ae upstream. + +The commit 3bc04e28a030 ("usb: dwc2: host: Get aligned DMA in a more +supported way") introduced a common way to align DMA allocations. +The code in the commit aligns the struct dma_aligned_buffer but the +actual DMA address pointed by data[0] gets aligned to an offset from +the allocated boundary by the kmalloc_ptr and the old_xfer_buffer +pointers. + +This is against the recommendation in Documentation/DMA-API.txt which +states: + + Therefore, it is recommended that driver writers who don't take + special care to determine the cache line size at run time only map + virtual regions that begin and end on page boundaries (which are + guaranteed also to be cache line boundaries). + +The effect of this is that architectures with non-coherent DMA caches +may run into memory corruption or kernel crashes with Unhandled +kernel unaligned accesses exceptions. + +Fix the alignment by positioning the DMA area in front of the allocation +and use memory at the end of the area for storing the orginal +transfer_buffer pointer. This may have the added benefit of increased +performance as the DMA area is now fully aligned on all architectures. + +Tested with Lantiq xRX200 (MIPS) and RPi Model B Rev 2 (ARM). + +Fixes: 3bc04e28a030 ("usb: dwc2: host: Get aligned DMA in a more supported way") +Cc: +Reviewed-by: Douglas Anderson +Signed-off-by: Antti Seppälä +Signed-off-by: Felipe Balbi +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/dwc2/hcd.c | 44 +++++++++++++++++++++++--------------------- + 1 file changed, 23 insertions(+), 21 deletions(-) + +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -2627,34 +2627,29 @@ static void dwc2_hc_init_xfer(struct dwc + + #define DWC2_USB_DMA_ALIGN 4 + +-struct dma_aligned_buffer { +- void *kmalloc_ptr; +- void *old_xfer_buffer; +- u8 data[0]; +-}; +- + static void dwc2_free_dma_aligned_buffer(struct urb *urb) + { +- struct dma_aligned_buffer *temp; ++ void *stored_xfer_buffer; + + if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) + return; + +- temp = container_of(urb->transfer_buffer, +- struct dma_aligned_buffer, data); ++ /* Restore urb->transfer_buffer from the end of the allocated area */ ++ memcpy(&stored_xfer_buffer, urb->transfer_buffer + ++ urb->transfer_buffer_length, sizeof(urb->transfer_buffer)); + + if (usb_urb_dir_in(urb)) +- memcpy(temp->old_xfer_buffer, temp->data, ++ memcpy(stored_xfer_buffer, urb->transfer_buffer, + urb->transfer_buffer_length); +- urb->transfer_buffer = temp->old_xfer_buffer; +- kfree(temp->kmalloc_ptr); ++ kfree(urb->transfer_buffer); ++ urb->transfer_buffer = stored_xfer_buffer; + + urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; + } + + static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) + { +- struct dma_aligned_buffer *temp, *kmalloc_ptr; ++ void *kmalloc_ptr; + size_t kmalloc_size; + + if (urb->num_sgs || urb->sg || +@@ -2662,22 +2657,29 @@ static int dwc2_alloc_dma_aligned_buffer + !((uintptr_t)urb->transfer_buffer & (DWC2_USB_DMA_ALIGN - 1))) + return 0; + +- /* Allocate a buffer with enough padding for alignment */ ++ /* ++ * Allocate a buffer with enough padding for original transfer_buffer ++ * pointer. This allocation is guaranteed to be aligned properly for ++ * DMA ++ */ + kmalloc_size = urb->transfer_buffer_length + +- sizeof(struct dma_aligned_buffer) + DWC2_USB_DMA_ALIGN - 1; ++ sizeof(urb->transfer_buffer); + + kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); + if (!kmalloc_ptr) + return -ENOMEM; + +- /* Position our struct dma_aligned_buffer such that data is aligned */ +- temp = PTR_ALIGN(kmalloc_ptr + 1, DWC2_USB_DMA_ALIGN) - 1; +- temp->kmalloc_ptr = kmalloc_ptr; +- temp->old_xfer_buffer = urb->transfer_buffer; ++ /* ++ * Position value of original urb->transfer_buffer pointer to the end ++ * of allocation for later referencing ++ */ ++ memcpy(kmalloc_ptr + urb->transfer_buffer_length, ++ &urb->transfer_buffer, sizeof(urb->transfer_buffer)); ++ + if (usb_urb_dir_out(urb)) +- memcpy(temp->data, urb->transfer_buffer, ++ memcpy(kmalloc_ptr, urb->transfer_buffer, + urb->transfer_buffer_length); +- urb->transfer_buffer = temp->data; ++ urb->transfer_buffer = kmalloc_ptr; + + urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; + diff --git a/queue-4.17/usb-gadget-f_fs-only-return-delayed-status-when-len-is-0.patch b/queue-4.17/usb-gadget-f_fs-only-return-delayed-status-when-len-is-0.patch new file mode 100644 index 00000000000..f80d7dcb14f --- /dev/null +++ b/queue-4.17/usb-gadget-f_fs-only-return-delayed-status-when-len-is-0.patch @@ -0,0 +1,54 @@ +From 4d644abf25698362bd33d17c9ddc8f7122c30f17 Mon Sep 17 00:00:00 2001 +From: Jerry Zhang +Date: Mon, 2 Jul 2018 12:48:08 -0700 +Subject: usb: gadget: f_fs: Only return delayed status when len is 0 + +From: Jerry Zhang + +commit 4d644abf25698362bd33d17c9ddc8f7122c30f17 upstream. + +Commit 1b9ba000 ("Allow function drivers to pause control +transfers") states that USB_GADGET_DELAYED_STATUS is only +supported if data phase is 0 bytes. + +It seems that when the length is not 0 bytes, there is no +need to explicitly delay the data stage since the transfer +is not completed until the user responds. However, when the +length is 0, there is no data stage and the transfer is +finished once setup() returns, hence there is a need to +explicitly delay completion. + +This manifests as the following bugs: + +Prior to 946ef68ad4e4 ('Let setup() return +USB_GADGET_DELAYED_STATUS'), when setup is 0 bytes, ffs +would require user to queue a 0 byte request in order to +clear setup state. However, that 0 byte request was actually +not needed and would hang and cause errors in other setup +requests. + +After the above commit, 0 byte setups work since the gadget +now accepts empty queues to ep0 to clear the delay, but all +other setups hang. + +Fixes: 946ef68ad4e4 ("Let setup() return USB_GADGET_DELAYED_STATUS") +Signed-off-by: Jerry Zhang +Cc: stable +Acked-by: Felipe Balbi +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/gadget/function/f_fs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/gadget/function/f_fs.c ++++ b/drivers/usb/gadget/function/f_fs.c +@@ -3242,7 +3242,7 @@ static int ffs_func_setup(struct usb_fun + __ffs_event_add(ffs, FUNCTIONFS_SETUP); + spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); + +- return USB_GADGET_DELAYED_STATUS; ++ return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0; + } + + static bool ffs_func_req_match(struct usb_function *f, diff --git a/queue-4.17/usb-gadget-fix-os-descriptors-support.patch b/queue-4.17/usb-gadget-fix-os-descriptors-support.patch new file mode 100644 index 00000000000..642f8264090 --- /dev/null +++ b/queue-4.17/usb-gadget-fix-os-descriptors-support.patch @@ -0,0 +1,39 @@ +From 50b9773c13bffbef32060e67c4483ea7b2eca7b5 Mon Sep 17 00:00:00 2001 +From: Benjamin Herrenschmidt +Date: Wed, 27 Jun 2018 12:33:56 +1000 +Subject: usb: gadget: Fix OS descriptors support + +From: Benjamin Herrenschmidt + +commit 50b9773c13bffbef32060e67c4483ea7b2eca7b5 upstream. + +The current code is broken as it re-defines "req" inside the +if block, then goto out of it. Thus the request that ends +up being sent is not the one that was populated by the +code in question. + +This fixes RNDIS driver autodetect by Windows 10 for me. + +The bug was introduced by Chris rework to remove the local +queuing inside the if { } block of the redefined request. + +Fixes: 636ba13aec8a ("usb: gadget: composite: remove duplicated code in OS desc handling") +Cc: # v4.17 +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Felipe Balbi +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/gadget/composite.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/usb/gadget/composite.c ++++ b/drivers/usb/gadget/composite.c +@@ -1816,7 +1816,6 @@ unknown: + if (cdev->use_os_string && cdev->os_desc_config && + (ctrl->bRequestType & USB_TYPE_VENDOR) && + ctrl->bRequest == cdev->b_vendor_code) { +- struct usb_request *req; + struct usb_configuration *os_desc_cfg; + u8 *buf; + int interface; diff --git a/queue-4.17/usb-xhci-fix-memory-leak-in-xhci_endpoint_reset.patch b/queue-4.17/usb-xhci-fix-memory-leak-in-xhci_endpoint_reset.patch new file mode 100644 index 00000000000..a1a6449eef8 --- /dev/null +++ b/queue-4.17/usb-xhci-fix-memory-leak-in-xhci_endpoint_reset.patch @@ -0,0 +1,31 @@ +From d89b7664f76047e7beca8f07e86f2ccfad085a28 Mon Sep 17 00:00:00 2001 +From: Zheng Xiaowei +Date: Fri, 20 Jul 2018 18:05:11 +0300 +Subject: usb: xhci: Fix memory leak in xhci_endpoint_reset() + +From: Zheng Xiaowei + +commit d89b7664f76047e7beca8f07e86f2ccfad085a28 upstream. + +If td_list is not empty the cfg_cmd will not be freed, +call xhci_free_command to free it. + +Signed-off-by: Zheng Xiaowei +Cc: +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -2981,6 +2981,7 @@ static void xhci_endpoint_reset(struct u + if (!list_empty(&ep->ring->td_list)) { + dev_err(&udev->dev, "EP not empty, refuse reset\n"); + spin_unlock_irqrestore(&xhci->lock, flags); ++ xhci_free_command(xhci, cfg_cmd); + goto cleanup; + } + xhci_queue_stop_endpoint(xhci, stop_cmd, udev->slot_id, ep_index, 0);