Skip to content
This repository has been archived by the owner on Jul 16, 2024. It is now read-only.

Commit

Permalink
BACKPORT: usb: add a hcd_uses_dma helper
Browse files Browse the repository at this point in the history
The USB buffer allocation code is the only place in the usb core (and in
fact the whole kernel) that uses is_device_dma_capable, while the URB
mapping code uses the uses_dma flag in struct usb_bus.  Switch the buffer
allocation to use the uses_dma flag used by the rest of the USB code,
and create a helper in hcd.h that checks this flag as well as the
CONFIG_HAS_DMA to simplify the caller a bit.

If MSI is supported, somehow the check of is_device_dma_capable caused
issue, and buffer could not be created. This patch switched the buffer
allocation of USB code to use another flag and helped to resolve the
issue.
This patch is a part of usb patch set to fix the crash in CentOS 8.0.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v5.6-rc1&id=edfbcb321faf07ca970e4191abe061deeb7d3788

Signed-off-by: Christoph Hellwig <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Greg Kroah-Hartman <[email protected]>
Signed-off-by: Khuong Dinh <[email protected]>
  • Loading branch information
Christoph Hellwig authored and tphan-ampere committed Apr 21, 2020
1 parent 391bde5 commit cea1f46
Show file tree
Hide file tree
Showing 5 changed files with 10 additions and 11 deletions.
10 changes: 3 additions & 7 deletions drivers/usb/core/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
char name[16];
int i, size;

if (hcd->localmem_pool ||
!IS_ENABLED(CONFIG_HAS_DMA) ||
!is_device_dma_capable(hcd->self.sysdev))
if (hcd->localmem_pool || !hcd_uses_dma(hcd))
return 0;

for (i = 0; i < HCD_BUFFER_POOLS; i++) {
Expand Down Expand Up @@ -133,8 +131,7 @@ void *hcd_buffer_alloc(
return gen_pool_dma_alloc(hcd->localmem_pool, size, dma);

/* some USB hosts just use PIO */
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
!is_device_dma_capable(bus->sysdev)) {
if (!hcd_uses_dma(hcd)) {
*dma = ~(dma_addr_t) 0;
return kmalloc(size, mem_flags);
}
Expand Down Expand Up @@ -164,8 +161,7 @@ void hcd_buffer_free(
return;
}

if (!IS_ENABLED(CONFIG_HAS_DMA) ||
!is_device_dma_capable(bus->sysdev)) {
if (!hcd_uses_dma(hcd)) {
kfree(addr);
return;
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/usb/core/hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1511,7 +1511,7 @@ 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 (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
if (hcd_uses_dma(hcd)) {
if (is_vmalloc_addr(urb->setup_packet)) {
WARN_ONCE(1, "setup packet is not dma capable\n");
return -EAGAIN;
Expand Down Expand Up @@ -1545,7 +1545,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
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 (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
if (hcd_uses_dma(hcd)) {
if (urb->num_sgs) {
int n;

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/dwc2/hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -4733,7 +4733,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,

buf = urb->transfer_buffer;

if (hcd->self.uses_dma) {
if (hcd_uses_dma(hcd)) {
if (!buf && (urb->transfer_dma & 3)) {
dev_err(hsotg->dev,
"%s: unaligned transfer with no transfer_buffer",
Expand Down
2 changes: 1 addition & 1 deletion include/linux/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -1457,7 +1457,7 @@ typedef void (*usb_complete_t)(struct urb *);
* field rather than determining a dma address themselves.
*
* Note that transfer_buffer must still be set if the controller
* does not support DMA (as indicated by bus.uses_dma) and when talking
* does not support DMA (as indicated by hcd_uses_dma()) and when talking
* to root hub. If you have to trasfer between highmem zone and the device
* on such controller, create a bounce buffer or bail out with an error.
* If transfer_buffer cannot be set (is in highmem) and the controller is DMA
Expand Down
3 changes: 3 additions & 0 deletions include/linux/usb/hcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,9 @@ static inline bool hcd_periodic_completion_in_progress(struct usb_hcd *hcd,
return hcd->high_prio_bh.completing_ep == ep;
}

#define hcd_uses_dma(hcd) \
(IS_ENABLED(CONFIG_HAS_DMA) && (hcd)->self.uses_dma)

extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
int status);
Expand Down

0 comments on commit cea1f46

Please sign in to comment.