* Add this nice filesystem testing tool that I've recently
[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.2 2003/09/15 23:38:13 hsu Exp $
7  */
8
9 #include <sys/param.h>
10 #include <sys/systm.h>
11 #include <sys/proc.h>
12 #include <sys/interrupt.h>
13 #include <sys/socket.h>
14 #include <sys/sysctl.h>
15 #include <net/if.h>
16 #include <net/if_var.h>
17 #include <net/netisr.h>
18 #include <machine/cpufunc.h>
19 #include <machine/ipl.h>
20
21 int isrmask;
22 static int isrsoftint_installed;
23 static struct netisr netisrs[NETISR_MAX];
24
25 /* SYSCTL_NODE(_net, OID_AUTO, isr, CTLFLAG_RW, 0, "netisr counters"); */
26
27 static int netisr_directdispatch = 0;
28 /*
29 SYSCTL_INT(_net_isr, OID_AUTO, directdispatch, CTLFLAG_RW,
30     &netisr_directdispatch, 0, "enable direct dispatch");
31 */
32
33 static void
34 swi_net(void *arg)
35 {
36     int mask;
37     int bit;
38         
39     while ((mask = isrmask) != 0) {
40         bit = bsfl(mask);
41         if (btrl(&isrmask, bit)) {
42             struct netisr *ni = &netisrs[bit];
43             netisr_fn_t func = ni->ni_handler;
44
45             if (ni->ni_queue) {
46                 while (1) {
47                     struct mbuf *m;
48                     int s;
49
50                     s = splimp();
51                     IF_DEQUEUE(ni->ni_queue, m);
52                     splx(s);
53                     if (!m)
54                         break;
55                     func(m);
56                 }
57             } else
58                 func(NULL);
59         }
60     }
61 }
62
63 /*
64  * Call the netisr directly instead of queueing the packet, if possible.
65  */
66 void
67 netisr_dispatch(int num, struct mbuf *m)
68 {
69     struct netisr *ni;
70
71     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
72         ("bad isr %d", num));
73
74     ni = &netisrs[num];
75
76     if (!ni->ni_queue) {
77         m_freem(m);
78         return;
79     }
80
81     if (netisr_directdispatch) {
82       /*
83        * missing check for concurrent execution from swi_net() XXX JH
84        * Address this after conversion to message ports.
85        */
86         ni->ni_handler(m);
87     } else {
88         if (IF_HANDOFF(ni->ni_queue, m, NULL))
89             schednetisr(num);
90     }
91 }
92
93 /*
94  * Same as netisr_dispatch(), but always queue.
95  * This is either used in places where we are not confident that
96  * direct dispatch is possible, or where queueing is required.
97  */
98 int
99 netisr_queue(int num, struct mbuf *m)
100 {
101     struct netisr *ni;
102
103     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
104         ("bad isr %d", num));
105
106     ni = &netisrs[num];
107
108     if (!ni->ni_queue) {
109         m_freem(m);
110         return (ENOBUFS);
111     }
112
113     if (!IF_HANDOFF(ni->ni_queue, m, NULL))
114         return (ENOBUFS);
115
116     schednetisr(num);
117     return (0);
118 }
119
120 int
121 netisr_register(int num, netisr_fn_t handler, struct ifqueue *ifq)
122 {
123     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
124         ("bad isr %d", num));
125
126     if (isrsoftint_installed == 0) {
127         isrsoftint_installed = 1;
128         register_swi(SWI_NET, swi_net, NULL, "swi_net");
129     }
130     netisrs[num].ni_handler = handler;
131     netisrs[num].ni_queue = ifq;
132     return (0);
133 }
134
135 int
136 netisr_unregister(int num)
137 {
138     KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))),
139         ("unregister_netisr: bad isr number: %d\n", num));
140
141     if (netisrs[num].ni_queue != NULL) {
142         int s;
143
144         s = splimp();
145         IF_DRAIN(netisrs[num].ni_queue);
146         splx(s);
147     }
148     netisrs[num].ni_handler = NULL;
149     return (0);
150 }