Add the standard DragonFly copyright notice to go along with mine.
[dragonfly.git] / sys / net / netisr.c
1 /*
2  * Copyright (c) 2003, 2004 Matthew Dillon. All rights reserved.
3  * Copyright (c) 2003, 2004 Jeffrey M. Hsu.  All rights reserved.
4  * Copyright (c) 2003 Jonathan Lemon.  All rights reserved.
5  * Copyright (c) 2003, 2004 The DragonFly Project.  All rights reserved.
6  *
7  * This code is derived from software contributed to The DragonFly Project
8  * by Jonathan Lemon, Jeffrey M. Hsu, and Matthew Dillon.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of The DragonFly Project nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific, prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $DragonFly: src/sys/net/netisr.c,v 1.19 2004/07/08 22:07:34 hsu Exp $
36  */
37
38 /*
39  * Copyright (c) 2003, 2004 Jeffrey M. Hsu.  All rights reserved.
40  *
41  * License terms: all terms for the DragonFly license above plus the following:
42  *
43  * 4. All advertising materials mentioning features or use of this software
44  *    must display the following acknowledgement:
45  *
46  *      This product includes software developed by Jeffrey M. Hsu
47  *      for the DragonFly Project.
48  *
49  *    This requirement may be waived with permission from Jeffrey Hsu.
50  *    This requirement will sunset and may be removed on July 8 2005,
51  *    after which the standard DragonFly license (as shown above) will
52  *    apply.
53  */
54
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/kernel.h>
58 #include <sys/malloc.h>
59 #include <sys/msgport.h>
60 #include <sys/proc.h>
61 #include <sys/interrupt.h>
62 #include <sys/socket.h>
63 #include <sys/sysctl.h>
64 #include <net/if.h>
65 #include <net/if_var.h>
66 #include <net/netisr.h>
67 #include <machine/cpufunc.h>
68 #include <machine/ipl.h>
69
70 #include <sys/thread2.h>
71 #include <sys/msgport2.h>
72
73 static struct netisr netisrs[NETISR_MAX];
74
75 /* Per-CPU thread to handle any protocol.  */
76 struct thread netisr_cpu[MAXCPU];
77 lwkt_port netisr_afree_rport;
78 lwkt_port netisr_adone_rport;
79 lwkt_port netisr_sync_port;
80
81 /*
82  * netisr_afree_rport replymsg function, only used to handle async
83  * messages which the sender has abandoned to their fate.
84  */
85 static void
86 netisr_autofree_reply(lwkt_port_t port, lwkt_msg_t msg)
87 {
88     free(msg, M_LWKTMSG);
89 }
90
91 static void
92 netisr_autodone_reply(lwkt_port_t port, lwkt_msg_t msg)
93 {
94     crit_enter();
95     msg->ms_flags |= MSGF_DONE|MSGF_REPLY1;
96     crit_exit();
97 }
98
99 /*
100  * We must construct a custom putport function (which runs in the context
101  * of the message originator)
102  *
103  * Our custom putport must check for self-referential messages, which can
104  * occur when the so_upcall routine is called (e.g. nfs).  Self referential
105  * messages are executed synchronously.  However, we must panic if the message
106  * is not marked DONE on completion because the self-referential case cannot
107  * block without deadlocking.
108  *
109  * note: ms_target_port does not need to be set when returning a synchronous
110  * error code.
111  */
112 int
113 netmsg_put_port(lwkt_port_t port, lwkt_msg_t lmsg)
114 {
115     int error;
116
117     if ((lmsg->ms_flags & MSGF_ASYNC) == 0 && port->mp_td == curthread) {
118         error = lmsg->ms_cmd.cm_func(lmsg);
119         if (error == EASYNC && (lmsg->ms_flags & MSGF_DONE) == 0)
120             panic("netmsg_put_port: self-referential deadlock on netport");
121         return(error);
122     } else {
123         return(lwkt_default_putport(port, lmsg));
124     }
125 }
126
127 /*
128  * UNIX DOMAIN sockets still have to run their uipc functions synchronously,
129  * because they depend on the user proc context for a number of things 
130  * (like creds) which we have not yet incorporated into the message structure.
131  *
132  * However, we maintain or message/port abstraction.  Having a special 
133  * synchronous port which runs the commands synchronously gives us the
134  * ability to serialize operations in one place later on when we start
135  * removing the BGL.
136  *
137  * We clear MSGF_DONE prior to executing the message in order to close
138  * any potential replymsg races with the flags field.  If a synchronous
139  * result code is returned we set MSGF_DONE again.  MSGF_DONE's flag state
140  * must be correct or the caller will be confused.
141  */
142 static int
143 netmsg_sync_putport(lwkt_port_t port, lwkt_msg_t lmsg)
144 {
145     int error;
146
147     lmsg->ms_flags &= ~MSGF_DONE;
148     lmsg->ms_target_port = port;        /* required for abort */
149     error = lmsg->ms_cmd.cm_func(lmsg);
150     if (error == EASYNC)
151         error = lwkt_waitmsg(lmsg);
152     else
153         lmsg->ms_flags |= MSGF_DONE;
154     return(error);
155 }
156
157 static void
158 netmsg_sync_abortport(lwkt_port_t port, lwkt_msg_t lmsg)
159 {
160     lmsg->ms_abort_port = lmsg->ms_reply_port;
161     lmsg->ms_flags |= MSGF_ABORTED;
162     lmsg->ms_abort.cm_func(lmsg);
163 }
164
165 static void
166 netisr_init(void)
167 {
168     int i;
169
170     /*
171      * Create default per-cpu threads for generic protocol handling.
172      */
173     for (i = 0; i < ncpus; ++i) {
174         lwkt_create(netmsg_service_loop, NULL, NULL, &netisr_cpu[i], 0, i,
175             "netisr_cpu %d", i);
176         netisr_cpu[i].td_msgport.mp_putport = netmsg_put_port;
177     }
178
179     /*
180      * The netisr_afree_rport is a special reply port which automatically
181      * frees the replied message.  The netisr_adone_rport() simply marks
182      * the message as being done.
183      */
184     lwkt_initport(&netisr_afree_rport, NULL);
185     netisr_afree_rport.mp_replyport = netisr_autofree_reply;
186     lwkt_initport(&netisr_adone_rport, NULL);
187     netisr_adone_rport.mp_replyport = netisr_autodone_reply;
188
189     /*
190      * The netisr_syncport is a special port which executes the message
191      * synchronously and waits for it if EASYNC is returned.
192      */
193     lwkt_initport(&netisr_sync_port, NULL);
194     netisr_sync_port.mp_putport = netmsg_sync_putport;
195     netisr_sync_port.mp_abortport = netmsg_sync_abortport;
196 }
197
198 SYSINIT(netisr, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, netisr_init, NULL);
199
200 void
201 netmsg_service_loop(void *arg)
202 {
203     struct netmsg *msg;
204
205     while ((msg = lwkt_waitport(&curthread->td_msgport, NULL))) {
206         msg->nm_lmsg.ms_cmd.cm_func(&msg->nm_lmsg);
207     }
208 }
209
210 /*
211  * Call the netisr directly.
212  * Queueing may be done in the msg port layer at its discretion.
213  */
214 void
215 netisr_dispatch(int num, struct mbuf *m)
216 {
217     /* just queue it for now XXX JH */
218     netisr_queue(num, m);
219 }
220
221 /*
222  * Same as netisr_dispatch(), but always queue.
223  * This is either used in places where we are not confident that
224  * direct dispatch is possible, or where queueing is required.
225  */
226 int
227 netisr_queue(int num, struct mbuf *m)
228 {
229     struct netisr *ni;
230     struct netmsg_packet *pmsg;
231     lwkt_port_t port;
232
233     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
234         ("netisr_queue: bad isr %d", num));
235
236     ni = &netisrs[num];
237     if (ni->ni_handler == NULL) {
238         printf("netisr_queue: unregistered isr %d\n", num);
239         return (EIO);
240     }
241
242     if (!(port = ni->ni_mport(m)))
243         return (EIO);
244
245     /* use better message allocation system with limits later XXX JH */
246     pmsg = malloc(sizeof(struct netmsg_packet), M_LWKTMSG, M_WAITOK);
247
248     lwkt_initmsg(&pmsg->nm_lmsg, &netisr_afree_rport, 0,
249                 lwkt_cmd_func((void *)ni->ni_handler), lwkt_cmd_op_none);
250     pmsg->nm_packet = m;
251     pmsg->nm_lmsg.u.ms_result = num;
252     lwkt_sendmsg(port, &pmsg->nm_lmsg);
253     return (0);
254 }
255
256 void
257 netisr_register(int num, lwkt_portfn_t mportfn, netisr_fn_t handler)
258 {
259     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
260         ("netisr_register: bad isr %d", num));
261     lwkt_initmsg(&netisrs[num].ni_netmsg.nm_lmsg, &netisr_adone_rport, 0,
262             lwkt_cmd_op_none, lwkt_cmd_op_none);
263     netisrs[num].ni_mport = mportfn;
264     netisrs[num].ni_handler = handler;
265 }
266
267 int
268 netisr_unregister(int num)
269 {
270     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
271         ("unregister_netisr: bad isr number: %d\n", num));
272
273     /* XXX JH */
274     return (0);
275 }
276
277 /*
278  * Return message port for default handler thread on CPU 0.
279  */
280 lwkt_port_t
281 cpu0_portfn(struct mbuf *m)
282 {
283     return (&netisr_cpu[0].td_msgport);
284 }
285
286 /* ARGSUSED */
287 lwkt_port_t
288 cpu0_soport(struct socket *so __unused, struct sockaddr *nam __unused,
289             int req __unused)
290 {
291     return (&netisr_cpu[0].td_msgport);
292 }
293
294 lwkt_port_t
295 sync_soport(struct socket *so __unused, struct sockaddr *nam __unused,
296             int req __unused)
297 {
298     return (&netisr_sync_port);
299 }
300
301 /*
302  * schednetisr() is used to call the netisr handler from the appropriate
303  * netisr thread for polling and other purposes.
304  *
305  * This function may be called from a hard interrupt or IPI and must be
306  * MP SAFE and non-blocking.  We use a fixed per-cpu message instead of
307  * trying to allocate one.  We must get ourselves onto the target cpu
308  * to safely check the MSGF_DONE bit on the message but since the message
309  * will be sent to that cpu anyway this does not add any extra work beyond
310  * what lwkt_sendmsg() would have already had to do to schedule the target
311  * thread.
312  */
313 static void
314 schednetisr_remote(void *data)
315 {
316     int num = (int)data;
317     struct netisr *ni = &netisrs[num];
318     lwkt_port_t port = &netisr_cpu[0].td_msgport;
319     struct netmsg *pmsg;
320
321     pmsg = &netisrs[num].ni_netmsg;
322     crit_enter();
323     if (pmsg->nm_lmsg.ms_flags & MSGF_DONE) {
324         lwkt_initmsg(&pmsg->nm_lmsg, &netisr_adone_rport, 0,
325                     lwkt_cmd_func((void *)ni->ni_handler), lwkt_cmd_op_none);
326         pmsg->nm_lmsg.u.ms_result = num;
327         lwkt_sendmsg(port, &pmsg->nm_lmsg);
328     }
329     crit_exit();
330 }
331
332 void
333 schednetisr(int num)
334 {
335     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
336         ("schednetisr: bad isr %d", num));
337 #ifdef SMP
338     if (mycpu->gd_cpuid != 0)
339         lwkt_send_ipiq(globaldata_find(0), schednetisr_remote, (void *)num);
340     else
341         schednetisr_remote((void *)num);
342 #else
343     schednetisr_remote((void *)num);
344 #endif
345 }
346