Subject: kern/30349: Input error counter of wm(4) doesn't count error frames
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <umezawa@iij.ad.jp>
List: netbsd-bugs
Date: 05/27/2005 04:57:00
>Number: 30349
>Category: kern
>Synopsis: Input error counter of wm(4) doesn't count error frames
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri May 27 04:57: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_ierrors of wm(4) is incremented only when wm_add_rxbuf() failed, and is
not incremented when hardware received error frames.
There is the code that increments if_ierrors according to error status of
RX descriptors. But error frames are never stored to RX buffer because
RCTL_SBP (Store Bad Packets) bit of WMREG_RCTL is not set.
>How-To-Repeat:
Connect with duplex mismatch, and receive packets.
There must be many input errors, but if_ierrors is not (or rarely)
incremented.
>Fix:
There are two ways to count error frames.
The first way is, as written in Full Description, setting RCTL_SBP bit.
And the second way is correcting error counts from hardware statistics
registers periodically.
The advantage of the first way is:
1. If the number of error frames is small, the impact for performance
is also small.
The advantages of the second way is:
1. Regardless of the number of error frames, the impact for
performance is constant.
2. Regardless of the number of received (or error) frames, error
counter can be correctly incremented.
I have written a patch that implements the second way. Note that this
patch requires the patch which is submitted in PR kern/30221.
diff -u old/if_wm.c new/if_wm.c
--- old/if_wm.c Fri May 27 13:52:32 2005
+++ new/if_wm.c Fri May 27 13:52:44 2005
@@ -1749,7 +1749,6 @@
*/
if (errors &
(WRX_ER_CE|WRX_ER_SE|WRX_ER_SEQ|WRX_ER_CXE|WRX_ER_RXE)) {
- ifp->if_ierrors++;
if (errors & WRX_ER_SE)
printf("%s: symbol error\n",
sc->sc_dev.dv_xname);
@@ -1943,6 +1942,15 @@
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
ifp->if_collisions += CSR_READ(sc, WMREG_COLC);
+
+ ifp->if_ierrors += 0ULL + /* ensure quad_t */
+ CSR_READ(sc, WMREG_CRCERRS) +
+ CSR_READ(sc, WMREG_ALGNERRC) +
+ CSR_READ(sc, WMREG_SYMERRC) +
+ CSR_READ(sc, WMREG_RXERRC) +
+ CSR_READ(sc, WMREG_SEC) +
+ CSR_READ(sc, WMREG_CEXTERR) +
+ CSR_READ(sc, WMREG_RLEC);
}
/*
diff -u old/if_wmreg.h new/if_wmreg.h
--- old/if_wmreg.h Fri May 27 13:52:32 2005
+++ new/if_wmreg.h Fri May 27 13:52:44 2005
@@ -514,7 +514,14 @@
#define TSPMT_TSMT(x) (x) /* TCP seg min transfer */
#define TSPMT_TSPBP(x) ((x) << 16) /* TCP seg pkt buf padding */
+#define WMREG_CRCERRS 0x4000 /* CRC Error Count */
+#define WMREG_ALGNERRC 0x4004 /* Alignment Error Count */
+#define WMREG_SYMERRC 0x4008 /* Symbol Error Count */
+#define WMREG_RXERRC 0x400c /* RX Error Count */
#define WMREG_COLC 0x4028 /* Collision Count */
+#define WMREG_SEC 0x4038 /* Sequence Error Count */
+#define WMREG_CEXTERR 0x403c /* Carrier Extension Error Count */
+#define WMREG_RLEC 0x4040 /* Receive Length Error Count */
#define WMREG_RXCSUM 0x5000 /* Receive Checksum register */
#define RXCSUM_PCSS 0x000000ff /* Packet Checksum Start */