usb: chipidea: Simplify Tegra DMA alignment code
[ Upstream commit2ae61a2562
] 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:fc53d52790
("usb: chipidea: tegra: Support host mode") Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl> Link: https://lore.kernel.org/r/a0d917d492b1f91ee0019e68b8e8bca9c585393f.1695934946.git.mirq-linux@rere.qmqm.pl Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
58e8316b20
commit
2941a29fe9
@ -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[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -372,60 +371,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;
|
||||||
@ -442,7 +433,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;
|
||||||
}
|
}
|
||||||
@ -450,7 +441,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ci_hdrc_host_init(struct ci_hdrc *ci)
|
int ci_hdrc_host_init(struct ci_hdrc *ci)
|
||||||
|
Reference in New Issue
Block a user