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