Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 364789
b: refs/heads/master
c: 8408fd1
h: refs/heads/master
i:
  364787: 1e888d6
v: v3
  • Loading branch information
Ruslan Bilovol authored and Felipe Balbi committed Apr 2, 2013
1 parent 7173d23 commit e799de3
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 2f1d57069338b14fcf4765ae2c25fc377da45b1f
refs/heads/master: 8408fd1d83e39bf856d31a36b70bcc53527702fd
117 changes: 117 additions & 0 deletions trunk/drivers/usb/musb/musb_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -2465,6 +2465,118 @@ static int musb_bus_resume(struct usb_hcd *hcd)
return 0;
}


#ifndef CONFIG_MUSB_PIO_ONLY

#define MUSB_USB_DMA_ALIGN 4

struct musb_temp_buffer {
void *kmalloc_ptr;
void *old_xfer_buffer;
u8 data[0];
};

static void musb_free_temp_buffer(struct urb *urb)
{
enum dma_data_direction dir;
struct musb_temp_buffer *temp;

if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
return;

dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;

temp = container_of(urb->transfer_buffer, struct musb_temp_buffer,
data);

if (dir == DMA_FROM_DEVICE) {
memcpy(temp->old_xfer_buffer, temp->data,
urb->transfer_buffer_length);
}
urb->transfer_buffer = temp->old_xfer_buffer;
kfree(temp->kmalloc_ptr);

urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
}

static int musb_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
{
enum dma_data_direction dir;
struct musb_temp_buffer *temp;
void *kmalloc_ptr;
size_t kmalloc_size;

if (urb->num_sgs || urb->sg ||
urb->transfer_buffer_length == 0 ||
!((uintptr_t)urb->transfer_buffer & (MUSB_USB_DMA_ALIGN - 1)))
return 0;

dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;

/* Allocate a buffer with enough padding for alignment */
kmalloc_size = urb->transfer_buffer_length +
sizeof(struct musb_temp_buffer) + MUSB_USB_DMA_ALIGN - 1;

kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
if (!kmalloc_ptr)
return -ENOMEM;

/* Position our struct temp_buffer such that data is aligned */
temp = PTR_ALIGN(kmalloc_ptr, MUSB_USB_DMA_ALIGN);


temp->kmalloc_ptr = kmalloc_ptr;
temp->old_xfer_buffer = urb->transfer_buffer;
if (dir == DMA_TO_DEVICE)
memcpy(temp->data, urb->transfer_buffer,
urb->transfer_buffer_length);
urb->transfer_buffer = temp->data;

urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;

return 0;
}

static int musb_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
struct musb *musb = hcd_to_musb(hcd);
int ret;

/*
* The DMA engine in RTL1.8 and above cannot handle
* DMA addresses that are not aligned to a 4 byte boundary.
* For such engine implemented (un)map_urb_for_dma hooks.
* Do not use these hooks for RTL<1.8
*/
if (musb->hwvers < MUSB_HWVERS_1800)
return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);

ret = musb_alloc_temp_buffer(urb, mem_flags);
if (ret)
return ret;

ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
if (ret)
musb_free_temp_buffer(urb);

return ret;
}

static void musb_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
struct musb *musb = hcd_to_musb(hcd);

usb_hcd_unmap_urb_for_dma(hcd, urb);

/* Do not use this hook for RTL<1.8 (see description above) */
if (musb->hwvers < MUSB_HWVERS_1800)
return;

musb_free_temp_buffer(urb);
}
#endif /* !CONFIG_MUSB_PIO_ONLY */

const struct hc_driver musb_hc_driver = {
.description = "musb-hcd",
.product_desc = "MUSB HDRC host driver",
Expand All @@ -2484,6 +2596,11 @@ const struct hc_driver musb_hc_driver = {
.urb_dequeue = musb_urb_dequeue,
.endpoint_disable = musb_h_disable,

#ifndef CONFIG_MUSB_PIO_ONLY
.map_urb_for_dma = musb_map_urb_for_dma,
.unmap_urb_for_dma = musb_unmap_urb_for_dma,
#endif

.hub_status_data = musb_hub_status_data,
.hub_control = musb_hub_control,
.bus_suspend = musb_bus_suspend,
Expand Down

0 comments on commit e799de3

Please sign in to comment.