Add hardware MAC statistics support. This statistics could be

extracted from dev.vge.%d.stats sysctl node.
This commit is contained in:
Pyun YongHyeon 2009-12-16 19:41:40 +00:00
parent 84bc0aa3b0
commit 7129fb20d6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=200615
3 changed files with 322 additions and 3 deletions

View File

@ -93,6 +93,7 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_arp.h>
@ -131,6 +132,13 @@ MODULE_DEPEND(vge, miibus, 1, 1, 1);
static int msi_disable = 0;
TUNABLE_INT("hw.vge.msi_disable", &msi_disable);
/*
* The SQE error counter of MIB seems to report bogus value.
* Vendor's workaround does not seem to work on PCIe based
* controllers. Disable it until we find better workaround.
*/
#undef VGE_ENABLE_SQEERR
/*
* Various supported device vendors/types and their names.
*/
@ -183,7 +191,10 @@ static void vge_rxfilter(struct vge_softc *);
static void vge_setvlan(struct vge_softc *);
static void vge_start(struct ifnet *);
static void vge_start_locked(struct ifnet *);
static void vge_stats_clear(struct vge_softc *);
static void vge_stats_update(struct vge_softc *);
static void vge_stop(struct vge_softc *);
static void vge_sysctl_node(struct vge_softc *);
static int vge_tx_list_init(struct vge_softc *);
static void vge_txeof(struct vge_softc *);
static void vge_watchdog(void *);
@ -1057,6 +1068,7 @@ vge_attach(device_t dev)
else
sc->vge_phyaddr = CSR_READ_1(sc, VGE_MIICFG) &
VGE_MIICFG_PHYADDR;
vge_sysctl_node(sc);
error = vge_dma_alloc(sc);
if (error)
goto fail;
@ -1698,7 +1710,6 @@ vge_poll (struct ifnet *ifp, enum poll_cmd cmd, int count)
if (status & (VGE_ISR_RXOFLOW|VGE_ISR_RXNODESC)) {
vge_rxeof(sc, count);
ifp->if_ierrors++;
CSR_WRITE_1(sc, VGE_RXQCSRS, VGE_RXQCSR_RUN);
CSR_WRITE_1(sc, VGE_RXQCSRS, VGE_RXQCSR_WAK);
}
@ -2034,7 +2045,8 @@ vge_init_locked(struct vge_softc *sc)
return;
}
vge_tx_list_init(sc);
/* Clear MAC statistics. */
vge_stats_clear(sc);
/* Set our station address */
for (i = 0; i < ETHER_ADDR_LEN; i++)
CSR_WRITE_1(sc, VGE_PAR0 + i, IF_LLADDR(sc->vge_ifp)[i]);
@ -2358,6 +2370,7 @@ vge_watchdog(void *arg)
sc = arg;
VGE_LOCK_ASSERT(sc);
vge_stats_update(sc);
callout_reset(&sc->vge_watchdog, hz, vge_watchdog, sc);
if (sc->vge_timer == 0 || --sc->vge_timer > 0)
return;
@ -2396,6 +2409,7 @@ vge_stop(struct vge_softc *sc)
CSR_WRITE_1(sc, VGE_RXQCSRC, 0xFF);
CSR_WRITE_4(sc, VGE_RXDESC_ADDR_LO, 0);
vge_stats_update(sc);
VGE_CHAIN_RESET(sc);
vge_txeof(sc);
vge_freebufs(sc);
@ -2469,3 +2483,223 @@ vge_shutdown(device_t dev)
return (0);
}
#define VGE_SYSCTL_STAT_ADD32(c, h, n, p, d) \
SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
static void
vge_sysctl_node(struct vge_softc *sc)
{
struct sysctl_ctx_list *ctx;
struct sysctl_oid_list *child, *parent;
struct sysctl_oid *tree;
struct vge_hw_stats *stats;
stats = &sc->vge_stats;
ctx = device_get_sysctl_ctx(sc->vge_dev);
child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->vge_dev));
tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
NULL, "VGE 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);
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames",
&stats->rx_frames, "frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "good_frames",
&stats->rx_good_frames, "Good frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "fifo_oflows",
&stats->rx_fifo_oflows, "FIFO overflows");
VGE_SYSCTL_STAT_ADD32(ctx, child, "runts",
&stats->rx_runts, "Too short frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "runts_errs",
&stats->rx_runts_errs, "Too short frames with errors");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_64",
&stats->rx_pkts_64, "64 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_65_127",
&stats->rx_pkts_65_127, "65 to 127 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_128_255",
&stats->rx_pkts_128_255, "128 to 255 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_256_511",
&stats->rx_pkts_256_511, "256 to 511 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_512_1023",
&stats->rx_pkts_512_1023, "512 to 1023 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_1024_1518",
&stats->rx_pkts_1024_1518, "1024 to 1518 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_1519_max",
&stats->rx_pkts_1519_max, "1519 to max frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_1519_max_errs",
&stats->rx_pkts_1519_max_errs, "1519 to max frames with error");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_jumbo",
&stats->rx_jumbos, "Jumbo frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "crcerrs",
&stats->rx_crcerrs, "CRC errors");
VGE_SYSCTL_STAT_ADD32(ctx, child, "pause_frames",
&stats->rx_pause_frames, "CRC errors");
VGE_SYSCTL_STAT_ADD32(ctx, child, "align_errs",
&stats->rx_alignerrs, "Alignment errors");
VGE_SYSCTL_STAT_ADD32(ctx, child, "nobufs",
&stats->rx_nobufs, "Frames with no buffer event");
VGE_SYSCTL_STAT_ADD32(ctx, child, "sym_errs",
&stats->rx_symerrs, "Frames with symbol errors");
VGE_SYSCTL_STAT_ADD32(ctx, child, "len_errs",
&stats->rx_lenerrs, "Frames with length mismatched");
/* Tx statistics. */
tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
NULL, "TX MAC statistics");
child = SYSCTL_CHILDREN(tree);
VGE_SYSCTL_STAT_ADD32(ctx, child, "good_frames",
&stats->tx_good_frames, "Good frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_64",
&stats->tx_pkts_64, "64 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_65_127",
&stats->tx_pkts_65_127, "65 to 127 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_128_255",
&stats->tx_pkts_128_255, "128 to 255 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_256_511",
&stats->tx_pkts_256_511, "256 to 511 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_512_1023",
&stats->tx_pkts_512_1023, "512 to 1023 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_1024_1518",
&stats->tx_pkts_1024_1518, "1024 to 1518 bytes frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "frames_jumbo",
&stats->tx_jumbos, "Jumbo frames");
VGE_SYSCTL_STAT_ADD32(ctx, child, "colls",
&stats->tx_colls, "Collisions");
VGE_SYSCTL_STAT_ADD32(ctx, child, "late_colls",
&stats->tx_latecolls, "Late collisions");
VGE_SYSCTL_STAT_ADD32(ctx, child, "pause_frames",
&stats->tx_pause, "Pause frames");
#ifdef VGE_ENABLE_SQEERR
VGE_SYSCTL_STAT_ADD32(ctx, child, "sqeerrs",
&stats->tx_sqeerrs, "SQE errors");
#endif
/* Clear MAC statistics. */
vge_stats_clear(sc);
}
#undef VGE_SYSCTL_STAT_ADD32
static void
vge_stats_clear(struct vge_softc *sc)
{
int i;
VGE_LOCK_ASSERT(sc);
CSR_WRITE_1(sc, VGE_MIBCSR,
CSR_READ_1(sc, VGE_MIBCSR) | VGE_MIBCSR_FREEZE);
CSR_WRITE_1(sc, VGE_MIBCSR,
CSR_READ_1(sc, VGE_MIBCSR) | VGE_MIBCSR_CLR);
for (i = VGE_TIMEOUT; i > 0; i--) {
DELAY(1);
if ((CSR_READ_1(sc, VGE_MIBCSR) & VGE_MIBCSR_CLR) == 0)
break;
}
if (i == 0)
device_printf(sc->vge_dev, "MIB clear timed out!\n");
CSR_WRITE_1(sc, VGE_MIBCSR, CSR_READ_1(sc, VGE_MIBCSR) &
~VGE_MIBCSR_FREEZE);
}
static void
vge_stats_update(struct vge_softc *sc)
{
struct vge_hw_stats *stats;
struct ifnet *ifp;
uint32_t mib[VGE_MIB_CNT], val;
int i;
VGE_LOCK_ASSERT(sc);
stats = &sc->vge_stats;
ifp = sc->vge_ifp;
CSR_WRITE_1(sc, VGE_MIBCSR,
CSR_READ_1(sc, VGE_MIBCSR) | VGE_MIBCSR_FLUSH);
for (i = VGE_TIMEOUT; i > 0; i--) {
DELAY(1);
if ((CSR_READ_1(sc, VGE_MIBCSR) & VGE_MIBCSR_FLUSH) == 0)
break;
}
if (i == 0) {
device_printf(sc->vge_dev, "MIB counter dump timed out!\n");
vge_stats_clear(sc);
return;
}
bzero(mib, sizeof(mib));
reset_idx:
/* Set MIB read index to 0. */
CSR_WRITE_1(sc, VGE_MIBCSR,
CSR_READ_1(sc, VGE_MIBCSR) | VGE_MIBCSR_RINI);
for (i = 0; i < VGE_MIB_CNT; i++) {
val = CSR_READ_4(sc, VGE_MIBDATA);
if (i != VGE_MIB_DATA_IDX(val)) {
/* Reading interrupted. */
goto reset_idx;
}
mib[i] = val & VGE_MIB_DATA_MASK;
}
/* Rx stats. */
stats->rx_frames += mib[VGE_MIB_RX_FRAMES];
stats->rx_good_frames += mib[VGE_MIB_RX_GOOD_FRAMES];
stats->rx_fifo_oflows += mib[VGE_MIB_RX_FIFO_OVERRUNS];
stats->rx_runts += mib[VGE_MIB_RX_RUNTS];
stats->rx_runts_errs += mib[VGE_MIB_RX_RUNTS_ERRS];
stats->rx_pkts_64 += mib[VGE_MIB_RX_PKTS_64];
stats->rx_pkts_65_127 += mib[VGE_MIB_RX_PKTS_65_127];
stats->rx_pkts_128_255 += mib[VGE_MIB_RX_PKTS_128_255];
stats->rx_pkts_256_511 += mib[VGE_MIB_RX_PKTS_256_511];
stats->rx_pkts_512_1023 += mib[VGE_MIB_RX_PKTS_512_1023];
stats->rx_pkts_1024_1518 += mib[VGE_MIB_RX_PKTS_1024_1518];
stats->rx_pkts_1519_max += mib[VGE_MIB_RX_PKTS_1519_MAX];
stats->rx_pkts_1519_max_errs += mib[VGE_MIB_RX_PKTS_1519_MAX_ERRS];
stats->rx_jumbos += mib[VGE_MIB_RX_JUMBOS];
stats->rx_crcerrs += mib[VGE_MIB_RX_CRCERRS];
stats->rx_pause_frames += mib[VGE_MIB_RX_PAUSE];
stats->rx_alignerrs += mib[VGE_MIB_RX_ALIGNERRS];
stats->rx_nobufs += mib[VGE_MIB_RX_NOBUFS];
stats->rx_symerrs += mib[VGE_MIB_RX_SYMERRS];
stats->rx_lenerrs += mib[VGE_MIB_RX_LENERRS];
/* Tx stats. */
stats->tx_good_frames += mib[VGE_MIB_TX_GOOD_FRAMES];
stats->tx_pkts_64 += mib[VGE_MIB_TX_PKTS_64];
stats->tx_pkts_65_127 += mib[VGE_MIB_TX_PKTS_65_127];
stats->tx_pkts_128_255 += mib[VGE_MIB_TX_PKTS_128_255];
stats->tx_pkts_256_511 += mib[VGE_MIB_TX_PKTS_256_511];
stats->tx_pkts_512_1023 += mib[VGE_MIB_TX_PKTS_512_1023];
stats->tx_pkts_1024_1518 += mib[VGE_MIB_TX_PKTS_1024_1518];
stats->tx_jumbos += mib[VGE_MIB_TX_JUMBOS];
stats->tx_colls += mib[VGE_MIB_TX_COLLS];
stats->tx_pause += mib[VGE_MIB_TX_PAUSE];
#ifdef VGE_ENABLE_SQEERR
stats->tx_sqeerrs += mib[VGE_MIB_TX_SQEERRS];
#endif
stats->tx_latecolls += mib[VGE_MIB_TX_LATECOLLS];
/* Update counters in ifnet. */
ifp->if_opackets += mib[VGE_MIB_TX_GOOD_FRAMES];
ifp->if_collisions += mib[VGE_MIB_TX_COLLS] +
mib[VGE_MIB_TX_LATECOLLS];
ifp->if_oerrors += mib[VGE_MIB_TX_COLLS] +
mib[VGE_MIB_TX_LATECOLLS];
ifp->if_ipackets += mib[VGE_MIB_RX_GOOD_FRAMES];
ifp->if_ierrors += mib[VGE_MIB_RX_FIFO_OVERRUNS] +
mib[VGE_MIB_RX_RUNTS] +
mib[VGE_MIB_RX_RUNTS_ERRS] +
mib[VGE_MIB_RX_CRCERRS] +
mib[VGE_MIB_RX_ALIGNERRS] +
mib[VGE_MIB_RX_NOBUFS] +
mib[VGE_MIB_RX_SYMERRS] +
mib[VGE_MIB_RX_LENERRS];
}

