]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 19 Dec 2019 08:55:22 +0000 (09:55 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 19 Dec 2019 08:55:22 +0000 (09:55 +0100)
added patches:
usb-fix-incorrect-dma-allocations-for-local-memory-pool-drivers.patch

queue-5.4/series [new file with mode: 0644]
queue-5.4/usb-fix-incorrect-dma-allocations-for-local-memory-pool-drivers.patch [new file with mode: 0644]

diff --git a/queue-5.4/series b/queue-5.4/series
new file mode 100644 (file)
index 0000000..77d1182
--- /dev/null
@@ -0,0 +1 @@
+usb-fix-incorrect-dma-allocations-for-local-memory-pool-drivers.patch
diff --git a/queue-5.4/usb-fix-incorrect-dma-allocations-for-local-memory-pool-drivers.patch b/queue-5.4/usb-fix-incorrect-dma-allocations-for-local-memory-pool-drivers.patch
new file mode 100644 (file)
index 0000000..800a1b5
--- /dev/null
@@ -0,0 +1,126 @@
+From f8c63edfd78905320e86b6b2be2b7a5ac768fa4e Mon Sep 17 00:00:00 2001
+From: Fredrik Noring <noring@nocrew.org>
+Date: Tue, 10 Dec 2019 18:29:05 +0100
+Subject: USB: Fix incorrect DMA allocations for local memory pool drivers
+
+From: Fredrik Noring <noring@nocrew.org>
+
+commit f8c63edfd78905320e86b6b2be2b7a5ac768fa4e upstream.
+
+Fix commit 7b81cb6bddd2 ("usb: add a HCD_DMA flag instead of
+guestimating DMA capabilities") where local memory USB drivers
+erroneously allocate DMA memory instead of pool memory, causing
+
+       OHCI Unrecoverable Error, disabled
+       HC died; cleaning up
+
+The order between hcd_uses_dma() and hcd->localmem_pool is now
+arranged as in hcd_buffer_alloc() and hcd_buffer_free(), with the
+test for hcd->localmem_pool placed first.
+
+As an alternative, one might consider adjusting hcd_uses_dma() with
+
+ static inline bool hcd_uses_dma(struct usb_hcd *hcd)
+ {
+-      return IS_ENABLED(CONFIG_HAS_DMA) && (hcd->driver->flags & HCD_DMA);
++      return IS_ENABLED(CONFIG_HAS_DMA) &&
++              (hcd->driver->flags & HCD_DMA) &&
++              (hcd->localmem_pool == NULL);
+ }
+
+One can also consider unsetting HCD_DMA for local memory pool drivers.
+
+Fixes: 7b81cb6bddd2 ("usb: add a HCD_DMA flag instead of guestimating DMA capabilities")
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Fredrik Noring <noring@nocrew.org>
+Link: https://lore.kernel.org/r/20191210172905.GA52526@sx9
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/core/hcd.c         |   42 ++++++++++++++++++++---------------------
+ drivers/usb/storage/scsiglue.c |    3 +-
+ 2 files changed, 23 insertions(+), 22 deletions(-)
+
+--- a/drivers/usb/core/hcd.c
++++ b/drivers/usb/core/hcd.c
+@@ -1409,7 +1409,17 @@ int usb_hcd_map_urb_for_dma(struct usb_h
+       if (usb_endpoint_xfer_control(&urb->ep->desc)) {
+               if (hcd->self.uses_pio_for_control)
+                       return ret;
+-              if (hcd_uses_dma(hcd)) {
++              if (hcd->localmem_pool) {
++                      ret = hcd_alloc_coherent(
++                                      urb->dev->bus, mem_flags,
++                                      &urb->setup_dma,
++                                      (void **)&urb->setup_packet,
++                                      sizeof(struct usb_ctrlrequest),
++                                      DMA_TO_DEVICE);
++                      if (ret)
++                              return ret;
++                      urb->transfer_flags |= URB_SETUP_MAP_LOCAL;
++              } else if (hcd_uses_dma(hcd)) {
+                       if (is_vmalloc_addr(urb->setup_packet)) {
+                               WARN_ONCE(1, "setup packet is not dma capable\n");
+                               return -EAGAIN;
+@@ -1427,23 +1437,22 @@ int usb_hcd_map_urb_for_dma(struct usb_h
+                                               urb->setup_dma))
+                               return -EAGAIN;
+                       urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
+-              } else if (hcd->localmem_pool) {
+-                      ret = hcd_alloc_coherent(
+-                                      urb->dev->bus, mem_flags,
+-                                      &urb->setup_dma,
+-                                      (void **)&urb->setup_packet,
+-                                      sizeof(struct usb_ctrlrequest),
+-                                      DMA_TO_DEVICE);
+-                      if (ret)
+-                              return ret;
+-                      urb->transfer_flags |= URB_SETUP_MAP_LOCAL;
+               }
+       }
+       dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+       if (urb->transfer_buffer_length != 0
+           && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
+-              if (hcd_uses_dma(hcd)) {
++              if (hcd->localmem_pool) {
++                      ret = hcd_alloc_coherent(
++                                      urb->dev->bus, mem_flags,
++                                      &urb->transfer_dma,
++                                      &urb->transfer_buffer,
++                                      urb->transfer_buffer_length,
++                                      dir);
++                      if (ret == 0)
++                              urb->transfer_flags |= URB_MAP_LOCAL;
++              } else if (hcd_uses_dma(hcd)) {
+                       if (urb->num_sgs) {
+                               int n;
+@@ -1497,15 +1506,6 @@ int usb_hcd_map_urb_for_dma(struct usb_h
+                               else
+                                       urb->transfer_flags |= URB_DMA_MAP_SINGLE;
+                       }
+-              } else if (hcd->localmem_pool) {
+-                      ret = hcd_alloc_coherent(
+-                                      urb->dev->bus, mem_flags,
+-                                      &urb->transfer_dma,
+-                                      &urb->transfer_buffer,
+-                                      urb->transfer_buffer_length,
+-                                      dir);
+-                      if (ret == 0)
+-                              urb->transfer_flags |= URB_MAP_LOCAL;
+               }
+               if (ret && (urb->transfer_flags & (URB_SETUP_MAP_SINGLE |
+                               URB_SETUP_MAP_LOCAL)))
+--- a/drivers/usb/storage/scsiglue.c
++++ b/drivers/usb/storage/scsiglue.c
+@@ -135,7 +135,8 @@ static int slave_configure(struct scsi_d
+        * For such controllers we need to make sure the block layer sets
+        * up bounce buffers in addressable memory.
+        */
+-      if (!hcd_uses_dma(bus_to_hcd(us->pusb_dev->bus)))
++      if (!hcd_uses_dma(bus_to_hcd(us->pusb_dev->bus)) ||
++                      (bus_to_hcd(us->pusb_dev->bus)->localmem_pool != NULL))
+               blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_HIGH);
+       /*