diff --git a/sys/dev/ste/if_ste.c b/sys/dev/ste/if_ste.c index f25c9cf20fd..8c8b121ff1d 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); @@ -917,17 +931,75 @@ ste_txeof(struct ste_softc *sc) sc->ste_timer = 0; } +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)); + /* Accept VLAN length packets */ + CSR_WRITE_2(sc, STE_MAX_FRAMELEN, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN); + /* 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); - } - - ste_setmulti(sc); + 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 4ec1920f4cf..db0d2e7f92d 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; };