diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index bb1d0ac171a6..3f54d6add529 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -146,11 +146,6 @@ SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RW, extern char *syscallnames[]; #endif -#ifdef DEVICE_POLLING -extern u_int32_t poll_in_trap; -extern int ether_poll(int count); -#endif /* DEVICE_POLLING */ - /* * Exception, fault, and trap interface to the FreeBSD kernel. * This common code is called from assembly language IDT gate entry @@ -241,11 +236,6 @@ trap(frame) trap_fatal(&frame, frame.tf_addr); } -#ifdef DEVICE_POLLING - if (poll_in_trap) - ether_poll(poll_in_trap); -#endif /* DEVICE_POLLING */ - if (ISPL(frame.tf_cs) == SEL_UPL) { /* user trap */ diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c index 8a9e8c602046..a6f4304ae662 100644 --- a/sys/dev/dc/if_dc.c +++ b/sys/dev/dc/if_dc.c @@ -2265,10 +2265,10 @@ dc_attach(device_t dev) */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities |= IFCAP_VLAN_MTU; + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif - ifp->if_capenable = ifp->if_capabilities; callout_init_mtx(&sc->dc_stat_ch, &sc->dc_mtx, 0); @@ -2339,6 +2339,11 @@ dc_detach(device_t dev) ifp = sc->dc_ifp; +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { DC_LOCK(sc); @@ -2704,7 +2709,7 @@ dc_rxeof(struct dc_softc *sc) while (!(le32toh(sc->dc_ldata->dc_rx_list[i].dc_status) & DC_RXSTAT_OWN)) { #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) { + if (ifp->if_capenable & IFCAP_POLLING) { if (sc->rxcycles <= 0) break; sc->rxcycles--; @@ -3038,16 +3043,13 @@ dc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct dc_softc *sc = ifp->if_softc; - if (!(ifp->if_capenable & IFCAP_POLLING)) { - ether_poll_deregister(ifp); - cmd = POLL_DEREGISTER; - } - if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ - /* Re-enable interrupts. */ - CSR_WRITE_4(sc, DC_IMR, DC_INTRS); + DC_LOCK(sc); + + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + DC_UNLOCK(sc); return; } - DC_LOCK(sc); + sc->rxcycles = count; dc_rxeof(sc); dc_txeof(sc); @@ -3111,12 +3113,9 @@ dc_intr(void *arg) DC_LOCK(sc); ifp = sc->dc_ifp; #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) - goto done; - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(dc_poll, ifp)) { /* ok, disable interrupts */ - CSR_WRITE_4(sc, DC_IMR, 0x00000000); - goto done; + if (ifp->if_capenable & IFCAP_POLLING) { + DC_UNLOCK(sc); + return; } #endif @@ -3183,10 +3182,6 @@ dc_intr(void *arg) if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) dc_start_locked(ifp); -#ifdef DEVICE_POLLING -done: -#endif - DC_UNLOCK(sc); } @@ -3534,7 +3529,7 @@ dc_init_locked(struct dc_softc *sc) * the case of polling. Some cards (e.g. fxp) turn interrupts on * after a reset. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) CSR_WRITE_4(sc, DC_IMR, 0x00000000); else #endif @@ -3686,10 +3681,31 @@ dc_ioctl(struct ifnet *ifp, u_long command, caddr_t data) #endif break; case SIOCSIFCAP: - DC_LOCK(sc); - ifp->if_capenable &= ~IFCAP_POLLING; - ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; - DC_UNLOCK(sc); +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(dc_poll, ifp); + if (error) + return(error); + DC_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_4(sc, DC_IMR, 0x00000000); + ifp->if_capenable |= IFCAP_POLLING; + DC_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + DC_LOCK(sc); + CSR_WRITE_4(sc, DC_IMR, DC_INTRS); + ifp->if_capenable &= ~IFCAP_POLLING; + DC_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ break; default: error = ether_ioctl(ifp, command, data); @@ -3744,9 +3760,6 @@ dc_stop(struct dc_softc *sc) callout_stop(&sc->dc_stat_ch); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON | DC_NETCFG_TX_ON)); CSR_WRITE_4(sc, DC_IMR, 0x00000000); diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index f380e1e8face..3b5db5220c12 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -197,6 +197,9 @@ static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS); static void em_add_int_delay_sysctl(struct adapter *, const char *, const char *, struct em_int_delay_info *, int, int); +#ifdef DEVICE_POLLING +static poll_handler_t em_poll; +#endif /********************************************************************* * FreeBSD Device Interface Entry Points @@ -526,6 +529,11 @@ em_detach(device_t dev) INIT_DEBUGOUT("em_detach: begin"); +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + EM_LOCK(adapter); adapter->in_detach = 1; em_stop(adapter); @@ -717,7 +725,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) em_initialize_receive_unit(adapter); } #ifdef DEVICE_POLLING - if (!(ifp->if_flags & IFF_POLLING)) + if (!(ifp->if_capenable & IFCAP_POLLING)) #endif em_enable_intr(adapter); EM_UNLOCK(adapter); @@ -732,8 +740,26 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)"); reinit = 0; mask = ifr->ifr_reqcap ^ ifp->if_capenable; - 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(em_poll, ifp); + if (error) + return(error); + EM_LOCK(adapter); + em_disable_intr(adapter); + ifp->if_capenable |= IFCAP_POLLING; + EM_UNLOCK(adapter); + } else { + error = ether_poll_deregister(ifp); + /* Enable interrupt even in error case */ + EM_LOCK(adapter); + em_enable_intr(adapter); + ifp->if_capenable &= ~IFCAP_POLLING; + EM_UNLOCK(adapter); + } + } +#endif if (mask & IFCAP_HWCSUM) { ifp->if_capenable ^= IFCAP_HWCSUM; reinit = 1; @@ -895,7 +921,7 @@ em_init_locked(struct adapter * adapter) * Only enable interrupts if we are not polling, make sure * they are off otherwise. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) em_disable_intr(adapter); else #endif /* DEVICE_POLLING */ @@ -920,8 +946,6 @@ em_init(void *arg) #ifdef DEVICE_POLLING -static poll_handler_t em_poll; - static void em_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) { @@ -930,14 +954,6 @@ em_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) mtx_assert(&adapter->mtx, MA_OWNED); - if (!(ifp->if_capenable & IFCAP_POLLING)) { - ether_poll_deregister(ifp); - cmd = POLL_DEREGISTER; - } - if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ - em_enable_intr(adapter); - return; - } if (cmd == POLL_AND_CHECK_STATUS) { reg_icr = E1000_READ_REG(&adapter->hw, ICR); if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { @@ -948,13 +964,10 @@ em_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) callout_reset(&adapter->timer, hz, em_local_timer, adapter); } } - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - em_process_receive_interrupts(adapter, count); - em_clean_transmit_interrupts(adapter); - } + em_process_receive_interrupts(adapter, count); + em_clean_transmit_interrupts(adapter); - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) em_start_locked(ifp); } @@ -964,7 +977,8 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct adapter *adapter = ifp->if_softc; EM_LOCK(adapter); - em_poll_locked(ifp, cmd, count); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + em_poll_locked(ifp, cmd, count); EM_UNLOCK(adapter); } #endif /* DEVICE_POLLING */ @@ -987,18 +1001,10 @@ em_intr(void *arg) ifp = adapter->ifp; #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) { + if (ifp->if_capenable & IFCAP_POLLING) { EM_UNLOCK(adapter); return; } - - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(em_poll, ifp)) { - em_disable_intr(adapter); - em_poll_locked(ifp, 0, 1); - EM_UNLOCK(adapter); - return; - } #endif /* DEVICE_POLLING */ reg_icr = E1000_READ_REG(&adapter->hw, ICR); @@ -1718,9 +1724,7 @@ em_stop(void *arg) mtx_assert(&adapter->mtx, MA_OWNED); INIT_DEBUGOUT("em_stop: begin"); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif + em_disable_intr(adapter); em_reset_hw(&adapter->hw); callout_stop(&adapter->timer); @@ -1976,7 +1980,6 @@ em_setup_interface(device_t dev, struct adapter * adapter) #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; - ifp->if_capenable |= IFCAP_POLLING; #endif /* diff --git a/sys/dev/firewire/00README b/sys/dev/firewire/00README index d879f31a6b15..a6536ae61405 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 e9d9107b4b4d..1bf1bcd4b12f 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 @@ fwe_init(void *arg) 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 20916bc74300..b3fdda422b63 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 @@ fwip_init(void *arg) 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 *); diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index 944876dc3c71..133a96a70121 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: diff --git a/sys/dev/ixgb/README b/sys/dev/ixgb/README index 33f85a7c9bd8..1508eac95c44 100644 --- a/sys/dev/ixgb/README +++ b/sys/dev/ixgb/README @@ -196,18 +196,17 @@ all PRO/10GbE adapters. options DEVICE_POLLING options HZ=1000 - At runtime, use the following command to turn on polling mode. Similarly, - turn off polling mode by setting the variable to 0: + At runtime, use the following command to turn on polling mode. - sysctl kern.polling.enable=1 + ifconfig ixgb0 polling + Similarly, turn off polling mode by removing IFCAP_POLLING flag from + interface: - NOTES: DEVICE POLLING is only valid for non-SMP kernels. - - The driver has to be built into the kernel for DEVICE POLLING to be - enabled in the driver. - + ifconfig ixgb0 -polling + The driver has to be built into the kernel for DEVICE POLLING to be + enabled in the driver. Support ======= diff --git a/sys/dev/ixgb/if_ixgb.c b/sys/dev/ixgb/if_ixgb.c index 4cb9caa393c2..d273542b9185 100644 --- a/sys/dev/ixgb/if_ixgb.c +++ b/sys/dev/ixgb/if_ixgb.c @@ -141,6 +141,9 @@ static int ixgb_dma_malloc(struct adapter *, bus_size_t, struct ixgb_dma_alloc *, int); static void ixgb_dma_free(struct adapter *, struct ixgb_dma_alloc *); +#ifdef DEVICE_POLLING +static poll_handler_t ixgb_poll; +#endif /********************************************************************* * FreeBSD Device Interface Entry Points @@ -368,6 +371,11 @@ ixgb_detach(device_t dev) INIT_DEBUGOUT("ixgb_detach: begin"); +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + IXGB_LOCK(adapter); adapter->in_detach = 1; @@ -557,6 +565,26 @@ ixgb_ioctl(struct ifnet * ifp, IOCTL_CMD_TYPE command, caddr_t data) case SIOCSIFCAP: IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)"); mask = ifr->ifr_reqcap ^ ifp->if_capenable; +#ifdef DEVICE_POLLING + if (mask & IFCAP_POLLING) { + if (ifr->ifr_reqcap & IFCAP_POLLING) { + error = ether_poll_register(ixgb_poll, ifp); + if (error) + return(error); + IXGB_LOCK(adapter); + ixgb_disable_intr(adapter); + ifp->if_capenable |= IFCAP_POLLING; + IXGB_UNLOCK(adapter); + } else { + error = ether_poll_deregister(ifp); + /* Enable interrupt even in error case */ + IXGB_LOCK(adapter); + ixgb_enable_intr(adapter); + ifp->if_capenable &= ~IFCAP_POLLING; + IXGB_UNLOCK(adapter); + } + } +#endif /* DEVICE_POLLING */ if (mask & IFCAP_HWCSUM) { if (IFCAP_HWCSUM & ifp->if_capenable) ifp->if_capenable &= ~IFCAP_HWCSUM; @@ -695,10 +723,10 @@ ixgb_init_locked(struct adapter *adapter) * Only disable interrupts if we are polling, make sure they are on * otherwise. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) ixgb_disable_intr(adapter); else -#endif /* DEVICE_POLLING */ +#endif ixgb_enable_intr(adapter); return; @@ -716,8 +744,6 @@ ixgb_init(void *arg) } #ifdef DEVICE_POLLING -static poll_handler_t ixgb_poll; - static void ixgb_poll_locked(struct ifnet * ifp, enum poll_cmd cmd, int count) { @@ -726,15 +752,6 @@ ixgb_poll_locked(struct ifnet * ifp, enum poll_cmd cmd, int count) IXGB_LOCK_ASSERT(adapter); - if (!(ifp->if_capenable & IFCAP_POLLING)) { - ether_poll_deregister(ifp); - cmd = POLL_DEREGISTER; - } - - if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ - ixgb_enable_intr(adapter); - return; - } if (cmd == POLL_AND_CHECK_STATUS) { reg_icr = IXGB_READ_REG(&adapter->hw, ICR); if (reg_icr & (IXGB_INT_RXSEQ | IXGB_INT_LSC)) { @@ -745,12 +762,10 @@ ixgb_poll_locked(struct ifnet * ifp, enum poll_cmd cmd, int count) adapter); } } - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - ixgb_process_receive_interrupts(adapter, count); - ixgb_clean_transmit_interrupts(adapter); - } - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - ifp->if_snd.ifq_head != NULL) + ixgb_process_receive_interrupts(adapter, count); + ixgb_clean_transmit_interrupts(adapter); + + if (ifp->if_snd.ifq_head != NULL) ixgb_start_locked(ifp); } @@ -760,10 +775,11 @@ ixgb_poll(struct ifnet * ifp, enum poll_cmd cmd, int count) struct adapter *adapter = ifp->if_softc; IXGB_LOCK(adapter); - ixgb_poll_locked(ifp, cmd, count); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ixgb_poll_locked(ifp, cmd, count); IXGB_UNLOCK(adapter); } -#endif /* DEVICE_POLLING */ +#endif /* DEVICE_POLLING */ /********************************************************************* * @@ -785,19 +801,11 @@ ixgb_intr(void *arg) ifp = adapter->ifp; #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) { + if (ifp->if_capenable & IFCAP_POLLING) { IXGB_UNLOCK(adapter); return; } - - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(ixgb_poll, ifp)) { - ixgb_disable_intr(adapter); - ixgb_poll_locked(ifp, 0, 1); - IXGB_UNLOCK(adapter); - return; - } -#endif /* DEVICE_POLLING */ +#endif reg_icr = IXGB_READ_REG(&adapter->hw, ICR); if (reg_icr == 0) { @@ -1355,9 +1363,6 @@ ixgb_setup_interface(device_t dev, struct adapter * adapter) #endif ifp->if_capabilities = IFCAP_HWCSUM; -#ifdef DEVICE_POLLING - ifp->if_capabilities |= IFCAP_POLLING; -#endif /* * Tell the upper layer(s) we support long frames. @@ -1370,6 +1375,10 @@ ixgb_setup_interface(device_t dev, struct adapter * adapter) ifp->if_capenable = ifp->if_capabilities; +#ifdef DEVICE_POLLING + ifp->if_capabilities |= IFCAP_POLLING; +#endif + /* * Specify the media types supported by this adapter and register * callbacks to update media and link information diff --git a/sys/dev/nge/if_nge.c b/sys/dev/nge/if_nge.c index a14d4ef080e4..e8a89ea43dd2 100644 --- a/sys/dev/nge/if_nge.c +++ b/sys/dev/nge/if_nge.c @@ -869,10 +869,10 @@ nge_attach(dev) ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1; ifp->if_hwassist = NGE_CSUM_FEATURES; ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING; + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif - ifp->if_capenable = ifp->if_capabilities; /* * Do MII setup. @@ -958,6 +958,10 @@ nge_detach(dev) sc = device_get_softc(dev); ifp = sc->nge_ifp; +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif NGE_LOCK(sc); nge_reset(sc); nge_stop(sc); @@ -1126,12 +1130,12 @@ nge_rxeof(sc) u_int32_t extsts; #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->nge_ldata->nge_rx_list[i]; rxstat = cur_rx->nge_rxstat; @@ -1376,12 +1380,7 @@ nge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct nge_softc *sc = ifp->if_softc; NGE_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_4(sc, NGE_IER, 1); + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { NGE_UNLOCK(sc); return; } @@ -1433,18 +1432,11 @@ nge_intr(arg) NGE_LOCK(sc); #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) { + if (ifp->if_capenable & IFCAP_POLLING) { NGE_UNLOCK(sc); return; } - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(nge_poll, ifp)) { /* ok, disable interrupts */ - CSR_WRITE_4(sc, NGE_IER, 0); - NGE_UNLOCK(sc); - nge_poll(ifp, 0, 1); - return; - } -#endif /* DEVICE_POLLING */ +#endif /* Supress unwanted interrupts */ if (!(ifp->if_flags & IFF_UP)) { @@ -1840,10 +1832,10 @@ nge_init_locked(sc) * ... only enable interrupts if we are not polling, make sure * they are off otherwise. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) CSR_WRITE_4(sc, NGE_IER, 0); else -#endif /* DEVICE_POLLING */ +#endif CSR_WRITE_4(sc, NGE_IER, 1); /* Enable receiver and transmitter. */ @@ -2047,8 +2039,31 @@ nge_ioctl(ifp, command, data) } break; case SIOCSIFCAP: - ifp->if_capenable &= ~IFCAP_POLLING; - ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(nge_poll, ifp); + if (error) + return(error); + NGE_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_4(sc, NGE_IER, 0); + ifp->if_capenable |= IFCAP_POLLING; + NGE_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + NGE_LOCK(sc); + CSR_WRITE_4(sc, NGE_IER, 1); + ifp->if_capenable &= ~IFCAP_POLLING; + NGE_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ break; default: error = ether_ioctl(ifp, command, data); @@ -2105,9 +2120,6 @@ nge_stop(sc) } callout_stop(&sc->nge_stat_ch); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif CSR_WRITE_4(sc, NGE_IER, 0); CSR_WRITE_4(sc, NGE_IMR, 0); NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c index c3ce9d7ffb7f..72fff4ec1ff2 100644 --- a/sys/dev/re/if_re.c +++ b/sys/dev/re/if_re.c @@ -1202,6 +1202,7 @@ re_attach(dev) ifp->if_start = re_start; ifp->if_hwassist = /*RE_CSUM_FEATURES*/0; ifp->if_capabilities |= IFCAP_HWCSUM|IFCAP_VLAN_HWTAGGING; + ifp->if_capenable = ifp->if_capabilities & ~IFCAP_HWCSUM; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif @@ -1214,7 +1215,6 @@ re_attach(dev) IFQ_SET_MAXLEN(&ifp->if_snd, RL_IFQ_MAXLEN); ifp->if_snd.ifq_drv_maxlen = RL_IFQ_MAXLEN; IFQ_SET_READY(&ifp->if_snd); - ifp->if_capenable = ifp->if_capabilities & ~IFCAP_HWCSUM; /* * Call MI attach routine. @@ -1264,6 +1264,11 @@ re_detach(dev) ifp = sc->rl_ifp; KASSERT(mtx_initialized(&sc->rl_mtx), ("re mutex not initialized")); +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { RL_LOCK(sc); @@ -1756,7 +1761,8 @@ re_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct rl_softc *sc = ifp->if_softc; RL_LOCK(sc); - re_poll_locked(ifp, cmd, count); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + re_poll_locked(ifp, cmd, count); RL_UNLOCK(sc); } @@ -1767,15 +1773,6 @@ re_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) RL_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, RL_IMR, RL_INTRS_CPLUS); - return; - } - sc->rxcycles = count; re_rxeof(sc); re_txeof(sc); @@ -1822,15 +1819,9 @@ re_intr(arg) goto done_locked; #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) goto done_locked; - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(re_poll, ifp)) { /* ok, disable interrupts */ - CSR_WRITE_2(sc, RL_IMR, 0x0000); - re_poll_locked(ifp, 0, 1); - goto done_locked; - } -#endif /* DEVICE_POLLING */ +#endif for (;;) { @@ -2171,10 +2162,10 @@ re_init_locked(sc) /* * Disable interrupts if we are polling. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) CSR_WRITE_2(sc, RL_IMR, 0); else /* otherwise ... */ -#endif /* DEVICE_POLLING */ +#endif /* * Enable interrupts. */ @@ -2289,7 +2280,7 @@ re_ioctl(ifp, command, data) struct rl_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; struct mii_data *mii; - int error; + int error = 0; switch (command) { case SIOCSIFMTU: @@ -2298,7 +2289,6 @@ re_ioctl(ifp, command, data) error = EINVAL; ifp->if_mtu = ifr->ifr_mtu; RL_UNLOCK(sc); - error = 0; break; case SIOCSIFFLAGS: RL_LOCK(sc); @@ -2307,14 +2297,12 @@ re_ioctl(ifp, command, data) else if (ifp->if_drv_flags & IFF_DRV_RUNNING) re_stop(sc); RL_UNLOCK(sc); - error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: RL_LOCK(sc); re_setmulti(sc); RL_UNLOCK(sc); - error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: @@ -2322,18 +2310,42 @@ re_ioctl(ifp, command, data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: - RL_LOCK(sc); - ifp->if_capenable &= ~(IFCAP_HWCSUM | IFCAP_POLLING); - ifp->if_capenable |= - ifr->ifr_reqcap & (IFCAP_HWCSUM | IFCAP_POLLING); - if (ifp->if_capenable & IFCAP_TXCSUM) - ifp->if_hwassist = RE_CSUM_FEATURES; - else - ifp->if_hwassist = 0; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - re_init_locked(sc); - RL_UNLOCK(sc); - error = 0; + { + int mask = ifr->ifr_reqcap ^ ifp->if_capenable; +#ifdef DEVICE_POLLING + if (mask & IFCAP_POLLING) { + if (ifr->ifr_reqcap & IFCAP_POLLING) { + error = ether_poll_register(re_poll, ifp); + if (error) + return(error); + RL_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_2(sc, RL_IMR, 0x0000); + ifp->if_capenable |= IFCAP_POLLING; + RL_UNLOCK(sc); + + } else { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + RL_LOCK(sc); + CSR_WRITE_2(sc, RL_IMR, RL_INTRS_CPLUS); + ifp->if_capenable &= ~IFCAP_POLLING; + RL_UNLOCK(sc); + } + } +#endif /* DEVICE_POLLING */ + if (mask & IFCAP_HWCSUM) { + RL_LOCK(sc); + ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_HWCSUM; + if (ifp->if_capenable & IFCAP_TXCSUM) + ifp->if_hwassist = RE_CSUM_FEATURES; + else + ifp->if_hwassist = 0; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + re_init_locked(sc); + RL_UNLOCK(sc); + } + } break; default: error = ether_ioctl(ifp, command, data); @@ -2379,9 +2391,6 @@ re_stop(sc) callout_stop(&sc->rl_stat_callout); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* DEVICE_POLLING */ CSR_WRITE_1(sc, RL_COMMAND, 0x00); CSR_WRITE_2(sc, RL_IMR, 0x0000); diff --git a/sys/dev/sf/if_sf.c b/sys/dev/sf/if_sf.c index fa7eb83a71cc..691a0f665006 100644 --- a/sys/dev/sf/if_sf.c +++ b/sys/dev/sf/if_sf.c @@ -165,11 +165,9 @@ static int sf_miibus_readreg(device_t, int, int); static int sf_miibus_writereg(device_t, int, int, int); static void sf_miibus_statchg(device_t); #ifdef DEVICE_POLLING -static void sf_poll(struct ifnet *ifp, enum poll_cmd cmd, - int count); -static void sf_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, - int count); -#endif /* DEVICE_POLLING */ +static void sf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count); +static void sf_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count); +#endif static u_int32_t csr_read_4(struct sf_softc *, int); static void csr_write_4(struct sf_softc *, int, u_int32_t); @@ -560,10 +558,31 @@ sf_ioctl(ifp, command, data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: - SF_LOCK(sc); - ifp->if_capenable &= ~IFCAP_POLLING; - ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; - SF_UNLOCK(sc); +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(sf_poll, ifp); + if (error) + return(error); + SF_LOCK(sc); + /* Disable interrupts */ + csr_write_4(sc, SF_IMR, 0x00000000); + ifp->if_capenable |= IFCAP_POLLING; + SF_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + SF_LOCK(sc); + csr_write_4(sc, SF_IMR, SF_INTRS); + ifp->if_capenable &= ~IFCAP_POLLING; + SF_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ break; default: error = ether_ioctl(ifp, command, data); @@ -749,10 +768,10 @@ sf_attach(dev) IFQ_SET_MAXLEN(&ifp->if_snd, SF_TX_DLIST_CNT - 1); ifp->if_snd.ifq_drv_maxlen = SF_TX_DLIST_CNT - 1; IFQ_SET_READY(&ifp->if_snd); + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; -#endif /* DEVICE_POLLING */ - ifp->if_capenable = ifp->if_capabilities; +#endif /* * Call MI attach routine. @@ -794,6 +813,11 @@ sf_detach(dev) KASSERT(mtx_initialized(&sc->sf_mtx), ("sf mutex not initialized")); ifp = sc->sf_ifp; +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { SF_LOCK(sc); @@ -946,12 +970,12 @@ sf_rxeof(sc) struct mbuf *m0; #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->sf_ldata->sf_rx_clist[cmpconsidx]; desc = &sc->sf_ldata->sf_rx_dlist_big[cur_rx->sf_endidx]; @@ -1068,7 +1092,8 @@ sf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct sf_softc *sc = ifp->if_softc; SF_LOCK(sc); - sf_poll_locked(ifp, cmd, count); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + sf_poll_locked(ifp, cmd, count); SF_UNLOCK(sc); } @@ -1079,17 +1104,6 @@ sf_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) SF_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_4(sc, SF_IMR, SF_INTRS); - return; - } - sc->rxcycles = count; sf_rxeof(sc); sf_txeof(sc); @@ -1131,17 +1145,11 @@ sf_intr(arg) ifp = sc->sf_ifp; #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) - goto done_locked; - - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(sf_poll, ifp)) { - /* OK, disable interrupts. */ - csr_write_4(sc, SF_IMR, 0x00000000); - sf_poll_locked(ifp, 0, 1); - goto done_locked; + if (ifp->if_capenable & IFCAP_POLLING) { + SF_UNLOCK(sc); + return; } -#endif /* DEVICE_POLLING */ +#endif if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED)) { SF_UNLOCK(sc); @@ -1185,9 +1193,6 @@ sf_intr(arg) if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) sf_start_locked(ifp); -#ifdef DEVICE_POLLING -done_locked: -#endif /* DEVICE_POLLING */ SF_UNLOCK(sc); } @@ -1296,10 +1301,10 @@ sf_init_locked(sc) #ifdef DEVICE_POLLING /* Disable interrupts if we are polling. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) csr_write_4(sc, SF_IMR, 0x00000000); else -#endif /* DEVICE_POLLING */ +#endif /* Enable interrupts. */ csr_write_4(sc, SF_IMR, SF_INTRS); @@ -1478,10 +1483,6 @@ sf_stop(sc) callout_stop(&sc->sf_stat_callout); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* DEVICE_POLLING */ - csr_write_4(sc, SF_GEN_ETH_CTL, 0); csr_write_4(sc, SF_CQ_CONSIDX, 0); csr_write_4(sc, SF_CQ_PRODIDX, 0); diff --git a/sys/dev/vge/if_vge.c b/sys/dev/vge/if_vge.c index 0780bc527f60..9101945efe48 100644 --- a/sys/dev/vge/if_vge.c +++ b/sys/dev/vge/if_vge.c @@ -1051,16 +1051,14 @@ vge_attach(dev) ifp->if_start = vge_start; ifp->if_hwassist = VGE_CSUM_FEATURES; ifp->if_capabilities |= IFCAP_HWCSUM|IFCAP_VLAN_HWTAGGING; + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING -#ifdef IFCAP_POLLING ifp->if_capabilities |= IFCAP_POLLING; -#endif #endif ifp->if_watchdog = vge_watchdog; ifp->if_init = vge_init; ifp->if_baudrate = 1000000000; ifp->if_snd.ifq_maxlen = VGE_IFQ_MAXLEN; - ifp->if_capenable = ifp->if_capabilities; TASK_INIT(&sc->vge_txtask, 0, vge_tx_task, ifp); @@ -1105,6 +1103,11 @@ vge_detach(dev) KASSERT(mtx_initialized(&sc->vge_mtx), ("vge mutex not initialized")); ifp = sc->vge_ifp; +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { vge_stop(sc); @@ -1351,12 +1354,12 @@ vge_rxeof(sc) while (!VGE_OWN(&sc->vge_ldata.vge_rx_list[i])) { #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->vge_ldata.vge_rx_list[i]; m = sc->vge_ldata.vge_rx_mbuf[i]; @@ -1617,18 +1620,8 @@ vge_poll (struct ifnet *ifp, enum poll_cmd cmd, int count) struct vge_softc *sc = ifp->if_softc; VGE_LOCK(sc); -#ifdef IFCAP_POLLING - if (!(ifp->if_capenable & IFCAP_POLLING)) { - ether_poll_deregister(ifp); - cmd = POLL_DEREGISTER; - } -#endif - if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ - CSR_WRITE_4(sc, VGE_IMR, VGE_INTRS); - CSR_WRITE_4(sc, VGE_ISR, 0xFFFFFFFF); - CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK); + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) goto done; - } sc->rxcycles = count; vge_rxeof(sc); @@ -1692,20 +1685,11 @@ vge_intr(arg) } #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) - goto done; - if ( -#ifdef IFCAP_POLLING - (ifp->if_capenable & IFCAP_POLLING) && -#endif - ether_poll_register(vge_poll, ifp)) { /* ok, disable interrupts */ - CSR_WRITE_4(sc, VGE_IMR, 0); - CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); - vge_poll(ifp, 0, 1); - goto done; + if (ifp->if_capenable & IFCAP_POLLING) { + VGE_UNLOCK(sc); + return; } - -#endif /* DEVICE_POLLING */ +#endif /* Disable interrupts */ CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); @@ -1745,9 +1729,6 @@ vge_intr(arg) /* Re-enable interrupts */ CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK); -#ifdef DEVICE_POLLING -done: -#endif VGE_UNLOCK(sc); #if __FreeBSD_version < 502114 @@ -2104,11 +2085,11 @@ vge_init(xsc) /* * Disable interrupts if we are polling. */ - if (ifp->if_flags & IFF_POLLING) { + if (ifp->if_capenable & IFCAP_POLLING) { CSR_WRITE_4(sc, VGE_IMR, 0); CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); } else /* otherwise ... */ -#endif /* DEVICE_POLLING */ +#endif { /* * Enable interrupts. @@ -2268,23 +2249,42 @@ vge_ioctl(ifp, command, data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: -#ifdef IFCAP_POLLING - ifp->if_capenable &= ~(IFCAP_HWCSUM | IFCAP_POLLING); -#else - ifp->if_capenable &= ~(IFCAP_HWCSUM); -#endif - ifp->if_capenable |= -#ifdef IFCAP_POLLING - ifr->ifr_reqcap & (IFCAP_HWCSUM | IFCAP_POLLING); -#else - ifr->ifr_reqcap & (IFCAP_HWCSUM); -#endif - if (ifp->if_capenable & IFCAP_TXCSUM) - ifp->if_hwassist = VGE_CSUM_FEATURES; - else - ifp->if_hwassist = 0; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - vge_init(sc); + { + int mask = ifr->ifr_reqcap ^ ifp->if_capenable; +#ifdef DEVICE_POLLING + if (mask & IFCAP_POLLING) { + if (ifr->ifr_reqcap & IFCAP_POLLING) { + error = ether_poll_register(vge_poll, ifp); + if (error) + return(error); + VGE_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_4(sc, VGE_IMR, 0); + CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); + ifp->if_capenable |= IFCAP_POLLING; + VGE_UNLOCK(sc); + } else { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + VGE_LOCK(sc); + CSR_WRITE_4(sc, VGE_IMR, VGE_INTRS); + CSR_WRITE_4(sc, VGE_ISR, 0xFFFFFFFF); + CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK); + ifp->if_capenable &= ~IFCAP_POLLING; + VGE_UNLOCK(sc); + } + } +#endif /* DEVICE_POLLING */ + if (mask & IFCAP_HWCSUM) { + ifp->if_capenable |= ifr->ifr_reqcap & (IFCAP_HWCSUM); + if (ifp->if_capenable & IFCAP_TXCSUM) + ifp->if_hwassist = VGE_CSUM_FEATURES; + else + ifp->if_hwassist = 0; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + vge_init(sc); + } + } break; default: error = ether_ioctl(ifp, command, data); @@ -2331,9 +2331,6 @@ vge_stop(sc) ifp->if_timer = 0; ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* DEVICE_POLLING */ CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); CSR_WRITE_1(sc, VGE_CRS0, VGE_CR0_STOP); diff --git a/sys/dev/vr/if_vr.c b/sys/dev/vr/if_vr.c index 5eabc21dafa1..b3c92eae4f75 100644 --- a/sys/dev/vr/if_vr.c +++ b/sys/dev/vr/if_vr.c @@ -742,10 +742,10 @@ vr_attach(dev) IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1); ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; IFQ_SET_READY(&ifp->if_snd); + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif - ifp->if_capenable = ifp->if_capabilities; /* Do MII setup. */ if (mii_phy_probe(dev, &sc->vr_miibus, @@ -794,6 +794,11 @@ vr_detach(device_t dev) KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + VR_LOCK(sc); sc->suspended = 1; @@ -952,12 +957,12 @@ vr_rxeof(struct vr_softc *sc) while (!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & VR_RXSTAT_OWN)) { #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 m0 = NULL; cur_rx = sc->vr_cdata.vr_rx_head; sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; @@ -1151,7 +1156,8 @@ vr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct vr_softc *sc = ifp->if_softc; VR_LOCK(sc); - vr_poll_locked(ifp, cmd, count); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + vr_poll_locked(ifp, cmd, count); VR_UNLOCK(sc); } @@ -1162,17 +1168,6 @@ vr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) VR_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, VR_IMR, VR_INTRS); - return; - } - sc->rxcycles = count; vr_rxeof(sc); vr_txeof(sc); @@ -1249,17 +1244,9 @@ vr_intr(void *arg) } #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) goto done_locked; - - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(vr_poll, ifp)) { - /* OK, disable interrupts. */ - CSR_WRITE_2(sc, VR_IMR, 0x0000); - vr_poll_locked(ifp, 0, 1); - goto done_locked; - } -#endif /* DEVICE_POLLING */ +#endif /* Suppress unwanted interrupts. */ if (!(ifp->if_flags & IFF_UP)) { @@ -1534,10 +1521,10 @@ vr_init_locked(struct vr_softc *sc) /* * Disable interrupts if we are polling. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) CSR_WRITE_2(sc, VR_IMR, 0); else -#endif /* DEVICE_POLLING */ +#endif /* * Enable interrupts. */ @@ -1615,7 +1602,31 @@ vr_ioctl(struct ifnet *ifp, u_long command, caddr_t data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: - ifp->if_capenable = ifr->ifr_reqcap; +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(vr_poll, ifp); + if (error) + return(error); + VR_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_2(sc, VR_IMR, 0x0000); + ifp->if_capenable |= IFCAP_POLLING; + VR_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + VR_LOCK(sc); + CSR_WRITE_2(sc, VR_IMR, VR_INTRS); + ifp->if_capenable &= ~IFCAP_POLLING; + VR_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ break; default: error = ether_ioctl(ifp, command, data); @@ -1662,9 +1673,6 @@ vr_stop(struct vr_softc *sc) untimeout(vr_tick, sc, sc->vr_stat_ch); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* DEVICE_POLLING */ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 1e5a3465c79f..6ab47a51046b 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -160,11 +160,6 @@ SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RW, extern char *syscallnames[]; #endif -#ifdef DEVICE_POLLING -extern u_int32_t poll_in_trap; -extern int ether_poll(int count); -#endif /* DEVICE_POLLING */ - /* * Exception, fault, and trap interface to the FreeBSD kernel. * This common code is called from assembly language IDT gate entry @@ -272,11 +267,6 @@ trap(frame) trap_fatal(&frame, eva); } -#ifdef DEVICE_POLLING - if (poll_in_trap) - ether_poll(poll_in_trap); -#endif /* DEVICE_POLLING */ - if ((ISPL(frame.tf_cs) == SEL_UPL) || ((frame.tf_eflags & PSL_VM) && !(PCPU_GET(curpcb)->pcb_flags & PCB_VM86CALL))) { diff --git a/sys/kern/kern_poll.c b/sys/kern/kern_poll.c index 520ee521853c..71e6ff459bf2 100644 --- a/sys/kern/kern_poll.c +++ b/sys/kern/kern_poll.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include #include #include /* needed by net/if.h */ +#include #include #include @@ -44,14 +45,15 @@ __FBSDID("$FreeBSD$"); static void netisr_poll(void); /* the two netisr handlers */ static void netisr_pollmore(void); +static int poll_switch(SYSCTL_HANDLER_ARGS); void hardclock_device_poll(void); /* hook from hardclock */ -void ether_poll(int); /* polling while in trap */ +void ether_poll(int); /* polling in idle loop */ /* * Polling support for [network] device drivers. * - * Drivers which support this feature try to register with the + * Drivers which support this feature can register with the * polling code. * * If registration is successful, the driver must disable interrupts, @@ -64,10 +66,6 @@ void ether_poll(int); /* polling while in trap */ * POLL_AND_CHECK_STATUS: as above, plus check status registers or do * other more expensive operations. This command is issued periodically * but less frequently than POLL_ONLY. - * POLL_DEREGISTER: deregister and return to interrupt mode. - * - * The first two commands are only issued if the interface is marked as - * 'IFF_UP and IFF_DRV_RUNNING', the last one only if IFF_DRV_RUNNING is set. * * The count limit specifies how much work the handler can do during the * call -- typically this is the number of packets to be received, or @@ -75,11 +73,9 @@ void ether_poll(int); /* polling while in trap */ * as the max time spent in the function grows roughly linearly with the * count). * - * Deregistration can be requested by the driver itself (typically in the - * *_stop() routine), or by the polling code, by invoking the handler. - * - * Polling can be globally enabled or disabled with the sysctl variable - * kern.polling.enable (default is 0, disabled) + * Polling is enabled and disabled via setting IFCAP_POLLING flag on + * the interface. The driver ioctl handler should register interface + * with polling and disable interrupts, if registration was successful. * * A second variable controls the sharing of CPU between polling/kernel * network processing, and other activities (typically userlevel tasks): @@ -91,7 +87,7 @@ void ether_poll(int); /* polling while in trap */ * The following constraints hold * * 1 <= poll_each_burst <= poll_burst <= poll_burst_max - * 0 <= poll_in_trap <= poll_each_burst + * 0 <= poll_each_burst * MIN_POLL_BURST_MAX <= poll_burst_max <= MAX_POLL_BURST_MAX */ @@ -117,10 +113,6 @@ static u_int32_t poll_in_idle_loop=0; /* do we poll in idle loop ? */ SYSCTL_UINT(_kern_polling, OID_AUTO, idle_poll, CTLFLAG_RW, &poll_in_idle_loop, 0, "Enable device polling in idle loop"); -u_int32_t poll_in_trap; /* used in trap.c */ -SYSCTL_UINT(_kern_polling, OID_AUTO, poll_in_trap, CTLFLAG_RW, - &poll_in_trap, 0, "Poll burst size during a trap"); - static u_int32_t user_frac = 50; SYSCTL_UINT(_kern_polling, OID_AUTO, user_frac, CTLFLAG_RW, &user_frac, 0, "Desired user fraction of cpu time"); @@ -149,9 +141,9 @@ static u_int32_t poll_handlers; /* next free entry in pr[]. */ SYSCTL_UINT(_kern_polling, OID_AUTO, handlers, CTLFLAG_RD, &poll_handlers, 0, "Number of registered poll handlers"); -static int polling = 0; /* global polling enable */ -SYSCTL_UINT(_kern_polling, OID_AUTO, enable, CTLFLAG_RW, - &polling, 0, "Polling enabled"); +static int polling = 0; +SYSCTL_PROC(_kern_polling, OID_AUTO, enable, CTLTYPE_UINT | CTLFLAG_RW, + 0, sizeof(int), poll_switch, "I", "Switch polling for all interfaces"); static u_int32_t phase; SYSCTL_UINT(_kern_polling, OID_AUTO, phase, CTLFLAG_RW, @@ -174,23 +166,9 @@ SYSCTL_UINT(_kern_polling, OID_AUTO, idlepoll_sleeping, CTLFLAG_RD, struct pollrec { poll_handler_t *handler; struct ifnet *ifp; - /* - * Flags of polling record (protected by poll_mtx). - * PRF_RUNNING means that the handler is now executing. - * PRF_LEAVING means that the handler is now deregistering. - */ -#define PRF_RUNNING 0x1 -#define PRF_LEAVING 0x2 - uint32_t flags; }; static struct pollrec pr[POLL_LIST_LEN]; - -#define PR_VALID(i) (pr[(i)].handler != NULL && \ - !(pr[(i)].flags & (PRF_RUNNING|PRF_LEAVING)) && \ - (pr[(i)].ifp->if_drv_flags & IFF_DRV_RUNNING) &&\ - (pr[(i)].ifp->if_flags & IFF_UP)) - static struct mtx poll_mtx; static void @@ -258,30 +236,24 @@ hardclock_device_poll(void) } /* - * ether_poll is called from the idle loop or from the trap handler. + * ether_poll is called from the idle loop. */ void ether_poll(int count) { int i; + NET_LOCK_GIANT(); mtx_lock(&poll_mtx); if (count > poll_each_burst) count = poll_each_burst; - for (i = 0 ; i < poll_handlers ; i++) { - if (PR_VALID(i)) { - pr[i].flags |= PRF_RUNNING; - mtx_unlock(&poll_mtx); - NET_LOCK_GIANT(); - pr[i].handler(pr[i].ifp, POLL_ONLY, count); - NET_UNLOCK_GIANT(); - mtx_lock(&poll_mtx); - pr[i].flags &= ~PRF_RUNNING; - } - } + for (i = 0 ; i < poll_handlers ; i++) + pr[i].handler(pr[i].ifp, POLL_ONLY, count); + mtx_unlock(&poll_mtx); + NET_UNLOCK_GIANT(); } /* @@ -403,60 +375,29 @@ netisr_poll(void) residual_burst : poll_each_burst; residual_burst -= cycles; - if (polling) { - for (i = 0 ; i < poll_handlers ; i++) { - if (PR_VALID(i)) { - pr[i].flags |= PRF_RUNNING; - mtx_unlock(&poll_mtx); - pr[i].handler(pr[i].ifp, arg, cycles); - mtx_lock(&poll_mtx); - pr[i].flags &= ~PRF_RUNNING; - } - } - } else { /* unregister */ - for (i = 0 ; i < poll_handlers ; i++) { - if (pr[i].handler != NULL && - pr[i].ifp->if_drv_flags & IFF_DRV_RUNNING) { - pr[i].ifp->if_flags &= ~IFF_POLLING; - pr[i].flags |= PRF_LEAVING; - mtx_unlock(&poll_mtx); - pr[i].handler(pr[i].ifp, POLL_DEREGISTER, 1); - mtx_lock(&poll_mtx); - pr[i].flags &= ~PRF_LEAVING; - } - pr[i].handler = NULL; - } - residual_burst = 0; - poll_handlers = 0; - } + for (i = 0 ; i < poll_handlers ; i++) + pr[i].handler(pr[i].ifp, arg, cycles); phase = 4; mtx_unlock(&poll_mtx); } /* - * Try to register routine for polling. Returns 1 if successful - * (and polling should be enabled), 0 otherwise. + * Try to register routine for polling. Returns 0 if successful + * (and polling should be enabled), error code otherwise. * A device is not supposed to register itself multiple times. * - * This is called from within the *_intr() functions, so we do not need - * further ifnet locking. + * This is called from within the *_ioctl() functions. */ int ether_poll_register(poll_handler_t *h, struct ifnet *ifp) { int i; - NET_ASSERT_GIANT(); + KASSERT(h != NULL, ("%s: handler is NULL", __func__)); + KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); - if (polling == 0) /* polling disabled, cannot register */ - return 0; - if (h == NULL || ifp == NULL) /* bad arguments */ - return 0; - if ( !(ifp->if_flags & IFF_UP) ) /* must be up */ - return 0; - if (ifp->if_flags & IFF_POLLING) /* already polling */ - return 0; + NET_ASSERT_GIANT(); mtx_lock(&poll_mtx); if (poll_handlers >= POLL_LIST_LEN) { @@ -474,7 +415,7 @@ ether_poll_register(poll_handler_t *h, struct ifnet *ifp) verbose--; } mtx_unlock(&poll_mtx); - return 0; /* no polling for you */ + return (ENOMEM); /* no polling for you */ } for (i = 0 ; i < poll_handlers ; i++) @@ -482,45 +423,39 @@ ether_poll_register(poll_handler_t *h, struct ifnet *ifp) mtx_unlock(&poll_mtx); log(LOG_DEBUG, "ether_poll_register: %s: handler" " already registered\n", ifp->if_xname); - return (0); + return (EEXIST); } pr[poll_handlers].handler = h; pr[poll_handlers].ifp = ifp; poll_handlers++; - ifp->if_flags |= IFF_POLLING; mtx_unlock(&poll_mtx); if (idlepoll_sleeping) wakeup(&idlepoll_sleeping); - return 1; /* polling enabled in next call */ + return (0); } /* - * Remove interface from the polling list. Normally called by *_stop(). - * It is not an error to call it with IFF_POLLING clear, the call is - * sufficiently rare to be preferable to save the space for the extra - * test in each driver in exchange of one additional function call. + * Remove interface from the polling list. Called from *_ioctl(), too. */ int ether_poll_deregister(struct ifnet *ifp) { int i; - NET_ASSERT_GIANT(); + KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); - if ( !ifp || !(ifp->if_flags & IFF_POLLING) ) { - return 0; - } + NET_ASSERT_GIANT(); mtx_lock(&poll_mtx); + for (i = 0 ; i < poll_handlers ; i++) if (pr[i].ifp == ifp) /* found it */ break; - ifp->if_flags &= ~IFF_POLLING; /* found or not... */ if (i == poll_handlers) { - mtx_unlock(&poll_mtx); log(LOG_DEBUG, "ether_poll_deregister: %s: not found!\n", ifp->if_xname); - return (0); + mtx_unlock(&poll_mtx); + return (ENOENT); } poll_handlers--; if (i < poll_handlers) { /* Last entry replaces this one. */ @@ -528,7 +463,60 @@ ether_poll_deregister(struct ifnet *ifp) pr[i].ifp = pr[poll_handlers].ifp; } mtx_unlock(&poll_mtx); - return (1); + return (0); +} + +/* + * Legacy interface for turning polling on all interfaces at one time. + */ +static int +poll_switch(SYSCTL_HANDLER_ARGS) +{ + struct ifnet *ifp; + int error; + int val; + + mtx_lock(&poll_mtx); + val = polling; + mtx_unlock(&poll_mtx); + + error = sysctl_handle_int(oidp, &val, sizeof(int), req); + if (error || !req->newptr ) + return (error); + + if (val == polling) + return (0); + + if (val < 0 || val > 1) + return (EINVAL); + + mtx_lock(&poll_mtx); + polling = val; + mtx_unlock(&poll_mtx); + + NET_LOCK_GIANT(); + IFNET_RLOCK(); + TAILQ_FOREACH(ifp, &ifnet, if_link) { + if (ifp->if_capabilities & IFCAP_POLLING) { + struct ifreq ifr; + + if (val == 1) + ifr.ifr_reqcap = + ifp->if_capenable | IFCAP_POLLING; + else + ifr.ifr_reqcap = + ifp->if_capenable & ~IFCAP_POLLING; + IFF_LOCKGIANT(ifp); /* LOR here */ + (void) (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr); + IFF_UNLOCKGIANT(ifp); + } + } + IFNET_RUNLOCK(); + NET_UNLOCK_GIANT(); + + log(LOG_ERR, "kern.polling.enable is deprecated. Use ifconfig(8)"); + + return (0); } static void diff --git a/sys/net/if.h b/sys/net/if.h index 43173ce0de1b..460f37410a1a 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -148,7 +148,7 @@ struct if_data { #define IFF_LINK2 0x4000 /* per link layer defined bit */ #define IFF_ALTPHYS IFF_LINK2 /* use alternate physical connection */ #define IFF_MULTICAST 0x8000 /* (i) supports multicast */ -#define IFF_POLLING 0x10000 /* (n) Interface is in polling mode. */ +/* 0x10000 */ #define IFF_PPROMISC 0x20000 /* (n) user-requested promisc mode */ #define IFF_MONITOR 0x40000 /* (n) user-requested monitor mode */ #define IFF_STATICARP 0x80000 /* (n) static ARP */ @@ -166,8 +166,7 @@ struct if_data { /* flags set internally only: */ #define IFF_CANTCHANGE \ (IFF_BROADCAST|IFF_POINTOPOINT|IFF_DRV_RUNNING|IFF_DRV_OACTIVE|\ - IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_SMART|IFF_PROMISC|\ - IFF_POLLING) + IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_SMART|IFF_PROMISC) /* * Values for if_link_state. diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 1f0431eef161..783ddd85eb23 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -660,7 +660,7 @@ void if_deregister_com_alloc(u_char type); LLADDR((struct sockaddr_dl *) ifaddr_byindex((ifp)->if_index)->ifa_addr) #ifdef DEVICE_POLLING -enum poll_cmd { POLL_ONLY, POLL_AND_CHECK_STATUS, POLL_DEREGISTER }; +enum poll_cmd { POLL_ONLY, POLL_AND_CHECK_STATUS }; typedef void poll_handler_t(struct ifnet *ifp, enum poll_cmd cmd, int count); int ether_poll_register(poll_handler_t *h, struct ifnet *ifp); diff --git a/sys/pci/if_dc.c b/sys/pci/if_dc.c index 8a9e8c602046..a6f4304ae662 100644 --- a/sys/pci/if_dc.c +++ b/sys/pci/if_dc.c @@ -2265,10 +2265,10 @@ dc_attach(device_t dev) */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities |= IFCAP_VLAN_MTU; + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif - ifp->if_capenable = ifp->if_capabilities; callout_init_mtx(&sc->dc_stat_ch, &sc->dc_mtx, 0); @@ -2339,6 +2339,11 @@ dc_detach(device_t dev) ifp = sc->dc_ifp; +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { DC_LOCK(sc); @@ -2704,7 +2709,7 @@ dc_rxeof(struct dc_softc *sc) while (!(le32toh(sc->dc_ldata->dc_rx_list[i].dc_status) & DC_RXSTAT_OWN)) { #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) { + if (ifp->if_capenable & IFCAP_POLLING) { if (sc->rxcycles <= 0) break; sc->rxcycles--; @@ -3038,16 +3043,13 @@ dc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct dc_softc *sc = ifp->if_softc; - if (!(ifp->if_capenable & IFCAP_POLLING)) { - ether_poll_deregister(ifp); - cmd = POLL_DEREGISTER; - } - if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ - /* Re-enable interrupts. */ - CSR_WRITE_4(sc, DC_IMR, DC_INTRS); + DC_LOCK(sc); + + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + DC_UNLOCK(sc); return; } - DC_LOCK(sc); + sc->rxcycles = count; dc_rxeof(sc); dc_txeof(sc); @@ -3111,12 +3113,9 @@ dc_intr(void *arg) DC_LOCK(sc); ifp = sc->dc_ifp; #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) - goto done; - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(dc_poll, ifp)) { /* ok, disable interrupts */ - CSR_WRITE_4(sc, DC_IMR, 0x00000000); - goto done; + if (ifp->if_capenable & IFCAP_POLLING) { + DC_UNLOCK(sc); + return; } #endif @@ -3183,10 +3182,6 @@ dc_intr(void *arg) if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) dc_start_locked(ifp); -#ifdef DEVICE_POLLING -done: -#endif - DC_UNLOCK(sc); } @@ -3534,7 +3529,7 @@ dc_init_locked(struct dc_softc *sc) * the case of polling. Some cards (e.g. fxp) turn interrupts on * after a reset. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) CSR_WRITE_4(sc, DC_IMR, 0x00000000); else #endif @@ -3686,10 +3681,31 @@ dc_ioctl(struct ifnet *ifp, u_long command, caddr_t data) #endif break; case SIOCSIFCAP: - DC_LOCK(sc); - ifp->if_capenable &= ~IFCAP_POLLING; - ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; - DC_UNLOCK(sc); +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(dc_poll, ifp); + if (error) + return(error); + DC_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_4(sc, DC_IMR, 0x00000000); + ifp->if_capenable |= IFCAP_POLLING; + DC_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + DC_LOCK(sc); + CSR_WRITE_4(sc, DC_IMR, DC_INTRS); + ifp->if_capenable &= ~IFCAP_POLLING; + DC_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ break; default: error = ether_ioctl(ifp, command, data); @@ -3744,9 +3760,6 @@ dc_stop(struct dc_softc *sc) callout_stop(&sc->dc_stat_ch); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON | DC_NETCFG_TX_ON)); CSR_WRITE_4(sc, DC_IMR, 0x00000000); diff --git a/sys/pci/if_rl.c b/sys/pci/if_rl.c index c0e42e9321e2..a35e999aa509 100644 --- a/sys/pci/if_rl.c +++ b/sys/pci/if_rl.c @@ -195,10 +195,8 @@ static int rl_miibus_readreg(device_t, int, int); static void rl_miibus_statchg(device_t); static int rl_miibus_writereg(device_t, int, int, int); #ifdef DEVICE_POLLING -static void rl_poll(struct ifnet *ifp, enum poll_cmd cmd, - int count); -static void rl_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, - int count); +static void rl_poll(struct ifnet *ifp, enum poll_cmd cmd, int count); +static void rl_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count); #endif static int rl_probe(device_t); static void rl_read_eeprom(struct rl_softc *, uint8_t *, int, int, int); @@ -956,10 +954,10 @@ rl_attach(device_t dev) ifp->if_init = rl_init; ifp->if_baudrate = 10000000; ifp->if_capabilities = IFCAP_VLAN_MTU; + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif - ifp->if_capenable = ifp->if_capabilities; IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; IFQ_SET_READY(&ifp->if_snd); @@ -1002,6 +1000,10 @@ rl_detach(device_t dev) KASSERT(mtx_initialized(&sc->rl_mtx), ("rl mutex not initialized")); +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { RL_LOCK(sc); @@ -1115,12 +1117,12 @@ rl_rxeof(struct rl_softc *sc) while((CSR_READ_1(sc, RL_COMMAND) & RL_CMD_EMPTY_RXBUF) == 0) { #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 rxbufpos = sc->rl_cdata.rl_rx_buf + cur_rx; rxstat = le32toh(*(uint32_t *)rxbufpos); @@ -1283,7 +1285,8 @@ rl_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct rl_softc *sc = ifp->if_softc; RL_LOCK(sc); - rl_poll_locked(ifp, cmd, count); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + rl_poll_locked(ifp, cmd, count); RL_UNLOCK(sc); } @@ -1294,17 +1297,6 @@ rl_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) RL_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, RL_IMR, RL_INTRS); - return; - } - sc->rxcycles = count; rl_rxeof(sc); rl_txeof(sc); @@ -1345,17 +1337,9 @@ rl_intr(void *arg) goto done_locked; #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) goto done_locked; - - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(rl_poll, ifp)) { - /* Disable interrupts. */ - CSR_WRITE_2(sc, RL_IMR, 0x0000); - rl_poll_locked(ifp, 0, 1); - goto done_locked; - } -#endif /* DEVICE_POLLING */ +#endif for (;;) { status = CSR_READ_2(sc, RL_ISR); @@ -1574,10 +1558,10 @@ rl_init_locked(struct rl_softc *sc) #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, RL_IMR, 0); else -#endif /* DEVICE_POLLING */ +#endif /* Enable interrupts. */ CSR_WRITE_2(sc, RL_IMR, RL_INTRS); @@ -1669,8 +1653,31 @@ rl_ioctl(struct ifnet *ifp, u_long command, caddr_t data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: - ifp->if_capenable &= ~IFCAP_POLLING; - ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(rl_poll, ifp); + if (error) + return(error); + RL_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_2(sc, RL_IMR, 0x0000); + ifp->if_capenable |= IFCAP_POLLING; + RL_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + RL_LOCK(sc); + CSR_WRITE_2(sc, RL_IMR, RL_INTRS); + ifp->if_capenable &= ~IFCAP_POLLING; + RL_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ break; default: error = ether_ioctl(ifp, command, data); @@ -1712,9 +1719,6 @@ rl_stop(struct rl_softc *sc) ifp->if_timer = 0; callout_stop(&sc->rl_stat_callout); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* DEVICE_POLLING */ CSR_WRITE_1(sc, RL_COMMAND, 0x00); CSR_WRITE_2(sc, RL_IMR, 0x0000); diff --git a/sys/pci/if_sf.c b/sys/pci/if_sf.c index fa7eb83a71cc..691a0f665006 100644 --- a/sys/pci/if_sf.c +++ b/sys/pci/if_sf.c @@ -165,11 +165,9 @@ static int sf_miibus_readreg(device_t, int, int); static int sf_miibus_writereg(device_t, int, int, int); static void sf_miibus_statchg(device_t); #ifdef DEVICE_POLLING -static void sf_poll(struct ifnet *ifp, enum poll_cmd cmd, - int count); -static void sf_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, - int count); -#endif /* DEVICE_POLLING */ +static void sf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count); +static void sf_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count); +#endif static u_int32_t csr_read_4(struct sf_softc *, int); static void csr_write_4(struct sf_softc *, int, u_int32_t); @@ -560,10 +558,31 @@ sf_ioctl(ifp, command, data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: - SF_LOCK(sc); - ifp->if_capenable &= ~IFCAP_POLLING; - ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; - SF_UNLOCK(sc); +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(sf_poll, ifp); + if (error) + return(error); + SF_LOCK(sc); + /* Disable interrupts */ + csr_write_4(sc, SF_IMR, 0x00000000); + ifp->if_capenable |= IFCAP_POLLING; + SF_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + SF_LOCK(sc); + csr_write_4(sc, SF_IMR, SF_INTRS); + ifp->if_capenable &= ~IFCAP_POLLING; + SF_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ break; default: error = ether_ioctl(ifp, command, data); @@ -749,10 +768,10 @@ sf_attach(dev) IFQ_SET_MAXLEN(&ifp->if_snd, SF_TX_DLIST_CNT - 1); ifp->if_snd.ifq_drv_maxlen = SF_TX_DLIST_CNT - 1; IFQ_SET_READY(&ifp->if_snd); + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; -#endif /* DEVICE_POLLING */ - ifp->if_capenable = ifp->if_capabilities; +#endif /* * Call MI attach routine. @@ -794,6 +813,11 @@ sf_detach(dev) KASSERT(mtx_initialized(&sc->sf_mtx), ("sf mutex not initialized")); ifp = sc->sf_ifp; +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { SF_LOCK(sc); @@ -946,12 +970,12 @@ sf_rxeof(sc) struct mbuf *m0; #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->sf_ldata->sf_rx_clist[cmpconsidx]; desc = &sc->sf_ldata->sf_rx_dlist_big[cur_rx->sf_endidx]; @@ -1068,7 +1092,8 @@ sf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct sf_softc *sc = ifp->if_softc; SF_LOCK(sc); - sf_poll_locked(ifp, cmd, count); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + sf_poll_locked(ifp, cmd, count); SF_UNLOCK(sc); } @@ -1079,17 +1104,6 @@ sf_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) SF_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_4(sc, SF_IMR, SF_INTRS); - return; - } - sc->rxcycles = count; sf_rxeof(sc); sf_txeof(sc); @@ -1131,17 +1145,11 @@ sf_intr(arg) ifp = sc->sf_ifp; #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) - goto done_locked; - - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(sf_poll, ifp)) { - /* OK, disable interrupts. */ - csr_write_4(sc, SF_IMR, 0x00000000); - sf_poll_locked(ifp, 0, 1); - goto done_locked; + if (ifp->if_capenable & IFCAP_POLLING) { + SF_UNLOCK(sc); + return; } -#endif /* DEVICE_POLLING */ +#endif if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED)) { SF_UNLOCK(sc); @@ -1185,9 +1193,6 @@ sf_intr(arg) if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) sf_start_locked(ifp); -#ifdef DEVICE_POLLING -done_locked: -#endif /* DEVICE_POLLING */ SF_UNLOCK(sc); } @@ -1296,10 +1301,10 @@ sf_init_locked(sc) #ifdef DEVICE_POLLING /* Disable interrupts if we are polling. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) csr_write_4(sc, SF_IMR, 0x00000000); else -#endif /* DEVICE_POLLING */ +#endif /* Enable interrupts. */ csr_write_4(sc, SF_IMR, SF_INTRS); @@ -1478,10 +1483,6 @@ sf_stop(sc) callout_stop(&sc->sf_stat_callout); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* DEVICE_POLLING */ - csr_write_4(sc, SF_GEN_ETH_CTL, 0); csr_write_4(sc, SF_CQ_CONSIDX, 0); csr_write_4(sc, SF_CQ_PRODIDX, 0); diff --git a/sys/pci/if_sis.c b/sys/pci/if_sis.c index 117a46a80f6f..c0417bef2b48 100644 --- a/sys/pci/if_sis.c +++ b/sys/pci/if_sis.c @@ -1217,11 +1217,10 @@ sis_attach(device_t dev) */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities |= IFCAP_VLAN_MTU; - + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif - ifp->if_capenable = ifp->if_capabilities; /* Hook interrupt last to avoid having to lock softc */ error = bus_setup_intr(dev, sc->sis_res[1], INTR_TYPE_NET | INTR_MPSAFE, @@ -1257,6 +1256,11 @@ sis_detach(device_t dev) KASSERT(mtx_initialized(&sc->sis_mtx), ("sis mutex not initialized")); ifp = sc->sis_ifp; +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + /* These should only be active if attach succeeded. */ if (device_is_attached(dev)) { SIS_LOCK(sc); @@ -1404,12 +1408,12 @@ sis_rxeof(struct sis_softc *sc) cur_rx = cur_rx->sis_nextdesc) { #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 rxstat = cur_rx->sis_rxstat; bus_dmamap_sync(sc->sis_tag, cur_rx->sis_map, BUS_DMASYNC_POSTWRITE); @@ -1574,13 +1578,9 @@ sis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct sis_softc *sc = ifp->if_softc; SIS_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_4(sc, SIS_IER, 1); - goto done; + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + SIS_UNLOCK(sc); + return; } /* @@ -1613,7 +1613,7 @@ sis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) sis_initl(sc); } } -done: + SIS_UNLOCK(sc); } #endif /* DEVICE_POLLING */ @@ -1633,14 +1633,11 @@ sis_intr(void *arg) SIS_LOCK(sc); #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) - goto done; - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(sis_poll, ifp)) { /* ok, disable interrupts */ - CSR_WRITE_4(sc, SIS_IER, 0); - goto done; + if (ifp->if_capenable & IFCAP_POLLING) { + SIS_UNLOCK(sc); + return; } -#endif /* DEVICE_POLLING */ +#endif /* Disable interrupts. */ CSR_WRITE_4(sc, SIS_IER, 0); @@ -1679,9 +1676,6 @@ sis_intr(void *arg) if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) sis_startl(ifp); -#ifdef DEVICE_POLLING -done: -#endif /* DEVICE_POLLING */ SIS_UNLOCK(sc); } @@ -2033,10 +2027,10 @@ sis_initl(struct sis_softc *sc) * ... only enable interrupts if we are not polling, make sure * they are off otherwise. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) CSR_WRITE_4(sc, SIS_IER, 0); else -#endif /* DEVICE_POLLING */ +#endif CSR_WRITE_4(sc, SIS_IER, 1); /* Enable receiver and transmitter. */ @@ -2133,10 +2127,32 @@ sis_ioctl(struct ifnet *ifp, u_long command, caddr_t data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: - SIS_LOCK(sc); - ifp->if_capenable &= ~IFCAP_POLLING; - ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; - SIS_UNLOCK(sc); + /* ok, disable interrupts */ +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(sis_poll, ifp); + if (error) + return(error); + SIS_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_4(sc, SIS_IER, 0); + ifp->if_capenable |= IFCAP_POLLING; + SIS_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + SIS_LOCK(sc); + CSR_WRITE_4(sc, SIS_IER, 1); + ifp->if_capenable &= ~IFCAP_POLLING; + SIS_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ break; default: error = ether_ioctl(ifp, command, data); @@ -2192,9 +2208,6 @@ sis_stop(struct sis_softc *sc) callout_stop(&sc->sis_stat_ch); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif CSR_WRITE_4(sc, SIS_IER, 0); CSR_WRITE_4(sc, SIS_IMR, 0); CSR_READ_4(sc, SIS_ISR); /* clear any interrupts already pending */ diff --git a/sys/pci/if_ste.c b/sys/pci/if_ste.c index eca7e11b13d3..f80e676df30e 100644 --- a/sys/pci/if_ste.c +++ b/sys/pci/if_ste.c @@ -621,7 +621,8 @@ ste_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct ste_softc *sc = ifp->if_softc; STE_LOCK(sc); - ste_poll_locked(ifp, cmd, count); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ste_poll_locked(ifp, cmd, count); STE_UNLOCK(sc); } @@ -631,14 +632,6 @@ ste_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) struct ste_softc *sc = ifp->if_softc; STE_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, STE_IMR, STE_INTRS); - return; - } sc->rxcycles = count; if (cmd == POLL_AND_CHECK_STATUS) @@ -685,15 +678,11 @@ ste_intr(xsc) ifp = sc->ste_ifp; #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) - goto done; - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(ste_poll, ifp)) { /* ok, disable interrupts */ - CSR_WRITE_2(sc, STE_IMR, 0); - ste_poll_locked(ifp, 0, 1); - goto done; + if (ifp->if_capenable & IFCAP_POLLING) { + STE_UNLOCK(sc); + return; } -#endif /* DEVICE_POLLING */ +#endif /* See if this is really our interrupt. */ if (!(CSR_READ_2(sc, STE_ISR) & STE_ISR_INTLATCH)) { @@ -739,9 +728,6 @@ ste_intr(xsc) if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) ste_start_locked(ifp); -#ifdef DEVICE_POLLING -done: -#endif /* DEVICE_POLLING */ STE_UNLOCK(sc); return; @@ -791,12 +777,12 @@ ste_rxeof(sc) while((rxstat = sc->ste_cdata.ste_rx_head->ste_ptr->ste_status) & STE_RXSTAT_DMADONE) { #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 if ((STE_RX_LIST_CNT - count) < 3) { break; } @@ -1115,10 +1101,10 @@ ste_attach(dev) */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities |= IFCAP_VLAN_MTU; + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif - ifp->if_capenable = ifp->if_capabilities; /* Hook interrupt last to avoid having to lock softc */ error = bus_setup_intr(dev, sc->ste_irq, INTR_TYPE_NET | INTR_MPSAFE, @@ -1155,6 +1141,11 @@ ste_detach(dev) KASSERT(mtx_initialized(&sc->ste_mtx), ("ste mutex not initialized")); ifp = sc->ste_ifp; +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { STE_LOCK(sc); @@ -1386,10 +1377,10 @@ ste_init_locked(sc) CSR_WRITE_2(sc, STE_ISR, 0xFFFF); #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, STE_IMR, 0); else -#endif /* DEVICE_POLLING */ +#endif /* Enable interrupts. */ CSR_WRITE_2(sc, STE_IMR, STE_INTRS); @@ -1418,9 +1409,6 @@ ste_stop(sc) callout_stop(&sc->ste_stat_callout); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* DEVICE_POLLING */ CSR_WRITE_2(sc, STE_IMR, 0); STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_TX_DISABLE); @@ -1539,10 +1527,31 @@ ste_ioctl(ifp, command, data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: - STE_LOCK(sc); - ifp->if_capenable &= ~IFCAP_POLLING; - ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; - STE_UNLOCK(sc); +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(ste_poll, ifp); + if (error) + return(error); + STE_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_2(sc, STE_IMR, 0); + ifp->if_capenable |= IFCAP_POLLING; + STE_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + STE_LOCK(sc); + CSR_WRITE_2(sc, STE_IMR, STE_INTRS); + ifp->if_capenable &= ~IFCAP_POLLING; + STE_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ break; default: error = ether_ioctl(ifp, command, data); diff --git a/sys/pci/if_vr.c b/sys/pci/if_vr.c index 5eabc21dafa1..b3c92eae4f75 100644 --- a/sys/pci/if_vr.c +++ b/sys/pci/if_vr.c @@ -742,10 +742,10 @@ vr_attach(dev) IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1); ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; IFQ_SET_READY(&ifp->if_snd); + ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif - ifp->if_capenable = ifp->if_capabilities; /* Do MII setup. */ if (mii_phy_probe(dev, &sc->vr_miibus, @@ -794,6 +794,11 @@ vr_detach(device_t dev) KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + VR_LOCK(sc); sc->suspended = 1; @@ -952,12 +957,12 @@ vr_rxeof(struct vr_softc *sc) while (!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & VR_RXSTAT_OWN)) { #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 m0 = NULL; cur_rx = sc->vr_cdata.vr_rx_head; sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; @@ -1151,7 +1156,8 @@ vr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) struct vr_softc *sc = ifp->if_softc; VR_LOCK(sc); - vr_poll_locked(ifp, cmd, count); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + vr_poll_locked(ifp, cmd, count); VR_UNLOCK(sc); } @@ -1162,17 +1168,6 @@ vr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) VR_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, VR_IMR, VR_INTRS); - return; - } - sc->rxcycles = count; vr_rxeof(sc); vr_txeof(sc); @@ -1249,17 +1244,9 @@ vr_intr(void *arg) } #ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) goto done_locked; - - if ((ifp->if_capenable & IFCAP_POLLING) && - ether_poll_register(vr_poll, ifp)) { - /* OK, disable interrupts. */ - CSR_WRITE_2(sc, VR_IMR, 0x0000); - vr_poll_locked(ifp, 0, 1); - goto done_locked; - } -#endif /* DEVICE_POLLING */ +#endif /* Suppress unwanted interrupts. */ if (!(ifp->if_flags & IFF_UP)) { @@ -1534,10 +1521,10 @@ vr_init_locked(struct vr_softc *sc) /* * Disable interrupts if we are polling. */ - if (ifp->if_flags & IFF_POLLING) + if (ifp->if_capenable & IFCAP_POLLING) CSR_WRITE_2(sc, VR_IMR, 0); else -#endif /* DEVICE_POLLING */ +#endif /* * Enable interrupts. */ @@ -1615,7 +1602,31 @@ vr_ioctl(struct ifnet *ifp, u_long command, caddr_t data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: - ifp->if_capenable = ifr->ifr_reqcap; +#ifdef DEVICE_POLLING + if (ifr->ifr_reqcap & IFCAP_POLLING && + !(ifp->if_capenable & IFCAP_POLLING)) { + error = ether_poll_register(vr_poll, ifp); + if (error) + return(error); + VR_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_2(sc, VR_IMR, 0x0000); + ifp->if_capenable |= IFCAP_POLLING; + VR_UNLOCK(sc); + return (error); + + } + if (!(ifr->ifr_reqcap & IFCAP_POLLING) && + ifp->if_capenable & IFCAP_POLLING) { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + VR_LOCK(sc); + CSR_WRITE_2(sc, VR_IMR, VR_INTRS); + ifp->if_capenable &= ~IFCAP_POLLING; + VR_UNLOCK(sc); + return (error); + } +#endif /* DEVICE_POLLING */ break; default: error = ether_ioctl(ifp, command, data); @@ -1662,9 +1673,6 @@ vr_stop(struct vr_softc *sc) untimeout(vr_tick, sc, sc->vr_stat_ch); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* DEVICE_POLLING */ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c index 520f66829733..e49997aa13d9 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 @@ xl_rxeof(struct xl_softc *sc) 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);