Commit 2ae61a25 authored by Michał Mirosław's avatar Michał Mirosław Committed by Greg Kroah-Hartman

usb: chipidea: Simplify Tegra DMA alignment code

The USB host on Tegra3 works with 32-bit alignment. Previous code tried
to align the buffer, but it did align the wrapper struct instead, so
the buffer was at a constant offset of 8 bytes (two pointers) from
expected alignment.  Since kmalloc() guarantees at least 8-byte
alignment already, the alignment-extending is removed.

Fixes: fc53d527 ("usb: chipidea: tegra: Support host mode")
Signed-off-by: default avatarMichał Mirosław <mirq-linux@rere.qmqm.pl>
Link: https://lore.kernel.org/r/a0d917d492b1f91ee0019e68b8e8bca9c585393f.1695934946.git.mirq-linux@rere.qmqm.plSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7ab87167
...@@ -30,8 +30,7 @@ struct ehci_ci_priv { ...@@ -30,8 +30,7 @@ struct ehci_ci_priv {
}; };
struct ci_hdrc_dma_aligned_buffer { struct ci_hdrc_dma_aligned_buffer {
void *kmalloc_ptr; void *original_buffer;
void *old_xfer_buffer;
u8 data[]; u8 data[];
}; };
...@@ -380,60 +379,52 @@ static int ci_ehci_bus_suspend(struct usb_hcd *hcd) ...@@ -380,60 +379,52 @@ static int ci_ehci_bus_suspend(struct usb_hcd *hcd)
return 0; return 0;
} }
static void ci_hdrc_free_dma_aligned_buffer(struct urb *urb) static void ci_hdrc_free_dma_aligned_buffer(struct urb *urb, bool copy_back)
{ {
struct ci_hdrc_dma_aligned_buffer *temp; struct ci_hdrc_dma_aligned_buffer *temp;
size_t length;
if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
return; return;
urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
temp = container_of(urb->transfer_buffer, temp = container_of(urb->transfer_buffer,
struct ci_hdrc_dma_aligned_buffer, data); struct ci_hdrc_dma_aligned_buffer, data);
urb->transfer_buffer = temp->original_buffer;
if (copy_back && usb_urb_dir_in(urb)) {
size_t length;
if (usb_urb_dir_in(urb)) {
if (usb_pipeisoc(urb->pipe)) if (usb_pipeisoc(urb->pipe))
length = urb->transfer_buffer_length; length = urb->transfer_buffer_length;
else else
length = urb->actual_length; length = urb->actual_length;
memcpy(temp->old_xfer_buffer, temp->data, length); memcpy(temp->original_buffer, temp->data, length);
} }
urb->transfer_buffer = temp->old_xfer_buffer;
kfree(temp->kmalloc_ptr);
urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; kfree(temp);
} }
static int ci_hdrc_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) static int ci_hdrc_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
{ {
struct ci_hdrc_dma_aligned_buffer *temp, *kmalloc_ptr; struct ci_hdrc_dma_aligned_buffer *temp;
const unsigned int ci_hdrc_usb_dma_align = 32;
size_t kmalloc_size;
if (urb->num_sgs || urb->sg || urb->transfer_buffer_length == 0) if (urb->num_sgs || urb->sg || urb->transfer_buffer_length == 0)
return 0; return 0;
if (!((uintptr_t)urb->transfer_buffer & (ci_hdrc_usb_dma_align - 1)) && !(urb->transfer_buffer_length & 3)) if (IS_ALIGNED((uintptr_t)urb->transfer_buffer, 4)
&& IS_ALIGNED(urb->transfer_buffer_length, 4))
return 0; return 0;
/* Allocate a buffer with enough padding for alignment */ temp = kmalloc(sizeof(*temp) + ALIGN(urb->transfer_buffer_length, 4), mem_flags);
kmalloc_size = ALIGN(urb->transfer_buffer_length, 4) + if (!temp)
sizeof(struct ci_hdrc_dma_aligned_buffer) +
ci_hdrc_usb_dma_align - 1;
kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
if (!kmalloc_ptr)
return -ENOMEM; return -ENOMEM;
/* Position our struct dma_aligned_buffer such that data is aligned */
temp = PTR_ALIGN(kmalloc_ptr + 1, ci_hdrc_usb_dma_align) - 1;
temp->kmalloc_ptr = kmalloc_ptr;
temp->old_xfer_buffer = urb->transfer_buffer;
if (usb_urb_dir_out(urb)) if (usb_urb_dir_out(urb))
memcpy(temp->data, urb->transfer_buffer, memcpy(temp->data, urb->transfer_buffer,
urb->transfer_buffer_length); urb->transfer_buffer_length);
urb->transfer_buffer = temp->data;
temp->original_buffer = urb->transfer_buffer;
urb->transfer_buffer = temp->data;
urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
return 0; return 0;
...@@ -450,7 +441,7 @@ static int ci_hdrc_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ...@@ -450,7 +441,7 @@ static int ci_hdrc_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
if (ret) if (ret)
ci_hdrc_free_dma_aligned_buffer(urb); ci_hdrc_free_dma_aligned_buffer(urb, false);
return ret; return ret;
} }
...@@ -458,7 +449,7 @@ static int ci_hdrc_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ...@@ -458,7 +449,7 @@ static int ci_hdrc_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
static void ci_hdrc_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) static void ci_hdrc_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{ {
usb_hcd_unmap_urb_for_dma(hcd, urb); usb_hcd_unmap_urb_for_dma(hcd, urb);
ci_hdrc_free_dma_aligned_buffer(urb); ci_hdrc_free_dma_aligned_buffer(urb, true);
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment