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