Subject: Re: [patch 4/10] s390: network driver.

From: Tommy Christensen <[email-masked]>
Date: Mon, 31 Jan 2005 00:39:25 +0100

Tommy Christensen wrote:
> jamal wrote:
> 
>> Didnt see anymore discussion on this - have we given up on it?
> 
> 
> It is not forgotten - just stalled ...
> I'll try to look at it some more.

Sorry for the long delay.

Jamal, do you think something like this could work?

Flushing of the DMA ring could be added if the need arises.
e1000 does this already in the driver on link-down.

-Tommy

diff -ur linux-2.6.11-rc2-bk8/net/core/link_watch.c linux-2.6.11-work/net/core/link_watch.c
--- linux-2.6.11-rc2-bk8/net/core/link_watch.c	2005-01-30 22:08:44.000000000 +0100
+++ linux-2.6.11-work/net/core/link_watch.c	2005-01-31 00:17:45.716039247 +0100
@@ -16,6 +16,7 @@
 #include <linux/netdevice.h>
 #include <linux/if.h>
 #include <net/sock.h>
+#include <net/pkt_sched.h>
 #include <linux/rtnetlink.h>
 #include <linux/jiffies.h>
 #include <linux/spinlock.h>
@@ -74,6 +75,9 @@
 		clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
 
 		if (dev->flags & IFF_UP) {
+			if (netif_carrier_ok(dev) &&
+			    dev->qdisc_sleeping != &noop_qdisc)
+				dev_activate(dev);
 			netdev_state_change(dev);
 		}
 
diff -ur linux-2.6.11-rc2-bk8/net/sched/sch_generic.c linux-2.6.11-work/net/sched/sch_generic.c
--- linux-2.6.11-rc2-bk8/net/sched/sch_generic.c	2005-01-30 22:11:50.458216314 +0100
+++ linux-2.6.11-work/net/sched/sch_generic.c	2005-01-31 00:06:47.609769835 +0100
@@ -185,6 +185,7 @@
 static void dev_watchdog(unsigned long arg)
 {
 	struct net_device *dev = (struct net_device *)arg;
+	int check_carrier = 0;
 
 	spin_lock(&dev->xmit_lock);
 	if (dev->qdisc != &noop_qdisc) {
@@ -198,10 +199,23 @@
 			}
 			if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
 				dev_hold(dev);
-		}
+		} else
+			check_carrier = 1;
 	}
 	spin_unlock(&dev->xmit_lock);
 
+	if (check_carrier) {
+		spin_lock(&dev->queue_lock);
+		if (!netif_carrier_ok(dev) && netif_queue_stopped(dev)) {
+			struct Qdisc *qdisc;
+
+			qdisc = dev->qdisc;
+			dev->qdisc = &noop_qdisc;
+			qdisc_reset(qdisc);
+		}
+		spin_unlock(&dev->queue_lock);
+	}
+
 	dev_put(dev);
 }