xref: /netbsd/sys/arch/pmax/pmax/interrupt.c (revision bf9ec67e)
1 /*	$NetBSD: interrupt.c,v 1.3 2001/09/28 11:59:52 chs Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/malloc.h>
41 #include <sys/device.h>
42 #include <sys/proc.h>
43 
44 #include <uvm/uvm_extern.h>
45 
46 #include <mips/psl.h>
47 
48 #include <machine/autoconf.h>
49 #include <machine/sysconf.h>
50 #include <machine/intr.h>
51 
52 const u_int32_t ipl_si_to_sr[_IPL_NSOFT] = {
53 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFT */
54 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFTCLOCK */
55 	MIPS_SOFT_INT_MASK_1,			/* IPL_SOFTNET */
56 	MIPS_SOFT_INT_MASK_1,			/* IPL_SOFTSERIAL */
57 };
58 
59 struct pmax_soft_intr pmax_soft_intrs[_IPL_NSOFT];
60 
61 struct evcnt pmax_clock_evcnt =
62     EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "clock", "intr");
63 struct evcnt pmax_fpu_evcnt =
64     EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "fpu", "intr");
65 struct evcnt pmax_memerr_evcnt =
66     EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "memerr", "intr");
67 
68 /* XXX XXX XXX */
69 extern void MachFPInterrupt(unsigned, unsigned, unsigned, struct frame *);
70 #define	dealfpu(sr,cr,pc) \
71 		MachFPInterrupt((sr), (cr), (pc), curproc->p_md.md_regs)
72 /* XXX XXX XXX */
73 
74 /*
75  * pmax uses standard mips1 convention, wiring FPU to hard interupt 5.
76  */
77 void
78 cpu_intr(status, cause, pc, ipending)
79 	u_int32_t status;
80 	u_int32_t cause;
81 	u_int32_t pc;
82 	u_int32_t ipending;
83 {
84 
85 	int i, s;
86 	struct pmax_soft_intr *asi;
87 	struct pmax_soft_intrhand *sih;
88 
89 	uvmexp.intrs++;
90 
91 	/* device interrupts */
92 	if (ipending & (MIPS_INT_MASK_0|MIPS_INT_MASK_1|MIPS_INT_MASK_2|
93 			MIPS_INT_MASK_3|MIPS_INT_MASK_4)) {
94 		(*platform.iointr)(status, cause, pc, ipending);
95 	}
96 	/* FPU notification */
97 	if (ipending & MIPS_INT_MASK_5) {
98 		if (!USERMODE(status))
99 			goto kerneltouchedFPU;
100 		pmax_fpu_evcnt.ev_count++;
101 		dealfpu(status, cause, pc);
102 	}
103 
104 	ipending &= (MIPS_SOFT_INT_MASK_1|MIPS_SOFT_INT_MASK_0);
105 	if (ipending == 0)
106 		return;
107 
108 	_clrsoftintr(ipending);
109 
110 	for (i = _IPL_NSOFT - 1; i >= 0; i--) {
111 		if ((ipending & ipl_si_to_sr[i]) == 0)
112 			continue;
113 
114 		asi = &pmax_soft_intrs[i];
115 
116 		if (TAILQ_FIRST(&asi->softintr_q) != NULL)
117 			asi->softintr_evcnt.ev_count++;
118 
119 		for (;;) {
120 			s = splhigh();
121 
122 			sih = TAILQ_FIRST(&asi->softintr_q);
123 			if (sih != NULL) {
124 				TAILQ_REMOVE(&asi->softintr_q, sih, sih_q);
125 				sih->sih_pending = 0;
126 			}
127 
128 			splx(s);
129 
130 			if (sih == NULL)
131 				break;
132 
133 			uvmexp.softs++;
134 			(*sih->sih_fn)(sih->sih_arg);
135 		}
136 	}
137 	return;
138 kerneltouchedFPU:
139 	panic("kernel used FPU: PC %x, CR %x, SR %x", pc, cause, status);
140 }
141 
142 /* XXX For legacy software interrupts. */
143 struct pmax_soft_intrhand *softnet_intrhand;
144 
145 /*
146  * softintr_init:
147  *
148  *	Initialize the software interrupt system.
149  */
150 void
151 softintr_init(void)
152 {
153 	static const char *softintr_names[] = IPL_SOFTNAMES;
154 	struct pmax_soft_intr *asi;
155 	int i;
156 
157 	for (i = 0; i < _IPL_NSOFT; i++) {
158 		asi = &pmax_soft_intrs[i];
159 		TAILQ_INIT(&asi->softintr_q);
160 		asi->softintr_ipl = IPL_SOFT + i;
161 		evcnt_attach_dynamic(&asi->softintr_evcnt, EVCNT_TYPE_INTR,
162 		    NULL, "soft", softintr_names[i]);
163 	}
164 
165 	/* XXX Establish legacy soft interrupt handlers. */
166 	softnet_intrhand = softintr_establish(IPL_SOFTNET,
167 	    (void (*)(void *))netintr, NULL);
168 
169 	assert(softnet_intrhand != NULL);
170 }
171 
172 /*
173  * softintr_establish:		[interface]
174  *
175  *	Register a software interrupt handler.
176  */
177 void *
178 softintr_establish(int ipl, void (*func)(void *), void *arg)
179 {
180 	struct pmax_soft_intr *asi;
181 	struct pmax_soft_intrhand *sih;
182 
183 	if (__predict_false(ipl >= (IPL_SOFT + _IPL_NSOFT) ||
184 			    ipl < IPL_SOFT))
185 		panic("softintr_establish");
186 
187 	asi = &pmax_soft_intrs[ipl - IPL_SOFT];
188 
189 	sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT);
190 	if (__predict_true(sih != NULL)) {
191 		sih->sih_intrhead = asi;
192 		sih->sih_fn = func;
193 		sih->sih_arg = arg;
194 		sih->sih_pending = 0;
195 	}
196 	return (sih);
197 }
198 
199 /*
200  * softintr_disestablish:	[interface]
201  *
202  *	Unregister a software interrupt handler.
203  */
204 void
205 softintr_disestablish(void *arg)
206 {
207 	struct pmax_soft_intrhand *sih = arg;
208 	struct pmax_soft_intr *asi = sih->sih_intrhead;
209 	int s;
210 
211 	s = splhigh();
212 	if (sih->sih_pending) {
213 		TAILQ_REMOVE(&asi->softintr_q, sih, sih_q);
214 		sih->sih_pending = 0;
215 	}
216 	splx(s);
217 
218 	free(sih, M_DEVBUF);
219 }
220