1 /* $OpenBSD: softintr.c,v 1.2 2020/09/11 09:27:10 mpi Exp $ */
2 /* $NetBSD: softintr.c,v 1.1 2003/02/26 21:26:12 fvdl Exp $ */
3
4 /*-
5 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Generic soft interrupt implementation
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
40
41 #include <machine/intr.h>
42
43 #include <uvm/uvm_extern.h>
44
45 struct soft_intr soft_intrs[SI_NSOFTINTR];
46
47 const int soft_intr_to_ssir[SI_NSOFTINTR] = {
48 SIR_SOFT,
49 SIR_CLOCK,
50 SIR_NET,
51 SIR_TTY,
52 };
53
54 void softintr_biglock_wrap(void *);
55
56 /*
57 * softintr_init:
58 *
59 * Initialize the software interrupt system.
60 */
61 void
softintr_init(void)62 softintr_init(void)
63 {
64 struct soft_intr *si;
65 int i;
66
67 for (i = 0; i < SI_NSOFTINTR; i++) {
68 si = &soft_intrs[i];
69 TAILQ_INIT(&si->softintr_q);
70 mtx_init(&si->softintr_lock, IPL_HIGH);
71 si->softintr_ssir = soft_intr_to_ssir[i];
72 }
73 }
74
75 /*
76 * softintr_dispatch:
77 *
78 * Process pending software interrupts.
79 */
80 void
softintr_dispatch(int which)81 softintr_dispatch(int which)
82 {
83 struct soft_intr *si = &soft_intrs[which];
84 struct soft_intrhand *sih;
85 void *arg;
86 void (*fn)(void *);
87
88 for (;;) {
89 mtx_enter(&si->softintr_lock);
90 sih = TAILQ_FIRST(&si->softintr_q);
91 if (sih == NULL) {
92 mtx_leave(&si->softintr_lock);
93 break;
94 }
95 TAILQ_REMOVE(&si->softintr_q, sih, sih_q);
96 sih->sih_pending = 0;
97
98 uvmexp.softs++;
99 arg = sih->sih_arg;
100 fn = sih->sih_fn;
101 mtx_leave(&si->softintr_lock);
102
103 (*fn)(arg);
104 }
105 }
106
107 #ifdef MULTIPROCESSOR
108 void
softintr_biglock_wrap(void * arg)109 softintr_biglock_wrap(void *arg)
110 {
111 struct soft_intrhand *sih = arg;
112
113 KERNEL_LOCK();
114 sih->sih_fnwrap(sih->sih_argwrap);
115 KERNEL_UNLOCK();
116 }
117 #endif
118
119 /*
120 * softintr_establish: [interface]
121 *
122 * Register a software interrupt handler.
123 */
124 void *
softintr_establish_flags(int ipl,void (* func)(void *),void * arg,int flags)125 softintr_establish_flags(int ipl, void (*func)(void *), void *arg, int flags)
126 {
127 struct soft_intr *si;
128 struct soft_intrhand *sih;
129 int which;
130
131 switch (ipl) {
132 case IPL_SOFTCLOCK:
133 which = SIR_CLOCK;
134 break;
135
136 case IPL_SOFTNET:
137 which = SIR_NET;
138 break;
139
140 case IPL_TTY:
141 case IPL_SOFTTTY:
142 which = SIR_TTY;
143 break;
144
145 default:
146 panic("softintr_establish");
147 }
148
149 si = &soft_intrs[which];
150
151 sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT | M_ZERO);
152 if (__predict_true(sih != NULL)) {
153 sih->sih_intrhead = si;
154 #ifdef MULTIPROCESSOR
155 if (flags & SOFTINTR_ESTABLISH_MPSAFE) {
156 #endif
157 sih->sih_fn = func;
158 sih->sih_arg = arg;
159 #ifdef MULTIPROCESSOR
160 } else {
161 sih->sih_fnwrap = func;
162 sih->sih_argwrap = arg;
163 sih->sih_fn = softintr_biglock_wrap;
164 sih->sih_arg = sih;
165 }
166 #endif
167 }
168 return (sih);
169 }
170
171 /*
172 * softintr_disestablish: [interface]
173 *
174 * Unregister a software interrupt handler.
175 */
176 void
softintr_disestablish(void * arg)177 softintr_disestablish(void *arg)
178 {
179 struct soft_intrhand *sih = arg;
180 struct soft_intr *si = sih->sih_intrhead;
181
182 mtx_enter(&si->softintr_lock);
183 if (sih->sih_pending) {
184 TAILQ_REMOVE(&si->softintr_q, sih, sih_q);
185 sih->sih_pending = 0;
186 }
187 mtx_leave(&si->softintr_lock);
188
189 free(sih, M_DEVBUF, 0);
190 }
191
192 void
softintr(int intrq)193 softintr(int intrq)
194 {
195 // protected by mutex in caller
196 curcpu()->ci_ipending |= (1 << intrq);
197 }
198