On Thu, 20 Mar 2014, Aaro Koskinen wrote:

> octeon-hcd will crash the kernel when SLOB is used. This usually happens
> after the 18-byte control transfer when a device descriptor is read.
> The DMA engine is always transfering full 32-bit words and if the
> transfer is shorter, some random garbage appears after the buffer.
> The problem is not visible with SLUB since it rounds up the allocations
> to word boundary, and the extra bytes will go undetected.
> 
> Fix by providing quirk functions for DMA map/unmap that allocate a bigger
> temporary buffer when necessary. Tested by booting EdgeRouter Lite
> to USB stick root file system with SLAB, SLOB and SLUB kernels.
> 
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=72121
> Reported-by: Sergey Popov <pinkb...@gentoo.org>
> Signed-off-by: Aaro Koskinen <aaro.koski...@iki.fi>
> ---
>  drivers/staging/octeon-usb/octeon-hcd.c | 108 
> ++++++++++++++++++++++++++++++++
>  1 file changed, 108 insertions(+)
> 
> diff --git a/drivers/staging/octeon-usb/octeon-hcd.c 
> b/drivers/staging/octeon-usb/octeon-hcd.c
> index 5a001d9..9c152f9 100644
> --- a/drivers/staging/octeon-usb/octeon-hcd.c
> +++ b/drivers/staging/octeon-usb/octeon-hcd.c
> @@ -465,6 +465,112 @@ struct octeon_hcd {
>  #define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) 
> + ((channel)+1)*0x1000)
>  
>  /**
> + * struct octeon_temp_buffer - a bounce buffer for USB transfers
> + * @temp_buffer: the newly allocated temporary buffer (including meta-data)
> + * @orig_buffer: the original buffer passed by the USB stack
> + * @data:     the newly allocated temporary buffer (excluding meta-data)
> + *
> + * Both the DMA engine and FIFO mode will always transfer full 32-bit words. 
> If
> + * the buffer is too short, we need to allocate a temporary one, and this 
> struct
> + * represents it.
> + */
> +struct octeon_temp_buffer {
> +     void *temp_buffer;
> +     void *orig_buffer;
> +     u8 data[0];
> +};
> +
> +/**
> + * octeon_alloc_temp_buffer - allocate a temporary buffer for USB transfer
> + *                            (if needed)
> + * @urb:     URB.
> + * @mem_flags:       Memory allocation flags.
> + *
> + * This function allocates a temporary bounce buffer whenever it's needed
> + * due to HW limitations.
> + */
> +static int octeon_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
> +{
> +     struct octeon_temp_buffer *temp;
> +
> +     if (urb->num_sgs || urb->sg ||
> +         (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) ||
> +         !(urb->transfer_buffer_length % sizeof(u32)))
> +             return 0;
> +
> +     temp = kmalloc(ALIGN(urb->transfer_buffer_length, sizeof(u32)) +
> +                    sizeof(*temp), mem_flags);
> +     if (!temp)
> +             return -ENOMEM;
> +
> +     temp->temp_buffer = temp;
> +     temp->orig_buffer = urb->transfer_buffer;
> +     if (usb_urb_dir_out(urb))
> +             memcpy(temp->data, urb->transfer_buffer,
> +                    urb->transfer_buffer_length);
> +     urb->transfer_buffer = temp->data;
> +     urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
> +
> +     return 0;
> +}
> +
> 

I don't think you need the temp_buffer in struct octeon_temp_buffer.  
Once you have temp in octeon_free_temp_buffer via container_of, just free 
temp.  There is no need to look at temp_buffer to get its address.

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

Reply via email to