Appearently some out-of-tree USB host drivers do not handle DMA alignment for
URB buffers and let core/hcd.c to do the mapping on architectures that have
minimum DMA alignment requirements. This leads to random memory corruptions
and crashes when using USB device drivers that use unaligned URB buffers.

Instead of fixing host drivers, users end up posting bug reports against
those USB device drivers that use unaligned buffers for URB; such as with
rtl8192cu (http://thread.gmane.org/gmane.linux.kernel.wireless.general/105631).

Patch makes this issue more visible at core level, and hopefully gives hint
for future hcd driver implementors about this problem.

Signed-off-by: Jussi Kivilinna <jussi.kivili...@iki.fi>
---
 drivers/usb/core/hcd.c |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index d53547d..7ad13e6 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1405,6 +1405,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct 
urb *urb,
                            gfp_t mem_flags)
 {
        enum dma_data_direction dir;
+       unsigned int dma_align = dma_get_cache_alignment();
        int ret = 0;
 
        /* Map the URB's buffers for DMA access.
@@ -1417,6 +1418,14 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct 
urb *urb,
                if (hcd->self.uses_pio_for_control)
                        return ret;
                if (hcd->self.uses_dma) {
+                       if (PTR_ALIGN(urb->setup_packet, dma_align) !=
+                                       urb->setup_packet) {
+                               /* USB host driver does not appear to handle
+                                * buffer alignment for DMA; warn once.
+                                */
+                               WARN_ONCE(1, "urb->setup_packet not DMA 
aligned.\n");
+                       }
+
                        urb->setup_dma = dma_map_single(
                                        hcd->self.controller,
                                        urb->setup_packet,
@@ -1479,6 +1488,15 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct 
urb *urb,
                                else
                                        urb->transfer_flags |= URB_DMA_MAP_PAGE;
                        } else {
+                               if (PTR_ALIGN(urb->transfer_buffer, dma_align)
+                                               != urb->transfer_buffer) {
+                                       /* USB host driver does not appear to
+                                        * handle buffer alignment for DMA; warn
+                                        * once.
+                                        */
+                                       WARN_ONCE(1, "urb->transfer_buffer not 
DMA aligned.\n");
+                               }
+
                                urb->transfer_dma = dma_map_single(
                                                hcd->self.controller,
                                                urb->transfer_buffer,

--
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