aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ste
diff options
context:
space:
mode:
authorPyun YongHyeon <yongari@FreeBSD.org>2010-01-14 22:15:51 +0000
committerPyun YongHyeon <yongari@FreeBSD.org>2010-01-14 22:15:51 +0000
commit812b4b875dd5135500c12ebf7e579a4994e3fdb5 (patch)
treef9a4d91b54410be256a84ed905c797a3f84f257e /sys/dev/ste
parent0d9ae5891e7b706bf81dd6393dfe3c26cfabca55 (diff)
Notes
Diffstat (limited to 'sys/dev/ste')
-rw-r--r--sys/dev/ste/if_ste.c316
-rw-r--r--sys/dev/ste/if_stereg.h78
2 files changed, 266 insertions, 128 deletions
diff --git a/sys/dev/ste/if_ste.c b/sys/dev/ste/if_ste.c
index f25c9cf20fdc..8c8b121ff1da 100644
--- a/sys/dev/ste/if_ste.c
+++ b/sys/dev/ste/if_ste.c
@@ -103,7 +103,6 @@ static int ste_eeprom_wait(struct ste_softc *);
static int ste_encap(struct ste_softc *, struct mbuf **,
struct ste_chain *);
static int ste_ifmedia_upd(struct ifnet *);
-static void ste_ifmedia_upd_locked(struct ifnet *);
static void ste_ifmedia_sts(struct ifnet *, struct ifmediareq *);
static void ste_init(void *);
static void ste_init_locked(struct ste_softc *);
@@ -123,11 +122,13 @@ static int ste_read_eeprom(struct ste_softc *, caddr_t, int, int, int);
static void ste_reset(struct ste_softc *);
static void ste_restart_tx(struct ste_softc *);
static int ste_rxeof(struct ste_softc *, int);
-static void ste_setmulti(struct ste_softc *);
+static void ste_rxfilter(struct ste_softc *);
static void ste_start(struct ifnet *);
static void ste_start_locked(struct ifnet *);
+static void ste_stats_clear(struct ste_softc *);
static void ste_stats_update(struct ste_softc *);
static void ste_stop(struct ste_softc *);
+static void ste_sysctl_node(struct ste_softc *);
static void ste_tick(void *);
static void ste_txeoc(struct ste_softc *);
static void ste_txeof(struct ste_softc *);
@@ -449,31 +450,21 @@ static int
ste_ifmedia_upd(struct ifnet *ifp)
{
struct ste_softc *sc;
+ struct mii_data *mii;
+ struct mii_softc *miisc;
+ int error;
sc = ifp->if_softc;
STE_LOCK(sc);
- ste_ifmedia_upd_locked(ifp);
- STE_UNLOCK(sc);
-
- return (0);
-}
-
-static void
-ste_ifmedia_upd_locked(struct ifnet *ifp)
-{
- struct ste_softc *sc;
- struct mii_data *mii;
-
- sc = ifp->if_softc;
- STE_LOCK_ASSERT(sc);
mii = device_get_softc(sc->ste_miibus);
- sc->ste_flags &= ~STE_FLAG_LINK;
if (mii->mii_instance) {
- struct mii_softc *miisc;
LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
mii_phy_reset(miisc);
}
- mii_mediachg(mii);
+ error = mii_mediachg(mii);
+ STE_UNLOCK(sc);
+
+ return (error);
}
static void
@@ -486,6 +477,10 @@ ste_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
mii = device_get_softc(sc->ste_miibus);
STE_LOCK(sc);
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ STE_UNLOCK(sc);
+ return;
+ }
mii_pollstat(mii);
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
@@ -563,27 +558,33 @@ ste_read_eeprom(struct ste_softc *sc, caddr_t dest, int off, int cnt, int swap)
}
static void
-ste_setmulti(struct ste_softc *sc)
+ste_rxfilter(struct ste_softc *sc)
{
struct ifnet *ifp;
struct ifmultiaddr *ifma;
uint32_t hashes[2] = { 0, 0 };
+ uint8_t rxcfg;
int h;
+ STE_LOCK_ASSERT(sc);
+
ifp = sc->ste_ifp;
- if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
- STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_ALLMULTI);
- STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_MULTIHASH);
- return;
+ rxcfg = CSR_READ_1(sc, STE_RX_MODE);
+ rxcfg |= STE_RXMODE_UNICAST;
+ rxcfg &= ~(STE_RXMODE_ALLMULTI | STE_RXMODE_MULTIHASH |
+ STE_RXMODE_BROADCAST | STE_RXMODE_PROMISC);
+ if (ifp->if_flags & IFF_BROADCAST)
+ rxcfg |= STE_RXMODE_BROADCAST;
+ if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
+ if ((ifp->if_flags & IFF_ALLMULTI) != 0)
+ rxcfg |= STE_RXMODE_ALLMULTI;
+ if ((ifp->if_flags & IFF_PROMISC) != 0)
+ rxcfg |= STE_RXMODE_PROMISC;
+ goto chipit;
}
- /* first, zot all the existing hash bits */
- CSR_WRITE_2(sc, STE_MAR0, 0);
- CSR_WRITE_2(sc, STE_MAR1, 0);
- CSR_WRITE_2(sc, STE_MAR2, 0);
- CSR_WRITE_2(sc, STE_MAR3, 0);
-
- /* now program new ones */
+ rxcfg |= STE_RXMODE_MULTIHASH;
+ /* Now program new ones. */
if_maddr_rlock(ifp);
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
@@ -597,12 +598,13 @@ ste_setmulti(struct ste_softc *sc)
}
if_maddr_runlock(ifp);
+chipit:
CSR_WRITE_2(sc, STE_MAR0, hashes[0] & 0xFFFF);
CSR_WRITE_2(sc, STE_MAR1, (hashes[0] >> 16) & 0xFFFF);
CSR_WRITE_2(sc, STE_MAR2, hashes[1] & 0xFFFF);
CSR_WRITE_2(sc, STE_MAR3, (hashes[1] >> 16) & 0xFFFF);
- STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_ALLMULTI);
- STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_MULTIHASH);
+ CSR_WRITE_1(sc, STE_RX_MODE, rxcfg);
+ CSR_READ_1(sc, STE_RX_MODE);
}
#ifdef DEVICE_POLLING
@@ -643,8 +645,10 @@ ste_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
if (status & STE_ISR_STATS_OFLOW)
ste_stats_update(sc);
- if (status & STE_ISR_HOSTERR)
+ if (status & STE_ISR_HOSTERR) {
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
ste_init_locked(sc);
+ }
}
return (rx_npkts);
}
@@ -692,8 +696,10 @@ ste_intr(void *xsc)
if (status & STE_ISR_STATS_OFLOW)
ste_stats_update(sc);
- if (status & STE_ISR_HOSTERR)
+ if (status & STE_ISR_HOSTERR) {
ste_init_locked(sc);
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+ }
}
/* Re-enable interrupts */
@@ -832,6 +838,7 @@ ste_txeoc(struct ste_softc *sc)
STE_SETBIT4(sc, STE_DMACTL,
STE_DMACTL_TXDMA_STALL);
ste_wait(sc);
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
ste_init_locked(sc);
break;
}
@@ -870,6 +877,13 @@ ste_tick(void *arg)
*/
if ((sc->ste_flags & STE_FLAG_LINK) == 0)
ste_miibus_statchg(sc->ste_dev);
+ /*
+ * Because we are not generating Tx completion
+ * interrupt for every frame, reclaim transmitted
+ * buffers here.
+ */
+ ste_txeof(sc);
+ ste_txeoc(sc);
ste_stats_update(sc);
ste_watchdog(sc);
callout_reset(&sc->ste_callout, hz, ste_tick, sc);
@@ -918,16 +932,74 @@ ste_txeof(struct ste_softc *sc)
}
static void
+ste_stats_clear(struct ste_softc *sc)
+{
+
+ STE_LOCK_ASSERT(sc);
+
+ /* Rx stats. */
+ CSR_READ_2(sc, STE_STAT_RX_OCTETS_LO);
+ CSR_READ_2(sc, STE_STAT_RX_OCTETS_HI);
+ CSR_READ_2(sc, STE_STAT_RX_FRAMES);
+ CSR_READ_1(sc, STE_STAT_RX_BCAST);
+ CSR_READ_1(sc, STE_STAT_RX_MCAST);
+ CSR_READ_1(sc, STE_STAT_RX_LOST);
+ /* Tx stats. */
+ CSR_READ_2(sc, STE_STAT_TX_OCTETS_LO);
+ CSR_READ_2(sc, STE_STAT_TX_OCTETS_HI);
+ CSR_READ_2(sc, STE_STAT_TX_FRAMES);
+ CSR_READ_1(sc, STE_STAT_TX_BCAST);
+ CSR_READ_1(sc, STE_STAT_TX_MCAST);
+ CSR_READ_1(sc, STE_STAT_CARRIER_ERR);
+ CSR_READ_1(sc, STE_STAT_SINGLE_COLLS);
+ CSR_READ_1(sc, STE_STAT_MULTI_COLLS);
+ CSR_READ_1(sc, STE_STAT_LATE_COLLS);
+ CSR_READ_1(sc, STE_STAT_TX_DEFER);
+ CSR_READ_1(sc, STE_STAT_TX_EXDEFER);
+ CSR_READ_1(sc, STE_STAT_TX_ABORT);
+}
+
+static void
ste_stats_update(struct ste_softc *sc)
{
struct ifnet *ifp;
+ struct ste_hw_stats *stats;
+ uint32_t val;
STE_LOCK_ASSERT(sc);
ifp = sc->ste_ifp;
- ifp->if_collisions += CSR_READ_1(sc, STE_LATE_COLLS)
- + CSR_READ_1(sc, STE_MULTI_COLLS)
- + CSR_READ_1(sc, STE_SINGLE_COLLS);
+ stats = &sc->ste_stats;
+ /* Rx stats. */
+ val = (uint32_t)CSR_READ_2(sc, STE_STAT_RX_OCTETS_LO) |
+ ((uint32_t)CSR_READ_2(sc, STE_STAT_RX_OCTETS_HI)) << 16;
+ val &= 0x000FFFFF;
+ stats->rx_bytes += val;
+ stats->rx_frames += CSR_READ_2(sc, STE_STAT_RX_FRAMES);
+ stats->rx_bcast_frames += CSR_READ_1(sc, STE_STAT_RX_BCAST);
+ stats->rx_mcast_frames += CSR_READ_1(sc, STE_STAT_RX_MCAST);
+ stats->rx_lost_frames += CSR_READ_1(sc, STE_STAT_RX_LOST);
+ /* Tx stats. */
+ val = (uint32_t)CSR_READ_2(sc, STE_STAT_TX_OCTETS_LO) |
+ ((uint32_t)CSR_READ_2(sc, STE_STAT_TX_OCTETS_HI)) << 16;
+ val &= 0x000FFFFF;
+ stats->tx_bytes += val;
+ stats->tx_frames += CSR_READ_2(sc, STE_STAT_TX_FRAMES);
+ stats->tx_bcast_frames += CSR_READ_1(sc, STE_STAT_TX_BCAST);
+ stats->tx_mcast_frames += CSR_READ_1(sc, STE_STAT_TX_MCAST);
+ stats->tx_carrsense_errs += CSR_READ_1(sc, STE_STAT_CARRIER_ERR);
+ val = CSR_READ_1(sc, STE_STAT_SINGLE_COLLS);
+ stats->tx_single_colls += val;
+ ifp->if_collisions += val;
+ val = CSR_READ_1(sc, STE_STAT_MULTI_COLLS);
+ stats->tx_multi_colls += val;
+ ifp->if_collisions += val;
+ val += CSR_READ_1(sc, STE_STAT_LATE_COLLS);
+ stats->tx_late_colls += val;
+ ifp->if_collisions += val;
+ stats->tx_frames_defered += CSR_READ_1(sc, STE_STAT_TX_DEFER);
+ stats->tx_excess_defers += CSR_READ_1(sc, STE_STAT_TX_EXDEFER);
+ stats->tx_abort += CSR_READ_1(sc, STE_STAT_TX_ABORT);
}
/*
@@ -1027,6 +1099,7 @@ ste_attach(device_t dev)
error = ENXIO;;
goto fail;
}
+ ste_sysctl_node(sc);
if ((error = ste_dma_alloc(sc)) != 0)
goto fail;
@@ -1543,10 +1616,15 @@ static void
ste_init_locked(struct ste_softc *sc)
{
struct ifnet *ifp;
+ struct mii_data *mii;
int i;
STE_LOCK_ASSERT(sc);
ifp = sc->ste_ifp;
+ mii = device_get_softc(sc->ste_miibus);
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+ return;
ste_stop(sc);
/* Reset the chip to a known state. */
@@ -1582,24 +1660,11 @@ ste_init_locked(struct ste_softc *sc)
/* Set the TX reclaim threshold. */
CSR_WRITE_1(sc, STE_TX_RECLAIM_THRESH, (STE_PACKET_SIZE >> 4));
- /* Set up the RX filter. */
- CSR_WRITE_1(sc, STE_RX_MODE, STE_RXMODE_UNICAST);
-
- /* If we want promiscuous mode, set the allframes bit. */
- if (ifp->if_flags & IFF_PROMISC) {
- STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_PROMISC);
- } else {
- STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_PROMISC);
- }
-
- /* Set capture broadcast bit to accept broadcast frames. */
- if (ifp->if_flags & IFF_BROADCAST) {
- STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_BROADCAST);
- } else {
- STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_BROADCAST);
- }
+ /* Accept VLAN length packets */
+ CSR_WRITE_2(sc, STE_MAX_FRAMELEN, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
- ste_setmulti(sc);
+ /* Set up the RX filter. */
+ ste_rxfilter(sc);
/* Load the address of the RX list. */
STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
@@ -1628,6 +1693,8 @@ ste_init_locked(struct ste_softc *sc)
/* Enable stats counters. */
STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_STATS_ENABLE);
+ /* Clear stats counters. */
+ ste_stats_clear(sc);
CSR_WRITE_2(sc, STE_ISR, 0xFFFF);
#ifdef DEVICE_POLLING
@@ -1639,10 +1706,9 @@ ste_init_locked(struct ste_softc *sc)
/* Enable interrupts. */
CSR_WRITE_2(sc, STE_IMR, STE_INTRS);
- /* Accept VLAN length packets */
- CSR_WRITE_2(sc, STE_MAX_FRAMELEN, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
-
- ste_ifmedia_upd_locked(ifp);
+ sc->ste_flags &= ~STE_FLAG_LINK;
+ /* Switch to the current media. */
+ mii_mediachg(mii);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
@@ -1723,20 +1789,27 @@ ste_stop(struct ste_softc *sc)
static void
ste_reset(struct ste_softc *sc)
{
+ uint32_t ctl;
int i;
- STE_SETBIT4(sc, STE_ASICCTL,
- STE_ASICCTL_GLOBAL_RESET|STE_ASICCTL_RX_RESET|
- STE_ASICCTL_TX_RESET|STE_ASICCTL_DMA_RESET|
- STE_ASICCTL_FIFO_RESET|STE_ASICCTL_NETWORK_RESET|
- STE_ASICCTL_AUTOINIT_RESET|STE_ASICCTL_HOST_RESET|
- STE_ASICCTL_EXTRESET_RESET);
-
- DELAY(100000);
+ ctl = CSR_READ_4(sc, STE_ASICCTL);
+ ctl |= STE_ASICCTL_GLOBAL_RESET | STE_ASICCTL_RX_RESET |
+ STE_ASICCTL_TX_RESET | STE_ASICCTL_DMA_RESET |
+ STE_ASICCTL_FIFO_RESET | STE_ASICCTL_NETWORK_RESET |
+ STE_ASICCTL_AUTOINIT_RESET |STE_ASICCTL_HOST_RESET |
+ STE_ASICCTL_EXTRESET_RESET;
+ CSR_WRITE_4(sc, STE_ASICCTL, ctl);
+ CSR_READ_4(sc, STE_ASICCTL);
+ /*
+ * Due to the need of accessing EEPROM controller can take
+ * up to 1ms to complete the global reset.
+ */
+ DELAY(1000);
for (i = 0; i < STE_TIMEOUT; i++) {
if (!(CSR_READ_4(sc, STE_ASICCTL) & STE_ASICCTL_RESET_BUSY))
break;
+ DELAY(10);
}
if (i == STE_TIMEOUT)
@@ -1777,39 +1850,24 @@ ste_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
switch (command) {
case SIOCSIFFLAGS:
STE_LOCK(sc);
- if (ifp->if_flags & IFF_UP) {
- if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
- ifp->if_flags & IFF_PROMISC &&
- !(sc->ste_if_flags & IFF_PROMISC)) {
- STE_SETBIT1(sc, STE_RX_MODE,
- STE_RXMODE_PROMISC);
- } else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
- !(ifp->if_flags & IFF_PROMISC) &&
- sc->ste_if_flags & IFF_PROMISC) {
- STE_CLRBIT1(sc, STE_RX_MODE,
- STE_RXMODE_PROMISC);
- }
- if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
- (ifp->if_flags ^ sc->ste_if_flags) & IFF_ALLMULTI)
- ste_setmulti(sc);
- if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
- sc->ste_tx_thresh = STE_TXSTART_THRESH;
+ if ((ifp->if_flags & IFF_UP) != 0) {
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
+ ((ifp->if_flags ^ sc->ste_if_flags) &
+ (IFF_PROMISC | IFF_ALLMULTI)) != 0)
+ ste_rxfilter(sc);
+ else
ste_init_locked(sc);
- }
- } else {
- if (ifp->if_drv_flags & IFF_DRV_RUNNING)
- ste_stop(sc);
- }
+ } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+ ste_stop(sc);
sc->ste_if_flags = ifp->if_flags;
STE_UNLOCK(sc);
- error = 0;
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
STE_LOCK(sc);
- ste_setmulti(sc);
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+ ste_rxfilter(sc);
STE_UNLOCK(sc);
- error = 0;
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
@@ -1902,7 +1960,11 @@ ste_encap(struct ste_softc *sc, struct mbuf **m_head, struct ste_chain *txc)
* Tx descriptors here. Otherwise we race with controller.
*/
desc->ste_next = 0;
- desc->ste_ctl = htole32(STE_TXCTL_ALIGN_DIS | STE_TXCTL_DMAINTR);
+ if ((sc->ste_cdata.ste_tx_prod % STE_TX_INTR_FRAMES) == 0)
+ desc->ste_ctl = htole32(STE_TXCTL_ALIGN_DIS |
+ STE_TXCTL_DMAINTR);
+ else
+ desc->ste_ctl = htole32(STE_TXCTL_ALIGN_DIS);
txc->ste_mbuf = *m_head;
STE_INC(sc->ste_cdata.ste_tx_prod, STE_TX_LIST_CNT);
sc->ste_cdata.ste_tx_cnt++;
@@ -2005,6 +2067,7 @@ ste_watchdog(struct ste_softc *sc)
ste_txeof(sc);
ste_txeoc(sc);
ste_rxeof(sc, -1);
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
ste_init_locked(sc);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
@@ -2024,3 +2087,70 @@ ste_shutdown(device_t dev)
return (0);
}
+
+#define STE_SYSCTL_STAT_ADD32(c, h, n, p, d) \
+ SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
+#define STE_SYSCTL_STAT_ADD64(c, h, n, p, d) \
+ SYSCTL_ADD_QUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d)
+
+static void
+ste_sysctl_node(struct ste_softc *sc)
+{
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid_list *child, *parent;
+ struct sysctl_oid *tree;
+ struct ste_hw_stats *stats;
+
+ stats = &sc->ste_stats;
+ ctx = device_get_sysctl_ctx(sc->ste_dev);
+ child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ste_dev));
+
+ tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
+ NULL, "STE 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);
+ STE_SYSCTL_STAT_ADD64(ctx, child, "good_octets",
+ &stats->rx_bytes, "Good octets");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "good_frames",
+ &stats->rx_frames, "Good frames");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames",
+ &stats->rx_bcast_frames, "Good broadcast frames");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames",
+ &stats->rx_mcast_frames, "Good multicast frames");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "lost_frames",
+ &stats->rx_lost_frames, "Lost frames");
+
+ /* Tx statistics. */
+ tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
+ NULL, "Tx MAC statistics");
+ child = SYSCTL_CHILDREN(tree);
+ STE_SYSCTL_STAT_ADD64(ctx, child, "good_octets",
+ &stats->tx_bytes, "Good octets");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "good_frames",
+ &stats->tx_frames, "Good frames");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames",
+ &stats->tx_bcast_frames, "Good broadcast frames");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames",
+ &stats->tx_mcast_frames, "Good multicast frames");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "carrier_errs",
+ &stats->tx_carrsense_errs, "Carrier sense errors");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "single_colls",
+ &stats->tx_single_colls, "Single collisions");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "multi_colls",
+ &stats->tx_multi_colls, "Multiple collisions");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "late_colls",
+ &stats->tx_late_colls, "Late collisions");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "defers",
+ &stats->tx_frames_defered, "Frames with deferrals");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "excess_defers",
+ &stats->tx_excess_defers, "Frames with excessive derferrals");
+ STE_SYSCTL_STAT_ADD32(ctx, child, "abort",
+ &stats->tx_abort, "Aborted frames due to Excessive collisions");
+}
+
+#undef STE_SYSCTL_STAT_ADD32
+#undef STE_SYSCTL_STAT_ADD64
diff --git a/sys/dev/ste/if_stereg.h b/sys/dev/ste/if_stereg.h
index 4ec1920f4cf2..db0d2e7f92d1 100644
--- a/sys/dev/ste/if_stereg.h
+++ b/sys/dev/ste/if_stereg.h
@@ -63,6 +63,7 @@
#define STE_RX_DMABURST_THRESH 0x14
#define STE_RX_DMAURG_THRESH 0x15
#define STE_RX_DMAPOLL_PERIOD 0x16
+#define STE_COUNTDOWN 0x18
#define STE_DEBUGCTL 0x1A
#define STE_ASICCTL 0x30
#define STE_EEPROM_DATA 0x34
@@ -75,7 +76,6 @@
#define STE_WAKE_EVENT 0x45
#define STE_TX_STATUS 0x46
#define STE_TX_FRAMEID 0x47
-#define STE_COUNTDOWN 0x48
#define STE_ISR_ACK 0x4A
#define STE_IMR 0x4C
#define STE_ISR 0x4E
@@ -92,11 +92,25 @@
#define STE_MAR1 0x62
#define STE_MAR2 0x64
#define STE_MAR3 0x66
-#define STE_STATS 0x68
-#define STE_LATE_COLLS 0x75
-#define STE_MULTI_COLLS 0x76
-#define STE_SINGLE_COLLS 0x77
+#define STE_STAT_RX_OCTETS_LO 0x68
+#define STE_STAT_RX_OCTETS_HI 0x6A
+#define STE_STAT_TX_OCTETS_LO 0x6C
+#define STE_STAT_TX_OCTETS_HI 0x6E
+#define STE_STAT_TX_FRAMES 0x70
+#define STE_STAT_RX_FRAMES 0x72
+#define STE_STAT_CARRIER_ERR 0x74
+#define STE_STAT_LATE_COLLS 0x75
+#define STE_STAT_MULTI_COLLS 0x76
+#define STE_STAT_SINGLE_COLLS 0x77
+#define STE_STAT_TX_DEFER 0x78
+#define STE_STAT_RX_LOST 0x79
+#define STE_STAT_TX_EXDEFER 0x7A
+#define STE_STAT_TX_ABORT 0x7B
+#define STE_STAT_TX_BCAST 0x7C
+#define STE_STAT_RX_BCAST 0x7D
+#define STE_STAT_TX_MCAST 0x7E
+#define STE_STAT_RX_MCAST 0x7F
#define STE_DMACTL_RXDMA_STOPPED 0x00000001
#define STE_DMACTL_TXDMA_CMPREQ 0x00000002
@@ -199,18 +213,6 @@
#define STE_ASICCTL_SOFTINTR 0x02000000
#define STE_ASICCTL_RESET_BUSY 0x04000000
-#define STE_ASICCTL1_GLOBAL_RESET 0x0001
-#define STE_ASICCTL1_RX_RESET 0x0002
-#define STE_ASICCTL1_TX_RESET 0x0004
-#define STE_ASICCTL1_DMA_RESET 0x0008
-#define STE_ASICCTL1_FIFO_RESET 0x0010
-#define STE_ASICCTL1_NETWORK_RESET 0x0020
-#define STE_ASICCTL1_HOST_RESET 0x0040
-#define STE_ASICCTL1_AUTOINIT_RESET 0x0080
-#define STE_ASICCTL1_EXTRESET_RESET 0x0100
-#define STE_ASICCTL1_SOFTINTR 0x0200
-#define STE_ASICCTL1_RESET_BUSY 0x0400
-
#define STE_EECTL_ADDR 0x00FF
#define STE_EECTL_OPCODE 0x0300
#define STE_EECTL_BUSY 0x1000
@@ -388,24 +390,23 @@
#define STE_PME_EN 0x0010
#define STE_PME_STATUS 0x8000
-
-struct ste_stats {
- uint32_t ste_rx_bytes;
- uint32_t ste_tx_bytes;
- uint16_t ste_tx_frames;
- uint16_t ste_rx_frames;
- uint8_t ste_carrsense_errs;
- uint8_t ste_late_colls;
- uint8_t ste_multi_colls;
- uint8_t ste_single_colls;
- uint8_t ste_tx_frames_defered;
- uint8_t ste_rx_lost_frames;
- uint8_t ste_tx_excess_defers;
- uint8_t ste_tx_abort_excess_colls;
- uint8_t ste_tx_bcast_frames;
- uint8_t ste_rx_bcast_frames;
- uint8_t ste_tx_mcast_frames;
- uint8_t ste_rx_mcast_frames;
+struct ste_hw_stats {
+ uint64_t rx_bytes;
+ uint32_t rx_frames;
+ uint32_t rx_bcast_frames;
+ uint32_t rx_mcast_frames;
+ uint32_t rx_lost_frames;
+ uint64_t tx_bytes;
+ uint32_t tx_frames;
+ uint32_t tx_bcast_frames;
+ uint32_t tx_mcast_frames;
+ uint32_t tx_carrsense_errs;
+ uint32_t tx_single_colls;
+ uint32_t tx_multi_colls;
+ uint32_t tx_late_colls;
+ uint32_t tx_frames_defered;
+ uint32_t tx_excess_defers;
+ uint32_t tx_abort;
};
struct ste_frag {
@@ -493,6 +494,12 @@ struct ste_desc_onefrag {
#define STE_ADDR_LO(x) ((uint64_t)(x) & 0xFFFFFFFF)
#define STE_ADDR_HI(x) ((uint64_t)(x) >> 32)
+/*
+ * Since Tx status can hold up to 31 status bytes we should
+ * check Tx status before controller fills it up. Otherwise
+ * Tx MAC stalls.
+ */
+#define STE_TX_INTR_FRAMES 16
#define STE_TX_TIMEOUT 5
#define STE_TIMEOUT 1000
#define STE_MIN_FRAMELEN 60
@@ -566,6 +573,7 @@ struct ste_softc {
struct ste_list_data ste_ldata;
struct ste_chain_data ste_cdata;
struct callout ste_callout;
+ struct ste_hw_stats ste_stats;
struct mtx ste_mtx;
};