patch "USB: Fix incorrect DMA allocations for local memory pool drivers" added to usb-linus
Subsystems (3)
This is a note to let you know that I've just added the patch titled
USB: Fix incorrect DMA allocations for local memory pool drivers
to my usb git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
in the usb-linus branch.
The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.)
The patch will hopefully also be merged in Linus's tree for the next -rc kernel release.
If you have any questions about this process, please let me know.
From f8c63edfd78905320e86b6b2be2b7a5ac768fa4e Mon Sep 17 00:00:00 2001
From: Fredrik Noring <[email protected]>
Date: Tue, 10 Dec 2019 18:29:05 +0100
Subject: USB: Fix incorrect DMA allocations for local memory pool drivers
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.
--- drivers/usb/core/hcd.c | 42 +++++++++++++++++----------------- drivers/usb/storage/scsiglue.c | 3 ++- 2 files changed, 23 insertions(+), 22 deletions(-)
drivers/usb/core/hcd.c +21 -21
@@ -1409,7 +1409,17 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,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 (object_is_on_stack (urb->setup_packet)) {WARN_ONCE (1 ,"setup packet is on stack\n" );return -EAGAIN ;
@@ -1424,23 +1434,22 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, 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;
@@ -1491,15 +1500,6 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,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 )))
drivers/usb/storage/scsiglue.c +2 -1
@@ -135,7 +135,8 @@ static int slave_configure(struct scsi_device *sdev)* 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 );/*
Signature · 1 line
2.24.0