Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 29 May 2008 23:01:41 -0700
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        Coleman Kane <cokane@FreeBSD.org>
Cc:        current@FreeBSD.org
Subject:   Re: ndis(4) patch to replace obsolete if_watchdog interface
Message-ID:  <20080530060141.GB68753@citylink.fud.org.nz>
In-Reply-To: <1212104731.1606.9.camel@localhost>
References:  <1212093692.1681.8.camel@localhost> <20080529214604.GA68753@citylink.fud.org.nz> <1212104731.1606.9.camel@localhost>

next in thread | previous in thread | raw e-mail | index | archive | help

--2oS5YaxWCcQjTEyO
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Thu, May 29, 2008 at 07:45:31PM -0400, Coleman Kane wrote:
> On Thu, 2008-05-29 at 14:46 -0700, Andrew Thompson wrote:
> > On Thu, May 29, 2008 at 04:41:32PM -0400, Coleman Kane wrote:
> > > Hi,
> > > 
> > > I just replaced the obsoleted if_watchdog interface in ndis(4) with a
> > > local implementation. This should remove the obnoxious warning message
> > > on device init. Anyone using -CURRENT with an ndis card, could you send
> > > me success/fails?
> > > 
> > > The patch is here:
> > >   * http://people.freebsd.org/~cokane/patches/if_ndis-new_wd.patch
> > 
> > 
> > This works different to the rest of the network drivers. The existing
> > drivers use a callout tick that runs while the driver is up and an
> > integer counter.
> > 
> >  if (x && --x == 0)
> > 	 ...timeout...
> > 
> > You arm the callout and stop it after each Tx, does this have any
> > perfornace impact?
> > 
> > 
> > Andrew
> > 
> 
> I am attaching a new patch, where I use the method that you suggested
> and do away with the extra callout for the watchdog. A "tick" function
> was already implemented for timeouts related to the NDIS systems.
> 
> I am not sure if the ndis-timeout code using ndis_stat_callout
> duplicates the if_watchdog code (and what I replaced it with), but I
> don't think so as both were implemented side-by-side before...
> 

A few comments inline

>diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c
>+	NDIS_LOCK(sc);
>+	if(sc->ndis_timer_countdown &&
>+	    (sc->ndis_timer_countdown -=
>+	    sc->ndis_block->nmb_checkforhangsecs) < 1) {
>+		sc->ndis_timer_countdown = 0;
>+		NDIS_UNLOCK(sc);
>+		ndis_watchdog(xsc);
>+	} else {
>+		NDIS_UNLOCK(sc);
>+	}

I think this is harder than it needs to be. It locks, unlocks, and then
locks again in ndis_watchdog. I have attached a version of this diff
that nukes ndis_watchdog() and just merges the code. Its also a pain to
use nmb_checkforhangsecs for the timer period, the ndis driver blob can
set this to whatever it desires and it could be far greater than the
watchdog period of 5 secs.

I introduced two counters, ndis_tx_timer and ndis_hang_timer, that allow
these events to be independent of each other.

> 	return;
> }
> 
>@@ -1888,7 +1904,9 @@ ndis_start(ifp)
> 	/*
> 	 * Set a timeout in case the chip goes out to lunch.
> 	 */
>-	ifp->if_timer = 5;
>+	if(sc->ndis_timer_countdown == 0) {
>+		sc->ndis_timer_countdown = 5;
>+	}

This isnt right. The timer doesnt need to expire in order to be reset,
it should just set it each time. Otherwise if the timer is at 1 and the
callout is _just_ about to fire then you will get a false watchdog
timeout.



cheers,
Andrew

--2oS5YaxWCcQjTEyO
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="ndis_watchdog.diff"

