summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2008-12-04 02:16:53 +0000
committeryongari <yongari@FreeBSD.org>2008-12-04 02:16:53 +0000
commit153b44ab56e4c7bd7ae849aab8fa4723070bb637 (patch)
treed9ccffec741961154ecb1c477296af5042a9490b /sys
parent20e7552f469bcf3d64dae25b11f9c4a9ff38f69e (diff)
downloadFreeBSD-src-153b44ab56e4c7bd7ae849aab8fa4723070bb637.zip
FreeBSD-src-153b44ab56e4c7bd7ae849aab8fa4723070bb637.tar.gz
Add HW MAC counter support for newer JMC250/JMC260 revisions.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/jme/if_jme.c167
-rw-r--r--sys/dev/jme/if_jmereg.h39
-rw-r--r--sys/dev/jme/if_jmevar.h15
3 files changed, 197 insertions, 24 deletions
diff --git a/sys/dev/jme/if_jme.c b/sys/dev/jme/if_jme.c
index 300dfb7..8353b04 100644
--- a/sys/dev/jme/if_jme.c
+++ b/sys/dev/jme/if_jme.c
@@ -150,6 +150,9 @@ static void jme_init_ssb(struct jme_softc *);
static int jme_newbuf(struct jme_softc *, struct jme_rxdesc *);
static void jme_set_vlan(struct jme_softc *);
static void jme_set_filter(struct jme_softc *);
+static void jme_stats_clear(struct jme_softc *);
+static void jme_stats_save(struct jme_softc *);
+static void jme_stats_update(struct jme_softc *);
static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
static int sysctl_hw_jme_tx_coal_to(SYSCTL_HANDLER_ARGS);
static int sysctl_hw_jme_tx_coal_pkt(SYSCTL_HANDLER_ARGS);
@@ -656,6 +659,7 @@ jme_attach(device_t dev)
CHIPMODE_REVFM(sc->jme_chip_rev) == 2)
sc->jme_flags |= JME_FLAG_DMA32BIT;
sc->jme_flags |= JME_FLAG_TXCLK;
+ sc->jme_flags |= JME_FLAG_HWMIB;
}
/* Reset the ethernet controller. */
@@ -887,35 +891,41 @@ jme_detach(device_t dev)
return (0);
}
+#define JME_SYSCTL_STAT_ADD32(c, h, n, p, d) \
+ SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
+
static void
jme_sysctl_node(struct jme_softc *sc)
{
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid_list *child, *parent;
+ struct sysctl_oid *tree;
+ struct jme_hw_stats *stats;
int error;
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->jme_dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(sc->jme_dev)), OID_AUTO,
- "tx_coal_to", CTLTYPE_INT | CTLFLAG_RW, &sc->jme_tx_coal_to,
- 0, sysctl_hw_jme_tx_coal_to, "I", "jme tx coalescing timeout");
-
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->jme_dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(sc->jme_dev)), OID_AUTO,
- "tx_coal_pkt", CTLTYPE_INT | CTLFLAG_RW, &sc->jme_tx_coal_pkt,
- 0, sysctl_hw_jme_tx_coal_pkt, "I", "jme tx coalescing packet");
-
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->jme_dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(sc->jme_dev)), OID_AUTO,
- "rx_coal_to", CTLTYPE_INT | CTLFLAG_RW, &sc->jme_rx_coal_to,
- 0, sysctl_hw_jme_rx_coal_to, "I", "jme rx coalescing timeout");
-
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->jme_dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(sc->jme_dev)), OID_AUTO,
- "rx_coal_pkt", CTLTYPE_INT | CTLFLAG_RW, &sc->jme_rx_coal_pkt,
- 0, sysctl_hw_jme_rx_coal_pkt, "I", "jme rx coalescing packet");
-
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->jme_dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(sc->jme_dev)), OID_AUTO,
- "process_limit", CTLTYPE_INT | CTLFLAG_RW, &sc->jme_process_limit,
- 0, sysctl_hw_jme_proc_limit, "I",
+ stats = &sc->jme_stats;
+ ctx = device_get_sysctl_ctx(sc->jme_dev);
+ child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->jme_dev));
+
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_coal_to",
+ CTLTYPE_INT | CTLFLAG_RW, &sc->jme_tx_coal_to, 0,
+ sysctl_hw_jme_tx_coal_to, "I", "jme tx coalescing timeout");
+
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_coal_pkt",
+ CTLTYPE_INT | CTLFLAG_RW, &sc->jme_tx_coal_pkt, 0,
+ sysctl_hw_jme_tx_coal_pkt, "I", "jme tx coalescing packet");
+
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_coal_to",
+ CTLTYPE_INT | CTLFLAG_RW, &sc->jme_rx_coal_to, 0,
+ sysctl_hw_jme_rx_coal_to, "I", "jme rx coalescing timeout");
+
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_coal_pkt",
+ CTLTYPE_INT | CTLFLAG_RW, &sc->jme_rx_coal_pkt, 0,
+ sysctl_hw_jme_rx_coal_pkt, "I", "jme rx coalescing packet");
+
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "process_limit",
+ CTLTYPE_INT | CTLFLAG_RW, &sc->jme_process_limit, 0,
+ sysctl_hw_jme_proc_limit, "I",
"max number of Rx events to process");
/* Pull in device tunables. */
@@ -984,8 +994,43 @@ jme_sysctl_node(struct jme_softc *sc)
sc->jme_rx_coal_pkt = PCCRX_COAL_PKT_DEFAULT;
}
}
+
+ if ((sc->jme_flags & JME_FLAG_HWMIB) == 0)
+ return;
+
+ tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
+ NULL, "JME 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);
+ JME_SYSCTL_STAT_ADD32(ctx, child, "good_frames",
+ &stats->rx_good_frames, "Good frames");
+ JME_SYSCTL_STAT_ADD32(ctx, child, "crc_errs",
+ &stats->rx_crc_errs, "CRC errors");
+ JME_SYSCTL_STAT_ADD32(ctx, child, "mii_errs",
+ &stats->rx_mii_errs, "MII errors");
+ JME_SYSCTL_STAT_ADD32(ctx, child, "fifo_oflows",
+ &stats->rx_fifo_oflows, "FIFO overflows");
+ JME_SYSCTL_STAT_ADD32(ctx, child, "desc_empty",
+ &stats->rx_desc_empty, "Descriptor empty");
+ JME_SYSCTL_STAT_ADD32(ctx, child, "bad_frames",
+ &stats->rx_bad_frames, "Bad frames");
+
+ /* Tx statistics. */
+ tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
+ NULL, "Tx MAC statistics");
+ child = SYSCTL_CHILDREN(tree);
+ JME_SYSCTL_STAT_ADD32(ctx, child, "good_frames",
+ &stats->tx_good_frames, "Good frames");
+ JME_SYSCTL_STAT_ADD32(ctx, child, "bad_frames",
+ &stats->tx_bad_frames, "Bad frames");
}
+#undef JME_SYSCTL_STAT_ADD32
+
struct jme_dmamap_arg {
bus_addr_t jme_busaddr;
};
@@ -2164,6 +2209,7 @@ jme_link_task(void *arg, int pending)
/* Program MAC with resolved speed/duplex/flow-control. */
if ((sc->jme_flags & JME_FLAG_LINK) != 0) {
jme_mac_config(sc);
+ jme_stats_clear(sc);
CSR_WRITE_4(sc, JME_RXCSR, sc->jme_rxcsr);
CSR_WRITE_4(sc, JME_TXCSR, sc->jme_txcsr);
@@ -2553,6 +2599,7 @@ jme_tick(void *arg)
* faster and limit the maximum delay to a hz.
*/
jme_txeof(sc);
+ jme_stats_update(sc);
jme_watchdog(sc);
callout_reset(&sc->jme_tick_ch, hz, jme_tick, sc);
}
@@ -2862,6 +2909,8 @@ jme_stop(struct jme_softc *sc)
txd->tx_ndesc = 0;
}
}
+ jme_stats_update(sc);
+ jme_stats_save(sc);
}
static void
@@ -3093,6 +3142,76 @@ jme_set_filter(struct jme_softc *sc)
CSR_WRITE_4(sc, JME_RXMAC, rxcfg);
}
+static void
+jme_stats_clear(struct jme_softc *sc)
+{
+
+ JME_LOCK_ASSERT(sc);
+
+ if ((sc->jme_flags & JME_FLAG_HWMIB) == 0)
+ return;
+
+ /* Disable and clear counters. */
+ CSR_WRITE_4(sc, JME_STATCSR, 0xFFFFFFFF);
+ /* Activate hw counters. */
+ CSR_WRITE_4(sc, JME_STATCSR, 0);
+ CSR_READ_4(sc, JME_STATCSR);
+ bzero(&sc->jme_stats, sizeof(struct jme_hw_stats));
+}
+
+static void
+jme_stats_save(struct jme_softc *sc)
+{
+
+ JME_LOCK_ASSERT(sc);
+
+ if ((sc->jme_flags & JME_FLAG_HWMIB) == 0)
+ return;
+ /* Save current counters. */
+ bcopy(&sc->jme_stats, &sc->jme_ostats, sizeof(struct jme_hw_stats));
+ /* Disable and clear counters. */
+ CSR_WRITE_4(sc, JME_STATCSR, 0xFFFFFFFF);
+}
+
+static void
+jme_stats_update(struct jme_softc *sc)
+{
+ struct jme_hw_stats *stat, *ostat;
+ uint32_t reg;
+
+ JME_LOCK_ASSERT(sc);
+
+ if ((sc->jme_flags & JME_FLAG_HWMIB) == 0)
+ return;
+ stat = &sc->jme_stats;
+ ostat = &sc->jme_ostats;
+ stat->tx_good_frames = CSR_READ_4(sc, JME_STAT_TXGOOD);
+ stat->rx_good_frames = CSR_READ_4(sc, JME_STAT_RXGOOD);
+ reg = CSR_READ_4(sc, JME_STAT_CRCMII);
+ stat->rx_crc_errs = (reg & STAT_RX_CRC_ERR_MASK) >>
+ STAT_RX_CRC_ERR_SHIFT;
+ stat->rx_mii_errs = (reg & STAT_RX_MII_ERR_MASK) >>
+ STAT_RX_MII_ERR_SHIFT;
+ reg = CSR_READ_4(sc, JME_STAT_RXERR);
+ stat->rx_fifo_oflows = (reg & STAT_RXERR_OFLOW_MASK) >>
+ STAT_RXERR_OFLOW_SHIFT;
+ stat->rx_desc_empty = (reg & STAT_RXERR_MPTY_MASK) >>
+ STAT_RXERR_MPTY_SHIFT;
+ reg = CSR_READ_4(sc, JME_STAT_FAIL);
+ stat->rx_bad_frames = (reg & STAT_FAIL_RX_MASK) >> STAT_FAIL_RX_SHIFT;
+ stat->tx_bad_frames = (reg & STAT_FAIL_TX_MASK) >> STAT_FAIL_TX_SHIFT;
+
+ /* Account for previous counters. */
+ stat->rx_good_frames += ostat->rx_good_frames;
+ stat->rx_crc_errs += ostat->rx_crc_errs;
+ stat->rx_mii_errs += ostat->rx_mii_errs;
+ stat->rx_fifo_oflows += ostat->rx_fifo_oflows;
+ stat->rx_desc_empty += ostat->rx_desc_empty;
+ stat->rx_bad_frames += ostat->rx_bad_frames;
+ stat->tx_good_frames += ostat->tx_good_frames;
+ stat->tx_bad_frames += ostat->tx_bad_frames;
+}
+
static int
sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
{
diff --git a/sys/dev/jme/if_jmereg.h b/sys/dev/jme/if_jmereg.h
index 8465355..482c65f 100644
--- a/sys/dev/jme/if_jmereg.h
+++ b/sys/dev/jme/if_jmereg.h
@@ -199,6 +199,7 @@
#define TXMAC_IFG2_DEFAULT 0x40000000
#define TXMAC_IFG1_MASK 0x30000000
#define TXMAC_IFG1_DEFAULT 0x20000000
+#define TXMAC_PAUSE_CNT_MASK 0x00FF0000
#define TXMAC_THRESH_1_PKT 0x00000300
#define TXMAC_THRESH_1_2_PKT 0x00000200
#define TXMAC_THRESH_1_4_PKT 0x00000100
@@ -403,6 +404,44 @@
#define PMCS_MAGIC_FRAME_ENB 0x00000001
#define PMCS_WOL_ENB_MASK 0x0000FFFF
+/*
+ * Statistic registers control and status.
+ * These statistics registers are valid only for JMC250/JMC260 REVFM >= 2.
+ */
+#define JME_STATCSR 0x0064
+#define STATCSR_RXMPT_DIS 0x00000080
+#define STATCSR_OFLOW_DIS 0x00000040
+#define STATCSR_MIIRXER_DIS 0x00000020
+#define STATCSR_CRCERR_DIS 0x00000010
+#define STATCSR_RXBAD_DIS 0x00000008
+#define STATCSR_RXGOOD_DIS 0x00000004
+#define STATCSR_TXBAD_DIS 0x00000002
+#define STATCSR_TXGOOD_DIS 0x00000001
+
+#define JME_STAT_TXGOOD 0x0068
+
+#define JME_STAT_RXGOOD 0x006C
+
+#define JME_STAT_CRCMII 0x0070
+#define STAT_RX_CRC_ERR_MASK 0xFFFF0000
+#define STAT_RX_MII_ERR_MASK 0x0000FFFF
+#define STAT_RX_CRC_ERR_SHIFT 16
+#define STAT_RX_MII_ERR_SHIFT 0
+
+#define JME_STAT_RXERR 0x0074
+#define STAT_RXERR_OFLOW_MASK 0xFFFF0000
+#define STAT_RXERR_MPTY_MASK 0x0000FFFF
+#define STAT_RXERR_OFLOW_SHIFT 16
+#define STAT_RXERR_MPTY_SHIFT 0
+
+#define JME_STAT_RESERVED1 0x0078
+
+#define JME_STAT_FAIL 0x007C
+#define STAT_FAIL_RX_MASK 0xFFFF0000
+#define STAT_FAIL_TX_MASK 0x0000FFFF
+#define STAT_FAIL_RX_SHIFT 16
+#define STAT_FAIL_TX_SHIFT 0
+
/* Giga PHY & EEPROM registers. */
#define JME_PHY_EEPROM_BASE_ADDR 0x0400
diff --git a/sys/dev/jme/if_jmevar.h b/sys/dev/jme/if_jmevar.h
index 3575dc1..e73e7ba 100644
--- a/sys/dev/jme/if_jmevar.h
+++ b/sys/dev/jme/if_jmevar.h
@@ -154,6 +154,18 @@ struct jme_ring_data {
(sizeof(struct jme_desc) * JME_RX_RING_CNT)
#define JME_SSB_SIZE sizeof(struct jme_ssb)
+/* Statistics counters. */
+struct jme_hw_stats {
+ uint32_t rx_good_frames;
+ uint32_t rx_crc_errs;
+ uint32_t rx_mii_errs;
+ uint32_t rx_fifo_oflows;
+ uint32_t rx_desc_empty;
+ uint32_t rx_bad_frames;
+ uint32_t tx_good_frames;
+ uint32_t tx_bad_frames;
+};
+
/*
* Software state per device.
*/
@@ -183,9 +195,12 @@ struct jme_softc {
#define JME_FLAG_NOJUMBO 0x0080
#define JME_FLAG_TXCLK 0x0100
#define JME_FLAG_DMA32BIT 0x0200
+#define JME_FLAG_HWMIB 0x0400
#define JME_FLAG_DETACH 0x4000
#define JME_FLAG_LINK 0x8000
+ struct jme_hw_stats jme_ostats;
+ struct jme_hw_stats jme_stats;
struct callout jme_tick_ch;
struct jme_chain_data jme_cdata;
struct jme_ring_data jme_rdata;
OpenPOWER on IntegriCloud