xref: /freebsd/sys/net/netisr.c (revision fb68148f4a68481f1e491c6790615fbc069eba17)
11cafed39SJonathan Lemon /*-
21cafed39SJonathan Lemon  * Copyright (c) 2001,2002,2003 Jonathan Lemon <jlemon@FreeBSD.org>
3e3b6e33cSJake Burkholder  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
4e3b6e33cSJake Burkholder  * All rights reserved.
5e3b6e33cSJake Burkholder  *
6e3b6e33cSJake Burkholder  * Redistribution and use in source and binary forms, with or without
7e3b6e33cSJake Burkholder  * modification, are permitted provided that the following conditions
8e3b6e33cSJake Burkholder  * are met:
9e3b6e33cSJake Burkholder  * 1. Redistributions of source code must retain the above copyright
101cafed39SJonathan Lemon  *    notice, this list of conditions and the following disclaimer.
11e3b6e33cSJake Burkholder  * 2. Redistributions in binary form must reproduce the above copyright
12e3b6e33cSJake Burkholder  *    notice, this list of conditions and the following disclaimer in the
13e3b6e33cSJake Burkholder  *    documentation and/or other materials provided with the distribution.
14e3b6e33cSJake Burkholder  *
151cafed39SJonathan Lemon  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161cafed39SJonathan Lemon  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171cafed39SJonathan Lemon  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181cafed39SJonathan Lemon  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191cafed39SJonathan Lemon  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201cafed39SJonathan Lemon  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211cafed39SJonathan Lemon  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221cafed39SJonathan Lemon  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231cafed39SJonathan Lemon  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241cafed39SJonathan Lemon  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251cafed39SJonathan Lemon  * SUCH DAMAGE.
26e3b6e33cSJake Burkholder  *
27e3b6e33cSJake Burkholder  * $FreeBSD$
28e3b6e33cSJake Burkholder  */
29e3b6e33cSJake Burkholder 
30e3b6e33cSJake Burkholder #include <sys/param.h>
31e3b6e33cSJake Burkholder #include <sys/bus.h>
321cafed39SJonathan Lemon #include <sys/rtprio.h>
331cafed39SJonathan Lemon #include <sys/systm.h>
34e3b6e33cSJake Burkholder #include <sys/interrupt.h>
35e3b6e33cSJake Burkholder #include <sys/kernel.h>
361cafed39SJonathan Lemon #include <sys/kthread.h>
371cafed39SJonathan Lemon #include <sys/lock.h>
381cafed39SJonathan Lemon #include <sys/malloc.h>
391cafed39SJonathan Lemon #include <sys/proc.h>
401cafed39SJonathan Lemon #include <sys/random.h>
411cafed39SJonathan Lemon #include <sys/resourcevar.h>
421cafed39SJonathan Lemon #include <sys/sysctl.h>
431cafed39SJonathan Lemon #include <sys/unistd.h>
441cafed39SJonathan Lemon #include <machine/atomic.h>
451cafed39SJonathan Lemon #include <machine/cpu.h>
461cafed39SJonathan Lemon #include <machine/stdarg.h>
47e3b6e33cSJake Burkholder 
481cafed39SJonathan Lemon #include <sys/mbuf.h>
491cafed39SJonathan Lemon #include <sys/socket.h>
501cafed39SJonathan Lemon 
511cafed39SJonathan Lemon #include <net/if.h>
521cafed39SJonathan Lemon #include <net/if_types.h>
531cafed39SJonathan Lemon #include <net/if_var.h>
54e3b6e33cSJake Burkholder #include <net/netisr.h>
55e3b6e33cSJake Burkholder 
561cafed39SJonathan Lemon volatile unsigned int	netisr;	/* scheduling bits for network */
57e3b6e33cSJake Burkholder 
581cafed39SJonathan Lemon struct netisr {
591cafed39SJonathan Lemon 	netisr_t	*ni_handler;
601cafed39SJonathan Lemon 	struct ifqueue	*ni_queue;
611cafed39SJonathan Lemon } netisrs[32];
621cafed39SJonathan Lemon 
631cafed39SJonathan Lemon static struct mtx netisr_mtx;
641cafed39SJonathan Lemon static void *net_ih;
65e3b6e33cSJake Burkholder 
66e3b6e33cSJake Burkholder void
67e3b6e33cSJake Burkholder legacy_setsoftnet(void)
68e3b6e33cSJake Burkholder {
69e3b6e33cSJake Burkholder 	swi_sched(net_ih, 0);
70e3b6e33cSJake Burkholder }
71e3b6e33cSJake Burkholder 
721cafed39SJonathan Lemon void
731cafed39SJonathan Lemon netisr_register(int num, netisr_t *handler, struct ifqueue *inq)
74e3b6e33cSJake Burkholder {
75e3b6e33cSJake Burkholder 
761cafed39SJonathan Lemon 	KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))),
771cafed39SJonathan Lemon 	    ("bad isr %d", num));
781cafed39SJonathan Lemon 	netisrs[num].ni_handler = handler;
791cafed39SJonathan Lemon 	netisrs[num].ni_queue = inq;
80e3b6e33cSJake Burkholder }
81e3b6e33cSJake Burkholder 
821cafed39SJonathan Lemon void
831cafed39SJonathan Lemon netisr_unregister(int num)
84e3b6e33cSJake Burkholder {
851cafed39SJonathan Lemon 	struct netisr *ni;
861cafed39SJonathan Lemon 	int s;
87e3b6e33cSJake Burkholder 
881cafed39SJonathan Lemon 	KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))),
891cafed39SJonathan Lemon 	    ("bad isr %d", num));
901cafed39SJonathan Lemon 	ni = &netisrs[num];
911cafed39SJonathan Lemon 	ni->ni_handler = NULL;
921cafed39SJonathan Lemon 	if (ni->ni_queue != NULL) {
931cafed39SJonathan Lemon 		s = splimp();
941cafed39SJonathan Lemon 		IF_DRAIN(ni->ni_queue);
951cafed39SJonathan Lemon 		splx(s);
96e3b6e33cSJake Burkholder 	}
971cafed39SJonathan Lemon }
981cafed39SJonathan Lemon 
991cafed39SJonathan Lemon struct isrstat {
1001cafed39SJonathan Lemon 	int	isrs_count;			/* dispatch count */
1011cafed39SJonathan Lemon 	int	isrs_directed;			/* ...successfully dispatched */
1021cafed39SJonathan Lemon 	int	isrs_deferred;			/* ...queued instead */
1031cafed39SJonathan Lemon 	int	isrs_bypassed;			/* bypassed queued packets */
1041cafed39SJonathan Lemon 	int	isrs_queued;			/* intentionally queueued */
1051cafed39SJonathan Lemon 	int	isrs_swi_count;			/* swi_net handlers called */
1061cafed39SJonathan Lemon };
1071cafed39SJonathan Lemon static struct isrstat isrstat;
1081cafed39SJonathan Lemon 
1091cafed39SJonathan Lemon SYSCTL_NODE(_net, OID_AUTO, isr, CTLFLAG_RW, 0, "netisr counters");
1101cafed39SJonathan Lemon 
1111cafed39SJonathan Lemon static int	netisr_enable = 0;
1121cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, enable, CTLFLAG_RW,
1131cafed39SJonathan Lemon     &netisr_enable, 0, "enable direct dispatch");
1141cafed39SJonathan Lemon 
1151cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, count, CTLFLAG_RD,
1161cafed39SJonathan Lemon     &isrstat.isrs_count, 0, "");
1171cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, directed, CTLFLAG_RD,
1181cafed39SJonathan Lemon     &isrstat.isrs_directed, 0, "");
1191cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, deferred, CTLFLAG_RD,
1201cafed39SJonathan Lemon     &isrstat.isrs_deferred, 0, "");
1211cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, bypassed, CTLFLAG_RD,
1221cafed39SJonathan Lemon     &isrstat.isrs_bypassed, 0, "");
1231cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, queued, CTLFLAG_RD,
1241cafed39SJonathan Lemon     &isrstat.isrs_queued, 0, "");
1251cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, swi_count, CTLFLAG_RD,
1261cafed39SJonathan Lemon     &isrstat.isrs_swi_count, 0, "");
1271cafed39SJonathan Lemon 
1281cafed39SJonathan Lemon /*
1291cafed39SJonathan Lemon  * Call the netisr directly instead of queueing the packet, if possible.
1301cafed39SJonathan Lemon  *
1311cafed39SJonathan Lemon  * Ideally, the permissibility of calling the routine would be determined
1321cafed39SJonathan Lemon  * by checking if splnet() was asserted at the time the device interrupt
1331cafed39SJonathan Lemon  * occurred; if so, this indicates that someone is in the network stack.
1341cafed39SJonathan Lemon  *
1351cafed39SJonathan Lemon  * However, bus_setup_intr uses INTR_TYPE_NET, which sets splnet before
1361cafed39SJonathan Lemon  * calling the interrupt handler, so the previous mask is unavailable.
1371cafed39SJonathan Lemon  * Approximate this by checking intr_nesting_level instead; if any SWI
1381cafed39SJonathan Lemon  * handlers are running, the packet is queued instead.
1391cafed39SJonathan Lemon  */
1401cafed39SJonathan Lemon void
1411cafed39SJonathan Lemon netisr_dispatch(int num, struct mbuf *m)
1421cafed39SJonathan Lemon {
1431cafed39SJonathan Lemon 	struct netisr *ni;
1441cafed39SJonathan Lemon 
1451cafed39SJonathan Lemon 	isrstat.isrs_count++;
1461cafed39SJonathan Lemon 	KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))),
1471cafed39SJonathan Lemon 	    ("bad isr %d", num));
1481cafed39SJonathan Lemon 	ni = &netisrs[num];
149fb68148fSJonathan Lemon 	if (ni->ni_queue == NULL) {
150fb68148fSJonathan Lemon 		m_freem(m);
151fb68148fSJonathan Lemon 		return;
152fb68148fSJonathan Lemon 	}
1531cafed39SJonathan Lemon 	if (netisr_enable && mtx_trylock(&netisr_mtx)) {
1541cafed39SJonathan Lemon 		isrstat.isrs_directed++;
1551cafed39SJonathan Lemon 		/*
1561cafed39SJonathan Lemon 		 * One slight problem here is that packets might bypass
1571cafed39SJonathan Lemon 		 * each other in the stack, if an earlier one happened
1581cafed39SJonathan Lemon 		 * to get stuck in the queue.
1591cafed39SJonathan Lemon 		 *
1601cafed39SJonathan Lemon 		 * we can either:
1611cafed39SJonathan Lemon 		 *	a. drain the queue before handling this packet,
1621cafed39SJonathan Lemon 		 *	b. fallback to queueing the packet,
1631cafed39SJonathan Lemon 		 *	c. sweep the issue under the rug and ignore it.
1641cafed39SJonathan Lemon 		 *
1651cafed39SJonathan Lemon 		 * Currently, we do c), and keep a rough event counter.
1661cafed39SJonathan Lemon 		 */
1671cafed39SJonathan Lemon 		if (_IF_QLEN(ni->ni_queue) > 0)
1681cafed39SJonathan Lemon 			isrstat.isrs_bypassed++;
1691cafed39SJonathan Lemon 		ni->ni_handler(m);
1701cafed39SJonathan Lemon 		mtx_unlock(&netisr_mtx);
1711cafed39SJonathan Lemon 	} else {
1721cafed39SJonathan Lemon 		isrstat.isrs_deferred++;
1731cafed39SJonathan Lemon 		if (IF_HANDOFF(ni->ni_queue, m, NULL))
1741cafed39SJonathan Lemon 			schednetisr(num);
1751cafed39SJonathan Lemon 	}
1761cafed39SJonathan Lemon }
1771cafed39SJonathan Lemon 
1781cafed39SJonathan Lemon /*
1791cafed39SJonathan Lemon  * Same as above, but always queue.
1801cafed39SJonathan Lemon  * This is either used in places where we are not confident that
1811cafed39SJonathan Lemon  * direct dispatch is possible, or where queueing is required.
1821cafed39SJonathan Lemon  */
1831cafed39SJonathan Lemon int
1841cafed39SJonathan Lemon netisr_queue(int num, struct mbuf *m)
1851cafed39SJonathan Lemon {
1861cafed39SJonathan Lemon 	struct netisr *ni;
1871cafed39SJonathan Lemon 
1881cafed39SJonathan Lemon 	KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))),
1891cafed39SJonathan Lemon 	    ("bad isr %d", num));
1901cafed39SJonathan Lemon 	ni = &netisrs[num];
191fb68148fSJonathan Lemon 	if (ni->ni_queue == NULL) {
192fb68148fSJonathan Lemon 		m_freem(m);
193fb68148fSJonathan Lemon 		return (1);
194fb68148fSJonathan Lemon 	}
1951cafed39SJonathan Lemon 	isrstat.isrs_queued++;
1961cafed39SJonathan Lemon 	if (!IF_HANDOFF(ni->ni_queue, m, NULL))
197e3b6e33cSJake Burkholder 		return (0);
1981cafed39SJonathan Lemon 	schednetisr(num);
1991cafed39SJonathan Lemon 	return (1);
200e3b6e33cSJake Burkholder }
201e3b6e33cSJake Burkholder 
202e3b6e33cSJake Burkholder static void
203e3b6e33cSJake Burkholder swi_net(void *dummy)
204e3b6e33cSJake Burkholder {
2051cafed39SJonathan Lemon 	struct netisr *ni;
2061cafed39SJonathan Lemon 	struct mbuf *m;
207e3b6e33cSJake Burkholder 	u_int bits;
208e3b6e33cSJake Burkholder 	int i;
2091cafed39SJonathan Lemon #ifdef DEVICE_POLLING
2101cafed39SJonathan Lemon 	const int polling = 1;
2111cafed39SJonathan Lemon #else
2121cafed39SJonathan Lemon 	const int polling = 0;
2131cafed39SJonathan Lemon #endif
214e3b6e33cSJake Burkholder 
2151cafed39SJonathan Lemon 	mtx_lock(&netisr_mtx);
2161cafed39SJonathan Lemon 	do {
217e3b6e33cSJake Burkholder 		bits = atomic_readandclear_int(&netisr);
218e3b6e33cSJake Burkholder 		if (bits == 0)
2191cafed39SJonathan Lemon 			break;
220e3b6e33cSJake Burkholder 		while ((i = ffs(bits)) != 0) {
2211cafed39SJonathan Lemon 			isrstat.isrs_swi_count++;
222e3b6e33cSJake Burkholder 			i--;
223e3b6e33cSJake Burkholder 			bits &= ~(1 << i);
2241cafed39SJonathan Lemon 			ni = &netisrs[i];
2251cafed39SJonathan Lemon 			if (ni->ni_handler == NULL) {
2261cafed39SJonathan Lemon 				printf("swi_net: unregistered isr %d.\n", i);
2271cafed39SJonathan Lemon 				continue;
228e3b6e33cSJake Burkholder 			}
2291cafed39SJonathan Lemon 			if (ni->ni_queue == NULL)
2301cafed39SJonathan Lemon 				ni->ni_handler(NULL);
2311cafed39SJonathan Lemon 			else
2321cafed39SJonathan Lemon 				for (;;) {
2331cafed39SJonathan Lemon 					IF_DEQUEUE(ni->ni_queue, m);
2341cafed39SJonathan Lemon 					if (m == NULL)
2351cafed39SJonathan Lemon 						break;
2361cafed39SJonathan Lemon 					ni->ni_handler(m);
237e3b6e33cSJake Burkholder 				}
2381cafed39SJonathan Lemon 		}
2391cafed39SJonathan Lemon 	} while (polling);
2401cafed39SJonathan Lemon 	mtx_unlock(&netisr_mtx);
241e3b6e33cSJake Burkholder }
242e3b6e33cSJake Burkholder 
243e3b6e33cSJake Burkholder static void
244e3b6e33cSJake Burkholder start_netisr(void *dummy)
245e3b6e33cSJake Burkholder {
246e3b6e33cSJake Burkholder 
2471cafed39SJonathan Lemon 	mtx_init(&netisr_mtx, "netisr lock", NULL, MTX_DEF);
248e3b6e33cSJake Burkholder 	if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, 0, &net_ih))
249e3b6e33cSJake Burkholder 		panic("start_netisr");
250e3b6e33cSJake Burkholder }
251e3b6e33cSJake Burkholder SYSINIT(start_netisr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_netisr, NULL)
252