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/dev/fxp | |
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/dev/fxp')
-rw-r--r-- | sys/dev/fxp/if_fxp.c | 56 |
1 files changed, 32 insertions, 24 deletions
diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index 944876d..133a96a 100644 --- a/sys/dev/fxp/if_fxp.c +++ b/sys/dev/fxp/if_fxp.c @@ -773,7 +773,6 @@ fxp_attach(device_t dev) #ifdef DEVICE_POLLING /* Inform the world we support polling. */ ifp->if_capabilities |= IFCAP_POLLING; - ifp->if_capenable |= IFCAP_POLLING; #endif /* @@ -891,6 +890,11 @@ fxp_detach(device_t dev) { struct fxp_softc *sc = device_get_softc(dev); +#ifdef DEVICE_POLLING + if (sc->ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(sc->ifp); +#endif + FXP_LOCK(sc); sc->suspended = 1; /* Do same thing as we do for suspend */ /* @@ -1448,15 +1452,11 @@ fxp_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) uint8_t statack; FXP_LOCK(sc); - if (!(ifp->if_capenable & IFCAP_POLLING)) { - ether_poll_deregister(ifp); - cmd = POLL_DEREGISTER; - } - if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ - CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0); + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { FXP_UNLOCK(sc); return; } + statack = FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA | FXP_SCB_STATACK_FR; if (cmd == POLL_AND_CHECK_STATUS) { @@ -1495,18 +1495,10 @@ fxp_intr(void *xsc) } #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) { + if (ifp->if_capenable & IFCAP_POLLING) { FXP_UNLOCK(sc); return; } - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(fxp_poll, ifp)) { - /* disable interrupts */ - CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE); - FXP_UNLOCK(sc); - fxp_poll(ifp, 0, 1); - return; - } #endif while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) { /* @@ -1837,9 +1829,6 @@ fxp_stop(struct fxp_softc *sc) ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); ifp->if_timer = 0; -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* * Cancel stats updater. */ @@ -2163,7 +2152,7 @@ fxp_init_body(struct fxp_softc *sc) * ... but only do that if we are not polling. And because (presumably) * the default is interrupts on, we need to disable them explicitly! */ - if ( ifp->if_flags & IFF_POLLING ) + if (ifp->if_capenable & IFCAP_POLLING ) CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE); else #endif /* DEVICE_POLLING */ @@ -2418,11 +2407,30 @@ fxp_ioctl(struct ifnet *ifp, u_long command, caddr_t data) break; case SIOCSIFCAP: - FXP_LOCK(sc); mask = ifp->if_capenable ^ ifr->ifr_reqcap; - if (mask & IFCAP_POLLING) - ifp->if_capenable ^= IFCAP_POLLING; +#ifdef DEVICE_POLLING + if (mask & IFCAP_POLLING) { + if (ifr->ifr_reqcap & IFCAP_POLLING) { + error = ether_poll_register(fxp_poll, ifp); + if (error) + return(error); + FXP_LOCK(sc); + CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, + FXP_SCB_INTR_DISABLE); + ifp->if_capenable |= IFCAP_POLLING; + FXP_UNLOCK(sc); + } else { + error = ether_poll_deregister(ifp); + /* Enable interrupts in any case */ + FXP_LOCK(sc); + CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0); + ifp->if_capenable &= ~IFCAP_POLLING; + FXP_UNLOCK(sc); + } + } +#endif if (mask & IFCAP_VLAN_MTU) { + FXP_LOCK(sc); ifp->if_capenable ^= IFCAP_VLAN_MTU; if (sc->revision != FXP_REV_82557) flag = FXP_FLAG_LONG_PKT_EN; @@ -2431,8 +2439,8 @@ fxp_ioctl(struct ifnet *ifp, u_long command, caddr_t data) sc->flags ^= flag; if (ifp->if_flags & IFF_UP) fxp_init_body(sc); + FXP_UNLOCK(sc); } - FXP_UNLOCK(sc); break; default: |