Hi Stephen, list;

 Patch attached backports the current sky2 driver in GIT to 2.6.15-1.
This version works, I don't know if I'm missing anything crucial in
the port.

 It also seems to alleviate problems we have been experiencing (and
are well documented in various forums/lists online) where the ethernet
device would become unresponsive under moderate to heavy loads and
require restarting the interface to come back up.  I found a lot of
(recent) discourse about these problems and as such figured the port
might have some use in the public domain.

 I apologize in advance if gmail incorrectly mails my patch.

Cheers,
Tom Burns
Software Developer
International Datacasting
http://www.intldata.ca
--- /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);
 
--- /home/tburns/kernel-git/linux-2.6/drivers/net/sky2.h	2007-04-18 15:55:08.000000000 -0400
+++ ./sky2-patched.h	2007-04-19 14:57:40.000000000 -0400
@@ -1880,6 +1880,8 @@
 	u32		     msg_enable;
 	spinlock_t	     phy_lock;
 
+	spinlock_t           tx_lock  ____cacheline_aligned_in_smp;
+
 	struct tx_ring_info  *tx_ring;
 	struct sky2_tx_le    *tx_le;
 	u16		     tx_cons;		/* next le to check */

Reply via email to