Paul Janzen <[EMAIL PROTECTED]> writes:
> In mv643xx_eth_start_xmit:
> [...]
> spin_lock_irqsave(&mp->lock, flags);
> [...]
> /* Since hardware can't handle unaligned fragments smaller
> * than 9 bytes, if we find any, we linearize the skb
> * and start again. */
> [...]
> skb_linearize(skb, GFP_ATOMIC);
> [...]
>
> which ends up calling kunmap_skb_frag(vaddr), which, when
> CONFIG_HIGHMEM=y, calls local_bh_enable with interrupts off.
A patch for this problem is enclosed. I believe it also solves a
potential deadlock if skb_linearize() returns -ENOMEM.
Signed-off-by: Paul Janzen <[EMAIL PROTECTED]>
--- a/drivers/net/mv643xx_eth.c 2005-12-24 15:47:48.000000000 -0800
+++ b/drivers/net/mv643xx_eth.c 2006-01-08 20:30:25.000000000 -0800
@@ -1093,6 +1093,27 @@ static int mv643xx_poll(struct net_devic
}
#endif
+/* Hardware can't handle unaligned fragments smaller than 9 bytes.
+ * This helper function detects that case. When I've seen it, it's
+ * always been the first frag (probably near the end of the page), but
+ * we check all frags to be safe.
+ */
+
+static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb)
+{
+ unsigned int frag;
+ skb_frag_t *fragp;
+
+ for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+ fragp = &skb_shinfo(skb)->frags[frag];
+ if (fragp->size <= 8 && fragp->page_offset & 0x7)
+ return 1;
+
+ }
+ return 0;
+}
+
+
/*
* mv643xx_eth_start_xmit
*
@@ -1136,12 +1157,22 @@ static int mv643xx_eth_start_xmit(struct
return 1;
}
+ if (has_tiny_unaligned_frags(skb)) {
+ if ((skb_linearize(skb, GFP_ATOMIC) != 0)
+ || has_tiny_unaligned_frags(skb)) {
+ stats->tx_dropped++;
+ printk(KERN_ERR
+ "%s: failed to linearize tiny unaligned
fragment\n",
+ dev->name);
+ return 1;
+ }
+ }
+
spin_lock_irqsave(&mp->lock, flags);
/* Update packet info data structure -- DMA owned, first last */
#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
if (!skb_shinfo(skb)->nr_frags) {
-linear:
if (skb->ip_summed != CHECKSUM_HW) {
/* Errata BTS #50, IHL must be 5 if no HW checksum */
pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
@@ -1183,26 +1214,6 @@ linear:
} else {
unsigned int frag;
- /* Since hardware can't handle unaligned fragments smaller
- * than 9 bytes, if we find any, we linearize the skb
- * and start again. When I've seen it, it's always been
- * the first frag (probably near the end of the page),
- * but we check all frags to be safe.
- */
- for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
- skb_frag_t *fragp;
-
- fragp = &skb_shinfo(skb)->frags[frag];
- if (fragp->size <= 8 && fragp->page_offset & 0x7) {
- skb_linearize(skb, GFP_ATOMIC);
- printk(KERN_DEBUG "%s: unaligned tiny fragment"
- "%d of %d, fixed\n",
- dev->name, frag,
- skb_shinfo(skb)->nr_frags);
- goto linear;
- }
- }
-
/* first frag which is skb header */
pkt_info.byte_cnt = skb_headlen(skb);
pkt_info.buf_ptr = dma_map_single(NULL, skb->data,
-- Paul
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html