View File

@ -301,7 +301,7 @@
VGE_ISR_RXOFLOW|VGE_ISR_PHYINT| \
VGE_ISR_LINKSTS|VGE_ISR_RXNODESC| \
VGE_ISR_RXDMA_STALL|VGE_ISR_TXDMA_STALL| \
VGE_ISR_MIBOFLOW|VGE_ISR_TIMER0)
VGE_ISR_TIMER0)
/* Interrupt mask register */
@ -543,6 +543,54 @@
#define VGE_TXBLOCK_128PKTS 0x08
#define VGE_TXBLOCK_8PKTS 0x0C
/* MIB control/status register */
#define VGE_MIBCSR_CLR 0x01
#define VGE_MIBCSR_RINI 0x02
#define VGE_MIBCSR_FLUSH 0x04
#define VGE_MIBCSR_FREEZE 0x08
#define VGE_MIBCSR_HI_80 0x00
#define VGE_MIBCSR_HI_C0 0x10
#define VGE_MIBCSR_BISTGO 0x40
#define VGE_MIBCSR_BISTOK 0x80
/* MIB data index. */
#define VGE_MIB_RX_FRAMES 0
#define VGE_MIB_RX_GOOD_FRAMES 1
#define VGE_MIB_TX_GOOD_FRAMES 2
#define VGE_MIB_RX_FIFO_OVERRUNS 3
#define VGE_MIB_RX_RUNTS 4
#define VGE_MIB_RX_RUNTS_ERRS 5
#define VGE_MIB_RX_PKTS_64 6
#define VGE_MIB_TX_PKTS_64 7
#define VGE_MIB_RX_PKTS_65_127 8
#define VGE_MIB_TX_PKTS_65_127 9
#define VGE_MIB_RX_PKTS_128_255 10
#define VGE_MIB_TX_PKTS_128_255 11
#define VGE_MIB_RX_PKTS_256_511 12
#define VGE_MIB_TX_PKTS_256_511 13
#define VGE_MIB_RX_PKTS_512_1023 14
#define VGE_MIB_TX_PKTS_512_1023 15
#define VGE_MIB_RX_PKTS_1024_1518 16
#define VGE_MIB_TX_PKTS_1024_1518 17
#define VGE_MIB_TX_COLLS 18
#define VGE_MIB_RX_CRCERRS 19
#define VGE_MIB_RX_JUMBOS 20
#define VGE_MIB_TX_JUMBOS 21
#define VGE_MIB_RX_PAUSE 22
#define VGE_MIB_TX_PAUSE 23
#define VGE_MIB_RX_ALIGNERRS 24
#define VGE_MIB_RX_PKTS_1519_MAX 25
#define VGE_MIB_RX_PKTS_1519_MAX_ERRS 26
#define VGE_MIB_TX_SQEERRS 27
#define VGE_MIB_RX_NOBUFS 28
#define VGE_MIB_RX_SYMERRS 29
#define VGE_MIB_RX_LENERRS 30
#define VGE_MIB_TX_LATECOLLS 31
#define VGE_MIB_CNT (VGE_MIB_TX_LATECOLLS - VGE_MIB_RX_FRAMES + 1)
#define VGE_MIB_DATA_MASK 0x00FFFFFF
#define VGE_MIB_DATA_IDX(x) ((x) >> 24)
/* EEPROM control/status register */
#define VGE_EECSR_EDO 0x01 /* data out pin */

