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