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 <pinkbyte@xxxxxxxxxx> > Signed-off-by: Aaro Koskinen <aaro.koskinen@xxxxxx> > --- > 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html