Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 5 additions & 24 deletions drivers/usb/dwc2/hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2461,7 +2461,7 @@ static void dwc2_free_dma_aligned_buffer(struct urb *urb)

/* Restore urb->transfer_buffer from the end of the allocated area */
memcpy(&stored_xfer_buffer,
PTR_ALIGN(urb->transfer_buffer + urb->transfer_buffer_length + DWC2_USB_DMA_ALIGN,
PTR_ALIGN(urb->transfer_buffer + urb->transfer_buffer_length,
dma_get_cache_alignment()),
sizeof(urb->transfer_buffer));

Expand All @@ -2484,36 +2484,17 @@ static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
void *kmalloc_ptr;
size_t kmalloc_size;

if (urb->num_sgs || urb->sg || urb->transfer_buffer_length == 0)
return 0;

/*
* Hardware bug: the core will only do DMA writes of full words
* in length, and DMA buffers must start at a word boundary.
* TODO: is this limited to BCM2835 and friends, or other core variants?
*/
if (!(usb_urb_dir_in(urb) && (urb->transfer_buffer_length & (DWC2_USB_DMA_ALIGN - 1))) &&
if (urb->num_sgs || urb->sg ||
urb->transfer_buffer_length == 0 ||
!((uintptr_t)urb->transfer_buffer & (DWC2_USB_DMA_ALIGN - 1)))
return 0;

/*
* If the URB already has a DMA mapping, this alignment mechanism won't
* work - the replacement buffer won't be used by the core, as the HCD layer
* skips mapping. Mappings have the granularity of a page, so it's unlikely that the
* DMA length bug will cause data trampling. In any case, warn if there's a driver
* submitting unaligned mapped buffers.
*/
if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
if (urb->transfer_dma & (DWC2_USB_DMA_ALIGN - 1))
WARN_ONCE(1, "Unaligned DMA-mapped buffer");
return 0;
}
/*
* 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 + DWC2_USB_DMA_ALIGN +
kmalloc_size = urb->transfer_buffer_length +
(dma_get_cache_alignment() - 1) +
sizeof(urb->transfer_buffer);

Expand All @@ -2525,7 +2506,7 @@ static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
* Position value of original urb->transfer_buffer pointer to the end
* of allocation for later referencing
*/
memcpy(PTR_ALIGN(kmalloc_ptr + urb->transfer_buffer_length + DWC2_USB_DMA_ALIGN,
memcpy(PTR_ALIGN(kmalloc_ptr + urb->transfer_buffer_length,
dma_get_cache_alignment()),
&urb->transfer_buffer, sizeof(urb->transfer_buffer));

Expand Down
Loading