From a29576fcd8d0c20866710de100e13073a50fea35 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sun, 27 Jun 2004 19:40:14 +0000 Subject: [PATCH] The schednetisr() routine is supposed to be MP and interrupt safe, but wasn't because it allocated its messages. Instead of allocating a message use a fixed message in the netisr structure. Get rid of #ifdef SMP/#error. DEVICE_POLLING now works on SMP builds. Implement an emergency polling enable function to try to keep the system operational in a degraded state if interrupt routing is blown. NOTE: only vr0 uses the feature at the moment, and DEVICE_POLLING must be enabled. --- sys/kern/kern_poll.c | 59 ++++++++++++++------------------------ sys/net/if_var.h | 3 +- sys/net/netisr.c | 68 +++++++++++++++++++++++++++++++++++--------- sys/net/netisr.h | 5 ++-- 4 files changed, 80 insertions(+), 55 deletions(-) diff --git a/sys/kern/kern_poll.c b/sys/kern/kern_poll.c index 29e9b0e751..45d56d1042 100644 --- a/sys/kern/kern_poll.c +++ b/sys/kern/kern_poll.c @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/kern_poll.c,v 1.2.2.4 2002/06/27 23:26:33 luigi Exp $ - * $DragonFly: src/sys/kern/kern_poll.c,v 1.12 2004/04/21 18:13:47 dillon Exp $ + * $DragonFly: src/sys/kern/kern_poll.c,v 1.13 2004/06/27 19:40:12 dillon Exp $ */ #include @@ -41,13 +41,6 @@ #include /* for IFF_* flags */ #include /* for NETISR_POLL */ -#ifdef SMP -#include "opt_lint.h" -#ifndef COMPILING_LINT -#error DEVICE_POLLING is not compatible with SMP -#endif -#endif - /* the two netisr handlers */ static int netisr_poll(struct netmsg *); static int netisr_pollmore(struct netmsg *); @@ -55,7 +48,6 @@ static int netisr_pollmore(struct netmsg *); void init_device_poll(void); /* init routine */ void hardclock_device_poll(void); /* hook from hardclock */ void ether_poll(int); /* polling while in trap */ -int idle_poll(void); /* poll while in idle loop */ /* * Polling support for [network] device drivers. @@ -122,10 +114,6 @@ static u_int32_t poll_burst_max = 150; /* good for 100Mbit net and HZ=1000 */ SYSCTL_UINT(_kern_polling, OID_AUTO, burst_max, CTLFLAG_RW, &poll_burst_max, 0, "Max Polling burst size"); -static u_int32_t poll_in_idle_loop=1; /* 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"); @@ -264,25 +252,6 @@ ether_poll(int count) splx(s); } -/* - * idle_poll is replaces the body of the idle loop when DEVICE_POLLING - * is used. YYY not currently implemented. - */ -int -idle_poll(void) -{ - if (poll_in_idle_loop && poll_handlers > 0) { - int s = splimp(); - cpu_enable_intr(); - ether_poll(poll_each_burst); - cpu_disable_intr(); - splx(s); - vm_page_zero_idle(); - return 1; - } else - return vm_page_zero_idle(); -} - /* * netisr_pollmore is called after other netisr's, possibly scheduling * another NETISR_POLL call, or adapting the burst size for the next cycle. @@ -309,6 +278,7 @@ netisr_pollmore(struct netmsg *msg) int kern_load; int s = splhigh(); + lwkt_replymsg(&msg->nm_lmsg, 0); phase = 5; if (residual_burst > 0) { schednetisr(NETISR_POLL); @@ -329,9 +299,9 @@ netisr_pollmore(struct netmsg *msg) } pending_polls--; - if (pending_polls == 0) /* we are done */ + if (pending_polls == 0) { /* we are done */ phase = 0; - else { + } else { /* * Last cycle was long and caused us to miss one or more * hardclock ticks. Restart processing again, but slightly @@ -345,7 +315,6 @@ netisr_pollmore(struct netmsg *msg) } out: splx(s); - lwkt_replymsg(&msg->nm_lmsg, 0); return(EASYNC); } @@ -353,6 +322,9 @@ out: * netisr_poll is scheduled by schednetisr when appropriate, typically once * per tick. It is called at splnet() so first thing to do is to upgrade to * splimp(), and call all registered handlers. + * + * Note that the message is replied immediately in order to allow a new + * ISR to be scheduled in the handler. */ /* ARGSUSED */ static int @@ -361,8 +333,10 @@ netisr_poll(struct netmsg *msg) static int reg_frac_count; int i, cycles; enum poll_cmd arg = POLL_ONLY; - int s=splimp(); + int s; + lwkt_replymsg(&msg->nm_lmsg, 0); + s = splimp(); phase = 3; if (residual_burst == 0) { /* first call in this tick */ microuptime(&poll_start_t); @@ -402,10 +376,11 @@ netisr_poll(struct netmsg *msg) residual_burst -= cycles; if (polling) { - for (i = 0 ; i < poll_handlers ; i++) + 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); + } } else { /* unregister */ for (i = 0 ; i < poll_handlers ; i++) { if (pr[i].handler && @@ -421,7 +396,6 @@ netisr_poll(struct netmsg *msg) schednetisr(NETISR_POLLMORE); phase = 4; splx(s); - lwkt_replymsg(&msg->nm_lmsg, 0); return(EASYNC); } @@ -507,3 +481,12 @@ ether_poll_deregister(struct ifnet *ifp) splx(s); return 1; } + +void +emergency_poll_enable(const char *name) +{ + if (polling == 0) { + polling = 1; + printf("%s forced polling on\n", name); + } +} diff --git a/sys/net/if_var.h b/sys/net/if_var.h index d877ee52cc..17e7ae64b8 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -32,7 +32,7 @@ * * From: @(#)if.h 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/net/if_var.h,v 1.18.2.16 2003/04/15 18:11:19 fjoe Exp $ - * $DragonFly: src/sys/net/if_var.h,v 1.11 2004/04/16 14:24:36 joerg Exp $ + * $DragonFly: src/sys/net/if_var.h,v 1.12 2004/06/27 19:40:14 dillon Exp $ */ #ifndef _NET_IF_VAR_H_ @@ -416,6 +416,7 @@ 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); int ether_poll_deregister(struct ifnet *ifp); +void emergency_poll_enable(const char *name); #endif /* DEVICE_POLLING */ #endif /* _KERNEL */ diff --git a/sys/net/netisr.c b/sys/net/netisr.c index c3cde6d33b..5cb97bb274 100644 --- a/sys/net/netisr.c +++ b/sys/net/netisr.c @@ -3,7 +3,7 @@ * Copyright (c) 2003 Jonathan Lemon * Copyright (c) 2003 Matthew Dillon * - * $DragonFly: src/sys/net/netisr.c,v 1.17 2004/06/07 07:01:36 dillon Exp $ + * $DragonFly: src/sys/net/netisr.c,v 1.18 2004/06/27 19:40:14 dillon Exp $ */ #include @@ -29,6 +29,7 @@ static struct netisr netisrs[NETISR_MAX]; /* Per-CPU thread to handle any protocol. */ struct thread netisr_cpu[MAXCPU]; lwkt_port netisr_afree_rport; +lwkt_port netisr_adone_rport; lwkt_port netisr_sync_port; /* @@ -41,6 +42,14 @@ netisr_autofree_reply(lwkt_port_t port, lwkt_msg_t msg) free(msg, M_LWKTMSG); } +static void +netisr_autodone_reply(lwkt_port_t port, lwkt_msg_t msg) +{ + crit_enter(); + msg->ms_flags |= MSGF_DONE|MSGF_REPLY1; + crit_exit(); +} + /* * We must construct a custom putport function (which runs in the context * of the message originator) @@ -123,10 +132,13 @@ netisr_init(void) /* * The netisr_afree_rport is a special reply port which automatically - * frees the replied message. + * frees the replied message. The netisr_adone_rport() simply marks + * the message as being done. */ lwkt_initport(&netisr_afree_rport, NULL); netisr_afree_rport.mp_replyport = netisr_autofree_reply; + lwkt_initport(&netisr_adone_rport, NULL); + netisr_adone_rport.mp_replyport = netisr_autodone_reply; /* * The netisr_syncport is a special port which executes the message @@ -144,8 +156,9 @@ netmsg_service_loop(void *arg) { struct netmsg *msg; - while ((msg = lwkt_waitport(&curthread->td_msgport, NULL))) + while ((msg = lwkt_waitport(&curthread->td_msgport, NULL))) { msg->nm_lmsg.ms_cmd.cm_func(&msg->nm_lmsg); + } } /* @@ -189,6 +202,7 @@ netisr_queue(int num, struct mbuf *m) lwkt_initmsg(&pmsg->nm_lmsg, &netisr_afree_rport, 0, lwkt_cmd_func((void *)ni->ni_handler), lwkt_cmd_op_none); pmsg->nm_packet = m; + pmsg->nm_lmsg.u.ms_result = num; lwkt_sendmsg(port, &pmsg->nm_lmsg); return (0); } @@ -198,7 +212,8 @@ netisr_register(int num, lwkt_portfn_t mportfn, netisr_fn_t handler) { KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), ("netisr_register: bad isr %d", num)); - + lwkt_initmsg(&netisrs[num].ni_netmsg.nm_lmsg, &netisr_adone_rport, 0, + lwkt_cmd_op_none, lwkt_cmd_op_none); netisrs[num].ni_mport = mportfn; netisrs[num].ni_handler = handler; } @@ -238,23 +253,48 @@ sync_soport(struct socket *so __unused, struct sockaddr *nam __unused, } /* - * This function is used to call the netisr handler from the appropriate + * schednetisr() is used to call the netisr handler from the appropriate * netisr thread for polling and other purposes. + * + * This function may be called from a hard interrupt or IPI and must be + * MP SAFE and non-blocking. We use a fixed per-cpu message instead of + * trying to allocate one. We must get ourselves onto the target cpu + * to safely check the MSGF_DONE bit on the message but since the message + * will be sent to that cpu anyway this does not add any extra work beyond + * what lwkt_sendmsg() would have already had to do to schedule the target + * thread. */ -void -schednetisr(int num) +static void +schednetisr_remote(void *data) { + int num = (int)data; struct netisr *ni = &netisrs[num]; - struct netmsg *pmsg; lwkt_port_t port = &netisr_cpu[0].td_msgport; + struct netmsg *pmsg; - KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), - ("schednetisr: bad isr %d", num)); - - pmsg = malloc(sizeof(struct netmsg), M_LWKTMSG, M_NOWAIT); - if (pmsg) { - lwkt_initmsg(&pmsg->nm_lmsg, &netisr_afree_rport, 0, + pmsg = &netisrs[num].ni_netmsg; + crit_enter(); + if (pmsg->nm_lmsg.ms_flags & MSGF_DONE) { + lwkt_initmsg(&pmsg->nm_lmsg, &netisr_adone_rport, 0, lwkt_cmd_func((void *)ni->ni_handler), lwkt_cmd_op_none); + pmsg->nm_lmsg.u.ms_result = num; lwkt_sendmsg(port, &pmsg->nm_lmsg); } + crit_exit(); +} + +void +schednetisr(int num) +{ + KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), + ("schednetisr: bad isr %d", num)); +#ifdef SMP + if (mycpu->gd_cpuid != 0) + lwkt_send_ipiq(globaldata_find(0), schednetisr_remote, (void *)num); + else + schednetisr_remote((void *)num); +#else + schednetisr_remote((void *)num); +#endif } + diff --git a/sys/net/netisr.h b/sys/net/netisr.h index 87d67f8647..600a514876 100644 --- a/sys/net/netisr.h +++ b/sys/net/netisr.h @@ -32,7 +32,7 @@ * * @(#)netisr.h 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/net/netisr.h,v 1.21.2.5 2002/02/09 23:02:39 luigi Exp $ - * $DragonFly: src/sys/net/netisr.h,v 1.17 2004/04/24 06:55:57 hsu Exp $ + * $DragonFly: src/sys/net/netisr.h,v 1.18 2004/06/27 19:40:14 dillon Exp $ */ #ifndef _NET_NETISR_H_ @@ -152,9 +152,10 @@ int netmsg_so_notify_abort(lwkt_msg_t); typedef lwkt_port_t (*lwkt_portfn_t)(struct mbuf *); struct netisr { - lwkt_port ni_port; /* must be first */ + lwkt_port ni_port; /* must be first */ lwkt_portfn_t ni_mport; netisr_fn_t ni_handler; + struct netmsg ni_netmsg; /* for sched_netisr() (no-data) */ }; extern lwkt_port netisr_afree_rport; -- 2.41.0