1*311b6aa8Smpi /* $OpenBSD: softintr.c,v 1.10 2020/09/11 09:27:10 mpi Exp $ */
2b9d85be1Skettenis /* $NetBSD: softintr.c,v 1.2 2003/07/15 00:24:39 lukem Exp $ */
3b9d85be1Skettenis
4b9d85be1Skettenis /*
5b9d85be1Skettenis * Copyright (c) 2001 Wasabi Systems, Inc.
6b9d85be1Skettenis * All rights reserved.
7b9d85be1Skettenis *
8b9d85be1Skettenis * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9b9d85be1Skettenis *
10b9d85be1Skettenis * Redistribution and use in source and binary forms, with or without
11b9d85be1Skettenis * modification, are permitted provided that the following conditions
12b9d85be1Skettenis * are met:
13b9d85be1Skettenis * 1. Redistributions of source code must retain the above copyright
14b9d85be1Skettenis * notice, this list of conditions and the following disclaimer.
15b9d85be1Skettenis * 2. Redistributions in binary form must reproduce the above copyright
16b9d85be1Skettenis * notice, this list of conditions and the following disclaimer in the
17b9d85be1Skettenis * documentation and/or other materials provided with the distribution.
18b9d85be1Skettenis * 3. All advertising materials mentioning features or use of this software
19b9d85be1Skettenis * must display the following acknowledgement:
20b9d85be1Skettenis * This product includes software developed for the NetBSD Project by
21b9d85be1Skettenis * Wasabi Systems, Inc.
22b9d85be1Skettenis * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23b9d85be1Skettenis * or promote products derived from this software without specific prior
24b9d85be1Skettenis * written permission.
25b9d85be1Skettenis *
26b9d85be1Skettenis * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27b9d85be1Skettenis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28b9d85be1Skettenis * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29b9d85be1Skettenis * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
30b9d85be1Skettenis * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31b9d85be1Skettenis * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32b9d85be1Skettenis * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33b9d85be1Skettenis * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34b9d85be1Skettenis * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35b9d85be1Skettenis * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36b9d85be1Skettenis * POSSIBILITY OF SUCH DAMAGE.
37b9d85be1Skettenis */
38b9d85be1Skettenis
39b9d85be1Skettenis #include <sys/param.h>
40*311b6aa8Smpi #include <sys/systm.h>
41b9d85be1Skettenis #include <sys/malloc.h>
425b501b51Smatthieu #include <sys/mutex.h>
43b9d85be1Skettenis
44b9d85be1Skettenis #include <uvm/uvm_extern.h>
45b9d85be1Skettenis
46b9d85be1Skettenis #include <machine/atomic.h>
47b9d85be1Skettenis #include <machine/intr.h>
48b9d85be1Skettenis
49b9d85be1Skettenis struct soft_intrq soft_intrq[SI_NQUEUES];
50b9d85be1Skettenis
51b9d85be1Skettenis /*
52b9d85be1Skettenis * Initialize the software interrupt system.
53b9d85be1Skettenis */
54b9d85be1Skettenis void
softintr_init(void)55b9d85be1Skettenis softintr_init(void)
56b9d85be1Skettenis {
57b9d85be1Skettenis struct soft_intrq *siq;
58b9d85be1Skettenis int i;
59b9d85be1Skettenis
60b9d85be1Skettenis for (i = 0; i < SI_NQUEUES; i++) {
61b9d85be1Skettenis siq = &soft_intrq[i];
62b9d85be1Skettenis TAILQ_INIT(&siq->siq_list);
63b9d85be1Skettenis siq->siq_si = i;
64b9d85be1Skettenis mtx_init(&siq->siq_mtx, IPL_HIGH);
65b9d85be1Skettenis }
66b9d85be1Skettenis }
67b9d85be1Skettenis
68b9d85be1Skettenis /*
69b9d85be1Skettenis * Process pending software interrupts on the specified queue.
70b9d85be1Skettenis *
71b9d85be1Skettenis * NOTE: We must already be at the correct interrupt priority level.
72b9d85be1Skettenis */
73b9d85be1Skettenis void
softintr_dispatch(int si)74b9d85be1Skettenis softintr_dispatch(int si)
75b9d85be1Skettenis {
76b9d85be1Skettenis struct soft_intrq *siq = &soft_intrq[si];
77b9d85be1Skettenis struct soft_intrhand *sih;
78b9d85be1Skettenis
79b9d85be1Skettenis for (;;) {
80b9d85be1Skettenis mtx_enter(&siq->siq_mtx);
81b9d85be1Skettenis sih = TAILQ_FIRST(&siq->siq_list);
82b9d85be1Skettenis if (sih == NULL) {
83b9d85be1Skettenis mtx_leave(&siq->siq_mtx);
84b9d85be1Skettenis break;
85b9d85be1Skettenis }
86b9d85be1Skettenis
87b9d85be1Skettenis TAILQ_REMOVE(&siq->siq_list, sih, sih_list);
88b9d85be1Skettenis sih->sih_pending = 0;
89b9d85be1Skettenis
90b9d85be1Skettenis uvmexp.softs++;
91b9d85be1Skettenis
92b9d85be1Skettenis mtx_leave(&siq->siq_mtx);
93b9d85be1Skettenis
94b9d85be1Skettenis (*sih->sih_func)(sih->sih_arg);
95b9d85be1Skettenis }
96b9d85be1Skettenis }
97b9d85be1Skettenis
98b9d85be1Skettenis /*
99b9d85be1Skettenis * Register a software interrupt handler.
100b9d85be1Skettenis */
101b9d85be1Skettenis void *
softintr_establish(int ipl,void (* func)(void *),void * arg)102b9d85be1Skettenis softintr_establish(int ipl, void (*func)(void *), void *arg)
103b9d85be1Skettenis {
104b9d85be1Skettenis struct soft_intrhand *sih;
105b9d85be1Skettenis int si;
106b9d85be1Skettenis
107b9d85be1Skettenis switch (ipl) {
108b9d85be1Skettenis #if 0
109b9d85be1Skettenis case IPL_SOFT:
110b9d85be1Skettenis si = SI_SOFT;
111b9d85be1Skettenis break;
112b9d85be1Skettenis #endif
113b9d85be1Skettenis case IPL_SOFTCLOCK:
114b9d85be1Skettenis si = SI_SOFTCLOCK;
115b9d85be1Skettenis break;
116b9d85be1Skettenis case IPL_SOFTNET:
117b9d85be1Skettenis si = SI_SOFTNET;
118b9d85be1Skettenis break;
119b9d85be1Skettenis case IPL_TTY: /* XXX until MI code is fixed */
120b9d85be1Skettenis case IPL_SOFTTTY:
121b9d85be1Skettenis si = SI_SOFTTTY;
122b9d85be1Skettenis break;
123b9d85be1Skettenis default:
124b9d85be1Skettenis printf("softintr_establish: unknown soft IPL %d\n", ipl);
125b9d85be1Skettenis return NULL;
126b9d85be1Skettenis }
127b9d85be1Skettenis
128b9d85be1Skettenis sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT);
129b9d85be1Skettenis if (__predict_true(sih != NULL)) {
130b9d85be1Skettenis sih->sih_func = func;
131b9d85be1Skettenis sih->sih_arg = arg;
132b9d85be1Skettenis sih->sih_siq = &soft_intrq[si];
133b9d85be1Skettenis sih->sih_pending = 0;
134b9d85be1Skettenis }
135b9d85be1Skettenis return (sih);
136b9d85be1Skettenis }
137b9d85be1Skettenis
138b9d85be1Skettenis /*
139b9d85be1Skettenis * Unregister a software interrupt handler.
140b9d85be1Skettenis */
141b9d85be1Skettenis void
softintr_disestablish(void * arg)142b9d85be1Skettenis softintr_disestablish(void *arg)
143b9d85be1Skettenis {
144b9d85be1Skettenis struct soft_intrhand *sih = arg;
145b9d85be1Skettenis struct soft_intrq *siq = sih->sih_siq;
146b9d85be1Skettenis
147b9d85be1Skettenis mtx_enter(&siq->siq_mtx);
148b9d85be1Skettenis if (sih->sih_pending) {
149b9d85be1Skettenis TAILQ_REMOVE(&siq->siq_list, sih, sih_list);
150b9d85be1Skettenis sih->sih_pending = 0;
151b9d85be1Skettenis }
152b9d85be1Skettenis mtx_leave(&siq->siq_mtx);
153b9d85be1Skettenis
154473a6747Sderaadt free(sih, M_DEVBUF, sizeof *sih);
155b9d85be1Skettenis }
156b9d85be1Skettenis
157b9d85be1Skettenis /*
158b9d85be1Skettenis * Schedule a software interrupt.
159b9d85be1Skettenis */
160b9d85be1Skettenis void
softintr_schedule(void * arg)161b9d85be1Skettenis softintr_schedule(void *arg)
162b9d85be1Skettenis {
163b9d85be1Skettenis struct soft_intrhand *sih = (struct soft_intrhand *)arg;
164b9d85be1Skettenis struct soft_intrq *siq = sih->sih_siq;
165b9d85be1Skettenis struct cpu_info *ci = curcpu();
166b9d85be1Skettenis
167b9d85be1Skettenis mtx_enter(&siq->siq_mtx);
168b9d85be1Skettenis if (sih->sih_pending == 0) {
169b9d85be1Skettenis TAILQ_INSERT_TAIL(&siq->siq_list, sih, sih_list);
170b9d85be1Skettenis sih->sih_pending = 1;
171d7469fedSdrahn atomic_setbits_int(&ci->ci_ipending, SI_TO_IRQBIT(siq->siq_si));
172b9d85be1Skettenis }
173b9d85be1Skettenis mtx_leave(&siq->siq_mtx);
174b9d85be1Skettenis }
175b9d85be1Skettenis
176b9d85be1Skettenis void
dosoftint(int pcpl)1771c471f42Smpi dosoftint(int pcpl)
178b9d85be1Skettenis {
179b9d85be1Skettenis struct cpu_info *ci = curcpu();
180b9d85be1Skettenis int sir, q, mask;
181b9d85be1Skettenis
1821c471f42Smpi ppc_intr_enable(1);
1831c471f42Smpi KERNEL_LOCK();
1841c471f42Smpi
1851c471f42Smpi while ((sir = (ci->ci_ipending & ppc_smask[pcpl])) != 0) {
186b9d85be1Skettenis atomic_clearbits_int(&ci->ci_ipending, sir);
187b9d85be1Skettenis
188b9d85be1Skettenis for (q = SI_NQUEUES - 1; q >= 0; q--) {
1891c471f42Smpi mask = SI_TO_IRQBIT(q);
190b9d85be1Skettenis if (sir & mask)
191b9d85be1Skettenis softintr_dispatch(q);
192b9d85be1Skettenis }
193b9d85be1Skettenis }
1941c471f42Smpi
1951c471f42Smpi KERNEL_UNLOCK();
1961c471f42Smpi (void)ppc_intr_disable();
197b9d85be1Skettenis }
198