Add some missing fixes to alc(4) to sync with the latest FreeBSD and OpenBSD

alc(4)s.

Fix a long standing bug in MAC statistics register access. One
additional register was erroneously added in the MAC register set
such that 7 TX statistics counters were wrong. (from OpenBSD, if_alc.c 1.29)

Remove setting an initial assumed baudrate upon driver attach which is not
necessarily correct, there might not even be a link when attaching.
(from OpenBSD, if_alc.c 1.22)

Add some missing bus_dmamap_sync()'s and sync the others with
the FreeBSD code. (from OpenBSD, if_alc.c 1.21)

Help with the watchdog timeouts seen when unplugging the cable from
the alc(4) NIC while running or the NIC not working if the cable is
not plugged in upon boot up. (from OpenBSD, if_alc.c 1.16)

ok mrg@
This commit is contained in:
leot 2015-09-08 08:24:42 +00:00
parent 6639db6cc2
commit 5abfef80e1
2 changed files with 37 additions and 29 deletions

View File

@ -527,6 +527,9 @@ alc_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
struct alc_softc *sc = ifp->if_softc;
struct mii_data *mii = &sc->sc_miibus;
if ((ifp->if_flags & IFF_UP) == 0)
return;
mii_pollstat(mii);
ifmr->ifm_status = mii->mii_media_status;
ifmr->ifm_active = mii->mii_media_active;
@ -1405,7 +1408,6 @@ alc_attach(device_t parent, device_t self, void *aux)
ifp->if_start = alc_start;
ifp->if_stop = alc_stop;
ifp->if_watchdog = alc_watchdog;
ifp->if_baudrate = IF_Gbps(1);
IFQ_SET_MAXLEN(&ifp->if_snd, ALC_TX_RING_CNT - 1);
IFQ_SET_READY(&ifp->if_snd);
strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
@ -1959,6 +1961,10 @@ alc_start(struct ifnet *ifp)
if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
return;
if ((sc->alc_flags & ALC_FLAG_LINK) == 0)
return;
if (IFQ_IS_EMPTY(&ifp->if_snd))
return;
/* Reclaim transmitted frames. */
if (sc->alc_cdata.alc_tx_cnt >= ALC_TX_DESC_HIWAT)
@ -2021,9 +2027,7 @@ alc_watchdog(struct ifnet *ifp)
printf("%s: watchdog timeout\n", device_xname(sc->sc_dev));
ifp->if_oerrors++;
alc_init_backend(ifp, false);
if (!IFQ_IS_EMPTY(&ifp->if_snd))
alc_start(ifp);
alc_start(ifp);
}
static int
@ -2089,13 +2093,13 @@ alc_stats_clear(struct alc_softc *sc)
if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) {
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_smb_map, 0,
sc->alc_cdata.alc_smb_map->dm_mapsize,
BUS_DMASYNC_POSTREAD);
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
smb = sc->alc_rdata.alc_smb;
/* Update done, clear. */
smb->updated = 0;
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_smb_map, 0,
sc->alc_cdata.alc_smb_map->dm_mapsize,
BUS_DMASYNC_PREWRITE);
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
} else {
for (reg = &sb.rx_frames, i = 0; reg <= &sb.rx_pkts_filtered;
reg++) {
@ -2124,7 +2128,7 @@ alc_stats_update(struct alc_softc *sc)
if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) {
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_smb_map, 0,
sc->alc_cdata.alc_smb_map->dm_mapsize,
BUS_DMASYNC_POSTREAD);
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
smb = sc->alc_rdata.alc_smb;
if (smb->updated == 0)
return;
@ -2190,7 +2194,6 @@ alc_stats_update(struct alc_softc *sc)
stat->tx_multi_colls += smb->tx_multi_colls;
stat->tx_late_colls += smb->tx_late_colls;
stat->tx_excess_colls += smb->tx_excess_colls;
stat->tx_abort += smb->tx_abort;
stat->tx_underrun += smb->tx_underrun;
stat->tx_desc_underrun += smb->tx_desc_underrun;
stat->tx_lenerrs += smb->tx_lenerrs;
@ -2203,17 +2206,10 @@ alc_stats_update(struct alc_softc *sc)
ifp->if_collisions += smb->tx_single_colls +
smb->tx_multi_colls * 2 + smb->tx_late_colls +
smb->tx_abort * HDPX_CFG_RETRY_DEFAULT;
smb->tx_excess_colls * HDPX_CFG_RETRY_DEFAULT;
/*
* XXX
* tx_pkts_truncated counter looks suspicious. It constantly
* increments with no sign of Tx errors. This may indicate
* the counter name is not correct one so I've removed the
* counter in output errors.
*/
ifp->if_oerrors += smb->tx_abort + smb->tx_late_colls +
smb->tx_underrun;
ifp->if_oerrors += smb->tx_late_colls + smb->tx_excess_colls +
smb->tx_underrun + smb->tx_pkts_truncated;
ifp->if_ipackets += smb->rx_frames;
@ -2226,7 +2222,8 @@ alc_stats_update(struct alc_softc *sc)
/* Update done, clear. */
smb->updated = 0;
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_smb_map, 0,
sc->alc_cdata.alc_smb_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
sc->alc_cdata.alc_smb_map->dm_mapsize,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
}
@ -2318,6 +2315,8 @@ alc_txeof(struct alc_softc *sc)
txd = &sc->alc_cdata.alc_txdesc[cons];
if (txd->tx_m != NULL) {
/* Reclaim transmitted mbufs. */
bus_dmamap_sync(sc->sc_dmat, txd->tx_dmamap, 0,
txd->tx_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->sc_dmat, txd->tx_dmamap);
m_freem(txd->tx_m);
txd->tx_m = NULL;
@ -2326,7 +2325,7 @@ alc_txeof(struct alc_softc *sc)
if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0)
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_cmb_map, 0,
sc->alc_cdata.alc_cmb_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
sc->alc_cdata.alc_cmb_map->dm_mapsize, BUS_DMASYNC_PREREAD);
sc->alc_cdata.alc_tx_cons = cons;
/*
* Unarm watchdog timer only when there is no pending
@ -2381,6 +2380,8 @@ alc_newbuf(struct alc_softc *sc, struct alc_rxdesc *rxd, bool init)
map = rxd->rx_dmamap;
rxd->rx_dmamap = sc->alc_cdata.alc_rx_sparemap;
sc->alc_cdata.alc_rx_sparemap = map;
bus_dmamap_sync(sc->sc_dmat, rxd->rx_dmamap, 0, rxd->rx_dmamap->dm_mapsize,
BUS_DMASYNC_PREREAD);
rxd->rx_m = m;
rxd->rx_desc->addr = htole64(rxd->rx_dmamap->dm_segs[0].ds_addr);
return (0);
@ -2395,9 +2396,11 @@ alc_rxintr(struct alc_softc *sc)
int rr_cons, prog;
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_rr_ring_map, 0,
sc->alc_cdata.alc_rr_ring_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
sc->alc_cdata.alc_rr_ring_map->dm_mapsize,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_rx_ring_map, 0,
sc->alc_cdata.alc_rx_ring_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
sc->alc_cdata.alc_rx_ring_map->dm_mapsize,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
rr_cons = sc->alc_cdata.alc_rr_cons;
for (prog = 0; (ifp->if_flags & IFF_RUNNING) != 0;) {
rrd = &sc->alc_rdata.alc_rr_ring[rr_cons];
@ -2427,7 +2430,7 @@ alc_rxintr(struct alc_softc *sc)
/* Sync Rx return descriptors. */
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_rr_ring_map, 0,
sc->alc_cdata.alc_rr_ring_map->dm_mapsize,
BUS_DMASYNC_PREWRITE);
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
/*
* Sync updated Rx descriptors such that controller see
* modified buffer addresses.
@ -3153,6 +3156,8 @@ alc_stop(struct ifnet *ifp, int disable)
for (i = 0; i < ALC_RX_RING_CNT; i++) {
rxd = &sc->alc_cdata.alc_rxdesc[i];
if (rxd->rx_m != NULL) {
bus_dmamap_sync(sc->sc_dmat, rxd->rx_dmamap, 0,
rxd->rx_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->sc_dmat, rxd->rx_dmamap);
m_freem(rxd->rx_m);
rxd->rx_m = NULL;
@ -3161,6 +3166,8 @@ alc_stop(struct ifnet *ifp, int disable)
for (i = 0; i < ALC_TX_RING_CNT; i++) {
txd = &sc->alc_cdata.alc_txdesc[i];
if (txd->tx_m != NULL) {
bus_dmamap_sync(sc->sc_dmat, txd->tx_dmamap, 0,
txd->tx_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->sc_dmat, txd->tx_dmamap);
m_freem(txd->tx_m);
txd->tx_m = NULL;
@ -3319,7 +3326,8 @@ alc_init_rr_ring(struct alc_softc *sc)
rd = &sc->alc_rdata;
memset(rd->alc_rr_ring, 0, ALC_RR_RING_SZ);
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_rr_ring_map, 0,
sc->alc_cdata.alc_rr_ring_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
sc->alc_cdata.alc_rr_ring_map->dm_mapsize,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
static void
@ -3330,7 +3338,8 @@ alc_init_cmb(struct alc_softc *sc)
rd = &sc->alc_rdata;
memset(rd->alc_cmb, 0, ALC_CMB_SZ);
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_cmb_map, 0,
sc->alc_cdata.alc_cmb_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
sc->alc_cdata.alc_cmb_map->dm_mapsize,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
static void
@ -3341,7 +3350,8 @@ alc_init_smb(struct alc_softc *sc)
rd = &sc->alc_rdata;
memset(rd->alc_smb, 0, ALC_SMB_SZ);
bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_smb_map, 0,
sc->alc_cdata.alc_smb_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
sc->alc_cdata.alc_smb_map->dm_mapsize,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
static void

View File

@ -200,7 +200,7 @@
* alc(4) does not rely on Tx completion interrupts, so set it
* somewhat large value to reduce Tx completion interrupts.
*/
#define ALC_IM_TX_TIMER_DEFAULT 50000 /* 50ms */
#define ALC_IM_TX_TIMER_DEFAULT 1000 /* 1ms */
#define ALC_GPHY_CFG 0x140C /* 16 bits, 32 bits on AR816x */
#define GPHY_CFG_EXT_RESET 0x0001
@ -1147,7 +1147,6 @@ struct smb {
uint32_t tx_multi_colls;
uint32_t tx_late_colls;
uint32_t tx_excess_colls;
uint32_t tx_abort;
uint32_t tx_underrun;
uint32_t tx_desc_underrun;
uint32_t tx_lenerrs;
@ -1421,7 +1420,6 @@ struct alc_hw_stats {
uint32_t tx_multi_colls;
uint32_t tx_late_colls;
uint32_t tx_excess_colls;
uint32_t tx_abort;
uint32_t tx_underrun;
uint32_t tx_desc_underrun;
uint32_t tx_lenerrs;