Index: if_ndis.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/if_ndis/if_ndis.c,v
retrieving revision 1.139
diff -u -p -r1.139 if_ndis.c
--- if_ndis.c	12 May 2008 00:15:28 -0000	1.139
+++ if_ndis.c	30 May 2008 05:57:03 -0000
@@ -161,7 +161,6 @@ static void ndis_scan_curchan	(struct ie
 static void ndis_scan_mindwell	(struct ieee80211_scan_state *);
 static void ndis_init		(void *);
 static void ndis_stop		(struct ndis_softc *);
-static void ndis_watchdog	(struct ifnet *);
 static int ndis_ifmedia_upd	(struct ifnet *);
 static void ndis_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
 static void ndis_auth		(void *, int);
@@ -537,6 +536,7 @@ ndis_attach(dev)
 	KeInitializeSpinLock(&sc->ndis_spinlock);
 	KeInitializeSpinLock(&sc->ndis_rxlock);
 	InitializeListHead(&sc->ndis_shlist);
+	callout_init(&sc->ndis_stat_callout, CALLOUT_MPSAFE);
 
 	if (sc->ndis_iftype == PCMCIABus) {
 		error = ndis_alloc_amem(sc);
@@ -695,7 +695,6 @@ ndis_attach(dev)
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = ndis_ioctl;
 	ifp->if_start = ndis_start;
-	ifp->if_watchdog = ndis_watchdog;
 	ifp->if_init = ndis_init;
 	ifp->if_baudrate = 10000000;
 	IFQ_SET_MAXLEN(&ifp->if_snd, 50);
@@ -1540,7 +1539,7 @@ ndis_txeof(adapter, packet, status)
 	else
 		ifp->if_oerrors++;
 
-	ifp->if_timer = 0;
+	sc->ndis_tx_timer = 0;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
 	NDIS_UNLOCK(sc);
@@ -1642,14 +1641,29 @@ ndis_tick(xsc)
 	struct ndis_softc	*sc;
 
 	sc = xsc;
+	NDIS_LOCK(sc);
 
-	IoQueueWorkItem(sc->ndis_tickitem,
-	    (io_workitem_func)ndis_ticktask_wrap,
-	    WORKQUEUE_CRITICAL, sc);
-	callout_reset(&sc->ndis_stat_callout,
-	    hz * sc->ndis_block->nmb_checkforhangsecs, ndis_tick, sc);
+	if (sc->ndis_hang_timer && --sc->ndis_hang_timer == 0) {
+		IoQueueWorkItem(sc->ndis_tickitem,
+		    (io_workitem_func)ndis_ticktask_wrap,
+		    WORKQUEUE_CRITICAL, sc);
+		sc->ndis_hang_timer = sc->ndis_block->nmb_checkforhangsecs;
+	}
 
-	return;
+	if (sc->ndis_tx_timer && --sc->ndis_tx_timer == 0) {
+		sc->ifp->if_oerrors++;
+		device_printf(sc->ndis_dev, "watchdog timeout\n");
+
+		IoQueueWorkItem(sc->ndis_resetitem,
+		    (io_workitem_func)ndis_resettask_wrap,
+		    WORKQUEUE_CRITICAL, sc);
+		IoQueueWorkItem(sc->ndis_startitem,
+		    (io_workitem_func)ndis_starttask_wrap,
+		    WORKQUEUE_CRITICAL, sc->ifp);
+	}
+
+	callout_reset(&sc->ndis_stat_callout, hz, ndis_tick, sc);
+	NDIS_UNLOCK(sc);
 }
 
 static void
@@ -1888,7 +1902,7 @@ ndis_start(ifp)
 	/*
 	 * Set a timeout in case the chip goes out to lunch.
 	 */
-	ifp->if_timer = 5;
+	sc->ndis_tx_timer = 5;
 
 	NDIS_UNLOCK(sc);
 
@@ -1982,11 +1996,7 @@ ndis_init(xsc)
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-
-	NDIS_UNLOCK(sc);
-
-	/* XXX force handling */
-	ieee80211_start_all(ic);		/* start all vap's */
+	sc->ndis_tx_timer = 0;
 
 	/*
 	 * Some drivers don't set this value. The NDIS spec says
@@ -1994,15 +2004,15 @@ ndis_init(xsc)
 	 * seconds." We use 3 seconds, because it seems for some
 	 * drivers, exactly 2 seconds is too fast.
 	 */
-
 	if (sc->ndis_block->nmb_checkforhangsecs == 0)
 		sc->ndis_block->nmb_checkforhangsecs = 3;
 
-	callout_init(&sc->ndis_stat_callout, CALLOUT_MPSAFE);
-	callout_reset(&sc->ndis_stat_callout,
-	    hz * sc->ndis_block->nmb_checkforhangsecs, ndis_tick, sc);
+	sc->ndis_hang_timer = sc->ndis_block->nmb_checkforhangsecs;
+	callout_reset(&sc->ndis_stat_callout, hz, ndis_tick, sc);
+	NDIS_UNLOCK(sc);
 
-	return;
+	/* XXX force handling */
+	ieee80211_start_all(ic);		/* start all vap's */
 }
 
 /*
@@ -3112,29 +3122,6 @@ ndis_resettask(d, arg)
 	return;
 }
 
-static void
-ndis_watchdog(ifp)
-	struct ifnet		*ifp;
-{
-	struct ndis_softc		*sc;
-
-	sc = ifp->if_softc;
-
-	NDIS_LOCK(sc);
-	ifp->if_oerrors++;
-	device_printf(sc->ndis_dev, "watchdog timeout\n");
-	NDIS_UNLOCK(sc);
-
-	IoQueueWorkItem(sc->ndis_resetitem,
-	    (io_workitem_func)ndis_resettask_wrap,
-	    WORKQUEUE_CRITICAL, sc);
-	IoQueueWorkItem(sc->ndis_startitem,
-	    (io_workitem_func)ndis_starttask_wrap,
-	    WORKQUEUE_CRITICAL, ifp);
-
-	return;
-}
-
 /*
  * Stop the adapter and free any mbufs allocated to the
  * RX and TX lists.
@@ -3150,7 +3137,7 @@ ndis_stop(sc)
 	callout_drain(&sc->ndis_stat_callout);
 
 	NDIS_LOCK(sc);
-	ifp->if_timer = 0;
+	sc->ndis_tx_timer = 0;
 	sc->ndis_link = 0;
 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
 	NDIS_UNLOCK(sc);
Index: if_ndisvar.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/if_ndis/if_ndisvar.h,v
retrieving revision 1.31
diff -u -p -r1.31 if_ndisvar.h
--- if_ndisvar.h	10 May 2008 20:12:43 -0000	1.31
+++ if_ndisvar.h	30 May 2008 05:29:02 -0000
@@ -181,6 +181,8 @@ struct ndis_softc {
 	struct task		ndis_assoctask;
 	int			(*ndis_newstate)(struct ieee80211com *,
 				    enum ieee80211_state, int);
+	int			ndis_tx_timer;
+	int			ndis_hang_timer;
 };
 
 #define NDIS_LOCK(_sc)		KeAcquireSpinLock(&(_sc)->ndis_spinlock, \

--2oS5YaxWCcQjTEyO--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080530060141.GB68753>