View File

@ -130,6 +130,42 @@ struct vge_ring_data {
bus_addr_t vge_rx_ring_paddr;
};
struct vge_hw_stats {
uint32_t rx_frames;
uint32_t rx_good_frames;
uint32_t rx_fifo_oflows;
uint32_t rx_runts;
uint32_t rx_runts_errs;
uint32_t rx_pkts_64;
uint32_t rx_pkts_65_127;
uint32_t rx_pkts_128_255;
uint32_t rx_pkts_256_511;
uint32_t rx_pkts_512_1023;
uint32_t rx_pkts_1024_1518;
uint32_t rx_pkts_1519_max;
uint32_t rx_pkts_1519_max_errs;
uint32_t rx_jumbos;
uint32_t rx_crcerrs;
uint32_t rx_pause_frames;
uint32_t rx_alignerrs;
uint32_t rx_nobufs;
uint32_t rx_symerrs;
uint32_t rx_lenerrs;
uint32_t tx_good_frames;
uint32_t tx_pkts_64;
uint32_t tx_pkts_65_127;
uint32_t tx_pkts_128_255;
uint32_t tx_pkts_256_511;
uint32_t tx_pkts_512_1023;
uint32_t tx_pkts_1024_1518;
uint32_t tx_jumbos;
uint32_t tx_colls;
uint32_t tx_pause;
uint32_t tx_sqeerrs;
uint32_t tx_latecolls;
};
struct vge_softc {
struct ifnet *vge_ifp; /* interface info */
device_t vge_dev;
@ -152,6 +188,7 @@ struct vge_softc {
struct vge_chain_data vge_cdata;
struct vge_ring_data vge_rdata;
struct vge_hw_stats vge_stats;
int suspended; /* 0 = normal 1 = suspended */
};