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 */