Module Name:    src
Committed By:   martin
Date:           Thu Jun 22 08:14:35 UTC 2023

Modified Files:
        src/sys/dev/pci [netbsd-10]: if_wm.c if_wmreg.h if_wmvar.h

Log Message:
Pull up following revision(s) (requested by msaitoh in ticket #213):

        sys/dev/pci/if_wm.c: revision 1.770
        sys/dev/pci/if_wm.c: revision 1.771
        sys/dev/pci/if_wm.c: revision 1.772
        sys/dev/pci/if_wm.c: revision 1.773
        sys/dev/pci/if_wm.c: revision 1.774
        sys/dev/pci/if_wm.c: revision 1.775
        sys/dev/pci/if_wm.c: revision 1.776
        sys/dev/pci/if_wmreg.h: revision 1.129
        sys/dev/pci/if_wm.c: revision 1.777
        sys/dev/pci/if_wm.c: revision 1.778
        sys/dev/pci/if_wmvar.h: revision 1.49
        sys/dev/pci/if_wm.c: revision 1.779
        sys/dev/pci/if_wm.c: revision 1.768
        sys/dev/pci/if_wm.c: revision 1.769
        sys/dev/pci/if_wmreg.h: revision 1.130
        sys/dev/pci/if_wm.c: revision 1.780
        sys/dev/pci/if_wm.c: revision 1.781

Count some 64bit counters correctly.
 - Fix calculation of GORC, GOTC, TOR and TOT counters correctly.
 - Found by knakahara.

Add note for the TORL register.

The TOR register includes error, flow control and broadcast rejected.

Sort lines. No functional change.

 Rearrange the order of the registers so that they are roughly in ascending
order.

Sort lines. No functional change.

Reorder evcnt_attach_dynamic(), WM_EVCNT_ADD() and evcnt_detach() to match.
IC{TX,RX}*C registers are for older than 82575.

Fix a bug that the transmit underrun counter is incorrectly counted.
 The transmit underrun bit in the transmit status filed is only for 82544
(and older?), so don't use the counter for newer chips. The bit is reserved
for newer chips, but the bit sometimes set on 82575 at least.

Don't add "Count" for event counter's description.

 Some statistics registers were replaced with new counters.
 - 0x403c was CEXTERR(Carrier Extension Error). 82575 and newer except 80003,
   ICHs and PCHs have HTDPMC(Host Tx Discarded Packets by MAC). I don't really
   know for 82575. The 82575 datasheet say nothing about it.
 - The following two are changed for circuit breaker. Only 82576's datasheet
   describes abut it, so the registers might be only for 82576.
   Use those registers for 82575 and newer except 80003, ICHs and PCHs just in
   case.
   - 0x40fc was TSCTFC(TCP Segmentation Context Tx Fail). It was replaced by
     the CBRMPC(Circuit Breaker Rx Manageability Packet) register.
   - 0x4124 was ICRXOC(Interrupt Cause Receiver Overrun). It was replaced by
     the HTCBDPC(Host Tx Circuit Breaker Dropped Packet) register.
 - From 0x4104 to 0x4124:
   - For 0x4124, 82575's datasheet says it's not changed(ICRXOC).
     I don't know if it's correct. We use new HTCBDPC register for 82575.
   - 82576 and newer changed the meaning.
   - I don't know for 80003, ICHs and PCHs. Don't count those registers.
     At least, those registers in PCH2 and PCH_CNP are all zero.

Add some new event counters.

Add the following counters for 82575 and newer except 80003, ICHs and PCHs:
    - Only 82576 document describes about the circuit breaker,
      so the following two might be only for 82575:
        - Circuit Breaker TX Manageability Packet
        - Circuit Breaker RX Dropped Packet
    - 82575's document doesn't describe the following two, but we can see
      the same value as GO{T,R}C have:
        - Host Good Octets RX
        - Host Good Octets TX
    - 82575's document doesn't describe the LENERRS (Length Errors) counter.
      I don't know if it has.
    - Perhaps Non-SerDes/SGMII devices don't have SCVPC
      (SerDes/SGMII Code Violation Packet) register. We don't care if
      it's SerDes/SGMII or not for now.
    - HRMPC (Header Redirection Missed Packet) appears only once
      in 8257[56]'s datasheet. FreeBSD's igb counts it, so we do, too.
    - Count the following two for I350 and newer. I don't know if PCHs have:
        - EEE TX LPI
        - EEE RX LPI

 Move statistics updating code from wm_tick() to new wm_update_stats().
 - To reuse.
 - No functional change.

Add SOICZIFDATA (ifconfig -z) support for evcnt(9).

 First update the statistics data, then clear the event counters,
and finally copy and clear if_data via ether_ioctl().

Fix prc511's comment and description.

 Use WM_IS_ICHPCH(). No functional change.

Fix typo. s/ictxact/ictxatc/. No functional change.


To generate a diff of this commit:
cvs rdiff -u -r1.767 -r1.767.2.1 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.128 -r1.128.2.1 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.48 -r1.48.4.1 src/sys/dev/pci/if_wmvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.767 src/sys/dev/pci/if_wm.c:1.767.2.1
--- src/sys/dev/pci/if_wm.c:1.767	Thu Dec  8 08:14:28 2022
+++ src/sys/dev/pci/if_wm.c	Thu Jun 22 08:14:35 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.767 2022/12/08 08:14:28 knakahara Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.767.2.1 2023/06/22 08:14:35 martin Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -82,7 +82,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.767 2022/12/08 08:14:28 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.767.2.1 2023/06/22 08:14:35 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_if_wm.h"
@@ -585,10 +585,10 @@ struct wm_softc {
 	struct evcnt sc_ev_linkintr;	/* Link interrupts */
 
 	/* >= WM_T_82542_2_1 */
-	struct evcnt sc_ev_tx_xoff;	/* Tx PAUSE(!0) frames */
+	struct evcnt sc_ev_rx_xon;	/* Rx PAUSE(0) frames */
 	struct evcnt sc_ev_tx_xon;	/* Tx PAUSE(0) frames */
 	struct evcnt sc_ev_rx_xoff;	/* Rx PAUSE(!0) frames */
-	struct evcnt sc_ev_rx_xon;	/* Rx PAUSE(0) frames */
+	struct evcnt sc_ev_tx_xoff;	/* Tx PAUSE(!0) frames */
 	struct evcnt sc_ev_rx_macctl;	/* Rx Unsupported */
 
 	struct evcnt sc_ev_crcerrs;	/* CRC Error */
@@ -596,15 +596,29 @@ struct wm_softc {
 	struct evcnt sc_ev_symerrc;	/* Symbol Error */
 	struct evcnt sc_ev_rxerrc;	/* Receive Error */
 	struct evcnt sc_ev_mpc;		/* Missed Packets */
-	struct evcnt sc_ev_colc;	/* Collision */
-	struct evcnt sc_ev_sec;		/* Sequence Error */
-	struct evcnt sc_ev_cexterr;	/* Carrier Extension Error */
-	struct evcnt sc_ev_rlec;	/* Receive Length Error */
 	struct evcnt sc_ev_scc;		/* Single Collision */
 	struct evcnt sc_ev_ecol;	/* Excessive Collision */
 	struct evcnt sc_ev_mcc;		/* Multiple Collision */
 	struct evcnt sc_ev_latecol;	/* Late Collision */
+	struct evcnt sc_ev_colc;	/* Collision */
+	struct evcnt sc_ev_cbtmpc;	/* Circuit Breaker Tx Mng. Packet */
 	struct evcnt sc_ev_dc;		/* Defer */
+	struct evcnt sc_ev_tncrs;	/* Tx-No CRS */
+	struct evcnt sc_ev_sec;		/* Sequence Error */
+
+	/* Old */
+	struct evcnt sc_ev_cexterr;	/* Carrier Extension Error */
+	/* New */
+	struct evcnt sc_ev_htdpmc;	/* Host Tx Discarded Pkts by MAC */
+
+	struct evcnt sc_ev_rlec;	/* Receive Length Error */
+	struct evcnt sc_ev_cbrdpc;	/* Circuit Breaker Rx Dropped Packet */
+	struct evcnt sc_ev_prc64;	/* Packets Rx (64 bytes) */
+	struct evcnt sc_ev_prc127;	/* Packets Rx (65-127 bytes) */
+	struct evcnt sc_ev_prc255;	/* Packets Rx (128-255 bytes) */
+	struct evcnt sc_ev_prc511;	/* Packets Rx (256-511 bytes) */
+	struct evcnt sc_ev_prc1023;	/* Packets Rx (512-1023 bytes) */
+	struct evcnt sc_ev_prc1522;	/* Packets Rx (1024-1522 bytes) */
 	struct evcnt sc_ev_gprc;	/* Good Packets Rx */
 	struct evcnt sc_ev_bprc;	/* Broadcast Packets Rx */
 	struct evcnt sc_ev_mprc;	/* Multicast Packets Rx */
@@ -616,44 +630,62 @@ struct wm_softc {
 	struct evcnt sc_ev_rfc;		/* Rx Fragment */
 	struct evcnt sc_ev_roc;		/* Rx Oversize */
 	struct evcnt sc_ev_rjc;		/* Rx Jabber */
+	struct evcnt sc_ev_mgtprc;	/* Management Packets RX */
+	struct evcnt sc_ev_mgtpdc;	/* Management Packets Dropped */
+	struct evcnt sc_ev_mgtptc;	/* Management Packets TX */
 	struct evcnt sc_ev_tor;		/* Total Octets Rx */
 	struct evcnt sc_ev_tot;		/* Total Octets Tx */
 	struct evcnt sc_ev_tpr;		/* Total Packets Rx */
 	struct evcnt sc_ev_tpt;		/* Total Packets Tx */
-	struct evcnt sc_ev_mptc;	/* Multicast Packets Tx */
-	struct evcnt sc_ev_bptc;	/* Broadcast Packets Tx Count */
-	struct evcnt sc_ev_prc64;	/* Packets Rx (64 bytes) */
-	struct evcnt sc_ev_prc127;	/* Packets Rx (65-127 bytes) */
-	struct evcnt sc_ev_prc255;	/* Packets Rx (128-255 bytes) */
-	struct evcnt sc_ev_prc511;	/* Packets Rx (255-511 bytes) */
-	struct evcnt sc_ev_prc1023;	/* Packets Rx (512-1023 bytes) */
-	struct evcnt sc_ev_prc1522;	/* Packets Rx (1024-1522 bytes) */
 	struct evcnt sc_ev_ptc64;	/* Packets Tx (64 bytes) */
 	struct evcnt sc_ev_ptc127;	/* Packets Tx (65-127 bytes) */
 	struct evcnt sc_ev_ptc255;	/* Packets Tx (128-255 bytes) */
 	struct evcnt sc_ev_ptc511;	/* Packets Tx (256-511 bytes) */
 	struct evcnt sc_ev_ptc1023;	/* Packets Tx (512-1023 bytes) */
 	struct evcnt sc_ev_ptc1522;	/* Packets Tx (1024-1522 Bytes) */
+	struct evcnt sc_ev_mptc;	/* Multicast Packets Tx */
+	struct evcnt sc_ev_bptc;	/* Broadcast Packets Tx */
+	struct evcnt sc_ev_tsctc;	/* TCP Segmentation Context Tx */
+
+	/* Old */
+	struct evcnt sc_ev_tsctfc;	/* TCP Segmentation Context Tx Fail */
+	/* New */
+	struct evcnt sc_ev_cbrmpc;	/* Circuit Breaker Rx Mng. Packet */
+
 	struct evcnt sc_ev_iac;		/* Interrupt Assertion */
+
+	/* Old */
 	struct evcnt sc_ev_icrxptc;	/* Intr. Cause Rx Pkt Timer Expire */
 	struct evcnt sc_ev_icrxatc;	/* Intr. Cause Rx Abs Timer Expire */
 	struct evcnt sc_ev_ictxptc;	/* Intr. Cause Tx Pkt Timer Expire */
-	struct evcnt sc_ev_ictxact;	/* Intr. Cause Tx Abs Timer Expire */
+	struct evcnt sc_ev_ictxatc;	/* Intr. Cause Tx Abs Timer Expire */
 	struct evcnt sc_ev_ictxqec;	/* Intr. Cause Tx Queue Empty */
 	struct evcnt sc_ev_ictxqmtc;	/* Intr. Cause Tx Queue Min Thresh */
-	struct evcnt sc_ev_icrxdmtc;	/* Intr. Cause Rx Desc Min Thresh */
+	/*
+	 * sc_ev_rxdmtc is shared with both "Intr. cause" and
+	 * non "Intr. cause" register.
+	 */
+	struct evcnt sc_ev_rxdmtc;	/* (Intr. Cause) Rx Desc Min Thresh */
 	struct evcnt sc_ev_icrxoc;	/* Intr. Cause Receiver Overrun */
-	struct evcnt sc_ev_tncrs;	/* Tx-No CRS */
-	struct evcnt sc_ev_tsctc;	/* TCP Segmentation Context Tx */
-	struct evcnt sc_ev_tsctfc;	/* TCP Segmentation Context Tx Fail */
-	struct evcnt sc_ev_mgtprc;	/* Management Packets RX */
-	struct evcnt sc_ev_mgtpdc;	/* Management Packets Dropped */
-	struct evcnt sc_ev_mgtptc;	/* Management Packets TX */
+	/* New */
+	struct evcnt sc_ev_rpthc;	/* Rx Packets To Host */
+	struct evcnt sc_ev_debug1;	/* Debug Counter 1 */
+	struct evcnt sc_ev_debug2;	/* Debug Counter 2 */
+	struct evcnt sc_ev_debug3;	/* Debug Counter 3 */
+	struct evcnt sc_ev_hgptc;	/* Host Good Packets TX */
+	struct evcnt sc_ev_debug4;	/* Debug Counter 4 */
+	struct evcnt sc_ev_htcbdpc;	/* Host Tx Circuit Breaker Drp. Pkts */
+	struct evcnt sc_ev_hgorc;	/* Host Good Octets Rx */
+	struct evcnt sc_ev_hgotc;	/* Host Good Octets Tx */
+	struct evcnt sc_ev_lenerrs;	/* Length Error */
+	struct evcnt sc_ev_tlpic;	/* EEE Tx LPI */
+	struct evcnt sc_ev_rlpic;	/* EEE Rx LPI */
 	struct evcnt sc_ev_b2ogprc;	/* BMC2OS pkts received by host */
 	struct evcnt sc_ev_o2bspc;	/* OS2BMC pkts transmitted by host */
 	struct evcnt sc_ev_b2ospc;	/* BMC2OS pkts sent by BMC */
 	struct evcnt sc_ev_o2bgptc;	/* OS2BMC pkts received by BMC */
-
+	struct evcnt sc_ev_scvpc;	/* SerDes/SGMII Code Violation Pkt. */
+	struct evcnt sc_ev_hrmpc;	/* Header Redirection Missed Packet */
 #endif /* WM_EVENT_COUNTERS */
 
 	struct sysctllog *sc_sysctllog;
@@ -725,25 +757,33 @@ do {									\
 #define	WM_EVCNT_INCR(ev)						\
 	atomic_store_relaxed(&((ev)->ev_count),				\
 	    atomic_load_relaxed(&(ev)->ev_count) + 1)
+#define	WM_EVCNT_STORE(ev, val)						\
+	atomic_store_relaxed(&((ev)->ev_count), (val))
 #define	WM_EVCNT_ADD(ev, val)						\
 	atomic_store_relaxed(&((ev)->ev_count),				\
 	    atomic_load_relaxed(&(ev)->ev_count) + (val))
 #else
 #define	WM_EVCNT_INCR(ev)						\
 	((ev)->ev_count)++
+#define	WM_EVCNT_STORE(ev, val)						\
+	((ev)->ev_count = (val))
 #define	WM_EVCNT_ADD(ev, val)						\
 	(ev)->ev_count += (val)
 #endif
 
 #define WM_Q_EVCNT_INCR(qname, evname)			\
 	WM_EVCNT_INCR(&(qname)->qname##_ev_##evname)
+#define WM_Q_EVCNT_STORE(qname, evname, val)		\
+	WM_EVCNT_STORE(&(qname)->qname##_ev_##evname, (val))
 #define WM_Q_EVCNT_ADD(qname, evname, val)		\
 	WM_EVCNT_ADD(&(qname)->qname##_ev_##evname, (val))
 #else /* !WM_EVENT_COUNTERS */
 #define	WM_EVCNT_INCR(ev)	/* nothing */
+#define	WM_EVCNT_STORE(ev, val)	/* nothing */
 #define	WM_EVCNT_ADD(ev, val)	/* nothing */
 
 #define WM_Q_EVCNT_INCR(qname, evname)		/* nothing */
+#define WM_Q_EVCNT_STORE(qname, evname, val)	/* nothing */
 #define WM_Q_EVCNT_ADD(qname, evname, val)	/* nothing */
 #endif /* !WM_EVENT_COUNTERS */
 
@@ -852,6 +892,8 @@ static int	wm_setup_msix(struct wm_softc
 static int	wm_init(struct ifnet *);
 static int	wm_init_locked(struct ifnet *);
 static void	wm_init_sysctls(struct wm_softc *);
+static void	wm_update_stats(struct wm_softc *);
+static void	wm_clear_evcnt(struct wm_softc *);
 static void	wm_unset_stopping_flags(struct wm_softc *);
 static void	wm_set_stopping_flags(struct wm_softc *);
 static void	wm_stop(struct ifnet *, int);
@@ -3199,6 +3241,53 @@ alloc_retry:
 	evcnt_attach_dynamic(&sc->sc_ev_linkintr, EVCNT_TYPE_INTR,
 	    NULL, xname, "linkintr");
 
+	evcnt_attach_dynamic(&sc->sc_ev_crcerrs, EVCNT_TYPE_MISC,
+	    NULL, xname, "CRC Error");
+	evcnt_attach_dynamic(&sc->sc_ev_symerrc, EVCNT_TYPE_MISC,
+	    NULL, xname, "Symbol Error");
+	evcnt_attach_dynamic(&sc->sc_ev_mpc, EVCNT_TYPE_MISC,
+	    NULL, xname, "Missed Packets");
+	evcnt_attach_dynamic(&sc->sc_ev_colc, EVCNT_TYPE_MISC,
+	    NULL, xname, "Collision");
+	evcnt_attach_dynamic(&sc->sc_ev_sec, EVCNT_TYPE_MISC,
+	    NULL, xname, "Sequence Error");
+	evcnt_attach_dynamic(&sc->sc_ev_rlec, EVCNT_TYPE_MISC,
+	    NULL, xname, "Receive Length Error");
+
+	if (sc->sc_type >= WM_T_82543) {
+		evcnt_attach_dynamic(&sc->sc_ev_algnerrc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Alignment Error");
+		evcnt_attach_dynamic(&sc->sc_ev_rxerrc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Receive Error");
+		/* XXX Does 82575 have HTDPMC? */
+		if ((sc->sc_type < WM_T_82575) || WM_IS_ICHPCH(sc))
+			evcnt_attach_dynamic(&sc->sc_ev_cexterr,
+			    EVCNT_TYPE_MISC, NULL, xname,
+			    "Carrier Extension Error");
+		else
+			evcnt_attach_dynamic(&sc->sc_ev_htdpmc,
+			    EVCNT_TYPE_MISC, NULL, xname,
+			    "Host Transmit Discarded Packets by MAC");
+
+		evcnt_attach_dynamic(&sc->sc_ev_tncrs, EVCNT_TYPE_MISC,
+		    NULL, xname, "Tx with No CRS");
+		evcnt_attach_dynamic(&sc->sc_ev_tsctc, EVCNT_TYPE_MISC,
+		    NULL, xname, "TCP Segmentation Context Tx");
+		if ((sc->sc_type < WM_T_82575) || WM_IS_ICHPCH(sc))
+			evcnt_attach_dynamic(&sc->sc_ev_tsctfc,
+			    EVCNT_TYPE_MISC, NULL, xname,
+			    "TCP Segmentation Context Tx Fail");
+		else {
+			/* XXX Is the circuit breaker only for 82576? */
+			evcnt_attach_dynamic(&sc->sc_ev_cbrdpc,
+			    EVCNT_TYPE_MISC, NULL, xname,
+			    "Circuit Breaker Rx Dropped Packet");
+			evcnt_attach_dynamic(&sc->sc_ev_cbrmpc,
+			    EVCNT_TYPE_MISC, NULL, xname,
+			    "Circuit Breaker Rx Manageability Packet");
+		}
+	}
+
 	if (sc->sc_type >= WM_T_82542_2_1) {
 		evcnt_attach_dynamic(&sc->sc_ev_tx_xoff, EVCNT_TYPE_MISC,
 		    NULL, xname, "tx_xoff");
@@ -3212,28 +3301,6 @@ alloc_retry:
 		    NULL, xname, "rx_macctl");
 	}
 
-	evcnt_attach_dynamic(&sc->sc_ev_crcerrs, EVCNT_TYPE_MISC,
-	    NULL, xname, "CRC Error");
-	evcnt_attach_dynamic(&sc->sc_ev_symerrc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Symbol Error");
-
-	if (sc->sc_type >= WM_T_82543) {
-		evcnt_attach_dynamic(&sc->sc_ev_algnerrc, EVCNT_TYPE_MISC,
-		    NULL, xname, "Alignment Error");
-		evcnt_attach_dynamic(&sc->sc_ev_rxerrc, EVCNT_TYPE_MISC,
-		    NULL, xname, "Receive Error");
-		evcnt_attach_dynamic(&sc->sc_ev_cexterr, EVCNT_TYPE_MISC,
-		    NULL, xname, "Carrier Extension Error");
-	}
-
-	evcnt_attach_dynamic(&sc->sc_ev_mpc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Missed Packets");
-	evcnt_attach_dynamic(&sc->sc_ev_colc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Collision");
-	evcnt_attach_dynamic(&sc->sc_ev_sec, EVCNT_TYPE_MISC,
-	    NULL, xname, "Sequence Error");
-	evcnt_attach_dynamic(&sc->sc_ev_rlec, EVCNT_TYPE_MISC,
-	    NULL, xname, "Receive Length Error");
 	evcnt_attach_dynamic(&sc->sc_ev_scc, EVCNT_TYPE_MISC,
 	    NULL, xname, "Single Collision");
 	evcnt_attach_dynamic(&sc->sc_ev_ecol, EVCNT_TYPE_MISC,
@@ -3242,8 +3309,25 @@ alloc_retry:
 	    NULL, xname, "Multiple Collision");
 	evcnt_attach_dynamic(&sc->sc_ev_latecol, EVCNT_TYPE_MISC,
 	    NULL, xname, "Late Collisions");
+
+	if ((sc->sc_type >= WM_T_I350) && !WM_IS_ICHPCH(sc))
+		evcnt_attach_dynamic(&sc->sc_ev_cbtmpc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Circuit Breaker Tx Manageability Packet");
+
 	evcnt_attach_dynamic(&sc->sc_ev_dc, EVCNT_TYPE_MISC,
 	    NULL, xname, "Defer");
+	evcnt_attach_dynamic(&sc->sc_ev_prc64, EVCNT_TYPE_MISC,
+	    NULL, xname, "Packets Rx (64 bytes)");
+	evcnt_attach_dynamic(&sc->sc_ev_prc127, EVCNT_TYPE_MISC,
+	    NULL, xname, "Packets Rx (65-127 bytes)");
+	evcnt_attach_dynamic(&sc->sc_ev_prc255, EVCNT_TYPE_MISC,
+	    NULL, xname, "Packets Rx (128-255 bytes)");
+	evcnt_attach_dynamic(&sc->sc_ev_prc511, EVCNT_TYPE_MISC,
+	    NULL, xname, "Packets Rx (256-511 bytes)");
+	evcnt_attach_dynamic(&sc->sc_ev_prc1023, EVCNT_TYPE_MISC,
+	    NULL, xname, "Packets Rx (512-1023 bytes)");
+	evcnt_attach_dynamic(&sc->sc_ev_prc1522, EVCNT_TYPE_MISC,
+	    NULL, xname, "Packets Rx (1024-1522 bytes)");
 	evcnt_attach_dynamic(&sc->sc_ev_gprc, EVCNT_TYPE_MISC,
 	    NULL, xname, "Good Packets Rx");
 	evcnt_attach_dynamic(&sc->sc_ev_bprc, EVCNT_TYPE_MISC,
@@ -3266,6 +3350,14 @@ alloc_retry:
 	    NULL, xname, "Rx Oversize");
 	evcnt_attach_dynamic(&sc->sc_ev_rjc, EVCNT_TYPE_MISC,
 	    NULL, xname, "Rx Jabber");
+	if (sc->sc_type >= WM_T_82540) {
+		evcnt_attach_dynamic(&sc->sc_ev_mgtprc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Management Packets RX");
+		evcnt_attach_dynamic(&sc->sc_ev_mgtpdc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Management Packets Dropped");
+		evcnt_attach_dynamic(&sc->sc_ev_mgtptc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Management Packets TX");
+	}
 	evcnt_attach_dynamic(&sc->sc_ev_tor, EVCNT_TYPE_MISC,
 	    NULL, xname, "Total Octets Rx");
 	evcnt_attach_dynamic(&sc->sc_ev_tot, EVCNT_TYPE_MISC,
@@ -3274,22 +3366,6 @@ alloc_retry:
 	    NULL, xname, "Total Packets Rx");
 	evcnt_attach_dynamic(&sc->sc_ev_tpt, EVCNT_TYPE_MISC,
 	    NULL, xname, "Total Packets Tx");
-	evcnt_attach_dynamic(&sc->sc_ev_mptc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Multicast Packets Tx");
-	evcnt_attach_dynamic(&sc->sc_ev_bptc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Broadcast Packets Tx Count");
-	evcnt_attach_dynamic(&sc->sc_ev_prc64, EVCNT_TYPE_MISC,
-	    NULL, xname, "Packets Rx (64 bytes)");
-	evcnt_attach_dynamic(&sc->sc_ev_prc127, EVCNT_TYPE_MISC,
-	    NULL, xname, "Packets Rx (65-127 bytes)");
-	evcnt_attach_dynamic(&sc->sc_ev_prc255, EVCNT_TYPE_MISC,
-	    NULL, xname, "Packets Rx (128-255 bytes)");
-	evcnt_attach_dynamic(&sc->sc_ev_prc511, EVCNT_TYPE_MISC,
-	    NULL, xname, "Packets Rx (255-511 bytes)");
-	evcnt_attach_dynamic(&sc->sc_ev_prc1023, EVCNT_TYPE_MISC,
-	    NULL, xname, "Packets Rx (512-1023 bytes)");
-	evcnt_attach_dynamic(&sc->sc_ev_prc1522, EVCNT_TYPE_MISC,
-	    NULL, xname, "Packets Rx (1024-1522 bytes)");
 	evcnt_attach_dynamic(&sc->sc_ev_ptc64, EVCNT_TYPE_MISC,
 	    NULL, xname, "Packets Tx (64 bytes)");
 	evcnt_attach_dynamic(&sc->sc_ev_ptc127, EVCNT_TYPE_MISC,
@@ -3302,41 +3378,77 @@ alloc_retry:
 	    NULL, xname, "Packets Tx (512-1023 bytes)");
 	evcnt_attach_dynamic(&sc->sc_ev_ptc1522, EVCNT_TYPE_MISC,
 	    NULL, xname, "Packets Tx (1024-1522 Bytes)");
+	evcnt_attach_dynamic(&sc->sc_ev_mptc, EVCNT_TYPE_MISC,
+	    NULL, xname, "Multicast Packets Tx");
+	evcnt_attach_dynamic(&sc->sc_ev_bptc, EVCNT_TYPE_MISC,
+	    NULL, xname, "Broadcast Packets Tx");
 	evcnt_attach_dynamic(&sc->sc_ev_iac, EVCNT_TYPE_MISC,
 	    NULL, xname, "Interrupt Assertion");
-	evcnt_attach_dynamic(&sc->sc_ev_icrxptc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Intr. Cause Rx Pkt Timer Expire");
-	evcnt_attach_dynamic(&sc->sc_ev_icrxatc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Intr. Cause Rx Abs Timer Expire");
-	evcnt_attach_dynamic(&sc->sc_ev_ictxptc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Intr. Cause Tx Pkt Timer Expire");
-	evcnt_attach_dynamic(&sc->sc_ev_ictxact, EVCNT_TYPE_MISC,
-	    NULL, xname, "Intr. Cause Tx Abs Timer Expire");
-	evcnt_attach_dynamic(&sc->sc_ev_ictxqec, EVCNT_TYPE_MISC,
-	    NULL, xname, "Intr. Cause Tx Queue Empty");
-	evcnt_attach_dynamic(&sc->sc_ev_ictxqmtc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Intr. Cause Tx Queue Min Thresh");
-	evcnt_attach_dynamic(&sc->sc_ev_icrxdmtc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Intr. Cause Rx Desc Min Thresh");
-	evcnt_attach_dynamic(&sc->sc_ev_icrxoc, EVCNT_TYPE_MISC,
-	    NULL, xname, "Interrupt Cause Receiver Overrun");
-	if (sc->sc_type >= WM_T_82543) {
-		evcnt_attach_dynamic(&sc->sc_ev_tncrs, EVCNT_TYPE_MISC,
-		    NULL, xname, "Tx with No CRS");
-		evcnt_attach_dynamic(&sc->sc_ev_tsctc, EVCNT_TYPE_MISC,
-		    NULL, xname, "TCP Segmentation Context Tx");
-		evcnt_attach_dynamic(&sc->sc_ev_tsctfc, EVCNT_TYPE_MISC,
-		    NULL, xname, "TCP Segmentation Context Tx Fail");
-	}
-	if (sc->sc_type >= WM_T_82540) {
-		evcnt_attach_dynamic(&sc->sc_ev_mgtprc, EVCNT_TYPE_MISC,
-		    NULL, xname, "Management Packets RX");
-		evcnt_attach_dynamic(&sc->sc_ev_mgtpdc, EVCNT_TYPE_MISC,
-		    NULL, xname, "Management Packets Dropped");
-		evcnt_attach_dynamic(&sc->sc_ev_mgtptc, EVCNT_TYPE_MISC,
-		    NULL, xname, "Management Packets TX");
-	}
-	if ((sc->sc_type >= WM_T_I350) && (sc->sc_type < WM_T_80003)) {
+	if (sc->sc_type < WM_T_82575) {
+		evcnt_attach_dynamic(&sc->sc_ev_icrxptc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Intr. Cause Rx Pkt Timer Expire");
+		evcnt_attach_dynamic(&sc->sc_ev_icrxatc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Intr. Cause Rx Abs Timer Expire");
+		evcnt_attach_dynamic(&sc->sc_ev_ictxptc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Intr. Cause Tx Pkt Timer Expire");
+		evcnt_attach_dynamic(&sc->sc_ev_ictxatc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Intr. Cause Tx Abs Timer Expire");
+		evcnt_attach_dynamic(&sc->sc_ev_ictxqec, EVCNT_TYPE_MISC,
+		    NULL, xname, "Intr. Cause Tx Queue Empty");
+		evcnt_attach_dynamic(&sc->sc_ev_ictxqmtc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Intr. Cause Tx Queue Min Thresh");
+		evcnt_attach_dynamic(&sc->sc_ev_rxdmtc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Intr. Cause Rx Desc Min Thresh");
+
+		/* XXX 82575 document says it has ICRXOC. Is that right? */
+		evcnt_attach_dynamic(&sc->sc_ev_icrxoc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Interrupt Cause Receiver Overrun");
+	} else if (!WM_IS_ICHPCH(sc)) {
+		/*
+		 * For 82575 and newer.
+		 *
+		 * On 80003, ICHs and PCHs, it seems all of the following
+		 * registers are zero.
+		 */
+		evcnt_attach_dynamic(&sc->sc_ev_rpthc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Rx Packets To Host");
+		evcnt_attach_dynamic(&sc->sc_ev_debug1, EVCNT_TYPE_MISC,
+		    NULL, xname, "Debug Counter 1");
+		evcnt_attach_dynamic(&sc->sc_ev_debug2, EVCNT_TYPE_MISC,
+		    NULL, xname, "Debug Counter 2");
+		evcnt_attach_dynamic(&sc->sc_ev_debug3, EVCNT_TYPE_MISC,
+		    NULL, xname, "Debug Counter 3");
+
+		/*
+		 * 82575 datasheet says 0x4118 is for TXQEC(Tx Queue Empty).
+		 * I think it's wrong. The real count I observed is the same
+		 * as GPTC(Good Packets Tx) and TPT(Total Packets Tx).
+		 * It's HGPTC(Host Good Packets Tx) which is described in
+		 * 82576's datasheet.
+		 */
+		evcnt_attach_dynamic(&sc->sc_ev_hgptc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Host Good Packets TX");
+
+		evcnt_attach_dynamic(&sc->sc_ev_debug4, EVCNT_TYPE_MISC,
+		    NULL, xname, "Debug Counter 4");
+		evcnt_attach_dynamic(&sc->sc_ev_rxdmtc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Rx Desc Min Thresh");
+		/* XXX Is the circuit breaker only for 82576? */
+		evcnt_attach_dynamic(&sc->sc_ev_htcbdpc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Host Tx Circuit Breaker Dropped Packets");
+
+		evcnt_attach_dynamic(&sc->sc_ev_hgorc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Host Good Octets Rx");
+		evcnt_attach_dynamic(&sc->sc_ev_hgotc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Host Good Octets Tx");
+		evcnt_attach_dynamic(&sc->sc_ev_lenerrs, EVCNT_TYPE_MISC,
+		    NULL, xname, "Length Errors");
+	}
+	if ((sc->sc_type >= WM_T_I350) && !WM_IS_ICHPCH(sc)) {
+		evcnt_attach_dynamic(&sc->sc_ev_tlpic, EVCNT_TYPE_MISC,
+		    NULL, xname, "EEE Tx LPI");
+		evcnt_attach_dynamic(&sc->sc_ev_rlpic, EVCNT_TYPE_MISC,
+		    NULL, xname, "EEE Rx LPI");
 		evcnt_attach_dynamic(&sc->sc_ev_b2ogprc, EVCNT_TYPE_MISC,
 		    NULL, xname, "BMC2OS Packets received by host");
 		evcnt_attach_dynamic(&sc->sc_ev_o2bspc, EVCNT_TYPE_MISC,
@@ -3345,6 +3457,10 @@ alloc_retry:
 		    NULL, xname, "BMC2OS Packets sent by BMC");
 		evcnt_attach_dynamic(&sc->sc_ev_o2bgptc, EVCNT_TYPE_MISC,
 		    NULL, xname, "OS2BMC Packets received by BMC");
+		evcnt_attach_dynamic(&sc->sc_ev_scvpc, EVCNT_TYPE_MISC,
+		    NULL, xname, "SerDes/SGMII Code Violation Packet");
+		evcnt_attach_dynamic(&sc->sc_ev_hrmpc, EVCNT_TYPE_MISC,
+		    NULL, xname, "Header Redirection Missed Packet");
 	}
 #endif /* WM_EVENT_COUNTERS */
 
@@ -3393,6 +3509,31 @@ wm_detach(device_t self, int flags __unu
 #ifdef WM_EVENT_COUNTERS
 	evcnt_detach(&sc->sc_ev_linkintr);
 
+	evcnt_detach(&sc->sc_ev_crcerrs);
+	evcnt_detach(&sc->sc_ev_symerrc);
+	evcnt_detach(&sc->sc_ev_mpc);
+	evcnt_detach(&sc->sc_ev_colc);
+	evcnt_detach(&sc->sc_ev_sec);
+	evcnt_detach(&sc->sc_ev_rlec);
+
+	if (sc->sc_type >= WM_T_82543) {
+		evcnt_detach(&sc->sc_ev_algnerrc);
+		evcnt_detach(&sc->sc_ev_rxerrc);
+		if ((sc->sc_type < WM_T_82575) || WM_IS_ICHPCH(sc))
+			evcnt_detach(&sc->sc_ev_cexterr);
+		else
+			evcnt_detach(&sc->sc_ev_htdpmc);
+
+		evcnt_detach(&sc->sc_ev_tncrs);
+		evcnt_detach(&sc->sc_ev_tsctc);
+		if ((sc->sc_type < WM_T_82575) || WM_IS_ICHPCH(sc))
+			evcnt_detach(&sc->sc_ev_tsctfc);
+		else {
+			evcnt_detach(&sc->sc_ev_cbrdpc);
+			evcnt_detach(&sc->sc_ev_cbrmpc);
+		}
+	}
+
 	if (sc->sc_type >= WM_T_82542_2_1) {
 		evcnt_detach(&sc->sc_ev_tx_xoff);
 		evcnt_detach(&sc->sc_ev_tx_xon);
@@ -3401,23 +3542,21 @@ wm_detach(device_t self, int flags __unu
 		evcnt_detach(&sc->sc_ev_rx_macctl);
 	}
 
-	evcnt_detach(&sc->sc_ev_crcerrs);
-	evcnt_detach(&sc->sc_ev_symerrc);
-
-	if (sc->sc_type >= WM_T_82543) {
-		evcnt_detach(&sc->sc_ev_algnerrc);
-		evcnt_detach(&sc->sc_ev_rxerrc);
-		evcnt_detach(&sc->sc_ev_cexterr);
-	}
-	evcnt_detach(&sc->sc_ev_mpc);
-	evcnt_detach(&sc->sc_ev_colc);
-	evcnt_detach(&sc->sc_ev_sec);
-	evcnt_detach(&sc->sc_ev_rlec);
 	evcnt_detach(&sc->sc_ev_scc);
 	evcnt_detach(&sc->sc_ev_ecol);
 	evcnt_detach(&sc->sc_ev_mcc);
 	evcnt_detach(&sc->sc_ev_latecol);
+
+	if ((sc->sc_type >= WM_T_I350) && !WM_IS_ICHPCH(sc))
+		evcnt_detach(&sc->sc_ev_cbtmpc);
+
 	evcnt_detach(&sc->sc_ev_dc);
+	evcnt_detach(&sc->sc_ev_prc64);
+	evcnt_detach(&sc->sc_ev_prc127);
+	evcnt_detach(&sc->sc_ev_prc255);
+	evcnt_detach(&sc->sc_ev_prc511);
+	evcnt_detach(&sc->sc_ev_prc1023);
+	evcnt_detach(&sc->sc_ev_prc1522);
 	evcnt_detach(&sc->sc_ev_gprc);
 	evcnt_detach(&sc->sc_ev_bprc);
 	evcnt_detach(&sc->sc_ev_mprc);
@@ -3429,48 +3568,56 @@ wm_detach(device_t self, int flags __unu
 	evcnt_detach(&sc->sc_ev_rfc);
 	evcnt_detach(&sc->sc_ev_roc);
 	evcnt_detach(&sc->sc_ev_rjc);
+	if (sc->sc_type >= WM_T_82540) {
+		evcnt_detach(&sc->sc_ev_mgtprc);
+		evcnt_detach(&sc->sc_ev_mgtpdc);
+		evcnt_detach(&sc->sc_ev_mgtptc);
+	}
 	evcnt_detach(&sc->sc_ev_tor);
 	evcnt_detach(&sc->sc_ev_tot);
 	evcnt_detach(&sc->sc_ev_tpr);
 	evcnt_detach(&sc->sc_ev_tpt);
-	evcnt_detach(&sc->sc_ev_mptc);
-	evcnt_detach(&sc->sc_ev_bptc);
-	evcnt_detach(&sc->sc_ev_prc64);
-	evcnt_detach(&sc->sc_ev_prc127);
-	evcnt_detach(&sc->sc_ev_prc255);
-	evcnt_detach(&sc->sc_ev_prc511);
-	evcnt_detach(&sc->sc_ev_prc1023);
-	evcnt_detach(&sc->sc_ev_prc1522);
 	evcnt_detach(&sc->sc_ev_ptc64);
 	evcnt_detach(&sc->sc_ev_ptc127);
 	evcnt_detach(&sc->sc_ev_ptc255);
 	evcnt_detach(&sc->sc_ev_ptc511);
 	evcnt_detach(&sc->sc_ev_ptc1023);
 	evcnt_detach(&sc->sc_ev_ptc1522);
+	evcnt_detach(&sc->sc_ev_mptc);
+	evcnt_detach(&sc->sc_ev_bptc);
 	evcnt_detach(&sc->sc_ev_iac);
-	evcnt_detach(&sc->sc_ev_icrxptc);
-	evcnt_detach(&sc->sc_ev_icrxatc);
-	evcnt_detach(&sc->sc_ev_ictxptc);
-	evcnt_detach(&sc->sc_ev_ictxact);
-	evcnt_detach(&sc->sc_ev_ictxqec);
-	evcnt_detach(&sc->sc_ev_ictxqmtc);
-	evcnt_detach(&sc->sc_ev_icrxdmtc);
-	evcnt_detach(&sc->sc_ev_icrxoc);
-	if (sc->sc_type >= WM_T_82543) {
-		evcnt_detach(&sc->sc_ev_tncrs);
-		evcnt_detach(&sc->sc_ev_tsctc);
-		evcnt_detach(&sc->sc_ev_tsctfc);
-	}
-	if (sc->sc_type >= WM_T_82540) {
-		evcnt_detach(&sc->sc_ev_mgtprc);
-		evcnt_detach(&sc->sc_ev_mgtpdc);
-		evcnt_detach(&sc->sc_ev_mgtptc);
-	}
-	if ((sc->sc_type >= WM_T_I350) && (sc->sc_type < WM_T_80003)) {
+	if (sc->sc_type < WM_T_82575) {
+		evcnt_detach(&sc->sc_ev_icrxptc);
+		evcnt_detach(&sc->sc_ev_icrxatc);
+		evcnt_detach(&sc->sc_ev_ictxptc);
+		evcnt_detach(&sc->sc_ev_ictxatc);
+		evcnt_detach(&sc->sc_ev_ictxqec);
+		evcnt_detach(&sc->sc_ev_ictxqmtc);
+		evcnt_detach(&sc->sc_ev_rxdmtc);
+		evcnt_detach(&sc->sc_ev_icrxoc);
+	} else if (!WM_IS_ICHPCH(sc)) {
+		evcnt_detach(&sc->sc_ev_rpthc);
+		evcnt_detach(&sc->sc_ev_debug1);
+		evcnt_detach(&sc->sc_ev_debug2);
+		evcnt_detach(&sc->sc_ev_debug3);
+		evcnt_detach(&sc->sc_ev_hgptc);
+		evcnt_detach(&sc->sc_ev_debug4);
+		evcnt_detach(&sc->sc_ev_rxdmtc);
+		evcnt_detach(&sc->sc_ev_htcbdpc);
+
+		evcnt_detach(&sc->sc_ev_hgorc);
+		evcnt_detach(&sc->sc_ev_hgotc);
+		evcnt_detach(&sc->sc_ev_lenerrs);
+	}
+	if ((sc->sc_type >= WM_T_I350) && !WM_IS_ICHPCH(sc)) {
+		evcnt_detach(&sc->sc_ev_tlpic);
+		evcnt_detach(&sc->sc_ev_rlpic);
 		evcnt_detach(&sc->sc_ev_b2ogprc);
 		evcnt_detach(&sc->sc_ev_o2bspc);
 		evcnt_detach(&sc->sc_ev_b2ospc);
 		evcnt_detach(&sc->sc_ev_o2bgptc);
+		evcnt_detach(&sc->sc_ev_scvpc);
+		evcnt_detach(&sc->sc_ev_hrmpc);
 	}
 #endif /* WM_EVENT_COUNTERS */
 
@@ -3744,8 +3891,6 @@ wm_tick(void *arg)
 {
 	struct wm_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
-	uint64_t crcerrs, algnerrc, symerrc, mpc, colc,  sec, rlec, rxerrc,
-	    cexterr;
 
 	mutex_enter(sc->sc_core_lock);
 
@@ -3754,120 +3899,7 @@ wm_tick(void *arg)
 		return;
 	}
 
-	crcerrs = CSR_READ(sc, WMREG_CRCERRS);
-	symerrc = CSR_READ(sc, WMREG_SYMERRC);
-	mpc = CSR_READ(sc, WMREG_MPC);
-	colc = CSR_READ(sc, WMREG_COLC);
-	sec = CSR_READ(sc, WMREG_SEC);
-	rlec = CSR_READ(sc, WMREG_RLEC);
-
-	WM_EVCNT_ADD(&sc->sc_ev_crcerrs, crcerrs);
-	WM_EVCNT_ADD(&sc->sc_ev_symerrc, symerrc);
-	WM_EVCNT_ADD(&sc->sc_ev_mpc, mpc);
-	WM_EVCNT_ADD(&sc->sc_ev_colc, colc);
-	WM_EVCNT_ADD(&sc->sc_ev_sec, sec);
-	WM_EVCNT_ADD(&sc->sc_ev_rlec, rlec);
-
-	if (sc->sc_type >= WM_T_82542_2_1) {
-		WM_EVCNT_ADD(&sc->sc_ev_rx_xon, CSR_READ(sc, WMREG_XONRXC));
-		WM_EVCNT_ADD(&sc->sc_ev_tx_xon, CSR_READ(sc, WMREG_XONTXC));
-		WM_EVCNT_ADD(&sc->sc_ev_rx_xoff, CSR_READ(sc, WMREG_XOFFRXC));
-		WM_EVCNT_ADD(&sc->sc_ev_tx_xoff, CSR_READ(sc, WMREG_XOFFTXC));
-		WM_EVCNT_ADD(&sc->sc_ev_rx_macctl, CSR_READ(sc, WMREG_FCRUC));
-	}
-	WM_EVCNT_ADD(&sc->sc_ev_scc, CSR_READ(sc, WMREG_SCC));
-	WM_EVCNT_ADD(&sc->sc_ev_ecol, CSR_READ(sc, WMREG_ECOL));
-	WM_EVCNT_ADD(&sc->sc_ev_mcc, CSR_READ(sc, WMREG_MCC));
-	WM_EVCNT_ADD(&sc->sc_ev_latecol, CSR_READ(sc, WMREG_LATECOL));
-	WM_EVCNT_ADD(&sc->sc_ev_dc, CSR_READ(sc, WMREG_DC));
-	WM_EVCNT_ADD(&sc->sc_ev_gprc, CSR_READ(sc, WMREG_GPRC));
-	WM_EVCNT_ADD(&sc->sc_ev_bprc, CSR_READ(sc, WMREG_BPRC));
-	WM_EVCNT_ADD(&sc->sc_ev_mprc, CSR_READ(sc, WMREG_MPRC));
-	WM_EVCNT_ADD(&sc->sc_ev_gptc, CSR_READ(sc, WMREG_GPTC));
-
-	WM_EVCNT_ADD(&sc->sc_ev_gorc,
-	    CSR_READ(sc, WMREG_GORCL) + CSR_READ(sc, WMREG_GORCH));
-	WM_EVCNT_ADD(&sc->sc_ev_gotc,
-	    CSR_READ(sc, WMREG_GOTCL) + CSR_READ(sc, WMREG_GOTCH));
-
-	WM_EVCNT_ADD(&sc->sc_ev_rnbc, CSR_READ(sc, WMREG_RNBC));
-	WM_EVCNT_ADD(&sc->sc_ev_ruc, CSR_READ(sc, WMREG_RUC));
-	WM_EVCNT_ADD(&sc->sc_ev_rfc, CSR_READ(sc, WMREG_RFC));
-	WM_EVCNT_ADD(&sc->sc_ev_roc, CSR_READ(sc, WMREG_ROC));
-	WM_EVCNT_ADD(&sc->sc_ev_rjc, CSR_READ(sc, WMREG_RJC));
-
-	WM_EVCNT_ADD(&sc->sc_ev_tor,
-	    CSR_READ(sc, WMREG_TORL) + CSR_READ(sc, WMREG_TORH));
-	WM_EVCNT_ADD(&sc->sc_ev_tot,
-	    CSR_READ(sc, WMREG_TOTL) + CSR_READ(sc, WMREG_TOTH));
-
-	WM_EVCNT_ADD(&sc->sc_ev_tpr, CSR_READ(sc, WMREG_TPR));
-	WM_EVCNT_ADD(&sc->sc_ev_tpt, CSR_READ(sc, WMREG_TPT));
-	WM_EVCNT_ADD(&sc->sc_ev_mptc, CSR_READ(sc, WMREG_MPTC));
-	WM_EVCNT_ADD(&sc->sc_ev_bptc, CSR_READ(sc, WMREG_BPTC));
-	WM_EVCNT_ADD(&sc->sc_ev_prc64, CSR_READ(sc, WMREG_PRC64));
-	WM_EVCNT_ADD(&sc->sc_ev_prc127, CSR_READ(sc, WMREG_PRC127));
-	WM_EVCNT_ADD(&sc->sc_ev_prc255, CSR_READ(sc, WMREG_PRC255));
-	WM_EVCNT_ADD(&sc->sc_ev_prc511, CSR_READ(sc, WMREG_PRC511));
-	WM_EVCNT_ADD(&sc->sc_ev_prc1023, CSR_READ(sc, WMREG_PRC1023));
-	WM_EVCNT_ADD(&sc->sc_ev_prc1522, CSR_READ(sc, WMREG_PRC1522));
-	WM_EVCNT_ADD(&sc->sc_ev_ptc64, CSR_READ(sc, WMREG_PTC64));
-	WM_EVCNT_ADD(&sc->sc_ev_ptc127, CSR_READ(sc, WMREG_PTC127));
-	WM_EVCNT_ADD(&sc->sc_ev_ptc255, CSR_READ(sc, WMREG_PTC255));
-	WM_EVCNT_ADD(&sc->sc_ev_ptc511, CSR_READ(sc, WMREG_PTC511));
-	WM_EVCNT_ADD(&sc->sc_ev_ptc1023, CSR_READ(sc, WMREG_PTC1023));
-	WM_EVCNT_ADD(&sc->sc_ev_ptc1522, CSR_READ(sc, WMREG_PTC1522));
-	WM_EVCNT_ADD(&sc->sc_ev_iac, CSR_READ(sc, WMREG_IAC));
-	WM_EVCNT_ADD(&sc->sc_ev_icrxptc, CSR_READ(sc, WMREG_ICRXPTC));
-	WM_EVCNT_ADD(&sc->sc_ev_icrxatc, CSR_READ(sc, WMREG_ICRXATC));
-	WM_EVCNT_ADD(&sc->sc_ev_ictxptc, CSR_READ(sc, WMREG_ICTXPTC));
-	WM_EVCNT_ADD(&sc->sc_ev_ictxact, CSR_READ(sc, WMREG_ICTXATC));
-	WM_EVCNT_ADD(&sc->sc_ev_ictxqec, CSR_READ(sc, WMREG_ICTXQEC));
-	WM_EVCNT_ADD(&sc->sc_ev_ictxqmtc, CSR_READ(sc, WMREG_ICTXQMTC));
-	WM_EVCNT_ADD(&sc->sc_ev_icrxdmtc, CSR_READ(sc, WMREG_ICRXDMTC));
-	WM_EVCNT_ADD(&sc->sc_ev_icrxoc, CSR_READ(sc, WMREG_ICRXOC));
-
-	if (sc->sc_type >= WM_T_82543) {
-		algnerrc = CSR_READ(sc, WMREG_ALGNERRC);
-		rxerrc = CSR_READ(sc, WMREG_RXERRC);
-		cexterr = CSR_READ(sc, WMREG_CEXTERR);
-		WM_EVCNT_ADD(&sc->sc_ev_algnerrc, algnerrc);
-		WM_EVCNT_ADD(&sc->sc_ev_rxerrc, rxerrc);
-		WM_EVCNT_ADD(&sc->sc_ev_cexterr, cexterr);
-
-		WM_EVCNT_ADD(&sc->sc_ev_tncrs, CSR_READ(sc, WMREG_TNCRS));
-		WM_EVCNT_ADD(&sc->sc_ev_tsctc, CSR_READ(sc, WMREG_TSCTC));
-		WM_EVCNT_ADD(&sc->sc_ev_tsctfc, CSR_READ(sc, WMREG_TSCTFC));
-	} else
-		algnerrc = rxerrc = cexterr = 0;
-
-	if (sc->sc_type >= WM_T_82540) {
-		WM_EVCNT_ADD(&sc->sc_ev_mgtprc, CSR_READ(sc, WMREG_MGTPRC));
-		WM_EVCNT_ADD(&sc->sc_ev_mgtpdc, CSR_READ(sc, WMREG_MGTPDC));
-		WM_EVCNT_ADD(&sc->sc_ev_mgtptc, CSR_READ(sc, WMREG_MGTPTC));
-	}
-	if (((sc->sc_type >= WM_T_I350) && (sc->sc_type < WM_T_80003))
-	    && ((CSR_READ(sc, WMREG_MANC) & MANC_EN_BMC2OS) != 0)) {
-		WM_EVCNT_ADD(&sc->sc_ev_b2ogprc, CSR_READ(sc, WMREG_B2OGPRC));
-		WM_EVCNT_ADD(&sc->sc_ev_o2bspc, CSR_READ(sc, WMREG_O2BSPC));
-		WM_EVCNT_ADD(&sc->sc_ev_b2ospc, CSR_READ(sc, WMREG_B2OSPC));
-		WM_EVCNT_ADD(&sc->sc_ev_o2bgptc, CSR_READ(sc, WMREG_O2BGPTC));
-	}
-	net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
-	if_statadd_ref(nsr, if_collisions, colc);
-	if_statadd_ref(nsr, if_ierrors,
-	    crcerrs + algnerrc + symerrc + rxerrc + sec + cexterr + rlec);
-	/*
-	 * WMREG_RNBC is incremented when there are no available buffers in
-	 * host memory. It does not mean the number of dropped packets, because
-	 * an Ethernet controller can receive packets in such case if there is
-	 * space in the phy's FIFO.
-	 *
-	 * If you want to know the nubmer of WMREG_RMBC, you should use such as
-	 * own EVCNT instead of if_iqdrops.
-	 */
-	if_statadd_ref(nsr, if_iqdrops, mpc);
-	IF_STAT_PUTREF(ifp);
+	wm_update_stats(sc);
 
 	if (sc->sc_flags & WM_F_HAS_MII)
 		mii_tick(&sc->sc_mii);
@@ -4005,6 +4037,18 @@ wm_ioctl(struct ifnet *ifp, u_long cmd, 
 		KASSERT(IFNET_LOCKED(ifp));
 	}
 
+	if (cmd == SIOCZIFDATA) {
+		/*
+		 * Special handling for SIOCZIFDATA.
+		 * Copying and clearing the if_data structure is done with
+		 * ether_ioctl() below.
+		 */
+		mutex_enter(sc->sc_core_lock);
+		wm_update_stats(sc);
+		wm_clear_evcnt(sc);
+		mutex_exit(sc->sc_core_lock);
+	}
+
 	switch (cmd) {
 	case SIOCSIFMEDIA:
 		mutex_enter(sc->sc_core_lock);
@@ -4970,7 +5014,7 @@ wm_initialize_hardware_bits(struct wm_so
 
 	/* For 82571 variant, 80003 and ICHs */
 	if (((sc->sc_type >= WM_T_82571) && (sc->sc_type <= WM_T_82583))
-	    || (sc->sc_type >= WM_T_80003)) {
+	    || WM_IS_ICHPCH(sc)) {
 
 		/* Transmit Descriptor Control 0 */
 		reg = CSR_READ(sc, WMREG_TXDCTL(0));
@@ -6502,6 +6546,350 @@ err:
 	    __func__, rv);
 }
 
+static void
+wm_update_stats(struct wm_softc *sc)
+{
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	uint64_t crcerrs, algnerrc, symerrc, mpc, colc,  sec, rlec, rxerrc,
+	    cexterr;
+
+	crcerrs = CSR_READ(sc, WMREG_CRCERRS);
+	symerrc = CSR_READ(sc, WMREG_SYMERRC);
+	mpc = CSR_READ(sc, WMREG_MPC);
+	colc = CSR_READ(sc, WMREG_COLC);
+	sec = CSR_READ(sc, WMREG_SEC);
+	rlec = CSR_READ(sc, WMREG_RLEC);
+
+	WM_EVCNT_ADD(&sc->sc_ev_crcerrs, crcerrs);
+	WM_EVCNT_ADD(&sc->sc_ev_symerrc, symerrc);
+	WM_EVCNT_ADD(&sc->sc_ev_mpc, mpc);
+	WM_EVCNT_ADD(&sc->sc_ev_colc, colc);
+	WM_EVCNT_ADD(&sc->sc_ev_sec, sec);
+	WM_EVCNT_ADD(&sc->sc_ev_rlec, rlec);
+
+	if (sc->sc_type >= WM_T_82543) {
+		algnerrc = CSR_READ(sc, WMREG_ALGNERRC);
+		rxerrc = CSR_READ(sc, WMREG_RXERRC);
+		WM_EVCNT_ADD(&sc->sc_ev_algnerrc, algnerrc);
+		WM_EVCNT_ADD(&sc->sc_ev_rxerrc, rxerrc);
+		if ((sc->sc_type < WM_T_82575) || WM_IS_ICHPCH(sc)) {
+			cexterr = CSR_READ(sc, WMREG_CEXTERR);
+			WM_EVCNT_ADD(&sc->sc_ev_cexterr, cexterr);
+		} else {
+			cexterr = 0;
+			/* Excessive collision + Link down */
+			WM_EVCNT_ADD(&sc->sc_ev_htdpmc,
+			    CSR_READ(sc, WMREG_HTDPMC));
+		}
+
+		WM_EVCNT_ADD(&sc->sc_ev_tncrs, CSR_READ(sc, WMREG_TNCRS));
+		WM_EVCNT_ADD(&sc->sc_ev_tsctc, CSR_READ(sc, WMREG_TSCTC));
+		if ((sc->sc_type < WM_T_82575) || WM_IS_ICHPCH(sc))
+			WM_EVCNT_ADD(&sc->sc_ev_tsctfc,
+			    CSR_READ(sc, WMREG_TSCTFC));
+		else {
+			WM_EVCNT_ADD(&sc->sc_ev_cbrmpc,
+			    CSR_READ(sc, WMREG_CBRMPC));
+		}
+	} else
+		algnerrc = rxerrc = cexterr = 0;
+
+	if (sc->sc_type >= WM_T_82542_2_1) {
+		WM_EVCNT_ADD(&sc->sc_ev_rx_xon, CSR_READ(sc, WMREG_XONRXC));
+		WM_EVCNT_ADD(&sc->sc_ev_tx_xon, CSR_READ(sc, WMREG_XONTXC));
+		WM_EVCNT_ADD(&sc->sc_ev_rx_xoff, CSR_READ(sc, WMREG_XOFFRXC));
+		WM_EVCNT_ADD(&sc->sc_ev_tx_xoff, CSR_READ(sc, WMREG_XOFFTXC));
+		WM_EVCNT_ADD(&sc->sc_ev_rx_macctl, CSR_READ(sc, WMREG_FCRUC));
+	}
+
+	WM_EVCNT_ADD(&sc->sc_ev_scc, CSR_READ(sc, WMREG_SCC));
+	WM_EVCNT_ADD(&sc->sc_ev_ecol, CSR_READ(sc, WMREG_ECOL));
+	WM_EVCNT_ADD(&sc->sc_ev_mcc, CSR_READ(sc, WMREG_MCC));
+	WM_EVCNT_ADD(&sc->sc_ev_latecol, CSR_READ(sc, WMREG_LATECOL));
+
+	if ((sc->sc_type >= WM_T_I350) && !WM_IS_ICHPCH(sc)) {
+		WM_EVCNT_ADD(&sc->sc_ev_cbtmpc, CSR_READ(sc, WMREG_CBTMPC));
+	}
+
+	WM_EVCNT_ADD(&sc->sc_ev_dc, CSR_READ(sc, WMREG_DC));
+	WM_EVCNT_ADD(&sc->sc_ev_prc64, CSR_READ(sc, WMREG_PRC64));
+	WM_EVCNT_ADD(&sc->sc_ev_prc127, CSR_READ(sc, WMREG_PRC127));
+	WM_EVCNT_ADD(&sc->sc_ev_prc255, CSR_READ(sc, WMREG_PRC255));
+	WM_EVCNT_ADD(&sc->sc_ev_prc511, CSR_READ(sc, WMREG_PRC511));
+	WM_EVCNT_ADD(&sc->sc_ev_prc1023, CSR_READ(sc, WMREG_PRC1023));
+	WM_EVCNT_ADD(&sc->sc_ev_prc1522, CSR_READ(sc, WMREG_PRC1522));
+	WM_EVCNT_ADD(&sc->sc_ev_gprc, CSR_READ(sc, WMREG_GPRC));
+	WM_EVCNT_ADD(&sc->sc_ev_bprc, CSR_READ(sc, WMREG_BPRC));
+	WM_EVCNT_ADD(&sc->sc_ev_mprc, CSR_READ(sc, WMREG_MPRC));
+	WM_EVCNT_ADD(&sc->sc_ev_gptc, CSR_READ(sc, WMREG_GPTC));
+
+	WM_EVCNT_ADD(&sc->sc_ev_gorc,
+	    CSR_READ(sc, WMREG_GORCL) +
+	    ((uint64_t)CSR_READ(sc, WMREG_GORCH) << 32));
+	WM_EVCNT_ADD(&sc->sc_ev_gotc,
+	    CSR_READ(sc, WMREG_GOTCL) +
+	    ((uint64_t)CSR_READ(sc, WMREG_GOTCH) << 32));
+
+	WM_EVCNT_ADD(&sc->sc_ev_rnbc, CSR_READ(sc, WMREG_RNBC));
+	WM_EVCNT_ADD(&sc->sc_ev_ruc, CSR_READ(sc, WMREG_RUC));
+	WM_EVCNT_ADD(&sc->sc_ev_rfc, CSR_READ(sc, WMREG_RFC));
+	WM_EVCNT_ADD(&sc->sc_ev_roc, CSR_READ(sc, WMREG_ROC));
+	WM_EVCNT_ADD(&sc->sc_ev_rjc, CSR_READ(sc, WMREG_RJC));
+
+	if (sc->sc_type >= WM_T_82540) {
+		WM_EVCNT_ADD(&sc->sc_ev_mgtprc, CSR_READ(sc, WMREG_MGTPRC));
+		WM_EVCNT_ADD(&sc->sc_ev_mgtpdc, CSR_READ(sc, WMREG_MGTPDC));
+		WM_EVCNT_ADD(&sc->sc_ev_mgtptc, CSR_READ(sc, WMREG_MGTPTC));
+	}
+
+	/*
+	 * The TOR(L) register includes:
+	 *  - Error
+	 *  - Flow control
+	 *  - Broadcast rejected (This note is described in 82574 and newer
+	 *    datasheets. What does "broadcast rejected" mean?)
+	 */
+	WM_EVCNT_ADD(&sc->sc_ev_tor,
+	    CSR_READ(sc, WMREG_TORL) +
+	    ((uint64_t)CSR_READ(sc, WMREG_TORH) << 32));
+	WM_EVCNT_ADD(&sc->sc_ev_tot,
+	    CSR_READ(sc, WMREG_TOTL) +
+	    ((uint64_t)CSR_READ(sc, WMREG_TOTH) << 32));
+
+	WM_EVCNT_ADD(&sc->sc_ev_tpr, CSR_READ(sc, WMREG_TPR));
+	WM_EVCNT_ADD(&sc->sc_ev_tpt, CSR_READ(sc, WMREG_TPT));
+	WM_EVCNT_ADD(&sc->sc_ev_ptc64, CSR_READ(sc, WMREG_PTC64));
+	WM_EVCNT_ADD(&sc->sc_ev_ptc127, CSR_READ(sc, WMREG_PTC127));
+	WM_EVCNT_ADD(&sc->sc_ev_ptc255, CSR_READ(sc, WMREG_PTC255));
+	WM_EVCNT_ADD(&sc->sc_ev_ptc511, CSR_READ(sc, WMREG_PTC511));
+	WM_EVCNT_ADD(&sc->sc_ev_ptc1023, CSR_READ(sc, WMREG_PTC1023));
+	WM_EVCNT_ADD(&sc->sc_ev_ptc1522, CSR_READ(sc, WMREG_PTC1522));
+	WM_EVCNT_ADD(&sc->sc_ev_mptc, CSR_READ(sc, WMREG_MPTC));
+	WM_EVCNT_ADD(&sc->sc_ev_bptc, CSR_READ(sc, WMREG_BPTC));
+	WM_EVCNT_ADD(&sc->sc_ev_iac, CSR_READ(sc, WMREG_IAC));
+	if (sc->sc_type < WM_T_82575) {
+		WM_EVCNT_ADD(&sc->sc_ev_icrxptc, CSR_READ(sc, WMREG_ICRXPTC));
+		WM_EVCNT_ADD(&sc->sc_ev_icrxatc, CSR_READ(sc, WMREG_ICRXATC));
+		WM_EVCNT_ADD(&sc->sc_ev_ictxptc, CSR_READ(sc, WMREG_ICTXPTC));
+		WM_EVCNT_ADD(&sc->sc_ev_ictxatc, CSR_READ(sc, WMREG_ICTXATC));
+		WM_EVCNT_ADD(&sc->sc_ev_ictxqec, CSR_READ(sc, WMREG_ICTXQEC));
+		WM_EVCNT_ADD(&sc->sc_ev_ictxqmtc,
+		    CSR_READ(sc, WMREG_ICTXQMTC));
+		WM_EVCNT_ADD(&sc->sc_ev_rxdmtc,
+		    CSR_READ(sc, WMREG_ICRXDMTC));
+		WM_EVCNT_ADD(&sc->sc_ev_icrxoc, CSR_READ(sc, WMREG_ICRXOC));
+	} else if (!WM_IS_ICHPCH(sc)) {
+		WM_EVCNT_ADD(&sc->sc_ev_rpthc, CSR_READ(sc, WMREG_RPTHC));
+		WM_EVCNT_ADD(&sc->sc_ev_debug1, CSR_READ(sc, WMREG_DEBUG1));
+		WM_EVCNT_ADD(&sc->sc_ev_debug2, CSR_READ(sc, WMREG_DEBUG2));
+		WM_EVCNT_ADD(&sc->sc_ev_debug3, CSR_READ(sc, WMREG_DEBUG3));
+		WM_EVCNT_ADD(&sc->sc_ev_hgptc,  CSR_READ(sc, WMREG_HGPTC));
+		WM_EVCNT_ADD(&sc->sc_ev_debug4, CSR_READ(sc, WMREG_DEBUG4));
+		WM_EVCNT_ADD(&sc->sc_ev_rxdmtc, CSR_READ(sc, WMREG_RXDMTC));
+		WM_EVCNT_ADD(&sc->sc_ev_htcbdpc, CSR_READ(sc, WMREG_HTCBDPC));
+
+		WM_EVCNT_ADD(&sc->sc_ev_hgorc,
+		    CSR_READ(sc, WMREG_HGORCL) +
+		    ((uint64_t)CSR_READ(sc, WMREG_HGORCH) << 32));
+		WM_EVCNT_ADD(&sc->sc_ev_hgotc,
+		    CSR_READ(sc, WMREG_HGOTCL) +
+		    ((uint64_t)CSR_READ(sc, WMREG_HGOTCH) << 32));
+		WM_EVCNT_ADD(&sc->sc_ev_lenerrs, CSR_READ(sc, WMREG_LENERRS));
+	}
+	if ((sc->sc_type >= WM_T_I350) && !WM_IS_ICHPCH(sc)) {
+		WM_EVCNT_ADD(&sc->sc_ev_tlpic, CSR_READ(sc, WMREG_TLPIC));
+		WM_EVCNT_ADD(&sc->sc_ev_rlpic, CSR_READ(sc, WMREG_RLPIC));
+		if ((CSR_READ(sc, WMREG_MANC) & MANC_EN_BMC2OS) != 0) {
+			WM_EVCNT_ADD(&sc->sc_ev_b2ogprc,
+			    CSR_READ(sc, WMREG_B2OGPRC));
+			WM_EVCNT_ADD(&sc->sc_ev_o2bspc,
+			    CSR_READ(sc, WMREG_O2BSPC));
+			WM_EVCNT_ADD(&sc->sc_ev_b2ospc,
+			    CSR_READ(sc, WMREG_B2OSPC));
+			WM_EVCNT_ADD(&sc->sc_ev_o2bgptc,
+			    CSR_READ(sc, WMREG_O2BGPTC));
+		}
+		WM_EVCNT_ADD(&sc->sc_ev_scvpc, CSR_READ(sc, WMREG_SCVPC));
+		WM_EVCNT_ADD(&sc->sc_ev_hrmpc, CSR_READ(sc, WMREG_HRMPC));
+	}
+	net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
+	if_statadd_ref(nsr, if_collisions, colc);
+	if_statadd_ref(nsr, if_ierrors,
+	    crcerrs + algnerrc + symerrc + rxerrc + sec + cexterr + rlec);
+	/*
+	 * WMREG_RNBC is incremented when there are no available buffers in
+	 * host memory. It does not mean the number of dropped packets, because
+	 * an Ethernet controller can receive packets in such case if there is
+	 * space in the phy's FIFO.
+	 *
+	 * If you want to know the nubmer of WMREG_RMBC, you should use such as
+	 * own EVCNT instead of if_iqdrops.
+	 */
+	if_statadd_ref(nsr, if_iqdrops, mpc);
+	IF_STAT_PUTREF(ifp);
+}
+
+void
+wm_clear_evcnt(struct wm_softc *sc)
+{
+#ifdef WM_EVENT_COUNTERS
+	int i;
+
+	/* RX queues */
+	for (i = 0; i < sc->sc_nqueues; i++) {
+		struct wm_rxqueue *rxq = &sc->sc_queue[i].wmq_rxq;
+
+		WM_Q_EVCNT_STORE(rxq, intr, 0);
+		WM_Q_EVCNT_STORE(rxq, defer, 0);
+		WM_Q_EVCNT_STORE(rxq, ipsum, 0);
+		WM_Q_EVCNT_STORE(rxq, tusum, 0);
+	}
+
+	/* TX queues */
+	for (i = 0; i < sc->sc_nqueues; i++) {
+		struct wm_txqueue *txq = &sc->sc_queue[i].wmq_txq;
+		int j;
+
+		WM_Q_EVCNT_STORE(txq, txsstall, 0);
+		WM_Q_EVCNT_STORE(txq, txdstall, 0);
+		WM_Q_EVCNT_STORE(txq, fifo_stall, 0);
+		WM_Q_EVCNT_STORE(txq, txdw, 0);
+		WM_Q_EVCNT_STORE(txq, txqe, 0);
+		WM_Q_EVCNT_STORE(txq, ipsum, 0);
+		WM_Q_EVCNT_STORE(txq, tusum, 0);
+		WM_Q_EVCNT_STORE(txq, tusum6, 0);
+		WM_Q_EVCNT_STORE(txq, tso, 0);
+		WM_Q_EVCNT_STORE(txq, tso6, 0);
+		WM_Q_EVCNT_STORE(txq, tsopain, 0);
+
+		for (j = 0; j < WM_NTXSEGS; j++)
+			WM_EVCNT_STORE(&txq->txq_ev_txseg[j], 0);
+
+		WM_Q_EVCNT_STORE(txq, pcqdrop, 0);
+		WM_Q_EVCNT_STORE(txq, descdrop, 0);
+		WM_Q_EVCNT_STORE(txq, toomanyseg, 0);
+		WM_Q_EVCNT_STORE(txq, defrag, 0);
+		if (sc->sc_type <= WM_T_82544)
+			WM_Q_EVCNT_STORE(txq, underrun, 0);
+		WM_Q_EVCNT_STORE(txq, skipcontext, 0);
+	}
+
+	/* Miscs */
+	WM_EVCNT_STORE(&sc->sc_ev_linkintr, 0);
+
+	WM_EVCNT_STORE(&sc->sc_ev_crcerrs, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_symerrc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_mpc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_colc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_sec, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_rlec, 0);
+
+	if (sc->sc_type >= WM_T_82543) {
+		WM_EVCNT_STORE(&sc->sc_ev_algnerrc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_rxerrc, 0);
+		if ((sc->sc_type < WM_T_82575) || WM_IS_ICHPCH(sc))
+			WM_EVCNT_STORE(&sc->sc_ev_cexterr, 0);
+		else
+			WM_EVCNT_STORE(&sc->sc_ev_htdpmc, 0);
+
+		WM_EVCNT_STORE(&sc->sc_ev_tncrs, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_tsctc, 0);
+		if ((sc->sc_type < WM_T_82575) || WM_IS_ICHPCH(sc))
+			WM_EVCNT_STORE(&sc->sc_ev_tsctfc, 0);
+		else {
+			WM_EVCNT_STORE(&sc->sc_ev_cbrdpc, 0);
+			WM_EVCNT_STORE(&sc->sc_ev_cbrmpc, 0);
+		}
+	}
+
+	if (sc->sc_type >= WM_T_82542_2_1) {
+		WM_EVCNT_STORE(&sc->sc_ev_tx_xoff, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_tx_xon, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_rx_xoff, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_rx_xon, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_rx_macctl, 0);
+	}
+
+	WM_EVCNT_STORE(&sc->sc_ev_scc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_ecol, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_mcc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_latecol, 0);
+
+	if ((sc->sc_type >= WM_T_I350) && !WM_IS_ICHPCH(sc))
+		WM_EVCNT_STORE(&sc->sc_ev_cbtmpc, 0);
+
+	WM_EVCNT_STORE(&sc->sc_ev_dc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_prc64, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_prc127, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_prc255, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_prc511, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_prc1023, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_prc1522, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_gprc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_bprc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_mprc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_gptc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_gorc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_gotc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_rnbc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_ruc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_rfc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_roc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_rjc, 0);
+	if (sc->sc_type >= WM_T_82540) {
+		WM_EVCNT_STORE(&sc->sc_ev_mgtprc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_mgtpdc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_mgtptc, 0);
+	}
+	WM_EVCNT_STORE(&sc->sc_ev_tor, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_tot, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_tpr, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_tpt, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_ptc64, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_ptc127, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_ptc255, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_ptc511, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_ptc1023, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_ptc1522, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_mptc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_bptc, 0);
+	WM_EVCNT_STORE(&sc->sc_ev_iac, 0);
+	if (sc->sc_type < WM_T_82575) {
+		WM_EVCNT_STORE(&sc->sc_ev_icrxptc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_icrxatc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_ictxptc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_ictxatc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_ictxqec, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_ictxqmtc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_rxdmtc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_icrxoc, 0);
+	} else if (!WM_IS_ICHPCH(sc)) {
+		WM_EVCNT_STORE(&sc->sc_ev_rpthc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_debug1, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_debug2, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_debug3, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_hgptc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_debug4, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_rxdmtc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_htcbdpc, 0);
+
+		WM_EVCNT_STORE(&sc->sc_ev_hgorc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_hgotc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_lenerrs, 0);
+	}
+	if ((sc->sc_type >= WM_T_I350) && !WM_IS_ICHPCH(sc)) {
+		WM_EVCNT_STORE(&sc->sc_ev_tlpic, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_rlpic, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_b2ogprc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_o2bspc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_b2ospc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_o2bgptc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_scvpc, 0);
+		WM_EVCNT_STORE(&sc->sc_ev_hrmpc, 0);
+	}
+#endif
+}
+
 /*
  * wm_init:		[ifnet interface function]
  *
@@ -7669,7 +8057,9 @@ wm_alloc_txrx_queues(struct wm_softc *sc
 		WM_Q_MISC_EVCNT_ATTACH(txq, descdrop, txq, i, xname);
 		WM_Q_MISC_EVCNT_ATTACH(txq, toomanyseg, txq, i, xname);
 		WM_Q_MISC_EVCNT_ATTACH(txq, defrag, txq, i, xname);
-		WM_Q_MISC_EVCNT_ATTACH(txq, underrun, txq, i, xname);
+		/* Only for 82544 (and earlier?) */
+		if (sc->sc_type <= WM_T_82544)
+			WM_Q_MISC_EVCNT_ATTACH(txq, underrun, txq, i, xname);
 		WM_Q_MISC_EVCNT_ATTACH(txq, skipcontext, txq, i, xname);
 #endif /* WM_EVENT_COUNTERS */
 
@@ -7790,7 +8180,8 @@ wm_free_txrx_queues(struct wm_softc *sc)
 		WM_Q_EVCNT_DETACH(txq, descdrop, txq, i);
 		WM_Q_EVCNT_DETACH(txq, toomanyseg, txq, i);
 		WM_Q_EVCNT_DETACH(txq, defrag, txq, i);
-		WM_Q_EVCNT_DETACH(txq, underrun, txq, i);
+		if (sc->sc_type <= WM_T_82544)
+			WM_Q_EVCNT_DETACH(txq, underrun, txq, i);
 		WM_Q_EVCNT_DETACH(txq, skipcontext, txq, i);
 #endif /* WM_EVENT_COUNTERS */
 
@@ -9412,14 +9803,8 @@ wm_txeof(struct wm_txqueue *txq, u_int l
 		    device_xname(sc->sc_dev), i, txs->txs_firstdesc,
 		    txs->txs_lastdesc));
 
-		/*
-		 * XXX We should probably be using the statistics
-		 * XXX registers, but I don't know if they exist
-		 * XXX on chips before the i82544.
-		 */
-
 #ifdef WM_EVENT_COUNTERS
-		if (status & WTX_ST_TU)
+		if ((status & WTX_ST_TU) && (sc->sc_type <= WM_T_82544))
 			WM_Q_EVCNT_INCR(txq, underrun);
 #endif /* WM_EVENT_COUNTERS */
 

Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.128 src/sys/dev/pci/if_wmreg.h:1.128.2.1
--- src/sys/dev/pci/if_wmreg.h:1.128	Wed Oct 19 06:37:25 2022
+++ src/sys/dev/pci/if_wmreg.h	Thu Jun 22 08:14:35 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmreg.h,v 1.128 2022/10/19 06:37:25 msaitoh Exp $	*/
+/*	$NetBSD: if_wmreg.h,v 1.128.2.1 2023/06/22 08:14:35 martin Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -1152,11 +1152,18 @@ struct livengood_tcpip_ctxdesc {
 #define	WMREG_MCC	0x401c	/* Multiple Collision Count - R/clr */
 #define	WMREG_LATECOL	0x4020	/* Late Collisions Count - R/clr */
 #define	WMREG_COLC	0x4028	/* Collision Count - R/clr */
+#define	WMREG_CBTMPC	0x402c	/* Circuit Breaker Tx Manageability Packet */
 #define	WMREG_DC	0x4030	/* Defer Count - R/clr */
 #define	WMREG_TNCRS	0x4034	/* Tx with No CRS - R/clr */
 #define	WMREG_SEC	0x4038	/* Sequence Error Count */
+
+/* Old */
 #define	WMREG_CEXTERR	0x403c	/* Carrier Extension Error Count */
+/* New */
+#define	WMREG_HTDPMC	0x403c	/* Host Tx Discarded Packets by MAC Count */
+
 #define	WMREG_RLEC	0x4040	/* Receive Length Error Count */
+#define	WMREG_CBRDPC	0x4044	/* Circuit Breaker Rx Dropped Packet Count */
 #define	WMREG_XONRXC	0x4048	/* XON Rx Count - R/clr */
 #define	WMREG_XONTXC	0x404c	/* XON Tx Count - R/clr */
 #define	WMREG_XOFFRXC	0x4050	/* XOFF Rx Count - R/clr */
@@ -1199,8 +1206,15 @@ struct livengood_tcpip_ctxdesc {
 #define	WMREG_MPTC	0x40f0	/* Multicast Packets Tx Count - R/clr */
 #define	WMREG_BPTC	0x40f4	/* Broadcast Packets Tx Count */
 #define	WMREG_TSCTC	0x40f8	/* TCP Segmentation Context Tx */
+
+/* Old */
 #define	WMREG_TSCTFC	0x40fc	/* TCP Segmentation Context Tx Fail */
+/* New */
+#define	WMREG_CBRMPC	0x40fc	/* Circuit Breaker Rx Manageability Packet */
+
 #define	WMREG_IAC	0x4100	/* Interrupt Assertion Count */
+
+/* Old */
 #define	WMREG_ICRXPTC	0x4104	/* Interrupt Cause Rx Pkt Timer Expire Count */
 #define	WMREG_ICRXATC	0x4108	/* Interrupt Cause Rx Abs Timer Expire Count */
 #define	WMREG_ICTXPTC	0x410c	/* Interrupt Cause Tx Pkt Timer Expire Count */
@@ -1209,6 +1223,21 @@ struct livengood_tcpip_ctxdesc {
 #define	WMREG_ICTXQMTC	0x411c	/* Interrupt Cause Tx Queue Min Thresh Count */
 #define	WMREG_ICRXDMTC	0x4120	/* Interrupt Cause Rx Desc Min Thresh Count */
 #define	WMREG_ICRXOC	0x4124	/* Interrupt Cause Receiver Overrun Count */
+/* New */
+#define	WMREG_RPTHC	0x4104	/* Rx Pkt To Host Count */
+#define	WMREG_DEBUG1	0x4108	/* Debug Counter 1 */
+#define	WMREG_DEBUG2	0x410c	/* Debug Counter 2 */
+#define	WMREG_DEBUG3	0x4110	/* Debug Counter 3 */
+#define	WMREG_HGPTC	0x4118	/* Host Good Packets Tx Count (>=82576?) */
+#define	WMREG_DEBUG4	0x411c	/* Debug Counter 4 */
+#define	WMREG_RXDMTC	0x4120	/* Rx Desc Min Thresh Count */
+#define	WMREG_HTCBDPC	0x4124	/* Host Tx Circuit Breaker Dropped Pkt. Cnt. */
+#define	WMREG_HGORCL	0x4128	/* Host Good Octets Rx Count Low (>=82576?) */
+#define	WMREG_HGORCH	0x412c	/* Host Good Octets Rx Count High (>=82576?) */
+#define	WMREG_HGOTCL	0x4130	/* Host Good Octets Tx Count Low (>=82576?) */
+#define	WMREG_HGOTCH	0x4134	/* Host Good Octets Tx Count High (>=82576?) */
+#define	WMREG_LENERRS	0x4138	/* Length Errors Count (>=82576?) */
+
 #define	WMREG_TLPIC	0x4148	/* EEE Tx LPI Count */
 #define	WMREG_RLPIC	0x414c	/* EEE Rx LPI Count */
 #define	WMREG_B2OGPRC	0x4158	/* BMC2OS packets received by host */
@@ -1248,6 +1277,7 @@ struct livengood_tcpip_ctxdesc {
 #define	WMREG_PCS_ANADV	0x4218	/* AN Advertsement */
 #define	WMREG_PCS_LPAB	0x421c	/* Link Partnet Ability */
 #define	WMREG_PCS_NPTX	0x4220	/* Next Page Transmit */
+#define	WMREG_SCVPC	0x4228	/* SerDes/SGMII Code Violation Packet Count */
 
 #define	WMREG_RXCSUM	0x5000	/* Receive Checksum register */
 #define	RXCSUM_PCSS	0x000000ff	/* Packet Checksum Start */
@@ -1445,6 +1475,8 @@ struct livengood_tcpip_ctxdesc {
 #define	WMREG_B2OSPC	0x8fe0	/* BMC2OS packets sent by BMC */
 #define	WMREG_O2BGPTC	0x8fe4	/* OS2BMC packets received by BMC */
 
+#define	WMREG_HRMPC	0xa018	/* Header Redirection Missed Packet Count */
+
 #define	WMREG_EEC	0x12010
 #define	EEC_FLASH_DETECTED __BIT(19)	/* FLASH */
 #define	EEC_FLUPD	__BIT(23)	/* Update FLASH */

Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.48 src/sys/dev/pci/if_wmvar.h:1.48.4.1
--- src/sys/dev/pci/if_wmvar.h:1.48	Mon Dec 20 12:50:35 2021
+++ src/sys/dev/pci/if_wmvar.h	Thu Jun 22 08:14:35 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmvar.h,v 1.48 2021/12/20 12:50:35 skrll Exp $	*/
+/*	$NetBSD: if_wmvar.h,v 1.48.4.1 2023/06/22 08:14:35 martin Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -213,4 +213,7 @@ typedef enum {
 #define	WM_MDIO_OWNERSHIP_TIMEOUT 10
 #define	WM_MAX_PLL_TRIES	5
 
+/* For 80003, ICHs and PCHs */
+#define	WM_IS_ICHPCH(x)	((x)->sc_type >= WM_T_80003)
+
 #endif /* _DEV_PCI_IF_WMVAR_H_ */

Reply via email to