Network threading stage 1/3: netisrs are already software interrupts,
[dragonfly.git] / sys / net / netisr.c
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.3 2003/11/08 07:57:42 dillon Exp $
7  */
8
9 #include <sys/param.h>
10 #include <sys/systm.h>
11 #include <sys/kernel.h>
12 #include <sys/msgport.h>
13 #include <sys/msgport2.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 struct netmsg {
25     struct lwkt_msg     nm_lmsg;
26     struct mbuf         *nm_packet;
27     netisr_fn_t         nm_handler;
28 };
29
30 #define CMD_NETMSG_NEWPKT       (MSG_CMD_NETMSG | 0x0001)
31 #define CMD_NETMSG_POLL         (MSG_CMD_NETMSG | 0x0002)
32
33 static struct netisr netisrs[NETISR_MAX];
34
35 /* Per-CPU thread to handle any protocol.  */
36 struct thread netisr_cpu[MAXCPU];
37
38 static void
39 netisr_init(void)
40 {
41     int i;
42
43     /* Create default per-cpu threads for generic protocol handling. */
44     for (i = 0; i < ncpus; ++i)
45         lwkt_create(netmsg_service_loop, NULL, NULL, &netisr_cpu[i], 0, i,
46             "netisr_cpu %d", i);
47 }
48
49 SYSINIT(netisr, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, netisr_init, NULL);
50
51 void
52 netmsg_service_loop(void *arg)
53 {
54     struct netmsg *msg;
55
56     while ((msg = lwkt_waitport(&curthread->td_msgport))) {
57         struct mbuf *m = msg->nm_packet;
58         netisr_fn_t handler = msg->nm_handler;
59
60         if (handler)
61                 handler(m);
62         else if (m)
63                 m_freem(m);
64         free(msg, M_TEMP);
65     }
66 }
67
68 /*
69  * Call the netisr directly.
70  * Queueing may be done in the msg port layer at its discretion.
71  */
72 void
73 netisr_dispatch(int num, struct mbuf *m)
74 {
75     /* just queue it for now XXX JH */
76     netisr_queue(num, m);
77 }
78
79 /*
80  * Same as netisr_dispatch(), but always queue.
81  * This is either used in places where we are not confident that
82  * direct dispatch is possible, or where queueing is required.
83  */
84 int
85 netisr_queue(int num, struct mbuf *m)
86 {
87     struct netisr *ni = &netisrs[num];
88     struct netmsg *pmsg;
89     lwkt_port_t port;
90
91     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
92         ("bad isr %d", num));
93
94     /* use better message allocation system with limits later XXX JH */
95     if (!(pmsg = malloc(sizeof(struct netmsg), M_TEMP, M_NOWAIT)))
96         return (ENOBUFS);
97
98     if (!(port = ni->ni_mport(m)))
99         return EIO;
100
101     lwkt_initmsg(&pmsg->nm_lmsg, port, CMD_NETMSG_NEWPKT);
102     pmsg->nm_packet = m;
103     pmsg->nm_handler = ni->ni_handler;
104     lwkt_sendmsg(port, &pmsg->nm_lmsg);
105     return (0);
106 }
107
108 void
109 netisr_register(int num, lwkt_portfn_t mportfn, netisr_fn_t handler)
110 {
111     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
112         ("bad isr %d", num));
113
114     netisrs[num].ni_mport = mportfn;
115     netisrs[num].ni_handler = handler;
116 }
117
118 int
119 netisr_unregister(int num)
120 {
121     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
122         ("unregister_netisr: bad isr number: %d\n", num));
123
124     /* XXX JH */
125     return (0);
126 }
127
128 /*
129  * Return message port for default handler thread on CPU 0.
130  */
131 lwkt_port_t
132 cpu0_portfn(struct mbuf *m)
133 {
134     return (&netisr_cpu[0].td_msgport);
135 }
136
137 /*
138  * This function is used to call the netisr handler from the appropriate
139  * netisr thread for polling and other purposes.  pmsg->nm_packet will be
140  * undefined.  At the moment operation is restricted to non-packet ISRs only.
141  */
142 void
143 schednetisr(int num)
144 {
145     struct netisr *ni = &netisrs[num];
146     struct netmsg *pmsg;
147     lwkt_port_t port = &netisr_cpu[0].td_msgport;
148
149     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
150         ("bad isr %d", num));
151
152     if (!(pmsg = malloc(sizeof(struct netmsg), M_TEMP, M_NOWAIT)))
153         return;
154
155     lwkt_initmsg(&pmsg->nm_lmsg, port, CMD_NETMSG_POLL);
156     pmsg->nm_handler = ni->ni_handler;
157     lwkt_sendmsg(port, &pmsg->nm_lmsg);
158 }