--- /home/tburns/kernel-git/linux-2.6/drivers/net/sky2.c 2007-04-18 15:55:08.000000000 -0400 +++ ./sky2-patched.c 2007-04-19 14:55:09.000000000 -0400 @@ -1034,13 +1034,13 @@ struct sky2_hw *hw = sky2->hw; u16 port = sky2->port; - netif_tx_lock_bh(dev); + spin_lock_bh(&sky2->tx_lock); sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_ON); sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_ON); sky2->vlgrp = grp; - netif_tx_unlock_bh(dev); + spin_unlock_bh(&sky2->tx_lock); } static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) @@ -1049,13 +1049,16 @@ struct sky2_hw *hw = sky2->hw; u16 port = sky2->port; - netif_tx_lock_bh(dev); + spin_lock_bh(&sky2->tx_lock); sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF); sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF); - vlan_group_set_device(sky2->vlgrp, vid, NULL); - netif_tx_unlock_bh(dev); + if (sky2->vlgrp) + sky2->vlgrp->vlan_devices[vid] = NULL; + + + spin_unlock_bh(&sky2->tx_lock); } #endif @@ -1074,7 +1077,7 @@ unsigned long p; int i; - skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + RX_SKB_ALIGN); + skb = alloc_skb(sky2->rx_data_size + RX_SKB_ALIGN, GFP_ATOMIC); if (!skb) goto nomem; @@ -1138,7 +1141,7 @@ thresh = (size - 8) / sizeof(u32); /* Account for overhead of skb - to avoid order > 0 allocation */ - space = SKB_DATA_ALIGN(size) + NET_SKB_PAD + space = SKB_DATA_ALIGN(size) + 16 + sizeof(struct skb_shared_info); sky2->rx_nfrags = space >> PAGE_SHIFT; @@ -1334,10 +1337,10 @@ count = sizeof(dma_addr_t) / sizeof(u32); count += skb_shinfo(skb)->nr_frags * count; - if (skb_is_gso(skb)) + if (skb_shinfo(skb)->tso_size) ++count; - if (skb->ip_summed == CHECKSUM_PARTIAL) + if (skb->ip_summed == CHECKSUM_HW) ++count; return count; @@ -1361,8 +1364,15 @@ u16 mss; u8 ctrl; - if (unlikely(tx_avail(sky2) < tx_le_req(skb))) + + if (!spin_trylock(&sky2->tx_lock)) + return NETDEV_TX_LOCKED; + + if (unlikely(tx_avail(sky2) < tx_le_req(skb))) { + spin_unlock(&sky2->tx_lock); + return NETDEV_TX_BUSY; + } if (unlikely(netif_msg_tx_queued(sky2))) printk(KERN_DEBUG "%s: tx queued, slot %u, len %d\n", @@ -1381,7 +1391,7 @@ } /* Check for TCP Segmentation Offload */ - mss = skb_shinfo(skb)->gso_size; + mss = skb_shinfo(skb)->tso_size; if (mss != 0) { mss += ((skb->h.th->doff - 5) * 4); /* TCP options */ mss += (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr); @@ -1411,12 +1421,12 @@ #endif /* Handle TCP checksum offload */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (skb->ip_summed == CHECKSUM_HW) { unsigned offset = skb->h.raw - skb->data; u32 tcpsum; tcpsum = offset << 16; /* sum start */ - tcpsum |= offset + skb->csum_offset; /* sum write */ + tcpsum |= offset + (u32) skb->csum; /* sum write */ ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; if (skb->nh.iph->protocol == IPPROTO_UDP) @@ -1478,6 +1488,8 @@ sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod); dev->trans_start = jiffies; + spin_unlock(&sky2->tx_lock); + return NETDEV_TX_OK; } @@ -1538,9 +1550,11 @@ { struct sky2_port *sky2 = netdev_priv(dev); - netif_tx_lock_bh(dev); + spin_lock_bh(&sky2->tx_lock); + sky2_tx_complete(sky2, sky2->tx_prod); - netif_tx_unlock_bh(dev); + + spin_unlock_bh(&sky2->tx_lock); } /* Network shutdown */ @@ -1954,7 +1968,8 @@ { struct sk_buff *skb; - skb = netdev_alloc_skb(sky2->netdev, length + 2); + skb = alloc_skb(length + 2, GFP_ATOMIC); + if (likely(skb)) { skb_reserve(skb, 2); pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->data_addr, @@ -2058,8 +2073,9 @@ if (length < copybreak) skb = receive_copy(sky2, re, length); - else + else skb = receive_new(sky2, re, length); + resubmit: sky2_rx_submit(sky2, re); @@ -2092,9 +2108,9 @@ struct sky2_port *sky2 = netdev_priv(dev); if (netif_running(dev)) { - netif_tx_lock(dev); + spin_lock_bh(&sky2->tx_lock); sky2_tx_complete(sky2, last); - netif_tx_unlock(dev); + spin_unlock_bh(&sky2->tx_lock); } } @@ -2134,6 +2150,7 @@ sky2->net_stats.rx_packets++; sky2->net_stats.rx_bytes += skb->len; dev->last_rx = jiffies; + skb->dev = sky2->netdev; #ifdef SKY2_VLAN_TAG_USED if (sky2->vlgrp && (status & GMR_FS_VLAN)) { @@ -2176,7 +2193,7 @@ */ if (likely(status >> 16 == (status & 0xffff))) { skb = sky2->rx_ring[sky2->rx_next].skb; - skb->ip_summed = CHECKSUM_COMPLETE; + skb->ip_summed = CHECKSUM_HW; skb->csum = status & 0xffff; } else { printk(KERN_NOTICE PFX "%s: hardware receive " @@ -2431,7 +2448,7 @@ } } -static irqreturn_t sky2_intr(int irq, void *dev_id) +static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) { struct sky2_hw *hw = dev_id; struct net_device *dev0 = hw->dev[0]; @@ -3404,6 +3421,8 @@ sky2->hw = hw; sky2->msg_enable = netif_msg_init(debug, default_msg); + spin_lock_init(&sky2->tx_lock); + /* Auto speed and flow control */ sky2->autoneg = AUTONEG_ENABLE; sky2->flow_mode = FC_BOTH; @@ -3455,7 +3474,7 @@ } /* Handle software interrupt used during MSI test */ -static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id) +static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id, struct pt_regs *regs) { struct sky2_hw *hw = dev_id; u32 status = sky2_read32(hw, B0_Y2_SP_ISRC2); @@ -3627,7 +3646,7 @@ goto err_out_free_netdev; } - err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : IRQF_SHARED, + err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : SA_SHIRQ, dev->name, hw); if (err) { dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq); @@ -3653,7 +3672,7 @@ } setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); - INIT_WORK(&hw->restart_work, sky2_restart); + INIT_WORK(&hw->restart_work, sky2_restart, &hw->restart_work); sky2_idle_start(hw);