xref: /netbsd/sys/arch/pmax/pmax/interrupt.c (revision c4a72b64)
1 /*	$NetBSD: interrupt.c,v 1.4 2002/07/07 00:22:19 gmcgarry 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 extern void MachFPInterrupt(unsigned, unsigned, unsigned, struct frame *);
69 
70 /*
71  * pmax uses standard mips1 convention, wiring FPU to hard interupt 5.
72  */
73 void
74 cpu_intr(status, cause, pc, ipending)
75 	u_int32_t status;
76 	u_int32_t cause;
77 	u_int32_t pc;
78 	u_int32_t ipending;
79 {
80 
81 	int i, s;
82 	struct pmax_soft_intr *asi;
83 	struct pmax_soft_intrhand *sih;
84 
85 	uvmexp.intrs++;
86 
87 	/* device interrupts */
88 	if (ipending & (MIPS_INT_MASK_0|MIPS_INT_MASK_1|MIPS_INT_MASK_2|
89 			MIPS_INT_MASK_3|MIPS_INT_MASK_4)) {
90 		(*platform.iointr)(status, cause, pc, ipending);
91 	}
92 	/* FPU notification */
93 	if (ipending & MIPS_INT_MASK_5) {
94 		if (!USERMODE(status))
95 			goto kerneltouchedFPU;
96 		pmax_fpu_evcnt.ev_count++;
97 #if !defined(SOFTFLOAT)
98 		MachFPInterrupt(status, cause, pc, curproc->p_md.md_regs);
99 #endif
100 	}
101 
102 	ipending &= (MIPS_SOFT_INT_MASK_1|MIPS_SOFT_INT_MASK_0);
103 	if (ipending == 0)
104 		return;
105 
106 	_clrsoftintr(ipending);
107 
108 	for (i = _IPL_NSOFT - 1; i >= 0; i--) {
109 		if ((ipending & ipl_si_to_sr[i]) == 0)
110 			continue;
111 
112 		asi = &pmax_soft_intrs[i];
113 
114 		if (TAILQ_FIRST(&asi->softintr_q) != NULL)
115 			asi->softintr_evcnt.ev_count++;
116 
117 		for (;;) {
118 			s = splhigh();
119 
120 			sih = TAILQ_FIRST(&asi->softintr_q);
121 			if (sih != NULL) {
122 				TAILQ_REMOVE(&asi->softintr_q, sih, sih_q);
123 				sih->sih_pending = 0;
124 			}
125 
126 			splx(s);
127 
128 			if (sih == NULL)
129 				break;
130 
131 			uvmexp.softs++;
132 			(*sih->sih_fn)(sih->sih_arg);
133 		}
134 	}
135 	return;
136 kerneltouchedFPU:
137 	panic("kernel used FPU: PC %x, CR %x, SR %x", pc, cause, status);
138 }
139 
140 /* XXX For legacy software interrupts. */
141 struct pmax_soft_intrhand *softnet_intrhand;
142 
143 /*
144  * softintr_init:
145  *
146  *	Initialize the software interrupt system.
147  */
148 void
149 softintr_init(void)
150 {
151 	static const char *softintr_names[] = IPL_SOFTNAMES;
152 	struct pmax_soft_intr *asi;
153 	int i;
154 
155 	for (i = 0; i < _IPL_NSOFT; i++) {
156 		asi = &pmax_soft_intrs[i];
157 		TAILQ_INIT(&asi->softintr_q);
158 		asi->softintr_ipl = IPL_SOFT + i;
159 		evcnt_attach_dynamic(&asi->softintr_evcnt, EVCNT_TYPE_INTR,
160 		    NULL, "soft", softintr_names[i]);
161 	}
162 
163 	/* XXX Establish legacy soft interrupt handlers. */
164 	softnet_intrhand = softintr_establish(IPL_SOFTNET,
165 	    (void (*)(void *))netintr, NULL);
166 
167 	assert(softnet_intrhand != NULL);
168 }
169 
170 /*
171  * softintr_establish:		[interface]
172  *
173  *	Register a software interrupt handler.
174  */
175 void *
176 softintr_establish(int ipl, void (*func)(void *), void *arg)
177 {
178 	struct pmax_soft_intr *asi;
179 	struct pmax_soft_intrhand *sih;
180 
181 	if (__predict_false(ipl >= (IPL_SOFT + _IPL_NSOFT) ||
182 			    ipl < IPL_SOFT))
183 		panic("softintr_establish");
184 
185 	asi = &pmax_soft_intrs[ipl - IPL_SOFT];
186 
187 	sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT);
188 	if (__predict_true(sih != NULL)) {
189 		sih->sih_intrhead = asi;
190 		sih->sih_fn = func;
191 		sih->sih_arg = arg;
192 		sih->sih_pending = 0;
193 	}
194 	return (sih);
195 }
196 
197 /*
198  * softintr_disestablish:	[interface]
199  *
200  *	Unregister a software interrupt handler.
201  */
202 void
203 softintr_disestablish(void *arg)
204 {
205 	struct pmax_soft_intrhand *sih = arg;
206 	struct pmax_soft_intr *asi = sih->sih_intrhead;
207 	int s;
208 
209 	s = splhigh();
210 	if (sih->sih_pending) {
211 		TAILQ_REMOVE(&asi->softintr_q, sih, sih_q);
212 		sih->sih_pending = 0;
213 	}
214 	splx(s);
215 
216 	free(sih, M_DEVBUF);
217 }
218