xref: /openbsd/sys/arch/powerpc/powerpc/softintr.c (revision 311b6aa8)
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