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]

 



Oliver Neukum a écrit :
Am Montag, 30. August 2010, 19:31:40 schrieb Martin Fuzzey:
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.

You are not handling the case of drivers mapping buffers
themselves. You need to export this attribute to the drivers.

For info here a patch we use on our side (in the usbnet driver).

Matthieu
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index f96fa56..e4cd7c0 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -315,8 +315,10 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
 		usb_free_urb (urb);
 		return;
 	}
+	/* P6 USB DMA controller cannot handle 2-byte aligned addresses */
+#if !defined(CONFIG_ARCH_PARROT6)
 	skb_reserve (skb, NET_IP_ALIGN);
-
+#endif
 	entry = (struct skb_data *) skb->cb;
 	entry->urb = urb;
 	entry->dev = dev;
@@ -368,6 +370,13 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
 
 static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
 {
+#if defined(CONFIG_ARCH_PARROT6)
+	if ((((unsigned long) skb->data) & 0x3) != NET_IP_ALIGN) {
+		/* we allocated this skb, therefore we have enough tailroom */
+		memmove(skb->data+NET_IP_ALIGN, skb->data, skb->len);
+		skb_reserve(skb, NET_IP_ALIGN);
+	}
+#endif
 	if (dev->driver_info->rx_fixup
 			&& !dev->driver_info->rx_fixup (dev, skb))
 		goto error;
@@ -947,6 +956,36 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
 			goto drop;
 		}
 	}
+
+/* ugly fixup to accomodate for P6 USB align constraints */
+#if defined(CONFIG_ARCH_PARROT6)
+	/* data must be 4-byte aligned */
+	length = ((unsigned long)skb->data) & 0x3;
+	if (length) {
+		if (skb_cloned(skb) ||
+		    ((skb_headroom(skb) < length) &&
+		     (skb_tailroom(skb) < (4-length)))) {
+			struct sk_buff *skb2;
+			/* copy skb with proper alignment */
+			skb2 = skb_copy_expand(skb, 0, 4, GFP_ATOMIC);
+			dev_kfree_skb_any(skb);
+			skb = skb2;
+			if (!skb) {
+				if (netif_msg_tx_err (dev)) {
+					devdbg (dev, "can't align skb for P6");
+				}
+				goto drop;
+			}
+		}
+		else {
+			/* move data inside buffer */
+			length = ((skb_headroom(skb) >= length)? 0 : 4)-length;
+			memmove(skb->data+length, skb->data, skb->len);
+			skb_reserve(skb, length);
+		}
+	}
+#endif /* CONFIG_ARCH_PARROT6 */
+
 	length = skb->len;
 
 	if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) {
@@ -1250,6 +1289,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 			dev->driver_info->description,
 			print_mac(mac, net->dev_addr));
 
+#if defined(CONFIG_ARCH_PARROT6)
+	devinfo(dev, "enabling P6 usb skb alignment fixups");
+#endif
 	// ok, it's ready to go.
 	usb_set_intfdata (udev, dev);
 

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

  Powered by Linux