diff options
author | yongari <yongari@FreeBSD.org> | 2008-10-03 03:58:16 +0000 |
---|---|---|
committer | yongari <yongari@FreeBSD.org> | 2008-10-03 03:58:16 +0000 |
commit | 7570f3398aa8c889259ef224e4ce5fdd77cc53ee (patch) | |
tree | 34f83d61d2e7d991c97d21b9ec469d266e0b5e7e /sys/dev | |
parent | 5af9b4daf219111a13b92959edcef0f894837ad0 (diff) | |
download | FreeBSD-src-7570f3398aa8c889259ef224e4ce5fdd77cc53ee.zip FreeBSD-src-7570f3398aa8c889259ef224e4ce5fdd77cc53ee.tar.gz |
Add hardware MAC statistics support. Register information was
obtained from Linux forcedeth driver.
While I'm here move creating a sysctl node for process_limit to
function nfe_sysctl_node().
Tested by: "Arno J. Klaassen" < arno <at> heho dot snv dot jussieu dot fr >
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/nfe/if_nfe.c | 241 | ||||
-rw-r--r-- | sys/dev/nfe/if_nfereg.h | 34 | ||||
-rw-r--r-- | sys/dev/nfe/if_nfevar.h | 37 |
3 files changed, 287 insertions, 25 deletions
diff --git a/sys/dev/nfe/if_nfe.c b/sys/dev/nfe/if_nfe.c index 51b8251..7a36a2e 100644 --- a/sys/dev/nfe/if_nfe.c +++ b/sys/dev/nfe/if_nfe.c @@ -122,6 +122,9 @@ static void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int); static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); static int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS); +static void nfe_sysctl_node(struct nfe_softc *); +static void nfe_stats_clear(struct nfe_softc *); +static void nfe_stats_update(struct nfe_softc *); #ifdef NFE_DEBUG static int nfedebug = 0; @@ -454,18 +457,19 @@ nfe_attach(device_t dev) break; case PCI_PRODUCT_NVIDIA_MCP51_LAN1: case PCI_PRODUCT_NVIDIA_MCP51_LAN2: - sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT; + sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | NFE_MIB_V1; break; case PCI_PRODUCT_NVIDIA_CK804_LAN1: case PCI_PRODUCT_NVIDIA_CK804_LAN2: case PCI_PRODUCT_NVIDIA_MCP04_LAN1: case PCI_PRODUCT_NVIDIA_MCP04_LAN2: - sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; + sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | + NFE_MIB_V1; break; case PCI_PRODUCT_NVIDIA_MCP55_LAN1: case PCI_PRODUCT_NVIDIA_MCP55_LAN2: sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | - NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL; + NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL | NFE_MIB_V2; break; case PCI_PRODUCT_NVIDIA_MCP61_LAN1: @@ -481,7 +485,7 @@ nfe_attach(device_t dev) case PCI_PRODUCT_NVIDIA_MCP73_LAN3: case PCI_PRODUCT_NVIDIA_MCP73_LAN4: sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | - NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL; + NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | NFE_MIB_V2; break; case PCI_PRODUCT_NVIDIA_MCP77_LAN1: case PCI_PRODUCT_NVIDIA_MCP77_LAN2: @@ -489,7 +493,7 @@ nfe_attach(device_t dev) case PCI_PRODUCT_NVIDIA_MCP77_LAN4: /* XXX flow control */ sc->nfe_flags |= NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_PWR_MGMT | - NFE_CORRECT_MACADDR; + NFE_CORRECT_MACADDR | NFE_MIB_V3; break; case PCI_PRODUCT_NVIDIA_MCP79_LAN1: case PCI_PRODUCT_NVIDIA_MCP79_LAN2: @@ -497,14 +501,15 @@ nfe_attach(device_t dev) case PCI_PRODUCT_NVIDIA_MCP79_LAN4: /* XXX flow control */ sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | - NFE_PWR_MGMT | NFE_CORRECT_MACADDR; + NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_MIB_V3; break; case PCI_PRODUCT_NVIDIA_MCP65_LAN1: case PCI_PRODUCT_NVIDIA_MCP65_LAN2: case PCI_PRODUCT_NVIDIA_MCP65_LAN3: case PCI_PRODUCT_NVIDIA_MCP65_LAN4: sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | - NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL; + NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | + NFE_MIB_V2; break; } @@ -551,24 +556,8 @@ nfe_attach(device_t dev) goto fail; nfe_alloc_jrx_ring(sc, &sc->jrxq); - - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), - SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW, - &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I", - "max number of Rx events to process"); - - sc->nfe_process_limit = NFE_PROC_DEFAULT; - error = resource_int_value(device_get_name(dev), device_get_unit(dev), - "process_limit", &sc->nfe_process_limit); - if (error == 0) { - if (sc->nfe_process_limit < NFE_PROC_MIN || - sc->nfe_process_limit > NFE_PROC_MAX) { - device_printf(dev, "process_limit value out of range; " - "using default: %d\n", NFE_PROC_DEFAULT); - sc->nfe_process_limit = NFE_PROC_DEFAULT; - } - } + /* Create sysctl node. */ + nfe_sysctl_node(sc); ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); @@ -2767,6 +2756,9 @@ nfe_init_locked(void *xsc) NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); + /* Clear hardware stats. */ + nfe_stats_clear(sc); + #ifdef DEVICE_POLLING if (ifp->if_capenable & IFCAP_POLLING) nfe_disable_intr(sc); @@ -2855,6 +2847,8 @@ nfe_stop(struct ifnet *ifp) tdata->m = NULL; } } + /* Update hardware stats. */ + nfe_stats_update(sc); } @@ -2906,6 +2900,7 @@ nfe_tick(void *xsc) mii = device_get_softc(sc->nfe_miibus); mii_tick(mii); + nfe_stats_update(sc); nfe_watchdog(ifp); callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); } @@ -3013,3 +3008,199 @@ sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS) return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN, NFE_PROC_MAX)); } + + +#define NFE_SYSCTL_STAT_ADD32(c, h, n, p, d) \ + SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) +#define NFE_SYSCTL_STAT_ADD64(c, h, n, p, d) \ + SYSCTL_ADD_QUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) + +static void +nfe_sysctl_node(struct nfe_softc *sc) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *child, *parent; + struct sysctl_oid *tree; + struct nfe_hw_stats *stats; + int error; + + stats = &sc->nfe_stats; + ctx = device_get_sysctl_ctx(sc->nfe_dev); + child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->nfe_dev)); + SYSCTL_ADD_PROC(ctx, child, + OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW, + &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I", + "max number of Rx events to process"); + + sc->nfe_process_limit = NFE_PROC_DEFAULT; + error = resource_int_value(device_get_name(sc->nfe_dev), + device_get_unit(sc->nfe_dev), "process_limit", + &sc->nfe_process_limit); + if (error == 0) { + if (sc->nfe_process_limit < NFE_PROC_MIN || + sc->nfe_process_limit > NFE_PROC_MAX) { + device_printf(sc->nfe_dev, + "process_limit value out of range; " + "using default: %d\n", NFE_PROC_DEFAULT); + sc->nfe_process_limit = NFE_PROC_DEFAULT; + } + } + + if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) + return; + + tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, + NULL, "NFE statistics"); + parent = SYSCTL_CHILDREN(tree); + + /* Rx statistics. */ + tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, + NULL, "Rx MAC statistics"); + child = SYSCTL_CHILDREN(tree); + + NFE_SYSCTL_STAT_ADD32(ctx, child, "frame_errors", + &stats->rx_frame_errors, "Framing Errors"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "extra_bytes", + &stats->rx_extra_bytes, "Extra Bytes"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", + &stats->rx_late_cols, "Late Collisions"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "runts", + &stats->rx_runts, "Runts"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "jumbos", + &stats->rx_jumbos, "Jumbos"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_overuns", + &stats->rx_fifo_overuns, "FIFO Overruns"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "crc_errors", + &stats->rx_crc_errors, "CRC Errors"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "fae", + &stats->rx_fae, "Frame Alignment Errors"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "len_errors", + &stats->rx_len_errors, "Length Errors"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", + &stats->rx_unicast, "Unicast Frames"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", + &stats->rx_multicast, "Multicast Frames"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "brocadcast", + &stats->rx_broadcast, "Broadcast Frames"); + if ((sc->nfe_flags & NFE_MIB_V2) != 0) { + NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", + &stats->rx_octets, "Octets"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", + &stats->rx_pause, "Pause frames"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "drops", + &stats->rx_drops, "Drop frames"); + } + + /* Tx statistics. */ + tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, + NULL, "Tx MAC statistics"); + child = SYSCTL_CHILDREN(tree); + NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", + &stats->tx_octets, "Octets"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "zero_rexmits", + &stats->tx_zero_rexmits, "Zero Retransmits"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "one_rexmits", + &stats->tx_one_rexmits, "One Retransmits"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "multi_rexmits", + &stats->tx_multi_rexmits, "Multiple Retransmits"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", + &stats->tx_late_cols, "Late Collisions"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_underuns", + &stats->tx_fifo_underuns, "FIFO Underruns"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "carrier_losts", + &stats->tx_carrier_losts, "Carrier Losts"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "excess_deferrals", + &stats->tx_excess_deferals, "Excess Deferrals"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "retry_errors", + &stats->tx_retry_errors, "Retry Errors"); + if ((sc->nfe_flags & NFE_MIB_V2) != 0) { + NFE_SYSCTL_STAT_ADD32(ctx, child, "deferrals", + &stats->tx_deferals, "Deferrals"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "frames", + &stats->tx_frames, "Frames"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", + &stats->tx_pause, "Pause Frames"); + } + if ((sc->nfe_flags & NFE_MIB_V3) != 0) { + NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", + &stats->tx_deferals, "Unicast Frames"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", + &stats->tx_frames, "Multicast Frames"); + NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", + &stats->tx_pause, "Broadcast Frames"); + } +} + +#undef NFE_SYSCTL_STAT_ADD32 +#undef NFE_SYSCTL_STAT_ADD64 + +static void +nfe_stats_clear(struct nfe_softc *sc) +{ + int i, mib_cnt; + + if ((sc->nfe_flags & NFE_MIB_V1) != 0) + mib_cnt = NFE_NUM_MIB_STATV1; + else if ((sc->nfe_flags & (NFE_MIB_V2 | NFE_MIB_V3)) != 0) + mib_cnt = NFE_NUM_MIB_STATV2; + else + return; + + for (i = 0; i < mib_cnt; i += sizeof(uint32_t)) + NFE_READ(sc, NFE_TX_OCTET + i); + + if ((sc->nfe_flags & NFE_MIB_V3) != 0) { + NFE_READ(sc, NFE_TX_UNICAST); + NFE_READ(sc, NFE_TX_MULTICAST); + NFE_READ(sc, NFE_TX_BROADCAST); + } +} + +static void +nfe_stats_update(struct nfe_softc *sc) +{ + struct nfe_hw_stats *stats; + + NFE_LOCK_ASSERT(sc); + + if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) + return; + + stats = &sc->nfe_stats; + stats->tx_octets += NFE_READ(sc, NFE_TX_OCTET); + stats->tx_zero_rexmits += NFE_READ(sc, NFE_TX_ZERO_REXMIT); + stats->tx_one_rexmits += NFE_READ(sc, NFE_TX_ONE_REXMIT); + stats->tx_multi_rexmits += NFE_READ(sc, NFE_TX_MULTI_REXMIT); + stats->tx_late_cols += NFE_READ(sc, NFE_TX_LATE_COL); + stats->tx_fifo_underuns += NFE_READ(sc, NFE_TX_FIFO_UNDERUN); + stats->tx_carrier_losts += NFE_READ(sc, NFE_TX_CARRIER_LOST); + stats->tx_excess_deferals += NFE_READ(sc, NFE_TX_EXCESS_DEFERRAL); + stats->tx_retry_errors += NFE_READ(sc, NFE_TX_RETRY_ERROR); + stats->rx_frame_errors += NFE_READ(sc, NFE_RX_FRAME_ERROR); + stats->rx_extra_bytes += NFE_READ(sc, NFE_RX_EXTRA_BYTES); + stats->rx_late_cols += NFE_READ(sc, NFE_RX_LATE_COL); + stats->rx_runts += NFE_READ(sc, NFE_RX_RUNT); + stats->rx_jumbos += NFE_READ(sc, NFE_RX_JUMBO); + stats->rx_fifo_overuns += NFE_READ(sc, NFE_RX_FIFO_OVERUN); + stats->rx_crc_errors += NFE_READ(sc, NFE_RX_CRC_ERROR); + stats->rx_fae += NFE_READ(sc, NFE_RX_FAE); + stats->rx_len_errors += NFE_READ(sc, NFE_RX_LEN_ERROR); + stats->rx_unicast += NFE_READ(sc, NFE_RX_UNICAST); + stats->rx_multicast += NFE_READ(sc, NFE_RX_MULTICAST); + stats->rx_broadcast += NFE_READ(sc, NFE_RX_BROADCAST); + + if ((sc->nfe_flags & NFE_MIB_V2) != 0) { + stats->tx_deferals += NFE_READ(sc, NFE_TX_DEFERAL); + stats->tx_frames += NFE_READ(sc, NFE_TX_FRAME); + stats->rx_octets += NFE_READ(sc, NFE_RX_OCTET); + stats->tx_pause += NFE_READ(sc, NFE_TX_PAUSE); + stats->rx_pause += NFE_READ(sc, NFE_RX_PAUSE); + stats->rx_drops += NFE_READ(sc, NFE_RX_DROP); + } + + if ((sc->nfe_flags & NFE_MIB_V3) != 0) { + stats->tx_unicast += NFE_READ(sc, NFE_TX_UNICAST); + stats->tx_multicast += NFE_READ(sc, NFE_TX_MULTICAST); + stats->rx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST); + } +} diff --git a/sys/dev/nfe/if_nfereg.h b/sys/dev/nfe/if_nfereg.h index 01cc01d..d3671ab 100644 --- a/sys/dev/nfe/if_nfereg.h +++ b/sys/dev/nfe/if_nfereg.h @@ -87,11 +87,41 @@ #define NFE_PHY_SPEED 0x18c #define NFE_PHY_CTL 0x190 #define NFE_PHY_DATA 0x194 +#define NFE_TX_UNICAST 0x1a0 +#define NFE_TX_MULTICAST 0x1a4 +#define NFE_TX_BROADCAST 0x1a8 #define NFE_WOL_CTL 0x200 #define NFE_PATTERN_CRC 0x204 #define NFE_PATTERN_MASK 0x208 #define NFE_PWR_CAP 0x268 #define NFE_PWR_STATE 0x26c +#define NFE_TX_OCTET 0x280 +#define NFE_TX_ZERO_REXMIT 0x284 +#define NFE_TX_ONE_REXMIT 0x288 +#define NFE_TX_MULTI_REXMIT 0x28c +#define NFE_TX_LATE_COL 0x290 +#define NFE_TX_FIFO_UNDERUN 0x294 +#define NFE_TX_CARRIER_LOST 0x298 +#define NFE_TX_EXCESS_DEFERRAL 0x29c +#define NFE_TX_RETRY_ERROR 0x2a0 +#define NFE_RX_FRAME_ERROR 0x2a4 +#define NFE_RX_EXTRA_BYTES 0x2a8 +#define NFE_RX_LATE_COL 0x2ac +#define NFE_RX_RUNT 0x2b0 +#define NFE_RX_JUMBO 0x2b4 +#define NFE_RX_FIFO_OVERUN 0x2b8 +#define NFE_RX_CRC_ERROR 0x2bc +#define NFE_RX_FAE 0x2c0 +#define NFE_RX_LEN_ERROR 0x2c4 +#define NFE_RX_UNICAST 0x2c8 +#define NFE_RX_MULTICAST 0x2cc +#define NFE_RX_BROADCAST 0x2d0 +#define NFE_TX_DEFERAL 0x2d4 +#define NFE_TX_FRAME 0x2d8 +#define NFE_RX_OCTET 0x2dc +#define NFE_TX_PAUSE 0x2e0 +#define NFE_RX_PAUSE 0x2e4 +#define NFE_RX_DROP 0x2e8 #define NFE_VTAG_CTL 0x300 #define NFE_MSIX_MAP0 0x3e0 #define NFE_MSIX_MAP1 0x3e4 @@ -182,6 +212,10 @@ #define NFE_SEED_100TX 0x00002d00 #define NFE_SEED_1000T 0x00007400 +#define NFE_NUM_MIB_STATV1 21 +#define NFE_NUM_MIB_STATV2 27 +#define NFE_NUM_MIB_STATV3 30 + #define NFE_MSI_MESSAGES 8 #define NFE_MSI_VECTOR_0_ENABLED 0x01 diff --git a/sys/dev/nfe/if_nfevar.h b/sys/dev/nfe/if_nfevar.h index b9c7217..3686254 100644 --- a/sys/dev/nfe/if_nfevar.h +++ b/sys/dev/nfe/if_nfevar.h @@ -70,6 +70,39 @@ struct nfe_jrx_ring { int jnext; }; +struct nfe_hw_stats { + uint64_t rx_octets; + uint32_t rx_frame_errors; + uint32_t rx_extra_bytes; + uint32_t rx_late_cols; + uint32_t rx_runts; + uint32_t rx_jumbos; + uint32_t rx_fifo_overuns; + uint32_t rx_crc_errors; + uint32_t rx_fae; + uint32_t rx_len_errors; + uint32_t rx_unicast; + uint32_t rx_multicast; + uint32_t rx_broadcast; + uint32_t rx_pause; + uint32_t rx_drops; + uint64_t tx_octets; + uint32_t tx_zero_rexmits; + uint32_t tx_one_rexmits; + uint32_t tx_multi_rexmits; + uint32_t tx_late_cols; + uint32_t tx_fifo_underuns; + uint32_t tx_carrier_losts; + uint32_t tx_excess_deferals; + uint32_t tx_retry_errors; + uint32_t tx_deferals; + uint32_t tx_frames; + uint32_t tx_pause; + uint32_t tx_unicast; + uint32_t tx_multicast; + uint32_t tx_broadcast; +}; + struct nfe_softc { struct ifnet *nfe_ifp; device_t nfe_dev; @@ -96,10 +129,14 @@ struct nfe_softc { #define NFE_PWR_MGMT 0x0010 #define NFE_CORRECT_MACADDR 0x0020 #define NFE_TX_FLOW_CTRL 0x0040 +#define NFE_MIB_V1 0x0080 +#define NFE_MIB_V2 0x0100 +#define NFE_MIB_V3 0x0200 int nfe_jumbo_disable; uint32_t rxtxctl; uint8_t mii_phyaddr; uint8_t eaddr[ETHER_ADDR_LEN]; + struct nfe_hw_stats nfe_stats; struct taskqueue *nfe_tq; struct task nfe_int_task; struct task nfe_tx_task; |