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