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.4 2003/11/10 05:00:50 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; 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 ni = &netisrs[num]; 95 if (ni->ni_handler == NULL) { 96 printf("netisr_queue: unregistered isr %d\n", num); 97 return EIO; 98 } 99 100 /* use better message allocation system with limits later XXX JH */ 101 if (!(pmsg = malloc(sizeof(struct netmsg), M_TEMP, M_NOWAIT))) 102 return ENOBUFS; 103 104 if (!(port = ni->ni_mport(m))) 105 return EIO; 106 107 lwkt_initmsg(&pmsg->nm_lmsg, port, CMD_NETMSG_NEWPKT); 108 pmsg->nm_packet = m; 109 pmsg->nm_handler = ni->ni_handler; 110 lwkt_sendmsg(port, &pmsg->nm_lmsg); 111 return (0); 112 } 113 114 void 115 netisr_register(int num, lwkt_portfn_t mportfn, netisr_fn_t handler) 116 { 117 KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), 118 ("bad isr %d", num)); 119 120 netisrs[num].ni_mport = mportfn; 121 netisrs[num].ni_handler = handler; 122 } 123 124 int 125 netisr_unregister(int num) 126 { 127 KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), 128 ("unregister_netisr: bad isr number: %d\n", num)); 129 130 /* XXX JH */ 131 return (0); 132 } 133 134 /* 135 * Return message port for default handler thread on CPU 0. 136 */ 137 lwkt_port_t 138 cpu0_portfn(struct mbuf *m) 139 { 140 return (&netisr_cpu[0].td_msgport); 141 } 142 143 /* 144 * This function is used to call the netisr handler from the appropriate 145 * netisr thread for polling and other purposes. pmsg->nm_packet will be 146 * undefined. At the moment operation is restricted to non-packet ISRs only. 147 */ 148 void 149 schednetisr(int num) 150 { 151 struct netisr *ni = &netisrs[num]; 152 struct netmsg *pmsg; 153 lwkt_port_t port = &netisr_cpu[0].td_msgport; 154 155 KASSERT((num > 0 && num <= (sizeof(netisrs)/sizeof(netisrs[0]))), 156 ("bad isr %d", num)); 157 158 if (!(pmsg = malloc(sizeof(struct netmsg), M_TEMP, M_NOWAIT))) 159 return; 160 161 lwkt_initmsg(&pmsg->nm_lmsg, port, CMD_NETMSG_POLL); 162 pmsg->nm_handler = ni->ni_handler; 163 lwkt_sendmsg(port, &pmsg->nm_lmsg); 164 } 165