Re: [PATCH 1/2] USB: Allow HCDs to specifiy their DMA alignment requirements

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2010/8/31 Martin Fuzzey <mfuzzey@xxxxxxxxx>:
> If these are not met use a bounce buffer.
>
> This is done by adding a member dma_align_shift to
> struct hc_driver. Defaulting to zero causes unmodified
> HCDs to be assumed to be byte aligned DMA capable.
>
> Signed-off-by: Martin Fuzzey <mfuzzey@xxxxxxxxx>
>
> ---
>
>  drivers/usb/core/hcd.c  |   54 +++++++++++++++++++++++++++++++++++++----------
>  include/linux/usb.h     |    1 +
>  include/linux/usb/hcd.h |    2 ++
>  3 files changed, 45 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> index 12742f1..8ad9367 100644
> --- a/drivers/usb/core/hcd.c
> +++ b/drivers/usb/core/hcd.c
> @@ -1286,12 +1286,19 @@ static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
>                                urb->transfer_dma,
>                                urb->transfer_buffer_length,
>                                dir);
> -       else if (urb->transfer_flags & URB_DMA_MAP_SINGLE)
> +       else if (urb->transfer_flags & URB_DMA_MAP_SINGLE) {
>                dma_unmap_single(hcd->self.controller,
>                                urb->transfer_dma,
>                                urb->transfer_buffer_length,
>                                dir);
> -       else if (urb->transfer_flags & URB_MAP_LOCAL)
> +               if (urb->bounce_buffer) {
> +                       if (dir == DMA_FROM_DEVICE)
> +                               memcpy(urb->transfer_buffer,
> +                                       urb->bounce_buffer,
> +                                       urb->transfer_buffer_length);
> +                       kfree(urb->bounce_buffer);

 dma_unmap_single is needed for bounce_buffer.

> +               }
> +       } else if (urb->transfer_flags & URB_MAP_LOCAL)
>                hcd_free_coherent(urb->dev->bus,
>                                &urb->transfer_dma,
>                                &urb->transfer_buffer,
> @@ -1373,16 +1380,39 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
>                                else
>                                        urb->transfer_flags |= URB_DMA_MAP_PAGE;
>                        } else {
> -                               urb->transfer_dma = dma_map_single(
> -                                               hcd->self.controller,
> -                                               urb->transfer_buffer,
> -                                               urb->transfer_buffer_length,
> -                                               dir);
> -                               if (dma_mapping_error(hcd->self.controller,
> -                                               urb->transfer_dma))
> -                                       ret = -EAGAIN;
> -                               else
> -                                       urb->transfer_flags |= URB_DMA_MAP_SINGLE;
> +                               void *buffer = urb->transfer_buffer;
> +
> +                               if (IS_ALIGNED((unsigned long)buffer,
> +                                               1 << hcd->driver->dma_align_shift))
> +                                       urb->bounce_buffer = NULL;

Suppose hcd->driver->dma_align_shift is zero and HC is byte aligned DMA
enabled, this means DMA is doable between byte aligned memory and HC,
but this does __not__ mean it is safe to do dma mapping or unmapping between
CPU and byte aligned memory, which may cause sync issues between memory
and CPU cache.

So seems the idea behind the patch is not correct, IMHO.

-- 
Lei Ming
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux