Subject: kern/30221: Collision counter of wm(4) only counts excessive collisions
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <umezawa@iij.ad.jp>
List: netbsd-bugs
Date: 05/13/2005 08:32:00
>Number:         30221
>Category:       kern
>Synopsis:       Collision counter of wm(4) only counts excessive collisions
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri May 13 08:32:00 +0000 2005
>Originator:     UMEZAWA Takeshi
>Release:        1.6.2
>Organization:
Internet Initiative Japan
>Environment:
NetBSD idgw07.iij.ad.jp 1.6.2_STABLE NetBSD 1.6.2_STABLE (GENERIC) #0: Mon May  2 11:40:58 JST 2005     root@idgw07.iij.ad.jp:/usr/src/sys/arch/i386/compile/GENERIC i386

>Description:
if_collision of wm(4) is incremented (+=16) only when the NIC failed to
send frames because of excessive collisions. If the number of contiguous
collisions are less than 16 and the transmission is finally successful,
if_collision is not incremented.

if_collision should be incremented whether collisions are excessive or not.
>How-To-Repeat:
-
>Fix:
A patch follows. It updates if_collision periodically in wm_tick().

diff -u orig/if_wm.c new/if_wm.c
--- orig/if_wm.c	Fri May 13 17:12:29 2005
+++ new/if_wm.c	Fri May 13 17:27:24 2005
@@ -396,6 +396,7 @@
 int	wm_add_rxbuf(struct wm_softc *, int);
 void	wm_read_eeprom(struct wm_softc *, int, int, u_int16_t *);
 void	wm_tick(void *);
+void	wm_stats_update(struct wm_softc *);
 
 void	wm_set_filter(struct wm_softc *);
 
@@ -1605,11 +1606,9 @@
 			if (status & WTX_ST_LC)
 				printf("%s: late collision\n",
 				    sc->sc_dev.dv_xname);
-			else if (status & WTX_ST_EC) {
-				ifp->if_collisions += 16;
+			else if (status & WTX_ST_EC)
 				printf("%s: excessive collisions\n",
 				    sc->sc_dev.dv_xname);
-			}
 		} else
 			ifp->if_opackets++;
 
@@ -1924,9 +1923,26 @@
 	else
 		wm_tbi_check_link(sc);
 
+	wm_stats_update(sc);
+
 	splx(s);
 
 	callout_reset(&sc->sc_tick_ch, hz, wm_tick, sc);
+}
+
+/*
+ * wm_stats_update:
+ *
+ *	Update statistics counters. Typically called from wm_tick().
+ *	Must be called at splnet().
+ *
+ */
+void
+wm_stats_update(struct wm_softc *sc)
+{
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+
+	ifp->if_collisions += CSR_READ(sc, WMREG_COLC);
 }
 
 /*
diff -u orig/if_wmreg.h new/if_wmreg.h
--- orig/if_wmreg.h	Fri May 13 17:12:29 2005
+++ new/if_wmreg.h	Fri May 13 17:12:13 2005
@@ -514,6 +514,8 @@
 #define	TSPMT_TSMT(x)	(x)		/* TCP seg min transfer */
 #define	TSPMT_TSPBP(x)	((x) << 16)	/* TCP seg pkt buf padding */
 
+#define	WMREG_COLC	0x4028	/* Collision Count */
+
 #define	WMREG_RXCSUM	0x5000	/* Receive Checksum register */
 #define	RXCSUM_PCSS	0x000000ff	/* Packet Checksum Start */
 #define	RXCSUM_IPOFL	(1U << 8)	/* IP checksum offload */