1 /* $OpenBSD: softintr.c,v 1.10 2020/09/11 09:27:09 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 for NetBSD/x86.
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 x86_soft_intr x86_soft_intrs[X86_NSOFTINTR];
46
47 const int x86_soft_intr_to_ssir[X86_NSOFTINTR] = {
48 SIR_CLOCK,
49 SIR_NET,
50 SIR_TTY,
51 };
52
53 /*
54 * softintr_init:
55 *
56 * Initialize the software interrupt system.
57 */
58 void
softintr_init(void)59 softintr_init(void)
60 {
61 struct x86_soft_intr *si;
62 int i;
63
64 for (i = 0; i < X86_NSOFTINTR; i++) {
65 si = &x86_soft_intrs[i];
66 TAILQ_INIT(&si->softintr_q);
67 mtx_init(&si->softintr_lock, IPL_HIGH);
68 si->softintr_ssir = x86_soft_intr_to_ssir[i];
69 }
70 }
71
72 /*
73 * softintr_dispatch:
74 *
75 * Process pending software interrupts.
76 */
77 void
softintr_dispatch(int which)78 softintr_dispatch(int which)
79 {
80 struct cpu_info *ci = curcpu();
81 struct x86_soft_intr *si = &x86_soft_intrs[which];
82 struct x86_soft_intrhand *sih;
83 int floor;
84
85 floor = ci->ci_handled_intr_level;
86 ci->ci_handled_intr_level = ci->ci_ilevel;
87
88 KERNEL_LOCK();
89 for (;;) {
90 mtx_enter(&si->softintr_lock);
91 sih = TAILQ_FIRST(&si->softintr_q);
92 if (sih == NULL) {
93 mtx_leave(&si->softintr_lock);
94 break;
95 }
96 TAILQ_REMOVE(&si->softintr_q, sih, sih_q);
97 sih->sih_pending = 0;
98
99 uvmexp.softs++;
100
101 mtx_leave(&si->softintr_lock);
102
103 (*sih->sih_fn)(sih->sih_arg);
104 }
105 KERNEL_UNLOCK();
106
107 ci->ci_handled_intr_level = floor;
108 }
109
110 /*
111 * softintr_establish: [interface]
112 *
113 * Register a software interrupt handler.
114 */
115 void *
softintr_establish(int ipl,void (* func)(void *),void * arg)116 softintr_establish(int ipl, void (*func)(void *), void *arg)
117 {
118 struct x86_soft_intr *si;
119 struct x86_soft_intrhand *sih;
120 int which;
121
122 switch (ipl) {
123 case IPL_SOFTCLOCK:
124 which = X86_SOFTINTR_SOFTCLOCK;
125 break;
126
127 case IPL_SOFTNET:
128 which = X86_SOFTINTR_SOFTNET;
129 break;
130
131 case IPL_TTY:
132 case IPL_SOFTTTY:
133 which = X86_SOFTINTR_SOFTTTY;
134 break;
135
136 default:
137 panic("softintr_establish");
138 }
139
140 si = &x86_soft_intrs[which];
141
142 sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT);
143 if (__predict_true(sih != NULL)) {
144 sih->sih_intrhead = si;
145 sih->sih_fn = func;
146 sih->sih_arg = arg;
147 sih->sih_pending = 0;
148 }
149 return (sih);
150 }
151
152 /*
153 * softintr_disestablish: [interface]
154 *
155 * Unregister a software interrupt handler.
156 */
157 void
softintr_disestablish(void * arg)158 softintr_disestablish(void *arg)
159 {
160 struct x86_soft_intrhand *sih = arg;
161 struct x86_soft_intr *si = sih->sih_intrhead;
162
163 mtx_enter(&si->softintr_lock);
164 if (sih->sih_pending) {
165 TAILQ_REMOVE(&si->softintr_q, sih, sih_q);
166 sih->sih_pending = 0;
167 }
168 mtx_leave(&si->softintr_lock);
169
170 free(sih, M_DEVBUF, sizeof(*sih));
171 }
172