diff options
author | glebius <glebius@FreeBSD.org> | 2005-10-01 18:56:19 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2005-10-01 18:56:19 +0000 |
commit | f41a83bf429b15386f43f43f3f5326d4ece7bfce (patch) | |
tree | b78f9e953b7b58b2789d042cf37cc725045fdcf1 /sys/pci/if_xl.c | |
parent | 6c6c328bd0bbb1d9f6b3230a33d194bf961b0eae (diff) | |
download | FreeBSD-src-f41a83bf429b15386f43f43f3f5326d4ece7bfce.zip FreeBSD-src-f41a83bf429b15386f43f43f3f5326d4ece7bfce.tar.gz |
Big polling(4) cleanup.
o Axe poll in trap.
o Axe IFF_POLLING flag from if_flags.
o Rework revision 1.21 (Giant removal), in such a way that
poll_mtx is not dropped during call to polling handler.
This fixes problem with idle polling.
o Make registration and deregistration from polling in a
functional way, insted of next tick/interrupt.
o Obsolete kern.polling.enable. Polling is turned on/off
with ifconfig.
Detailed kern_poll.c changes:
- Remove polling handler flags, introduced in 1.21. The are not
needed now.
- Forget and do not check if_flags, if_capenable and if_drv_flags.
- Call all registered polling handlers unconditionally.
- Do not drop poll_mtx, when entering polling handlers.
- In ether_poll() NET_LOCK_GIANT prior to locking poll_mtx.
- In netisr_poll() axe the block, where polling code asks drivers
to unregister.
- In netisr_poll() and ether_poll() do polling always, if any
handlers are present.
- In ether_poll_[de]register() remove a lot of error hiding code. Assert
that arguments are correct, instead.
- In ether_poll_[de]register() use standard return values in case of
error or success.
- Introduce poll_switch() that is a sysctl handler for kern.polling.enable.
poll_switch() goes through interface list and enabled/disables polling.
A message that kern.polling.enable is deprecated is printed.
Detailed driver changes:
- On attach driver announces IFCAP_POLLING in if_capabilities, but
not in if_capenable.
- On detach driver calls ether_poll_deregister() if polling is enabled.
- In polling handler driver obtains its lock and checks IFF_DRV_RUNNING
flag. If there is no, then unlocks and returns.
- In ioctl handler driver checks for IFCAP_POLLING flag requested to
be set or cleared. Driver first calls ether_poll_[de]register(), then
obtains driver lock and [dis/en]ables interrupts.
- In interrupt handler driver checks IFCAP_POLLING flag in if_capenable.
If present, then returns.This is important to protect from spurious
interrupts.
Reviewed by: ru, sam, jhb
Diffstat (limited to 'sys/pci/if_xl.c')
-rw-r--r-- | sys/pci/if_xl.c | 86 |
1 files changed, 45 insertions, 41 deletions
diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c index 520f668..e49997a 100644 --- a/sys/pci/if_xl.c +++ b/sys/pci/if_xl.c @@ -249,7 +249,7 @@ static int xl_resume(device_t); #ifdef DEVICE_POLLING static void xl_poll(struct ifnet *ifp, enum poll_cmd cmd, int count); static void xl_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count); -#endif /* DEVICE_POLLING */ +#endif static int xl_ifmedia_upd(struct ifnet *); static void xl_ifmedia_sts(struct ifnet *, struct ifmediareq *); @@ -1487,9 +1487,10 @@ xl_attach(device_t dev) ifp->if_capabilities |= IFCAP_HWCSUM; #endif } + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; -#endif /* DEVICE_POLLING */ +#endif ifp->if_start = xl_start; ifp->if_watchdog = xl_watchdog; ifp->if_init = xl_init; @@ -1497,7 +1498,6 @@ xl_attach(device_t dev) IFQ_SET_MAXLEN(&ifp->if_snd, XL_TX_LIST_CNT - 1); ifp->if_snd.ifq_drv_maxlen = XL_TX_LIST_CNT - 1; IFQ_SET_READY(&ifp->if_snd); - ifp->if_capenable = ifp->if_capabilities; /* * Now we have to see what sort of media we have. @@ -1690,6 +1690,11 @@ xl_detach(device_t dev) KASSERT(mtx_initialized(&sc->xl_mtx), ("xl mutex not initialized")); +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + if (sc->xl_flags & XL_FLAG_USE_MMIO) { rid = XL_PCI_LOMEM; res = SYS_RES_MEMORY; @@ -1960,12 +1965,12 @@ again: BUS_DMASYNC_POSTREAD); while ((rxstat = le32toh(sc->xl_cdata.xl_rx_head->xl_ptr->xl_status))) { #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) { + if (ifp->if_capenable & IFCAP_POLLING) { if (sc->rxcycles <= 0) break; sc->rxcycles--; } -#endif /* DEVICE_POLLING */ +#endif cur_rx = sc->xl_cdata.xl_rx_head; sc->xl_cdata.xl_rx_head = cur_rx->xl_next; total_len = rxstat & XL_RXSTAT_LENMASK; @@ -2275,24 +2280,11 @@ xl_intr(void *arg) XL_LOCK(sc); #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) { + if (ifp->if_capenable & IFCAP_POLLING) { XL_UNLOCK(sc); return; } - - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(xl_poll, ifp)) { - /* Disable interrupts. */ - CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0); - CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF); - if (sc->xl_flags & XL_FLAG_FUNCREG) - bus_space_write_4(sc->xl_ftag, sc->xl_fhandle, - 4, 0x8000); - xl_poll_locked(ifp, 0, 1); - XL_UNLOCK(sc); - return; - } -#endif /* DEVICE_POLLING */ +#endif while ((status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS && status != 0xFFFF) { @@ -2351,7 +2343,8 @@ xl_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct xl_softc *sc = ifp->if_softc; XL_LOCK(sc); - xl_poll_locked(ifp, cmd, count); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + xl_poll_locked(ifp, cmd, count); XL_UNLOCK(sc); } @@ -2362,21 +2355,6 @@ xl_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) XL_LOCK_ASSERT(sc); - if (!(ifp->if_capenable & IFCAP_POLLING)) { - ether_poll_deregister(ifp); - cmd = POLL_DEREGISTER; - } - - if (cmd == POLL_DEREGISTER) { - /* Final call; enable interrupts. */ - CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF); - CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS); - if (sc->xl_flags & XL_FLAG_FUNCREG) - bus_space_write_4(sc->xl_ftag, sc->xl_fhandle, - 4, 0x8000); - return; - } - sc->rxcycles = count; xl_rxeof(sc); if (sc->xl_type == XL_TYPE_905B) @@ -2989,10 +2967,10 @@ xl_init_locked(struct xl_softc *sc) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|XL_INTRS); #ifdef DEVICE_POLLING /* Disable interrupts if we are polling. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0); else -#endif /* DEVICE_POLLING */ +#endif CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS); if (sc->xl_flags & XL_FLAG_FUNCREG) bus_space_write_4(sc->xl_ftag, sc->xl_fhandle, 4, 0x8000); @@ -3204,6 +3182,35 @@ xl_ioctl(struct ifnet *ifp, u_long command, caddr_t data) &mii->mii_media, command); break; case SIOCSIFCAP: +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(xl_poll, ifp); + if (error) + return(error); + XL_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0); + ifp->if_capenable |= IFCAP_POLLING; + XL_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + XL_LOCK(sc); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS); + if (sc->xl_flags & XL_FLAG_FUNCREG) + bus_space_write_4(sc->xl_ftag, sc->xl_fhandle, + 4, 0x8000); + ifp->if_capenable &= ~IFCAP_POLLING; + XL_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ XL_LOCK(sc); ifp->if_capenable = ifr->ifr_reqcap; if (ifp->if_capenable & IFCAP_TXCSUM) @@ -3268,9 +3275,6 @@ xl_stop(struct xl_softc *sc) XL_LOCK_ASSERT(sc); ifp->if_timer = 0; -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* DEVICE_POLLING */ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISABLE); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE); |