Subject: another if_cnw.c stabilization
To: None <tech-net@netbsd.org>
From: Jun-ichiro itojun Hagino <itojun@iijlab.net>
List: tech-net
Date: 01/22/2000 01:48:49
------- =_aaaaaaaaaa0
Content-Type: text/plain; charset="us-ascii"
Content-ID: <19496.948473314.1@lychee.itojun.org>
Content-Transfer-Encoding: 7bit

	this patch integrates one of stabilization patch from freebsd PAO/bsdi
	cnw driver.  I'm not sure if it really stabilizes the behavior, so
	I'd like to solicit your experience reports.  Please let me know if
	it works for you, or not.

	taken against KAME NetBSD 1.4.1, but should apply fine against
	NetBSD-current.

itojun

------- =_aaaaaaaaaa0
Content-Type: text/plain; charset="us-ascii"
Content-ID: <19496.948473314.2@lychee.itojun.org>
Content-Transfer-Encoding: 7bit

Index: if_cnw.c
===================================================================
RCS file: /cvsroot/kame/kame/netbsd/sys/dev/pcmcia/if_cnw.c,v
retrieving revision 1.2
diff -c -r1.2 if_cnw.c
*** if_cnw.c	1999/11/29 12:23:17	1.2
--- if_cnw.c	2000/01/21 16:42:21
***************
*** 163,168 ****
--- 163,179 ----
  #endif
  int cnw_skey = CNW_SCRAMBLEKEY;		/* Scramble key */
  
+ /*
+  * The card appears to work much better when we only allow one packet
+  * "in the air" at a time.  This is done by not allowing another packet
+  * on the card, even if there is room.  Turning this off will allow the
+  * driver to stuff packets on the card as soon as a transmit buffer is
+  * available.  This does increase the number of collisions, though.
+  * We can que a second packet if there are transmit buffers available,
+  * but we do not actually send the packet until the last packet has
+  * been written.
+  */
+ #define	ONE_AT_A_TIME
  
  int	cnw_match __P((struct device *, struct cfdata *, void *));
  void	cnw_attach __P((struct device *, struct device *, void *));
***************
*** 186,191 ****
--- 197,204 ----
  	bus_space_tag_t sc_memt;	    /*   ...bus_space tag */
  	bus_space_handle_t sc_memh;	    /*   ...bus_space handle */
  	void *sc_ih;			    /* Interrupt cookie */
+ 	struct timeval sc_txlast;	    /* When the last xmit was made */
+ 	int sc_active;			    /* Currently xmitting a packet */
  };
  
  struct cfattach cnw_ca = {
***************
*** 386,391 ****
--- 399,405 ----
  		return (EIO);
  	}
  	cnw_init(sc);
+ 	ifp->if_flags &= ~IFF_OACTIVE;
  	ifp->if_flags |= IFF_RUNNING;
  	return (0);
  }
***************
*** 528,541 ****
--- 542,602 ----
  {
  	struct cnw_softc *sc = ifp->if_softc;
  	struct mbuf *m0;
+ 	int lif;
  	int asr;
+ #ifdef ONE_AT_A_TIME
+ 	struct timeval now;
+ #endif
  
  #ifdef CNW_DEBUG
  	if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  		printf("%s: cnw_start\n", ifp->if_xname);
+ 	if (ifp->if_flags & IFF_OACTIVE)
+ 		printf("%s: cnw_start reentered\n", ifp->if_xname);
  #endif
  
+ 	ifp->if_flags |= IFF_OACTIVE;
+ 
  	for (;;) {
+ #ifdef ONE_AT_A_TIME
+ 		microtime(&now);
+ 		now.tv_sec -= sc->sc_txlast.tv_sec;
+ 		now.tv_usec -= sc->sc_txlast.tv_usec;
+ 		if (now.tv_usec < 0) {
+ 			now.tv_usec += 1000000;
+ 			now.tv_sec--;
+ 		}
+ 
+ 		/*
+ 		 * Don't ship this packet out until the last
+ 		 * packet has left the building.
+ 		 * If we have not tried to send a packet for 1/5
+ 		 * a second then we assume we lost an interrupt,
+ 		 * lets go on and send the next packet anyhow.
+ 		 *
+ 		 * I suppose we could check to see if it is okay
+ 		 * to put additional packets on the card (beyond
+ 		 * the one already waiting to be sent) but I don't
+ 		 * think we would get any improvement in speed as
+ 		 * we should have ample time to put the next packet
+ 		 * on while this one is going out.
+ 		 */
+ 		if (sc->sc_active && now.tv_sec == 0 && now.tv_usec < 200000)
+ 			break;
+ #endif
+ 
+ 		/* Make sure the link integrity field is on */
+ 		WAIT_WOC(sc);
+ 		lif = bus_space_read_1(sc->sc_memt, sc->sc_memh,
+ 		    sc->sc_memoff + CNW_EREG_LIF);
+ 		if (lif == 0) {
+ #ifdef CNW_DEBUG
+ 			if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
+ 				printf("%s: link integrity %d\n", lif);
+ #endif
+ 			break;
+ 		}
+ 
  		/* Is there any buffer space available on the card? */
  		WAIT_WOC(sc);
  		asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
***************
*** 544,557 ****
  			if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  				printf("%s: no buffer space\n", ifp->if_xname);
  #endif
! 			return;
  		}
  
  		sc->sc_stats.nws_tx++;
  
  		IF_DEQUEUE(&ifp->if_snd, m0);
  		if (m0 == 0)
! 			return;
  
  #if NBPFILTER > 0
  		if (ifp->if_bpf)
--- 605,618 ----
  			if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  				printf("%s: no buffer space\n", ifp->if_xname);
  #endif
! 			break;
  		}
  
  		sc->sc_stats.nws_tx++;
  
  		IF_DEQUEUE(&ifp->if_snd, m0);
  		if (m0 == 0)
! 			break;
  
  #if NBPFILTER > 0
  		if (ifp->if_bpf)
***************
*** 561,569 ****
  		cnw_transmit(sc, m0);
  		++ifp->if_opackets;
  		ifp->if_timer = 3; /* start watchdog timer */
  	}
- }
  
  
  /*
   * Transmit a packet.
--- 622,634 ----
  		cnw_transmit(sc, m0);
  		++ifp->if_opackets;
  		ifp->if_timer = 3; /* start watchdog timer */
+ 
+ 		microtime(&sc->sc_txlast);
+ 		sc->sc_active = 1;
  	}
  
+ 	ifp->if_flags &= ~IFF_OACTIVE;
+ }
  
  /*
   * Transmit a packet.
***************
*** 869,874 ****
--- 934,943 ----
  				    (tser & CNW_TSER_ERROR) |
  				    CNW_TSER_RTRY);
  			}
+ 
+ 			sc->sc_active = 0;
+ 			ifp->if_flags &= ~IFF_OACTIVE;
+ 
  			/* Continue to send packets from the queue */
  			cnw_start(&sc->sc_ethercom.ec_if);
  		}

------- =_aaaaaaaaaa0--