Index: kern/kern_poll.c =================================================================== RCS file: /private/FreeBSD/src/sys/kern/kern_poll.c,v retrieving revision 1.18 diff -u -p -r1.18 kern_poll.c --- kern/kern_poll.c 3 Jul 2004 02:38:03 -0000 1.18 +++ kern/kern_poll.c 16 Feb 2005 00:08:03 -0000 @@ -41,12 +41,6 @@ __FBSDID("$FreeBSD: src/sys/kern/kern_po #include #include -#ifdef SMP -#ifndef COMPILING_LINT -#error DEVICE_POLLING is not compatible with SMP -#endif -#endif - static void netisr_poll(void); /* the two netisr handlers */ static void netisr_pollmore(void); @@ -150,7 +144,7 @@ static int residual_burst = 0; SYSCTL_INT(_kern_polling, OID_AUTO, residual_burst, CTLFLAG_RW, &residual_burst, 0, "# of residual cycles in burst"); -static u_int32_t poll_handlers; /* next free entry in pr[]. */ +static u_int32_t poll_handlers; SYSCTL_UINT(_kern_polling, OID_AUTO, handlers, CTLFLAG_RD, &poll_handlers, 0, "Number of registered poll handlers"); @@ -177,18 +171,22 @@ SYSCTL_UINT(_kern_polling, OID_AUTO, idl #define POLL_LIST_LEN 128 struct pollrec { - poll_handler_t *handler; - struct ifnet *ifp; + poll_handler_t *pr_handler; + struct ifnet *pr_ifp; + LIST_ENTRY(pollrec) pr_next; }; - -static struct pollrec pr[POLL_LIST_LEN]; +static LIST_HEAD(, pollrec) poll_list = LIST_HEAD_INITIALIZER(&poll_list); +static struct mtx poll_mtx; +MTX_SYSINIT(poll, &poll_mtx, "polling", MTX_DEF); static void init_device_poll(void) { - netisr_register(NETISR_POLL, (netisr_t *)netisr_poll, NULL, 0); - netisr_register(NETISR_POLLMORE, (netisr_t *)netisr_pollmore, NULL, 0); + netisr_register(NETISR_POLL, (netisr_t *)netisr_poll, NULL, + NETISR_MPSAFE); + netisr_register(NETISR_POLLMORE, (netisr_t *)netisr_pollmore, NULL, + NETISR_MPSAFE); } SYSINIT(device_poll, SI_SUB_CLOCKS, SI_ORDER_MIDDLE, init_device_poll, NULL) @@ -250,17 +248,17 @@ hardclock_device_poll(void) void ether_poll(int count) { - int i; - - mtx_lock(&Giant); + struct pollrec *prec, *prec_tmp; + mtx_lock(&poll_mtx); if (count > poll_each_burst) count = poll_each_burst; - for (i = 0 ; i < poll_handlers ; i++) - if (pr[i].handler && (IFF_UP|IFF_RUNNING) == - (pr[i].ifp->if_flags & (IFF_UP|IFF_RUNNING)) ) - pr[i].handler(pr[i].ifp, 0, count); /* quick check */ - mtx_unlock(&Giant); + LIST_FOREACH_SAFE(prec, &poll_list, pr_next, prec_tmp) { + mtx_unlock(&poll_mtx); + prec->pr_handler(prec->pr_ifp, 0, count); /* quick check */ + mtx_lock(&poll_mtx); + } + mtx_unlock(&poll_mtx); } /* @@ -332,11 +330,12 @@ netisr_pollmore() static void netisr_poll(void) { + struct pollrec *prec, *prec_tmp; static int reg_frac_count; - int i, cycles; + int cycles; enum poll_cmd arg = POLL_ONLY; - mtx_lock(&Giant); + mtx_lock(&poll_mtx); phase = 3; if (residual_burst == 0) { /* first call in this tick */ microuptime(&poll_start_t); @@ -378,25 +377,23 @@ netisr_poll(void) residual_burst -= cycles; if (polling) { - for (i = 0 ; i < poll_handlers ; i++) - if (pr[i].handler && (IFF_UP|IFF_RUNNING) == - (pr[i].ifp->if_flags & (IFF_UP|IFF_RUNNING)) ) - pr[i].handler(pr[i].ifp, arg, cycles); + LIST_FOREACH_SAFE(prec, &poll_list, pr_next, prec_tmp) { + mtx_unlock(&poll_mtx); + prec->pr_handler(prec->pr_ifp, arg, cycles); + mtx_lock(&poll_mtx); + } } else { /* unregister */ - for (i = 0 ; i < poll_handlers ; i++) { - if (pr[i].handler && - pr[i].ifp->if_flags & IFF_RUNNING) { - pr[i].ifp->if_flags &= ~IFF_POLLING; - pr[i].handler(pr[i].ifp, POLL_DEREGISTER, 1); - } - pr[i].handler=NULL; + LIST_FOREACH_SAFE(prec, &poll_list, pr_next, prec_tmp) { + mtx_unlock(&poll_mtx); + prec->pr_handler(prec->pr_ifp, POLL_DEREGISTER, 1); + mtx_lock(&poll_mtx); } residual_burst = 0; poll_handlers = 0; } /* on -stable, schednetisr(NETISR_POLLMORE); */ phase = 4; - mtx_unlock(&Giant); + mtx_unlock(&poll_mtx); } /* @@ -410,7 +407,7 @@ netisr_poll(void) int ether_poll_register(poll_handler_t *h, struct ifnet *ifp) { - int s; + struct pollrec *prec; if (polling == 0) /* polling disabled, cannot register */ return 0; @@ -421,8 +418,13 @@ ether_poll_register(poll_handler_t *h, s if (ifp->if_flags & IFF_POLLING) /* already polling */ return 0; - s = splhigh(); - if (poll_handlers >= POLL_LIST_LEN) { + mtx_lock(&poll_mtx); + LIST_FOREACH(prec, &poll_list, pr_next) { + /* already registered? */ + if (prec->pr_ifp == ifp) + break; + } + if (prec != NULL || poll_handlers >= POLL_LIST_LEN) { /* * List full, cannot register more entries. * This should never happen; if it does, it is probably a @@ -431,20 +433,26 @@ ether_poll_register(poll_handler_t *h, s * anyways, so just report a few times and then give up. */ static int verbose = 10 ; - splx(s); if (verbose >0) { printf("poll handlers list full, " "maybe a broken driver ?\n"); verbose--; } + mtx_unlock(&poll_mtx); return 0; /* no polling for you */ } - pr[poll_handlers].handler = h; - pr[poll_handlers].ifp = ifp; + prec = malloc(sizeof(*prec), M_TEMP, M_NOWAIT); + if (prec == NULL) { + mtx_unlock(&poll_mtx); + return 0; + } + + prec->pr_handler = h; + prec->pr_ifp = ifp; poll_handlers++; + mtx_unlock(&poll_mtx); ifp->if_flags |= IFF_POLLING; - splx(s); if (idlepoll_sleeping) wakeup(&idlepoll_sleeping); return 1; /* polling enabled in next call */ @@ -459,29 +467,22 @@ ether_poll_register(poll_handler_t *h, s int ether_poll_deregister(struct ifnet *ifp) { - int i; + struct pollrec *prec; - mtx_lock(&Giant); - if ( !ifp || !(ifp->if_flags & IFF_POLLING) ) { - mtx_unlock(&Giant); - return 0; - } - 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(&Giant); - printf("ether_poll_deregister: ifp not found!!!\n"); - return 0; - } - 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; + mtx_lock(&poll_mtx); + LIST_FOREACH(prec, &poll_list, pr_next) { + if (prec->pr_ifp == ifp) { + LIST_REMOVE(prec, pr_next); + poll_handlers--; + mtx_unlock(&poll_mtx); + ifp->if_flags &= ~IFF_POLLING; + free(prec, M_TEMP); + return (1); + } } - mtx_unlock(&Giant); - return 1; + mtx_unlock(&poll_mtx); + printf("ether_poll_deregister: ifp not found!!!\n"); + return (0); } static void @@ -501,10 +502,7 @@ poll_idle(void) for (;;) { if (poll_in_idle_loop && poll_handlers > 0) { idlepoll_sleeping = 0; - mtx_lock(&Giant); ether_poll(poll_each_burst); - mtx_unlock(&Giant); - mtx_assert(&Giant, MA_NOTOWNED); mtx_lock_spin(&sched_lock); mi_switch(SW_VOL, NULL); mtx_unlock_spin(&sched_lock); Index: dev/fxp/if_fxp.c =================================================================== RCS file: /private/FreeBSD/src/sys/dev/fxp/if_fxp.c,v retrieving revision 1.220 diff -u -p -r1.220 if_fxp.c --- dev/fxp/if_fxp.c 20 Dec 2004 10:18:21 -0000 1.220 +++ dev/fxp/if_fxp.c 16 Feb 2005 00:06:41 -0000 @@ -1469,6 +1469,10 @@ fxp_poll(struct ifnet *ifp, enum poll_cm u_int8_t statack; FXP_LOCK(sc); + if (!(ifp->if_flags & IFF_RUNNING)) { + FXP_UNLOCK(sc); + return; + } if (!(ifp->if_capenable & IFCAP_POLLING)) { ether_poll_deregister(ifp); cmd = POLL_DEREGISTER; @@ -1477,6 +1481,9 @@ fxp_poll(struct ifnet *ifp, enum poll_cm CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0); FXP_UNLOCK(sc); return; + } else if (!(ifp->if_flags & IFF_UP)) { + FXP_UNLOCK(sc); + return; } statack = FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA | FXP_SCB_STATACK_FR;