Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/et/if_et.c
Show First 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | |||||
static int et_resume(device_t); | static int et_resume(device_t); | ||||
static int et_miibus_readreg(device_t, int, int); | static int et_miibus_readreg(device_t, int, int); | ||||
static int et_miibus_writereg(device_t, int, int, int); | static int et_miibus_writereg(device_t, int, int, int); | ||||
static void et_miibus_statchg(device_t); | static void et_miibus_statchg(device_t); | ||||
static void et_init_locked(struct et_softc *); | static void et_init_locked(struct et_softc *); | ||||
static void et_init(void *); | static void et_init(void *); | ||||
static int et_ioctl(struct ifnet *, u_long, caddr_t); | static int et_ioctl(if_t, u_long, caddr_t); | ||||
static void et_start_locked(struct ifnet *); | static void et_start_locked(if_t); | ||||
static void et_start(struct ifnet *); | static void et_start(if_t); | ||||
static int et_watchdog(struct et_softc *); | static int et_watchdog(struct et_softc *); | ||||
static int et_ifmedia_upd_locked(struct ifnet *); | static int et_ifmedia_upd_locked(if_t); | ||||
static int et_ifmedia_upd(struct ifnet *); | static int et_ifmedia_upd(if_t); | ||||
static void et_ifmedia_sts(struct ifnet *, struct ifmediareq *); | static void et_ifmedia_sts(if_t, struct ifmediareq *); | ||||
static uint64_t et_get_counter(struct ifnet *, ift_counter); | static uint64_t et_get_counter(if_t, ift_counter); | ||||
static void et_add_sysctls(struct et_softc *); | static void et_add_sysctls(struct et_softc *); | ||||
static int et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS); | static int et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS); | ||||
static int et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS); | static int et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS); | ||||
static void et_intr(void *); | static void et_intr(void *); | ||||
static void et_rxeof(struct et_softc *); | static void et_rxeof(struct et_softc *); | ||||
static void et_txeof(struct et_softc *); | static void et_txeof(struct et_softc *); | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | et_probe(device_t dev) | ||||
} | } | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
static int | static int | ||||
et_attach(device_t dev) | et_attach(device_t dev) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
uint8_t eaddr[ETHER_ADDR_LEN]; | uint8_t eaddr[ETHER_ADDR_LEN]; | ||||
uint32_t pmcfg; | uint32_t pmcfg; | ||||
int cap, error, msic; | int cap, error, msic; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->dev = dev; | sc->dev = dev; | ||||
mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, | mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, | ||||
MTX_DEF); | MTX_DEF); | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | et_attach(device_t dev) | ||||
CSR_WRITE_4(sc, ET_PM, pmcfg); | CSR_WRITE_4(sc, ET_PM, pmcfg); | ||||
et_reset(sc); | et_reset(sc); | ||||
error = et_dma_alloc(sc); | error = et_dma_alloc(sc); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
ifp->if_softc = sc; | if_setsoftc(ifp, sc); | ||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | ||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); | ||||
ifp->if_init = et_init; | if_setinitfn(ifp, et_init); | ||||
ifp->if_ioctl = et_ioctl; | if_setioctlfn(ifp, et_ioctl); | ||||
ifp->if_start = et_start; | if_setstartfn(ifp, et_start); | ||||
ifp->if_get_counter = et_get_counter; | if_setgetcounterfn(ifp, et_get_counter); | ||||
ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_VLAN_MTU; | if_setcapabilities(ifp, IFCAP_TXCSUM | IFCAP_VLAN_MTU); | ||||
ifp->if_capenable = ifp->if_capabilities; | if_setcapenable(ifp, if_getcapabilities(ifp)); | ||||
ifp->if_snd.ifq_drv_maxlen = ET_TX_NDESC - 1; | if_setsendqlen(ifp, ET_TX_NDESC - 1); | ||||
IFQ_SET_MAXLEN(&ifp->if_snd, ET_TX_NDESC - 1); | if_setsendqready(ifp); | ||||
IFQ_SET_READY(&ifp->if_snd); | |||||
et_chip_attach(sc); | et_chip_attach(sc); | ||||
error = mii_attach(dev, &sc->sc_miibus, ifp, et_ifmedia_upd, | error = mii_attach(dev, &sc->sc_miibus, ifp, et_ifmedia_upd, | ||||
et_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, | et_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, | ||||
MIIF_DOPAUSE); | MIIF_DOPAUSE); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "attaching PHYs failed\n"); | device_printf(dev, "attaching PHYs failed\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
ether_ifattach(ifp, eaddr); | ether_ifattach(ifp, eaddr); | ||||
/* Tell the upper layer(s) we support long frames. */ | /* Tell the upper layer(s) we support long frames. */ | ||||
ifp->if_hdrlen = sizeof(struct ether_vlan_header); | if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); | ||||
error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_NET | INTR_MPSAFE, | error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_NET | INTR_MPSAFE, | ||||
NULL, et_intr, sc, &sc->sc_irq_handle); | NULL, et_intr, sc, &sc->sc_irq_handle); | ||||
if (error) { | if (error) { | ||||
ether_ifdetach(ifp); | ether_ifdetach(ifp); | ||||
device_printf(dev, "can't setup intr\n"); | device_printf(dev, "can't setup intr\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | #undef NRETRY | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
et_miibus_statchg(device_t dev) | et_miibus_statchg(device_t dev) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
uint32_t cfg1, cfg2, ctrl; | uint32_t cfg1, cfg2, ctrl; | ||||
int i; | int i; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
mii = device_get_softc(sc->sc_miibus); | mii = device_get_softc(sc->sc_miibus); | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
if (mii == NULL || ifp == NULL || | if (mii == NULL || ifp == NULL || | ||||
(ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | (if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) | ||||
return; | return; | ||||
sc->sc_flags &= ~ET_FLAG_LINK; | sc->sc_flags &= ~ET_FLAG_LINK; | ||||
if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | ||||
(IFM_ACTIVE | IFM_AVALID)) { | (IFM_ACTIVE | IFM_AVALID)) { | ||||
switch (IFM_SUBTYPE(mii->mii_media_active)) { | switch (IFM_SUBTYPE(mii->mii_media_active)) { | ||||
case IFM_10_T: | case IFM_10_T: | ||||
case IFM_100_TX: | case IFM_100_TX: | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | #define NRETRY 50 | ||||
if (i == NRETRY) | if (i == NRETRY) | ||||
if_printf(ifp, "can't enable RX/TX\n"); | if_printf(ifp, "can't enable RX/TX\n"); | ||||
sc->sc_flags |= ET_FLAG_TXRX_ENABLED; | sc->sc_flags |= ET_FLAG_TXRX_ENABLED; | ||||
#undef NRETRY | #undef NRETRY | ||||
} | } | ||||
static int | static int | ||||
et_ifmedia_upd_locked(struct ifnet *ifp) | et_ifmedia_upd_locked(if_t ifp) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
struct mii_softc *miisc; | struct mii_softc *miisc; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
mii = device_get_softc(sc->sc_miibus); | mii = device_get_softc(sc->sc_miibus); | ||||
LIST_FOREACH(miisc, &mii->mii_phys, mii_list) | LIST_FOREACH(miisc, &mii->mii_phys, mii_list) | ||||
PHY_RESET(miisc); | PHY_RESET(miisc); | ||||
return (mii_mediachg(mii)); | return (mii_mediachg(mii)); | ||||
} | } | ||||
static int | static int | ||||
et_ifmedia_upd(struct ifnet *ifp) | et_ifmedia_upd(if_t ifp) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
int res; | int res; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
res = et_ifmedia_upd_locked(ifp); | res = et_ifmedia_upd_locked(ifp); | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
return (res); | return (res); | ||||
} | } | ||||
static void | static void | ||||
et_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) | et_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
if ((ifp->if_flags & IFF_UP) == 0) { | if ((if_getflags(ifp) & IFF_UP) == 0) { | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
mii = device_get_softc(sc->sc_miibus); | mii = device_get_softc(sc->sc_miibus); | ||||
mii_pollstat(mii); | mii_pollstat(mii); | ||||
ifmr->ifm_active = mii->mii_media_active; | ifmr->ifm_active = mii->mii_media_active; | ||||
ifmr->ifm_status = mii->mii_media_status; | ifmr->ifm_status = mii->mii_media_status; | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
et_stop(struct et_softc *sc) | et_stop(struct et_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
ET_LOCK_ASSERT(sc); | ET_LOCK_ASSERT(sc); | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
callout_stop(&sc->sc_tick); | callout_stop(&sc->sc_tick); | ||||
/* Disable interrupts. */ | /* Disable interrupts. */ | ||||
CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); | CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); | ||||
CSR_WRITE_4(sc, ET_MAC_CFG1, CSR_READ_4(sc, ET_MAC_CFG1) & ~( | CSR_WRITE_4(sc, ET_MAC_CFG1, CSR_READ_4(sc, ET_MAC_CFG1) & ~( | ||||
ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN)); | ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN)); | ||||
DELAY(100); | DELAY(100); | ||||
et_stop_rxdma(sc); | et_stop_rxdma(sc); | ||||
et_stop_txdma(sc); | et_stop_txdma(sc); | ||||
et_stats_update(sc); | et_stats_update(sc); | ||||
et_free_tx_ring(sc); | et_free_tx_ring(sc); | ||||
et_free_rx_ring(sc); | et_free_rx_ring(sc); | ||||
sc->sc_tx = 0; | sc->sc_tx = 0; | ||||
sc->sc_tx_intr = 0; | sc->sc_tx_intr = 0; | ||||
sc->sc_flags &= ~ET_FLAG_TXRX_ENABLED; | sc->sc_flags &= ~ET_FLAG_TXRX_ENABLED; | ||||
sc->watchdog_timer = 0; | sc->watchdog_timer = 0; | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); | ||||
} | } | ||||
static int | static int | ||||
et_bus_config(struct et_softc *sc) | et_bus_config(struct et_softc *sc) | ||||
{ | { | ||||
uint32_t val, max_plsz; | uint32_t val, max_plsz; | ||||
uint16_t ack_latency, replay_timer; | uint16_t ack_latency, replay_timer; | ||||
▲ Show 20 Lines • Show All 485 Lines • ▼ Show 20 Lines | et_chip_attach(struct et_softc *sc) | ||||
/* Enable memory controllers */ | /* Enable memory controllers */ | ||||
CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); | CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); | ||||
} | } | ||||
static void | static void | ||||
et_intr(void *xsc) | et_intr(void *xsc) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
uint32_t status; | uint32_t status; | ||||
sc = xsc; | sc = xsc; | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) | ||||
goto done; | goto done; | ||||
status = CSR_READ_4(sc, ET_INTR_STATUS); | status = CSR_READ_4(sc, ET_INTR_STATUS); | ||||
if ((status & ET_INTRS) == 0) | if ((status & ET_INTRS) == 0) | ||||
goto done; | goto done; | ||||
/* Disable further interrupts. */ | /* Disable further interrupts. */ | ||||
CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); | CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); | ||||
if (status & (ET_INTR_RXDMA_ERROR | ET_INTR_TXDMA_ERROR)) { | if (status & (ET_INTR_RXDMA_ERROR | ET_INTR_TXDMA_ERROR)) { | ||||
device_printf(sc->dev, "DMA error(0x%08x) -- resetting\n", | device_printf(sc->dev, "DMA error(0x%08x) -- resetting\n", | ||||
status); | status); | ||||
ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); | ||||
et_init_locked(sc); | et_init_locked(sc); | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
if (status & ET_INTR_RXDMA) | if (status & ET_INTR_RXDMA) | ||||
et_rxeof(sc); | et_rxeof(sc); | ||||
if (status & (ET_INTR_TXDMA | ET_INTR_TIMER)) | if (status & (ET_INTR_TXDMA | ET_INTR_TIMER)) | ||||
et_txeof(sc); | et_txeof(sc); | ||||
if (status & ET_INTR_TIMER) | if (status & ET_INTR_TIMER) | ||||
CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); | CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { | ||||
CSR_WRITE_4(sc, ET_INTR_MASK, ~ET_INTRS); | CSR_WRITE_4(sc, ET_INTR_MASK, ~ET_INTRS); | ||||
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) | if (!if_sendq_empty(ifp)) | ||||
et_start_locked(ifp); | et_start_locked(ifp); | ||||
} | } | ||||
done: | done: | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
et_init_locked(struct et_softc *sc) | et_init_locked(struct et_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
int error; | int error; | ||||
ET_LOCK_ASSERT(sc); | ET_LOCK_ASSERT(sc); | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) | ||||
return; | return; | ||||
et_stop(sc); | et_stop(sc); | ||||
et_reset(sc); | et_reset(sc); | ||||
et_init_tx_ring(sc); | et_init_tx_ring(sc); | ||||
error = et_init_rx_ring(sc); | error = et_init_rx_ring(sc); | ||||
if (error) | if (error) | ||||
Show All 14 Lines | et_init_locked(struct et_softc *sc) | ||||
if (error) | if (error) | ||||
return; | return; | ||||
/* Enable interrupts. */ | /* Enable interrupts. */ | ||||
CSR_WRITE_4(sc, ET_INTR_MASK, ~ET_INTRS); | CSR_WRITE_4(sc, ET_INTR_MASK, ~ET_INTRS); | ||||
CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); | CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); | ||||
sc->sc_flags &= ~ET_FLAG_LINK; | sc->sc_flags &= ~ET_FLAG_LINK; | ||||
et_ifmedia_upd_locked(ifp); | et_ifmedia_upd_locked(ifp); | ||||
callout_reset(&sc->sc_tick, hz, et_tick, sc); | callout_reset(&sc->sc_tick, hz, et_tick, sc); | ||||
fail: | fail: | ||||
if (error) | if (error) | ||||
et_stop(sc); | et_stop(sc); | ||||
} | } | ||||
static void | static void | ||||
et_init(void *xsc) | et_init(void *xsc) | ||||
{ | { | ||||
struct et_softc *sc = xsc; | struct et_softc *sc = xsc; | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
et_init_locked(sc); | et_init_locked(sc); | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
} | } | ||||
static int | static int | ||||
et_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | et_ioctl(if_t ifp, u_long cmd, caddr_t data) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
struct ifreq *ifr; | struct ifreq *ifr; | ||||
int error, mask, max_framelen; | int error, mask, max_framelen; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
ifr = (struct ifreq *)data; | ifr = (struct ifreq *)data; | ||||
error = 0; | error = 0; | ||||
/* XXX LOCKSUSED */ | /* XXX LOCKSUSED */ | ||||
switch (cmd) { | switch (cmd) { | ||||
case SIOCSIFFLAGS: | case SIOCSIFFLAGS: | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
if (ifp->if_flags & IFF_UP) { | if (if_getflags(ifp) & IFF_UP) { | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { | ||||
if ((ifp->if_flags ^ sc->sc_if_flags) & | if ((if_getflags(ifp) ^ sc->sc_if_flags) & | ||||
(IFF_ALLMULTI | IFF_PROMISC | IFF_BROADCAST)) | (IFF_ALLMULTI | IFF_PROMISC | IFF_BROADCAST)) | ||||
et_setmulti(sc); | et_setmulti(sc); | ||||
} else { | } else { | ||||
et_init_locked(sc); | et_init_locked(sc); | ||||
} | } | ||||
} else { | } else { | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) | ||||
et_stop(sc); | et_stop(sc); | ||||
} | } | ||||
sc->sc_if_flags = ifp->if_flags; | sc->sc_if_flags = if_getflags(ifp); | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
break; | break; | ||||
case SIOCSIFMEDIA: | case SIOCSIFMEDIA: | ||||
case SIOCGIFMEDIA: | case SIOCGIFMEDIA: | ||||
mii = device_get_softc(sc->sc_miibus); | mii = device_get_softc(sc->sc_miibus); | ||||
error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); | error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); | ||||
break; | break; | ||||
case SIOCADDMULTI: | case SIOCADDMULTI: | ||||
case SIOCDELMULTI: | case SIOCDELMULTI: | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
et_setmulti(sc); | et_setmulti(sc); | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
} | } | ||||
break; | break; | ||||
case SIOCSIFMTU: | case SIOCSIFMTU: | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
#if 0 | #if 0 | ||||
if (sc->sc_flags & ET_FLAG_JUMBO) | if (sc->sc_flags & ET_FLAG_JUMBO) | ||||
max_framelen = ET_JUMBO_FRAMELEN; | max_framelen = ET_JUMBO_FRAMELEN; | ||||
else | else | ||||
#endif | #endif | ||||
max_framelen = MCLBYTES - 1; | max_framelen = MCLBYTES - 1; | ||||
if (ET_FRAMELEN(ifr->ifr_mtu) > max_framelen) { | if (ET_FRAMELEN(ifr->ifr_mtu) > max_framelen) { | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
break; | break; | ||||
} | } | ||||
if (ifp->if_mtu != ifr->ifr_mtu) { | if (if_getmtu(ifp) != ifr->ifr_mtu) { | ||||
ifp->if_mtu = ifr->ifr_mtu; | if_setmtu(ifp, ifr->ifr_mtu); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { | ||||
ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); | ||||
et_init_locked(sc); | et_init_locked(sc); | ||||
} | } | ||||
} | } | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
break; | break; | ||||
case SIOCSIFCAP: | case SIOCSIFCAP: | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
mask = ifr->ifr_reqcap ^ ifp->if_capenable; | mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); | ||||
if ((mask & IFCAP_TXCSUM) != 0 && | if ((mask & IFCAP_TXCSUM) != 0 && | ||||
(IFCAP_TXCSUM & ifp->if_capabilities) != 0) { | (IFCAP_TXCSUM & if_getcapabilities(ifp)) != 0) { | ||||
ifp->if_capenable ^= IFCAP_TXCSUM; | if_togglecapenable(ifp, IFCAP_TXCSUM); | ||||
if ((IFCAP_TXCSUM & ifp->if_capenable) != 0) | if ((IFCAP_TXCSUM & if_getcapenable(ifp)) != 0) | ||||
ifp->if_hwassist |= ET_CSUM_FEATURES; | if_sethwassistbits(ifp, ET_CSUM_FEATURES, 0); | ||||
else | else | ||||
ifp->if_hwassist &= ~ET_CSUM_FEATURES; | if_sethwassistbits(ifp, 0, ET_CSUM_FEATURES); | ||||
} | } | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
break; | break; | ||||
default: | default: | ||||
error = ether_ioctl(ifp, cmd, data); | error = ether_ioctl(ifp, cmd, data); | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
et_start_locked(struct ifnet *ifp) | et_start_locked(if_t ifp) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct mbuf *m_head = NULL; | struct mbuf *m_head = NULL; | ||||
struct et_txdesc_ring *tx_ring; | struct et_txdesc_ring *tx_ring; | ||||
struct et_txbuf_data *tbd; | struct et_txbuf_data *tbd; | ||||
uint32_t tx_ready_pos; | uint32_t tx_ready_pos; | ||||
int enq; | int enq; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
ET_LOCK_ASSERT(sc); | ET_LOCK_ASSERT(sc); | ||||
if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != | if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != | ||||
IFF_DRV_RUNNING || | IFF_DRV_RUNNING || | ||||
(sc->sc_flags & (ET_FLAG_LINK | ET_FLAG_TXRX_ENABLED)) != | (sc->sc_flags & (ET_FLAG_LINK | ET_FLAG_TXRX_ENABLED)) != | ||||
(ET_FLAG_LINK | ET_FLAG_TXRX_ENABLED)) | (ET_FLAG_LINK | ET_FLAG_TXRX_ENABLED)) | ||||
return; | return; | ||||
/* | /* | ||||
* Driver does not request TX completion interrupt for every | * Driver does not request TX completion interrupt for every | ||||
* queued frames to prevent generating excessive interrupts. | * queued frames to prevent generating excessive interrupts. | ||||
* This means driver may wait for TX completion interrupt even | * This means driver may wait for TX completion interrupt even | ||||
* though some frames were successfully transmitted. Reclaiming | * though some frames were successfully transmitted. Reclaiming | ||||
* transmitted frames will ensure driver see all available | * transmitted frames will ensure driver see all available | ||||
* descriptors. | * descriptors. | ||||
*/ | */ | ||||
tbd = &sc->sc_tx_data; | tbd = &sc->sc_tx_data; | ||||
if (tbd->tbd_used > (ET_TX_NDESC * 2) / 3) | if (tbd->tbd_used > (ET_TX_NDESC * 2) / 3) | ||||
et_txeof(sc); | et_txeof(sc); | ||||
for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { | for (enq = 0; !if_sendq_empty(ifp); ) { | ||||
if (tbd->tbd_used + ET_NSEG_SPARE >= ET_TX_NDESC) { | if (tbd->tbd_used + ET_NSEG_SPARE >= ET_TX_NDESC) { | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); | ||||
break; | break; | ||||
} | } | ||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); | m_head = if_dequeue(ifp); | ||||
if (m_head == NULL) | if (m_head == NULL) | ||||
break; | break; | ||||
if (et_encap(sc, &m_head)) { | if (et_encap(sc, &m_head)) { | ||||
if (m_head == NULL) { | if (m_head == NULL) { | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
break; | break; | ||||
} | } | ||||
IFQ_DRV_PREPEND(&ifp->if_snd, m_head); | if_sendq_prepend(ifp, m_head); | ||||
if (tbd->tbd_used > 0) | if (tbd->tbd_used > 0) | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); | ||||
break; | break; | ||||
} | } | ||||
enq++; | enq++; | ||||
ETHER_BPF_MTAP(ifp, m_head); | ETHER_BPF_MTAP(ifp, m_head); | ||||
} | } | ||||
if (enq > 0) { | if (enq > 0) { | ||||
tx_ring = &sc->sc_tx_ring; | tx_ring = &sc->sc_tx_ring; | ||||
bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, | bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
tx_ready_pos = tx_ring->tr_ready_index & | tx_ready_pos = tx_ring->tr_ready_index & | ||||
ET_TX_READY_POS_INDEX_MASK; | ET_TX_READY_POS_INDEX_MASK; | ||||
if (tx_ring->tr_ready_wrap) | if (tx_ring->tr_ready_wrap) | ||||
tx_ready_pos |= ET_TX_READY_POS_WRAP; | tx_ready_pos |= ET_TX_READY_POS_WRAP; | ||||
CSR_WRITE_4(sc, ET_TX_READY_POS, tx_ready_pos); | CSR_WRITE_4(sc, ET_TX_READY_POS, tx_ready_pos); | ||||
sc->watchdog_timer = 5; | sc->watchdog_timer = 5; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
et_start(struct ifnet *ifp) | et_start(if_t ifp) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
sc = ifp->if_softc; | sc = if_getsoftc(ifp); | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
et_start_locked(ifp); | et_start_locked(ifp); | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
} | } | ||||
static int | static int | ||||
et_watchdog(struct et_softc *sc) | et_watchdog(struct et_softc *sc) | ||||
{ | { | ||||
uint32_t status; | uint32_t status; | ||||
ET_LOCK_ASSERT(sc); | ET_LOCK_ASSERT(sc); | ||||
if (sc->watchdog_timer == 0 || --sc->watchdog_timer) | if (sc->watchdog_timer == 0 || --sc->watchdog_timer) | ||||
return (0); | return (0); | ||||
bus_dmamap_sync(sc->sc_tx_status.txsd_dtag, sc->sc_tx_status.txsd_dmap, | bus_dmamap_sync(sc->sc_tx_status.txsd_dtag, sc->sc_tx_status.txsd_dmap, | ||||
BUS_DMASYNC_POSTREAD); | BUS_DMASYNC_POSTREAD); | ||||
status = le32toh(*(sc->sc_tx_status.txsd_status)); | status = le32toh(*(sc->sc_tx_status.txsd_status)); | ||||
if_printf(sc->ifp, "watchdog timed out (0x%08x) -- resetting\n", | if_printf(sc->ifp, "watchdog timed out (0x%08x) -- resetting\n", | ||||
status); | status); | ||||
if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); | ||||
sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | if_setdrvflagbits(sc->ifp, 0, IFF_DRV_RUNNING); | ||||
et_init_locked(sc); | et_init_locked(sc); | ||||
return (EJUSTRETURN); | return (EJUSTRETURN); | ||||
} | } | ||||
static int | static int | ||||
et_stop_rxdma(struct et_softc *sc) | et_stop_rxdma(struct et_softc *sc) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | et_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) | ||||
*hp |= (1 << h); | *hp |= (1 << h); | ||||
return (1); | return (1); | ||||
} | } | ||||
static void | static void | ||||
et_setmulti(struct et_softc *sc) | et_setmulti(struct et_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
uint32_t hash[4] = { 0, 0, 0, 0 }; | uint32_t hash[4] = { 0, 0, 0, 0 }; | ||||
uint32_t rxmac_ctrl, pktfilt; | uint32_t rxmac_ctrl, pktfilt; | ||||
int i, count; | int i, count; | ||||
ET_LOCK_ASSERT(sc); | ET_LOCK_ASSERT(sc); | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
pktfilt = CSR_READ_4(sc, ET_PKTFILT); | pktfilt = CSR_READ_4(sc, ET_PKTFILT); | ||||
rxmac_ctrl = CSR_READ_4(sc, ET_RXMAC_CTRL); | rxmac_ctrl = CSR_READ_4(sc, ET_RXMAC_CTRL); | ||||
pktfilt &= ~(ET_PKTFILT_BCAST | ET_PKTFILT_MCAST | ET_PKTFILT_UCAST); | pktfilt &= ~(ET_PKTFILT_BCAST | ET_PKTFILT_MCAST | ET_PKTFILT_UCAST); | ||||
if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) { | if (if_getflags(ifp) & (IFF_PROMISC | IFF_ALLMULTI)) { | ||||
rxmac_ctrl |= ET_RXMAC_CTRL_NO_PKTFILT; | rxmac_ctrl |= ET_RXMAC_CTRL_NO_PKTFILT; | ||||
goto back; | goto back; | ||||
} | } | ||||
count = if_foreach_llmaddr(ifp, et_hash_maddr, &hash); | count = if_foreach_llmaddr(ifp, et_hash_maddr, &hash); | ||||
for (i = 0; i < 4; ++i) | for (i = 0; i < 4; ++i) | ||||
CSR_WRITE_4(sc, ET_MULTI_HASH + (i * 4), hash[i]); | CSR_WRITE_4(sc, ET_MULTI_HASH + (i * 4), hash[i]); | ||||
if (count > 0) | if (count > 0) | ||||
pktfilt |= ET_PKTFILT_MCAST; | pktfilt |= ET_PKTFILT_MCAST; | ||||
rxmac_ctrl &= ~ET_RXMAC_CTRL_NO_PKTFILT; | rxmac_ctrl &= ~ET_RXMAC_CTRL_NO_PKTFILT; | ||||
back: | back: | ||||
CSR_WRITE_4(sc, ET_PKTFILT, pktfilt); | CSR_WRITE_4(sc, ET_PKTFILT, pktfilt); | ||||
CSR_WRITE_4(sc, ET_RXMAC_CTRL, rxmac_ctrl); | CSR_WRITE_4(sc, ET_RXMAC_CTRL, rxmac_ctrl); | ||||
} | } | ||||
static int | static int | ||||
et_chip_init(struct et_softc *sc) | et_chip_init(struct et_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
uint32_t rxq_end; | uint32_t rxq_end; | ||||
int error, frame_len, rxmem_size; | int error, frame_len, rxmem_size; | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
/* | /* | ||||
* Split 16Kbytes internal memory between TX and RX | * Split 16Kbytes internal memory between TX and RX | ||||
* according to frame length. | * according to frame length. | ||||
*/ | */ | ||||
frame_len = ET_FRAMELEN(ifp->if_mtu); | frame_len = ET_FRAMELEN(if_getmtu(ifp)); | ||||
if (frame_len < 2048) { | if (frame_len < 2048) { | ||||
rxmem_size = ET_MEM_RXSIZE_DEFAULT; | rxmem_size = ET_MEM_RXSIZE_DEFAULT; | ||||
} else if (frame_len <= ET_RXMAC_CUT_THRU_FRMLEN) { | } else if (frame_len <= ET_RXMAC_CUT_THRU_FRMLEN) { | ||||
rxmem_size = ET_MEM_SIZE / 2; | rxmem_size = ET_MEM_SIZE / 2; | ||||
} else { | } else { | ||||
rxmem_size = ET_MEM_SIZE - | rxmem_size = ET_MEM_SIZE - | ||||
roundup(frame_len + ET_MEM_TXSIZE_EX, ET_MEM_UNIT); | roundup(frame_len + ET_MEM_TXSIZE_EX, ET_MEM_UNIT); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | et_init_txdma(struct et_softc *sc) | ||||
tx_ring->tr_ready_wrap = 0; | tx_ring->tr_ready_wrap = 0; | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
et_init_mac(struct et_softc *sc) | et_init_mac(struct et_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
const uint8_t *eaddr; | const uint8_t *eaddr; | ||||
uint32_t val; | uint32_t val; | ||||
/* Reset MAC */ | /* Reset MAC */ | ||||
CSR_WRITE_4(sc, ET_MAC_CFG1, | CSR_WRITE_4(sc, ET_MAC_CFG1, | ||||
ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | | ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | | ||||
ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | | ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | | ||||
ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); | ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); | ||||
Show All 21 Lines | et_init_mac(struct et_softc *sc) | ||||
/* Reset MII */ | /* Reset MII */ | ||||
CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); | CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); | ||||
/* | /* | ||||
* Set MAC address | * Set MAC address | ||||
*/ | */ | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
eaddr = IF_LLADDR(ifp); | eaddr = if_getlladdr(ifp); | ||||
val = eaddr[2] | (eaddr[3] << 8) | (eaddr[4] << 16) | (eaddr[5] << 24); | val = eaddr[2] | (eaddr[3] << 8) | (eaddr[4] << 16) | (eaddr[5] << 24); | ||||
CSR_WRITE_4(sc, ET_MAC_ADDR1, val); | CSR_WRITE_4(sc, ET_MAC_ADDR1, val); | ||||
val = (eaddr[0] << 16) | (eaddr[1] << 24); | val = (eaddr[0] << 16) | (eaddr[1] << 24); | ||||
CSR_WRITE_4(sc, ET_MAC_ADDR2, val); | CSR_WRITE_4(sc, ET_MAC_ADDR2, val); | ||||
/* Set max frame length */ | /* Set max frame length */ | ||||
CSR_WRITE_4(sc, ET_MAX_FRMLEN, ET_FRAMELEN(ifp->if_mtu)); | CSR_WRITE_4(sc, ET_MAX_FRMLEN, ET_FRAMELEN(if_getmtu(ifp))); | ||||
/* Bring MAC out of reset state */ | /* Bring MAC out of reset state */ | ||||
CSR_WRITE_4(sc, ET_MAC_CFG1, 0); | CSR_WRITE_4(sc, ET_MAC_CFG1, 0); | ||||
} | } | ||||
static void | static void | ||||
et_init_rxmac(struct et_softc *sc) | et_init_rxmac(struct et_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
const uint8_t *eaddr; | const uint8_t *eaddr; | ||||
uint32_t val; | uint32_t val; | ||||
int i; | int i; | ||||
/* Disable RX MAC and WOL */ | /* Disable RX MAC and WOL */ | ||||
CSR_WRITE_4(sc, ET_RXMAC_CTRL, ET_RXMAC_CTRL_WOL_DISABLE); | CSR_WRITE_4(sc, ET_RXMAC_CTRL, ET_RXMAC_CTRL_WOL_DISABLE); | ||||
/* | /* | ||||
* Clear all WOL related registers | * Clear all WOL related registers | ||||
*/ | */ | ||||
for (i = 0; i < 3; ++i) | for (i = 0; i < 3; ++i) | ||||
CSR_WRITE_4(sc, ET_WOL_CRC + (i * 4), 0); | CSR_WRITE_4(sc, ET_WOL_CRC + (i * 4), 0); | ||||
for (i = 0; i < 20; ++i) | for (i = 0; i < 20; ++i) | ||||
CSR_WRITE_4(sc, ET_WOL_MASK + (i * 4), 0); | CSR_WRITE_4(sc, ET_WOL_MASK + (i * 4), 0); | ||||
/* | /* | ||||
* Set WOL source address. XXX is this necessary? | * Set WOL source address. XXX is this necessary? | ||||
*/ | */ | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
eaddr = IF_LLADDR(ifp); | eaddr = if_getlladdr(ifp); | ||||
val = (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8) | eaddr[5]; | val = (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8) | eaddr[5]; | ||||
CSR_WRITE_4(sc, ET_WOL_SA_LO, val); | CSR_WRITE_4(sc, ET_WOL_SA_LO, val); | ||||
val = (eaddr[0] << 8) | eaddr[1]; | val = (eaddr[0] << 8) | eaddr[1]; | ||||
CSR_WRITE_4(sc, ET_WOL_SA_HI, val); | CSR_WRITE_4(sc, ET_WOL_SA_HI, val); | ||||
/* Clear packet filters */ | /* Clear packet filters */ | ||||
CSR_WRITE_4(sc, ET_PKTFILT, 0); | CSR_WRITE_4(sc, ET_PKTFILT, 0); | ||||
/* No ucast filtering */ | /* No ucast filtering */ | ||||
CSR_WRITE_4(sc, ET_UCAST_FILTADDR1, 0); | CSR_WRITE_4(sc, ET_UCAST_FILTADDR1, 0); | ||||
CSR_WRITE_4(sc, ET_UCAST_FILTADDR2, 0); | CSR_WRITE_4(sc, ET_UCAST_FILTADDR2, 0); | ||||
CSR_WRITE_4(sc, ET_UCAST_FILTADDR3, 0); | CSR_WRITE_4(sc, ET_UCAST_FILTADDR3, 0); | ||||
if (ET_FRAMELEN(ifp->if_mtu) > ET_RXMAC_CUT_THRU_FRMLEN) { | if (ET_FRAMELEN(if_getmtu(ifp)) > ET_RXMAC_CUT_THRU_FRMLEN) { | ||||
/* | /* | ||||
* In order to transmit jumbo packets greater than | * In order to transmit jumbo packets greater than | ||||
* ET_RXMAC_CUT_THRU_FRMLEN bytes, the FIFO between | * ET_RXMAC_CUT_THRU_FRMLEN bytes, the FIFO between | ||||
* RX MAC and RX DMA needs to be reduced in size to | * RX MAC and RX DMA needs to be reduced in size to | ||||
* (ET_MEM_SIZE - ET_MEM_TXSIZE_EX - framelen). In | * (ET_MEM_SIZE - ET_MEM_TXSIZE_EX - framelen). In | ||||
* order to implement this, we must use "cut through" | * order to implement this, we must use "cut through" | ||||
* mode in the RX MAC, which chops packets down into | * mode in the RX MAC, which chops packets down into | ||||
* segments. In this case we selected 256 bytes, | * segments. In this case we selected 256 bytes, | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
et_rxeof(struct et_softc *sc) | et_rxeof(struct et_softc *sc) | ||||
{ | { | ||||
struct et_rxstatus_data *rxsd; | struct et_rxstatus_data *rxsd; | ||||
struct et_rxstat_ring *rxst_ring; | struct et_rxstat_ring *rxst_ring; | ||||
struct et_rxbuf_data *rbd; | struct et_rxbuf_data *rbd; | ||||
struct et_rxdesc_ring *rx_ring; | struct et_rxdesc_ring *rx_ring; | ||||
struct et_rxstat *st; | struct et_rxstat *st; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
uint32_t rxstat_pos, rxring_pos; | uint32_t rxstat_pos, rxring_pos; | ||||
uint32_t rxst_info1, rxst_info2, rxs_stat_ring; | uint32_t rxst_info1, rxst_info2, rxs_stat_ring; | ||||
int buflen, buf_idx, npost[2], ring_idx; | int buflen, buf_idx, npost[2], ring_idx; | ||||
int rxst_index, rxst_wrap; | int rxst_index, rxst_wrap; | ||||
ET_LOCK_ASSERT(sc); | ET_LOCK_ASSERT(sc); | ||||
Show All 12 Lines | et_rxeof(struct et_softc *sc) | ||||
npost[0] = npost[1] = 0; | npost[0] = npost[1] = 0; | ||||
rxs_stat_ring = le32toh(rxsd->rxsd_status->rxs_stat_ring); | rxs_stat_ring = le32toh(rxsd->rxsd_status->rxs_stat_ring); | ||||
rxst_wrap = (rxs_stat_ring & ET_RXS_STATRING_WRAP) ? 1 : 0; | rxst_wrap = (rxs_stat_ring & ET_RXS_STATRING_WRAP) ? 1 : 0; | ||||
rxst_index = (rxs_stat_ring & ET_RXS_STATRING_INDEX_MASK) >> | rxst_index = (rxs_stat_ring & ET_RXS_STATRING_INDEX_MASK) >> | ||||
ET_RXS_STATRING_INDEX_SHIFT; | ET_RXS_STATRING_INDEX_SHIFT; | ||||
while (rxst_index != rxst_ring->rsr_index || | while (rxst_index != rxst_ring->rsr_index || | ||||
rxst_wrap != rxst_ring->rsr_wrap) { | rxst_wrap != rxst_ring->rsr_wrap) { | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) | ||||
break; | break; | ||||
MPASS(rxst_ring->rsr_index < ET_RX_NSTAT); | MPASS(rxst_ring->rsr_index < ET_RX_NSTAT); | ||||
st = &rxst_ring->rsr_stat[rxst_ring->rsr_index]; | st = &rxst_ring->rsr_stat[rxst_ring->rsr_index]; | ||||
rxst_info1 = le32toh(st->rxst_info1); | rxst_info1 = le32toh(st->rxst_info1); | ||||
rxst_info2 = le32toh(st->rxst_info2); | rxst_info2 = le32toh(st->rxst_info2); | ||||
buflen = (rxst_info2 & ET_RXST_INFO2_LEN_MASK) >> | buflen = (rxst_info2 & ET_RXST_INFO2_LEN_MASK) >> | ||||
ET_RXST_INFO2_LEN_SHIFT; | ET_RXST_INFO2_LEN_SHIFT; | ||||
Show All 35 Lines | if ((rxst_info1 & ET_RXST_INFO1_OK) == 0){ | ||||
buflen -= ETHER_CRC_LEN; | buflen -= ETHER_CRC_LEN; | ||||
if (buflen < ETHER_HDR_LEN) { | if (buflen < ETHER_HDR_LEN) { | ||||
m_freem(m); | m_freem(m); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | ||||
} else { | } else { | ||||
m->m_pkthdr.len = m->m_len = buflen; | m->m_pkthdr.len = m->m_len = buflen; | ||||
m->m_pkthdr.rcvif = ifp; | m->m_pkthdr.rcvif = ifp; | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
ifp->if_input(ifp, m); | if_input(ifp, m); | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
} | } | ||||
} | } | ||||
rx_ring = &sc->sc_rx_ring[ring_idx]; | rx_ring = &sc->sc_rx_ring[ring_idx]; | ||||
if (buf_idx != rx_ring->rr_index) { | if (buf_idx != rx_ring->rr_index) { | ||||
if_printf(ifp, | if_printf(ifp, | ||||
"WARNING!! ring %d, buf_idx %d, rr_idx %d\n", | "WARNING!! ring %d, buf_idx %d, rr_idx %d\n", | ||||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
et_txeof(struct et_softc *sc) | et_txeof(struct et_softc *sc) | ||||
{ | { | ||||
struct et_txdesc_ring *tx_ring; | struct et_txdesc_ring *tx_ring; | ||||
struct et_txbuf_data *tbd; | struct et_txbuf_data *tbd; | ||||
struct et_txbuf *tb; | struct et_txbuf *tb; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
uint32_t tx_done; | uint32_t tx_done; | ||||
int end, wrap; | int end, wrap; | ||||
ET_LOCK_ASSERT(sc); | ET_LOCK_ASSERT(sc); | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
tx_ring = &sc->sc_tx_ring; | tx_ring = &sc->sc_tx_ring; | ||||
tbd = &sc->sc_tx_data; | tbd = &sc->sc_tx_data; | ||||
Show All 29 Lines | while (tbd->tbd_start_index != end || tbd->tbd_start_wrap != wrap) { | ||||
MPASS(tbd->tbd_used > 0); | MPASS(tbd->tbd_used > 0); | ||||
tbd->tbd_used--; | tbd->tbd_used--; | ||||
} | } | ||||
if (tbd->tbd_used == 0) | if (tbd->tbd_used == 0) | ||||
sc->watchdog_timer = 0; | sc->watchdog_timer = 0; | ||||
if (tbd->tbd_used + ET_NSEG_SPARE < ET_TX_NDESC) | if (tbd->tbd_used + ET_NSEG_SPARE < ET_TX_NDESC) | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); | ||||
} | } | ||||
static void | static void | ||||
et_tick(void *xsc) | et_tick(void *xsc) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
▲ Show 20 Lines • Show All 255 Lines • ▼ Show 20 Lines | |||||
#undef ET_SYSCTL_STAT_ADD32 | #undef ET_SYSCTL_STAT_ADD32 | ||||
#undef ET_SYSCTL_STAT_ADD64 | #undef ET_SYSCTL_STAT_ADD64 | ||||
static int | static int | ||||
et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS) | et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
int error, v; | int error, v; | ||||
sc = arg1; | sc = arg1; | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
v = sc->sc_rx_intr_npkts; | v = sc->sc_rx_intr_npkts; | ||||
error = sysctl_handle_int(oidp, &v, 0, req); | error = sysctl_handle_int(oidp, &v, 0, req); | ||||
if (error || req->newptr == NULL) | if (error || req->newptr == NULL) | ||||
goto back; | goto back; | ||||
if (v <= 0) { | if (v <= 0) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto back; | goto back; | ||||
} | } | ||||
if (sc->sc_rx_intr_npkts != v) { | if (sc->sc_rx_intr_npkts != v) { | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) | ||||
CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, v); | CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, v); | ||||
sc->sc_rx_intr_npkts = v; | sc->sc_rx_intr_npkts = v; | ||||
} | } | ||||
back: | back: | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS) | et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
int error, v; | int error, v; | ||||
sc = arg1; | sc = arg1; | ||||
ifp = sc->ifp; | ifp = sc->ifp; | ||||
v = sc->sc_rx_intr_delay; | v = sc->sc_rx_intr_delay; | ||||
error = sysctl_handle_int(oidp, &v, 0, req); | error = sysctl_handle_int(oidp, &v, 0, req); | ||||
if (error || req->newptr == NULL) | if (error || req->newptr == NULL) | ||||
goto back; | goto back; | ||||
if (v <= 0) { | if (v <= 0) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto back; | goto back; | ||||
} | } | ||||
if (sc->sc_rx_intr_delay != v) { | if (sc->sc_rx_intr_delay != v) { | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) | ||||
CSR_WRITE_4(sc, ET_RX_INTR_DELAY, v); | CSR_WRITE_4(sc, ET_RX_INTR_DELAY, v); | ||||
sc->sc_rx_intr_delay = v; | sc->sc_rx_intr_delay = v; | ||||
} | } | ||||
back: | back: | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | et_stats_update(struct et_softc *sc) | ||||
stats->tx_crcerrs += CSR_READ_4(sc, ET_STAT_TX_CRC_ERR); | stats->tx_crcerrs += CSR_READ_4(sc, ET_STAT_TX_CRC_ERR); | ||||
stats->tx_control += CSR_READ_4(sc, ET_STAT_TX_CTL); | stats->tx_control += CSR_READ_4(sc, ET_STAT_TX_CTL); | ||||
stats->tx_oversize += CSR_READ_4(sc, ET_STAT_TX_OVERSIZE); | stats->tx_oversize += CSR_READ_4(sc, ET_STAT_TX_OVERSIZE); | ||||
stats->tx_undersize += CSR_READ_4(sc, ET_STAT_TX_UNDERSIZE); | stats->tx_undersize += CSR_READ_4(sc, ET_STAT_TX_UNDERSIZE); | ||||
stats->tx_fragments += CSR_READ_4(sc, ET_STAT_TX_FRAG); | stats->tx_fragments += CSR_READ_4(sc, ET_STAT_TX_FRAG); | ||||
} | } | ||||
static uint64_t | static uint64_t | ||||
et_get_counter(struct ifnet *ifp, ift_counter cnt) | et_get_counter(if_t ifp, ift_counter cnt) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
struct et_hw_stats *stats; | struct et_hw_stats *stats; | ||||
sc = if_getsoftc(ifp); | sc = if_getsoftc(ifp); | ||||
stats = &sc->sc_stats; | stats = &sc->sc_stats; | ||||
switch (cnt) { | switch (cnt) { | ||||
Show All 19 Lines | |||||
static int | static int | ||||
et_suspend(device_t dev) | et_suspend(device_t dev) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
uint32_t pmcfg; | uint32_t pmcfg; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) | if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) != 0) | ||||
et_stop(sc); | et_stop(sc); | ||||
/* Diable all clocks and put PHY into COMA. */ | /* Diable all clocks and put PHY into COMA. */ | ||||
pmcfg = CSR_READ_4(sc, ET_PM); | pmcfg = CSR_READ_4(sc, ET_PM); | ||||
pmcfg &= ~(EM_PM_GIGEPHY_ENB | ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | | pmcfg &= ~(EM_PM_GIGEPHY_ENB | ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | | ||||
ET_PM_RXCLK_GATE); | ET_PM_RXCLK_GATE); | ||||
pmcfg |= ET_PM_PHY_SW_COMA; | pmcfg |= ET_PM_PHY_SW_COMA; | ||||
CSR_WRITE_4(sc, ET_PM, pmcfg); | CSR_WRITE_4(sc, ET_PM, pmcfg); | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
et_resume(device_t dev) | et_resume(device_t dev) | ||||
{ | { | ||||
struct et_softc *sc; | struct et_softc *sc; | ||||
uint32_t pmcfg; | uint32_t pmcfg; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
ET_LOCK(sc); | ET_LOCK(sc); | ||||
/* Take PHY out of COMA and enable clocks. */ | /* Take PHY out of COMA and enable clocks. */ | ||||
pmcfg = ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | ET_PM_RXCLK_GATE; | pmcfg = ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | ET_PM_RXCLK_GATE; | ||||
if ((sc->sc_flags & ET_FLAG_FASTETHER) == 0) | if ((sc->sc_flags & ET_FLAG_FASTETHER) == 0) | ||||
pmcfg |= EM_PM_GIGEPHY_ENB; | pmcfg |= EM_PM_GIGEPHY_ENB; | ||||
CSR_WRITE_4(sc, ET_PM, pmcfg); | CSR_WRITE_4(sc, ET_PM, pmcfg); | ||||
if ((sc->ifp->if_flags & IFF_UP) != 0) | if ((if_getflags(sc->ifp) & IFF_UP) != 0) | ||||
et_init_locked(sc); | et_init_locked(sc); | ||||
ET_UNLOCK(sc); | ET_UNLOCK(sc); | ||||
return (0); | return (0); | ||||
} | } |