From owner-svn-src-projects@FreeBSD.ORG Mon Jan 19 21:40:16 2015 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 80A86C31; Mon, 19 Jan 2015 21:40:16 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 6B874CFC; Mon, 19 Jan 2015 21:40:16 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t0JLeGXi063493; Mon, 19 Jan 2015 21:40:16 GMT (envelope-from glebius@FreeBSD.org) Received: (from glebius@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t0JLeEDg063481; Mon, 19 Jan 2015 21:40:14 GMT (envelope-from glebius@FreeBSD.org) Message-Id: <201501192140.t0JLeEDg063481@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: glebius set sender to glebius@FreeBSD.org using -f From: Gleb Smirnoff Date: Mon, 19 Jan 2015 21:40:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r277399 - in projects/ifnet/sys: conf dev/bge dev/xl kern net X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 19 Jan 2015 21:40:16 -0000 Author: glebius Date: Mon Jan 19 21:40:13 2015 New Revision: 277399 URL: https://svnweb.freebsd.org/changeset/base/277399 Log: Bring polling(4) to new ifnet world order. o Since polling(4) is so much ifnet-oriented 'svn move' it: kern/kern_poll.c -> net/if_polling.c o Make the polling table not static, but dynamic and growing, taking idea from the ifindex table. Now registering an interface for polling can not fail. o Create if_poll_t method in the if_ops. Drivers that support polling should declare IFCAP_POLLING in their capabilities and impment ifop_poll. o Rename: ether_poll_register -> if_poll_register ether_poll_deregister -> if_poll_deregister And make these functions private to the stack. Note that they are voids now, due to not failing. o The stack calls if_poll_register/if_poll_deregister on SIOCSIFCAP and passes it down to driver. A driver needs to do only hardware specific things to turn polling on or off. Sponsored by: Netflix Sponsored by: Nginx, Inc. Added: projects/ifnet/sys/net/if_polling.c - copied, changed from r277397, projects/ifnet/sys/kern/kern_poll.c Deleted: projects/ifnet/sys/kern/kern_poll.c Modified: projects/ifnet/sys/conf/files projects/ifnet/sys/dev/bge/if_bge.c projects/ifnet/sys/dev/xl/if_xl.c projects/ifnet/sys/net/if.c projects/ifnet/sys/net/if.h projects/ifnet/sys/net/if_var.h Modified: projects/ifnet/sys/conf/files ============================================================================== --- projects/ifnet/sys/conf/files Mon Jan 19 21:30:40 2015 (r277398) +++ projects/ifnet/sys/conf/files Mon Jan 19 21:40:13 2015 (r277399) @@ -2981,7 +2981,6 @@ kern/kern_ntptime.c standard kern/kern_osd.c standard kern/kern_physio.c standard kern/kern_pmc.c standard -kern/kern_poll.c optional device_polling kern/kern_priv.c standard kern/kern_proc.c standard kern/kern_procctl.c standard @@ -3253,6 +3252,7 @@ net/if_llatbl.c standard net/if_me.c optional me inet net/if_media.c standard net/if_mib.c standard +net/if_polling.c optional device_polling net/if_spppfr.c optional sppp | netgraph_sppp net/if_spppsubr.c optional sppp | netgraph_sppp net/if_stf.c optional stf inet inet6 Modified: projects/ifnet/sys/dev/bge/if_bge.c ============================================================================== --- projects/ifnet/sys/dev/bge/if_bge.c Mon Jan 19 21:30:40 2015 (r277398) +++ projects/ifnet/sys/dev/bge/if_bge.c Mon Jan 19 21:40:13 2015 (r277399) @@ -539,6 +539,9 @@ static struct ifdriver bge_ifdrv = { .ifop_init = bge_init, .ifop_transmit = bge_transmit, .ifop_get_counter = bge_get_counter, +#ifdef DEVICE_POLLING + .ifop_poll = bge_poll, +#endif }, .ifdrv_name = "bge", .ifdrv_type = IFT_ETHER, @@ -3334,6 +3337,9 @@ bge_attach(device_t dev) .ifat_drv = &bge_ifdrv, .ifat_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST, .ifat_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING | +#ifdef DEVICE_POLLING + IFCAP_POLLING | +#endif IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM, }; struct bge_softc *sc; @@ -3927,9 +3933,6 @@ again: ifat.ifat_capabilities |= IFCAP_TSO4 | IFCAP_VLAN_HWTSO; } ifat.ifat_capenable = ifat.ifat_capabilities; -#ifdef DEVICE_POLLING - ifat.ifat_capabilities |= IFCAP_POLLING; -#endif /* * 5700 B0 chips do not support checksumming correctly due * to hardware bugs. @@ -3959,11 +3962,6 @@ bge_detach(device_t dev) sc = device_get_softc(dev); ifp = sc->bge_ifp; -#ifdef DEVICE_POLLING - if (sc->bge_capenable & IFCAP_POLLING) - ether_poll_deregister(ifp); -#endif - if (device_is_attached(dev)) { if_detach(ifp); BGE_LOCK(sc); @@ -4804,7 +4802,7 @@ bge_tick(void *xsc) */ #ifdef DEVICE_POLLING /* In polling mode we poll link state in bge_poll(). */ - if (!(if_getcapenable(sc->bge_ifp) & IFCAP_POLLING)) + if (!(sc->bge_capenable & IFCAP_POLLING)) #endif { sc->bge_link_evt++; @@ -5819,26 +5817,17 @@ bge_ioctl(if_t ifp, u_long command, void mask = ifr->ifr_reqcap ^ ifr->ifr_curcap; #ifdef DEVICE_POLLING if (mask & IFCAP_POLLING) { + BGE_LOCK(sc); if (ifr->ifr_reqcap & IFCAP_POLLING) { - error = ether_poll_register(bge_poll, ifp); - if (error) - return (error); - BGE_LOCK(sc); BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR); bge_writembx(sc, BGE_MBX_IRQ0_LO, 1); - BGE_UNLOCK(sc); } else { - error = ether_poll_deregister(ifp); - /* Enable interrupt even in error case */ - BGE_LOCK(sc); BGE_CLRBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR); bge_writembx(sc, BGE_MBX_IRQ0_LO, 0); - BGE_UNLOCK(sc); - if (error) - return (error); } + BGE_UNLOCK(sc); } #endif sc->bge_capenable = ifr->ifr_reqcap; Modified: projects/ifnet/sys/dev/xl/if_xl.c ============================================================================== --- projects/ifnet/sys/dev/xl/if_xl.c Mon Jan 19 21:30:40 2015 (r277398) +++ projects/ifnet/sys/dev/xl/if_xl.c Mon Jan 19 21:40:13 2015 (r277399) @@ -249,7 +249,6 @@ static void xl_setwol(struct xl_softc *) #ifdef DEVICE_POLLING static int xl_poll(if_t, enum poll_cmd cmd, int count); -static int xl_poll_locked(if_t, enum poll_cmd cmd, int count); #endif static int xl_ifmedia_upd(if_t); @@ -335,6 +334,9 @@ static struct ifdriver xl_ifdrv = { .ifop_ioctl = xl_ioctl, .ifop_transmit = xl_transmit, .ifop_init = xl_init, +#ifdef DEVICE_POLLING + .ifop_poll = xl_poll, +#endif }, .ifdrv_name = "xl", .ifdrv_type = IFT_ETHER, @@ -1571,11 +1573,6 @@ xl_detach(device_t dev) KASSERT(mtx_initialized(&sc->xl_mtx), ("xl mutex not initialized")); -#ifdef DEVICE_POLLING - if (ifp && 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; @@ -1846,7 +1843,7 @@ again: BUS_DMASYNC_POSTREAD); while ((rxstat = le32toh(sc->xl_cdata.xl_rx_head->xl_ptr->xl_status))) { #ifdef DEVICE_POLLING - if (ifp->if_capenable & IFCAP_POLLING) { + if (sc->xl_capenable & IFCAP_POLLING) { if (sc->rxcycles <= 0) break; sc->rxcycles--; @@ -2154,7 +2151,7 @@ xl_intr(void *arg) XL_LOCK(sc); #ifdef DEVICE_POLLING - if (ifp->if_capenable & IFCAP_POLLING) { + if (sc->xl_capenable & IFCAP_POLLING) { XL_UNLOCK(sc); return; } @@ -2212,23 +2209,15 @@ xl_intr(void *arg) static int xl_poll(if_t ifp, enum poll_cmd cmd, int count) { - struct xl_softc *sc = ifp->if_softc; + struct xl_softc *sc; int rx_npkts = 0; + sc = if_getsoftc(ifp, IF_DRIVER_SOFTC); XL_LOCK(sc); - if (sc->xl_flags & XL_FLAG_RUNNING) - rx_npkts = xl_poll_locked(ifp, cmd, count); - XL_UNLOCK(sc); - return (rx_npkts); -} - -static int -xl_poll_locked(if_t ifp, enum poll_cmd cmd, int count) -{ - struct xl_softc *sc = ifp->if_softc; - int rx_npkts; - - XL_LOCK_ASSERT(sc); + if (sc->xl_flags & XL_FLAG_RUNNING) { + XL_UNLOCK(sc); + return (0); + } sc->rxcycles = count; rx_npkts = xl_rxeof(sc); @@ -2239,9 +2228,9 @@ xl_poll_locked(if_t ifp, enum poll_cmd c if (if_snd_len(ifp)) { if (sc->xl_type == XL_TYPE_905B) - xl_start_90xB_locked(ifp); + xl_start_90xB_locked(sc); else - xl_start_locked(ifp); + xl_start_locked(sc); } if (cmd == POLL_AND_CHECK_STATUS) { @@ -2266,6 +2255,8 @@ xl_poll_locked(if_t ifp, enum poll_cmd c xl_stats_update(sc); } } + XL_UNLOCK(sc); + return (rx_npkts); } #endif /* DEVICE_POLLING */ @@ -2826,7 +2817,7 @@ 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_capenable & IFCAP_POLLING) + if (sc->xl_capenable & IFCAP_POLLING) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0); else #endif @@ -3028,16 +3019,11 @@ xl_ioctl(if_t ifp, u_long command, void case SIOCSIFCAP: #ifdef DEVICE_POLLING if (((ifr->ifr_reqcap ^ ifr->ifr_curcap) & IFCAP_POLLING)) { + XL_LOCK(sc); if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { - error = ether_poll_register(xl_poll, ifp); - if (error) - break; - XL_LOCK(sc); /* Disable interrupts */ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0); - XL_UNLOCK(sc); } else { - error = ether_poll_deregister(ifp); /* Enable interrupts. */ XL_LOCK(sc); CSR_WRITE_2(sc, XL_COMMAND, @@ -3047,10 +3033,8 @@ xl_ioctl(if_t ifp, u_long command, void if (sc->xl_flags & XL_FLAG_FUNCREG) bus_space_write_4(sc->xl_ftag, sc->xl_fhandle, 4, 0x8000); - XL_UNLOCK(sc); - if (error) - break; } + XL_UNLOCK(sc); } #endif /* DEVICE_POLLING */ sc->xl_capenable = ifr->ifr_reqcap; Modified: projects/ifnet/sys/net/if.c ============================================================================== --- projects/ifnet/sys/net/if.c Mon Jan 19 21:30:40 2015 (r277398) +++ projects/ifnet/sys/net/if.c Mon Jan 19 21:40:13 2015 (r277399) @@ -918,7 +918,10 @@ if_detach(if_t ifp) ifp->if_flags |= IFF_DYING; /* XXX: Locking */ bpfdetach(ifp); - +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + if_poll_deregister(ifp); +#endif CURVNET_SET_QUIET(ifp->if_vnet); if_detach_internal(ifp, 0); @@ -2521,13 +2524,21 @@ if_drvioctl(u_long cmd, struct ifnet *if return (0); ifr->ifr_curcap = ifp->if_capenable; error = if_ioctl(ifp, cmd, data, td); - if (error == 0) { - ifp->if_capenable = ifr->ifr_reqcap; - ifp->if_hwassist = ifr->ifr_hwassist; - getmicrotime(&ifp->if_lastchange); - if (ifp->if_vlantrunk != NULL) - (*vlan_trunk_cap_p)(ifp); + if (error != 0) + break; +#ifdef DEVICE_POLLING + if ((ifr->ifr_reqcap ^ ifr->ifr_curcap) & IFCAP_POLLING) { + if (ifr->ifr_reqcap & IFCAP_POLLING) + if_poll_register(ifp); + else + if_poll_deregister(ifp); } +#endif + ifp->if_capenable = ifr->ifr_reqcap; + ifp->if_hwassist = ifr->ifr_hwassist; + getmicrotime(&ifp->if_lastchange); + if (ifp->if_vlantrunk != NULL) + (*vlan_trunk_cap_p)(ifp); break; #ifdef MAC case SIOCSIFMAC: Modified: projects/ifnet/sys/net/if.h ============================================================================== --- projects/ifnet/sys/net/if.h Mon Jan 19 21:30:40 2015 (r277398) +++ projects/ifnet/sys/net/if.h Mon Jan 19 21:40:13 2015 (r277399) @@ -597,6 +597,10 @@ typedef void (*if_qflush_t)(if_t); typedef int (*if_resolvemulti_t)(if_t, struct sockaddr **, struct sockaddr *); typedef void (*if_reassign_t)(if_t, struct vnet *); +#ifdef DEVICE_POLLING +enum poll_cmd { POLL_ONLY, POLL_AND_CHECK_STATUS }; +typedef int (*if_poll_t)(if_t ifp, enum poll_cmd cmd, int count); +#endif /* * Interface methods. Usually stored in ifdriver definition, however @@ -607,6 +611,9 @@ struct ifops { if_input_t ifop_input; /* input routine (from h/w driver) */ if_transmit_t ifop_transmit; /* initiate output routine */ if_output_t ifop_output; +#ifdef DEVICE_POLLING + if_poll_t ifop_poll; +#endif if_ioctl_t ifop_ioctl; /* ioctl routine */ if_get_counter_t ifop_get_counter; /* get counter values */ if_init_t ifop_init; /* init routine */ Copied and modified: projects/ifnet/sys/net/if_polling.c (from r277397, projects/ifnet/sys/kern/kern_poll.c) ============================================================================== --- projects/ifnet/sys/kern/kern_poll.c Mon Jan 19 21:27:34 2015 (r277397, copy source) +++ projects/ifnet/sys/net/if_polling.c Mon Jan 19 21:40:13 2015 (r277399) @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); void hardclock_device_poll(void); /* hook from hardclock */ static struct mtx poll_mtx; +static MALLOC_DEFINE(M_IFPOLLING, "ifpoll", "interface polling table"); /* * Polling support for [network] device drivers. @@ -244,14 +245,33 @@ static uint32_t idlepoll_sleeping; /* id SYSCTL_UINT(_kern_polling, OID_AUTO, idlepoll_sleeping, CTLFLAG_RD, &idlepoll_sleeping, 0, "idlepoll is sleeping"); +static struct ifnet **poll_table; +static u_int poll_indexlim; -#define POLL_LIST_LEN 128 -struct pollrec { - poll_handler_t *handler; - struct ifnet *ifp; -}; +static void +poll_grow(void) +{ + int oldlim; + u_int n; + struct ifnet **e; -static struct pollrec pr[POLL_LIST_LEN]; + mtx_assert(&poll_mtx, MA_OWNED); + oldlim = poll_indexlim; + mtx_unlock(&poll_mtx); + n = (oldlim << 1) * sizeof(*e); + e = malloc(n, M_IFPOLLING, M_WAITOK | M_ZERO); + mtx_lock(&poll_mtx); + if (poll_indexlim != oldlim) { + free(e, M_IFPOLLING); + return; + } + if (poll_table != NULL) { + memcpy(e, poll_table, n/2); + free(poll_table, M_IFPOLLING); + } + poll_indexlim <<= 1; + poll_table = e; +} static void poll_shutdown(void *arg, int howto) @@ -338,7 +358,7 @@ ether_poll(int count) count = poll_each_burst; for (i = 0 ; i < poll_handlers ; i++) - pr[i].handler(pr[i].ifp, POLL_ONLY, count); + if_poll(poll_table[i], POLL_ONLY, count); mtx_unlock(&poll_mtx); } @@ -445,91 +465,45 @@ netisr_poll(void) residual_burst -= cycles; for (i = 0 ; i < poll_handlers ; i++) - pr[i].handler(pr[i].ifp, arg, cycles); + if_poll(poll_table[i], POLL_ONLY, cycles); phase = 4; mtx_unlock(&poll_mtx); } /* - * 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 *_ioctl() functions. + * Register routine for polling. Called in context of ioctl(2). */ -int -ether_poll_register(poll_handler_t *h, if_t ifp) +void +if_poll_register(struct ifnet *ifp) { - int i; - - KASSERT(h != NULL, ("%s: handler is NULL", __func__)); - KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); mtx_lock(&poll_mtx); - if (poll_handlers >= POLL_LIST_LEN) { - /* - * List full, cannot register more entries. - * This should never happen; if it does, it is probably a - * broken driver trying to register multiple times. Checking - * this at runtime is expensive, and won't solve the problem - * anyways, so just report a few times and then give up. - */ - static int verbose = 10 ; - if (verbose >0) { - log(LOG_ERR, "poll handlers list full, " - "maybe a broken driver ?\n"); - verbose--; - } - mtx_unlock(&poll_mtx); - return (ENOMEM); /* no polling for you */ - } - - for (i = 0 ; i < poll_handlers ; i++) - if (pr[i].ifp == ifp && pr[i].handler != NULL) { - mtx_unlock(&poll_mtx); - log(LOG_DEBUG, "ether_poll_register: %s: handler" - " already registered\n", ifp->if_xname); - return (EEXIST); - } - - pr[poll_handlers].handler = h; - pr[poll_handlers].ifp = ifp; - poll_handlers++; + if (poll_handlers >= poll_indexlim) + poll_grow(); + poll_table[poll_handlers++] = ifp; mtx_unlock(&poll_mtx); if (idlepoll_sleeping) wakeup(&idlepoll_sleeping); - return (0); } /* - * Remove interface from the polling list. Called from *_ioctl(), too. + * Remove interface from the polling list. Called from ioctl(2), too. */ -int -ether_poll_deregister(if_t ifp) +void +if_poll_deregister(struct ifnet *ifp) { int i; - KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); - mtx_lock(&poll_mtx); - for (i = 0 ; i < poll_handlers ; i++) - if (pr[i].ifp == ifp) /* found it */ + if (poll_table[i] == ifp) /* found it */ break; - if (i == poll_handlers) { - log(LOG_DEBUG, "ether_poll_deregister: %s: not found!\n", - ifp->if_xname); - mtx_unlock(&poll_mtx); - return (ENOENT); - } + KASSERT(i < poll_handlers, ("%s: can't find %p", __func__, ifp)); poll_handlers--; - if (i < poll_handlers) { /* Last entry replaces this one. */ - pr[i].handler = pr[poll_handlers].handler; - pr[i].ifp = pr[poll_handlers].ifp; - } + if (i < poll_handlers) /* Last entry replaces this one. */ + poll_table[i] = poll_table[poll_handlers]; mtx_unlock(&poll_mtx); - return (0); } static void Modified: projects/ifnet/sys/net/if_var.h ============================================================================== --- projects/ifnet/sys/net/if_var.h Mon Jan 19 21:30:40 2015 (r277398) +++ projects/ifnet/sys/net/if_var.h Mon Jan 19 21:40:13 2015 (r277399) @@ -424,12 +424,9 @@ void if_tsomax_common(const struct iftso int if_tsomax_update(if_t ifp, const struct iftsomax *); #ifdef DEVICE_POLLING -enum poll_cmd { POLL_ONLY, POLL_AND_CHECK_STATUS }; - -typedef int poll_handler_t(if_t ifp, enum poll_cmd cmd, int count); -int ether_poll_register(poll_handler_t *h, if_t ifp); -int ether_poll_deregister(if_t ifp); -#endif /* DEVICE_POLLING */ +void if_poll_register(struct ifnet *ifp); +void if_poll_deregister(struct ifnet *ifp); +#endif /* * Wrappers around ifops. Some ops are optional and can be NULL, @@ -515,6 +512,15 @@ if_reassign(if_t ifp, struct vnet *new) return (ifp->if_ops->ifop_reassign(ifp, new)); } +#ifdef DEVICE_POLLING +static inline int +if_poll(if_t ifp, enum poll_cmd cmd, int count) +{ + + return (ifp->if_ops->ifop_poll(ifp, cmd, count)); +} +#endif + /* * Inliners to shorten code, and make protocols more ifnet-agnostic. */