From f41a83bf429b15386f43f43f3f5326d4ece7bfce Mon Sep 17 00:00:00 2001 From: glebius Date: Sat, 1 Oct 2005 18:56:19 +0000 Subject: 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 --- sys/dev/firewire/00README | 3 -- sys/dev/firewire/if_fwe.c | 69 +++++++++++++++++++++++----------------- sys/dev/firewire/if_fwip.c | 78 ++++++++++++++++++++++++++++------------------ 3 files changed, 87 insertions(+), 63 deletions(-) (limited to 'sys/dev/firewire') diff --git a/sys/dev/firewire/00README b/sys/dev/firewire/00README index d879f31..a6536ae 100644 --- a/sys/dev/firewire/00README +++ b/sys/dev/firewire/00README @@ -70,9 +70,6 @@ IEEE 1394 support for FreeBSD-5.X and 4.X. It also has DEVICE_POLLING[5] support. To enable it, edit your kernel config file and Makefile.fwe then rebuild kernel and if_fwe.ko. - Note this driver checks kern.polling.enable only when enabling the - interface. When you enable polling after the interface is up, - try 'ifconfig fwe0 down;ifconfig fwe0 up'. 5. FireWire for Kernel Hackers diff --git a/sys/dev/firewire/if_fwe.c b/sys/dev/firewire/if_fwe.c index e9d9107..1bf1bcd 100644 --- a/sys/dev/firewire/if_fwe.c +++ b/sys/dev/firewire/if_fwe.c @@ -100,19 +100,6 @@ TUNABLE_INT("hw.firewire.fwe.tx_speed", &tx_speed); TUNABLE_INT("hw.firewire.fwe.rx_queue_len", &rx_queue_len); #ifdef DEVICE_POLLING -#define FWE_POLL_REGISTER(func, fwe, ifp) \ - if (ether_poll_register(func, ifp)) { \ - struct firewire_comm *fc = (fwe)->fd.fc; \ - fc->set_intr(fc, 0); \ - } - -#define FWE_POLL_DEREGISTER(fwe, ifp) \ - do { \ - struct firewire_comm *fc = (fwe)->fd.fc; \ - ether_poll_deregister(ifp); \ - fc->set_intr(fc, 1); \ - } while(0) \ - static poll_handler_t fwe_poll; static void @@ -121,19 +108,15 @@ fwe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct fwe_softc *fwe; struct firewire_comm *fc; + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + return; + fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; fc = fwe->fd.fc; - if (cmd == POLL_DEREGISTER) { - /* enable interrupts */ - fc->set_intr(fc, 1); - return; - } fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count); } -#else -#define FWE_POLL_REGISTER(func, fwe, ifp) -#define FWE_POLL_DEREGISTER(fwe, ifp) -#endif +#endif /* DEVICE_POLLING */ + static void fwe_identify(driver_t *driver, device_t parent) { @@ -242,7 +225,7 @@ fwe_attach(device_t dev) /* Tell the upper layer(s) we support long frames. */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 - ifp->if_capabilities |= IFCAP_VLAN_MTU; + ifp->if_capabilities |= IFCAP_VLAN_MTU & IFCAP_POLLING; ifp->if_capenable |= IFCAP_VLAN_MTU; #endif @@ -262,8 +245,6 @@ fwe_stop(struct fwe_softc *fwe) fc = fwe->fd.fc; - FWE_POLL_DEREGISTER(fwe, ifp); - if (fwe->dma_ch >= 0) { xferq = fc->ir[fwe->dma_ch]; @@ -305,6 +286,11 @@ fwe_detach(device_t dev) fwe = device_get_softc(dev); ifp = fwe->eth_softc.ifp; + +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif s = splimp(); fwe_stop(fwe); @@ -416,7 +402,6 @@ found: ifp->if_flags &= ~IFF_OACTIVE; #endif - FWE_POLL_REGISTER(fwe_poll, fwe, ifp); #if 0 /* attempt to start output */ fwe_start(ifp); @@ -468,6 +453,34 @@ fwe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) fwe->stream_ch, fwe->dma_ch); splx(s); break; + case SIOCSIFCAP: +#ifdef DEVICE_POLLING + { + struct ifreq *ifr = (struct ifreq *) data; + struct firewire_comm *fc = fc = fwe->fd.fc; + + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(fwe_poll, ifp); + if (error) + return(error); + /* Disable interrupts */ + fc->set_intr(fc, 0); + ifp->if_capenable |= IFCAP_POLLING; + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + fc->set_intr(fc, 1); + ifp->if_capenable &= ~IFCAP_POLLING; + return (error); + } + } +#endif /* DEVICE_POLLING */ + break; #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 default: #else @@ -634,9 +647,7 @@ fwe_as_input(struct fw_xferq *xferq) fwe = (struct fwe_softc *)xferq->sc; ifp = fwe->eth_softc.ifp; -#if 0 - FWE_POLL_REGISTER(fwe_poll, fwe, ifp); -#endif + while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) { STAILQ_REMOVE_HEAD(&xferq->stvalid, link); fp = mtod(sxfer->mbuf, struct fw_pkt *); diff --git a/sys/dev/firewire/if_fwip.c b/sys/dev/firewire/if_fwip.c index 20916bc..b3fdda4 100644 --- a/sys/dev/firewire/if_fwip.c +++ b/sys/dev/firewire/if_fwip.c @@ -107,19 +107,6 @@ SYSCTL_INT(_hw_firewire_fwip, OID_AUTO, rx_queue_len, CTLFLAG_RW, &rx_queue_len, TUNABLE_INT("hw.firewire.fwip.rx_queue_len", &rx_queue_len); #ifdef DEVICE_POLLING -#define FWIP_POLL_REGISTER(func, fwip, ifp) \ - if (ether_poll_register(func, ifp)) { \ - struct firewire_comm *fc = (fwip)->fd.fc; \ - fc->set_intr(fc, 0); \ - } - -#define FWIP_POLL_DEREGISTER(fwip, ifp) \ - do { \ - struct firewire_comm *fc = (fwip)->fd.fc; \ - ether_poll_deregister(ifp); \ - fc->set_intr(fc, 1); \ - } while(0) \ - static poll_handler_t fwip_poll; static void @@ -128,19 +115,15 @@ fwip_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct fwip_softc *fwip; struct firewire_comm *fc; + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + return; + fwip = ((struct fwip_eth_softc *)ifp->if_softc)->fwip; fc = fwip->fd.fc; - if (cmd == POLL_DEREGISTER) { - /* enable interrupts */ - fc->set_intr(fc, 1); - return; - } fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count); } -#else -#define FWIP_POLL_REGISTER(func, fwip, ifp) -#define FWIP_POLL_DEREGISTER(fwip, ifp) -#endif +#endif /* DEVICE_POLLING */ + static void fwip_identify(driver_t *driver, device_t parent) { @@ -214,6 +197,9 @@ fwip_attach(device_t dev) ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST| IFF_NEEDSGIANT); ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE; +#ifdef DEVICE_POLLING + ifp->if_capabilities |= IFCAP_POLLING; +#endif s = splimp(); firewire_ifattach(ifp, hwaddr); @@ -234,8 +220,6 @@ fwip_stop(struct fwip_softc *fwip) fc = fwip->fd.fc; - FWIP_POLL_DEREGISTER(fwip, ifp); - if (fwip->dma_ch >= 0) { xferq = fc->ir[fwip->dma_ch]; @@ -279,14 +263,22 @@ static int fwip_detach(device_t dev) { struct fwip_softc *fwip; + struct ifnet *ifp; int s; fwip = (struct fwip_softc *)device_get_softc(dev); + ifp = fwip->fw_softc.fwip_ifp; + +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + s = splimp(); fwip_stop(fwip); - firewire_ifdetach(fwip->fw_softc.fwip_ifp); - if_free(fwip->fw_softc.fwip_ifp); + firewire_ifdetach(ifp); + if_free(ifp); splx(s); return 0; @@ -408,7 +400,6 @@ found: ifp->if_flags &= ~IFF_OACTIVE; #endif - FWIP_POLL_REGISTER(fwip_poll, fwip, ifp); #if 0 /* attempt to start output */ fwip_start(ifp); @@ -444,7 +435,34 @@ fwip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCADDMULTI: case SIOCDELMULTI: break; - + case SIOCSIFCAP: +#ifdef DEVICE_POLLING + { + struct ifreq *ifr = (struct ifreq *) data; + struct firewire_comm *fc = fc = fwip->fd.fc; + + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(fwip_poll, ifp); + if (error) + return(error); + /* Disable interrupts */ + fc->set_intr(fc, 0); + ifp->if_capenable |= IFCAP_POLLING; + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + fc->set_intr(fc, 1); + ifp->if_capenable &= ~IFCAP_POLLING; + return (error); + } + } +#endif /* DEVICE_POLLING */ + break; #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 default: #else @@ -757,9 +775,7 @@ fwip_stream_input(struct fw_xferq *xferq) fwip = (struct fwip_softc *)xferq->sc; ifp = fwip->fw_softc.fwip_ifp; -#if 0 - FWIP_POLL_REGISTER(fwip_poll, fwip, ifp); -#endif + while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) { STAILQ_REMOVE_HEAD(&xferq->stvalid, link); fp = mtod(sxfer->mbuf, struct fw_pkt *); -- cgit v1.1