USB: Fix incorrect DMA allocations for local memory pool drivers
Fix commit7b81cb6bdd
("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:7b81cb6bdd
("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>
This commit is contained in:
parent
09068c1ad5
commit
f8c63edfd7
|
@ -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)))
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue