xref: /dflybsd-src/sys/net/netisr.c (revision c5541aee854b0d32586182b733a9ea4d4c92168b)
1 /*-
2  * Copyright (c) 2003 Jeffrey Hsu
3  * Copyright (c) 2003 Jonathan Lemon
4  * Copyright (c) 2003 Matthew Dillon
5  *
6  * $DragonFly: src/sys/net/netisr.c,v 1.10 2004/04/05 18:53:03 dillon Exp $
7  */
8 
9 #include <sys/param.h>
10 #include <sys/systm.h>
11 #include <sys/kernel.h>
12 #include <sys/malloc.h>
13 #include <sys/msgport.h>
14 #include <sys/proc.h>
15 #include <sys/interrupt.h>
16 #include <sys/socket.h>
17 #include <sys/sysctl.h>
18 #include <net/if.h>
19 #include <net/if_var.h>
20 #include <net/netisr.h>
21 #include <machine/cpufunc.h>
22 #include <machine/ipl.h>
23 
24 #include <sys/thread2.h>
25 #include <sys/msgport2.h>
26 
27 static struct netisr netisrs[NETISR_MAX];
28 
29 /* Per-CPU thread to handle any protocol.  */
30 struct thread netisr_cpu[MAXCPU];
31 lwkt_port netisr_afree_rport;
32 
33 /*
34  * netisr_afree_rport replymsg function, only used to handle async
35  * messages which the sender has abandoned to their fate.
36  */
37 static void
38 netisr_autofree_reply(lwkt_port_t port, lwkt_msg_t msg)
39 {
40     free(msg, M_LWKTMSG);
41 }
42 
43 static void
44 netisr_init(void)
45 {
46     int i;
47 
48     /* Create default per-cpu threads for generic protocol handling. */
49     for (i = 0; i < ncpus; ++i) {
50 	lwkt_create(netmsg_service_loop, NULL, NULL, &netisr_cpu[i], 0, i,
51 	    "netisr_cpu %d", i);
52     }
53     lwkt_initport(&netisr_afree_rport, NULL);
54     netisr_afree_rport.mp_replyport = netisr_autofree_reply;
55 }
56 
57 SYSINIT(netisr, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, netisr_init, NULL);
58 
59 /*
60  * We must construct a custom putport function (which runs in the context
61  * of the message originator)
62  * Our custom putport must check for self-referential messages, which can
63  * occur when the so_upcall routine is called (e.g. nfs).  Self referential
64  * messages are simply executed synchronously.
65  */
66 static int
67 netmsg_put_port(lwkt_port_t port, lwkt_msg_t lmsg)
68 {
69     if (port->mp_td == curthread) {
70 	struct netmsg *msg = (void *)lmsg;
71 	return(msg->nm_handler(msg));
72     }
73     return(lwkt_default_putport(port, lmsg));
74 }
75 
76 void
77 netmsg_service_loop(void *arg)
78 {
79     int error;
80     thread_t td;
81     struct netmsg *msg;
82 
83     td = curthread;
84     td->td_msgport.mp_putport = netmsg_put_port;
85 
86     while ((msg = lwkt_waitport(&td->td_msgport, NULL))) {
87 	error = msg->nm_handler(msg);
88 	lwkt_replymsg(&msg->nm_lmsg, error);
89     }
90 }
91 
92 /*
93  * Call the netisr directly.
94  * Queueing may be done in the msg port layer at its discretion.
95  */
96 void
97 netisr_dispatch(int num, struct mbuf *m)
98 {
99     /* just queue it for now XXX JH */
100     netisr_queue(num, m);
101 }
102 
103 /*
104  * Same as netisr_dispatch(), but always queue.
105  * This is either used in places where we are not confident that
106  * direct dispatch is possible, or where queueing is required.
107  */
108 int
109 netisr_queue(int num, struct mbuf *m)
110 {
111     struct netisr *ni;
112     struct netmsg_packet *pmsg;
113     lwkt_port_t port;
114 
115     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
116 	("netisr_queue: bad isr %d", num));
117 
118     ni = &netisrs[num];
119     if (ni->ni_handler == NULL) {
120 	printf("netisr_queue: unregistered isr %d\n", num);
121 	return (EIO);
122     }
123 
124     if (!(port = ni->ni_mport(m)))
125 	return (EIO);
126 
127     /* use better message allocation system with limits later XXX JH */
128     if (!(pmsg = malloc(sizeof(struct netmsg_packet), M_LWKTMSG, M_NOWAIT)))
129 	return (ENOBUFS);
130 
131     lwkt_initmsg_rp(&pmsg->nm_lmsg, &netisr_afree_rport, CMD_NETMSG_NEWPKT);
132     pmsg->nm_packet = m;
133     pmsg->nm_handler = ni->ni_handler;
134     lwkt_sendmsg(port, &pmsg->nm_lmsg);
135     return (0);
136 }
137 
138 void
139 netisr_register(int num, lwkt_portfn_t mportfn, netisr_fn_t handler)
140 {
141     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
142 	("netisr_register: bad isr %d", num));
143 
144     netisrs[num].ni_mport = mportfn;
145     netisrs[num].ni_handler = handler;
146 }
147 
148 int
149 netisr_unregister(int num)
150 {
151     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
152 	("unregister_netisr: bad isr number: %d\n", num));
153 
154     /* XXX JH */
155     return (0);
156 }
157 
158 /*
159  * Return message port for default handler thread on CPU 0.
160  */
161 lwkt_port_t
162 cpu0_portfn(struct mbuf *m)
163 {
164     return (&netisr_cpu[0].td_msgport);
165 }
166 
167 /* ARGSUSED */
168 lwkt_port_t
169 cpu0_soport(struct socket *so __unused, struct sockaddr *nam __unused)
170 {
171     return (&netisr_cpu[0].td_msgport);
172 }
173 
174 /*
175  * This function is used to call the netisr handler from the appropriate
176  * netisr thread for polling and other purposes.
177  */
178 void
179 schednetisr(int num)
180 {
181     struct netisr *ni = &netisrs[num];
182     struct netmsg *pmsg;
183     lwkt_port_t port = &netisr_cpu[0].td_msgport;
184 
185     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
186 	("schednetisr: bad isr %d", num));
187 
188     if (!(pmsg = malloc(sizeof(struct netmsg), M_LWKTMSG, M_NOWAIT)))
189 	return;
190 
191     lwkt_initmsg_rp(&pmsg->nm_lmsg, &netisr_afree_rport, CMD_NETMSG_POLL);
192     pmsg->nm_handler = ni->ni_handler;
193     lwkt_sendmsg(port, &pmsg->nm_lmsg);
194 }
195