Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / mips / atheros / ar5315_intr.c
blob1724fe1cf6e3e70ab1f236554ecb7cd093282dd2
1 /* $Id: ar5315_intr.c,v 1.5 2008/01/07 07:12:06 dyoung Exp $ */
2 /*
3 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
4 * Copyright (c) 2006 Garrett D'Amore.
5 * All rights reserved.
7 * This code was written by Garrett D'Amore for the Champaign-Urbana
8 * Community Wireless Network Project.
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions 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
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
19 * 3. All advertising materials mentioning features or use of this
20 * software must display the following acknowledgements:
21 * This product includes software developed by the Urbana-Champaign
22 * Independent Media Center.
23 * This product includes software developed by Garrett D'Amore.
24 * 4. Urbana-Champaign Independent Media Center's name and Garrett
25 * D'Amore's name may not be used to endorse or promote products
26 * derived from this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
29 * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR
30 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT
33 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT,
34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
35 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
38 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
40 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: ar5315_intr.c,v 1.4 2008/01/07 06:55:32 dyoung Exp $");
46 #include <sys/param.h>
47 #include <sys/queue.h>
48 #include <sys/malloc.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
51 #include <sys/kernel.h>
53 #include <machine/bus.h>
54 #include <machine/intr.h>
56 #include <mips/locore.h>
57 #include <mips/atheros/include/ar5315reg.h>
58 #include <mips/atheros/include/ar531xvar.h>
61 * Here's a little tidbit that can only be gleaned from Linux sources.
63 * IP2: (INT0) MISC
64 * IP3: (INT1) WLAN0
65 * IP4: (INT2) ENET0
66 * IP7: (INT5) CPU CLOCK
68 * Only MISC interrupts are easily masked at the interrupt controller.
69 * The others have to be masked at the source.
72 #define REGVAL(x) *((volatile uint32_t *)(MIPS_PHYS_TO_KSEG1((x))))
73 #define GETREG(x) REGVAL((x) + AR5315_SYSREG_BASE)
74 #define PUTREG(x,v) (REGVAL((x) + AR5315_SYSREG_BASE)) = (v)
76 #define NINTRS 3 /* MIPS INT2-INT4 (7 is clock interrupt) */
77 #define NIRQS 9 /* bits in Miscellaneous Interrupt Status Register */
79 struct ar531x_intrhand {
80 LIST_ENTRY(ar531x_intrhand) ih_q;
81 int (*ih_func)(void *);
82 void *ih_arg;
83 int ih_irq;
86 struct ar531x_intr {
87 LIST_HEAD(, ar531x_intrhand) intr_l;
88 struct evcnt intr_count;
91 const uint32_t ipl_sr_bits[_IPL_N] = {
92 0, /* 0: IPL_NONE */
93 MIPS_SOFT_INT_MASK_0, /* 1: IPL_SOFTCLOCK */
94 MIPS_SOFT_INT_MASK_0, /* 2: IPL_SOFTNET */
96 MIPS_SOFT_INT_MASK_0 |
97 MIPS_SOFT_INT_MASK_1 |
98 MIPS_INT_MASK_0 |
99 MIPS_INT_MASK_1 |
100 MIPS_INT_MASK_2, /* 3: IPL_VM */
102 MIPS_INT_MASK, /* 4: IPL_{SCHED,HIGH} */
105 static const char *ar5315_cpuintrnames[NINTRS] = {
106 "int 2 (misc)",
107 "int 3 (wlan)",
108 "int 4 (enet)",
111 static const char *ar5315_miscintrnames[NIRQS] = {
112 "misc 0 (uart)",
113 "misc 1 (i2c)",
114 "misc 2 (spi)",
115 "misc 3 (ahb error)",
116 "misc 4 (apb error)",
117 "misc 5 (timer)",
118 "misc 6 (gpio)",
119 "misc 7 (watchdog)",
120 "misc 8 (ir)"
123 static struct ar531x_intr ar5315_cpuintrs[NINTRS];
124 static struct ar531x_intr ar5315_miscintrs[NIRQS];
126 static int ar531x_miscintr(void *);
128 void
129 ar531x_intr_init(void)
131 int i;
133 for (i = 0; i < NINTRS; i++) {
134 LIST_INIT(&ar5315_cpuintrs[i].intr_l);
135 evcnt_attach_dynamic(&ar5315_cpuintrs[i].intr_count,
136 EVCNT_TYPE_INTR, NULL, "mips", ar5315_cpuintrnames[i]);
139 for (i = 0; i < NIRQS; i++) {
140 LIST_INIT(&ar5315_miscintrs[i].intr_l);
141 evcnt_attach_dynamic(&ar5315_miscintrs[i].intr_count,
142 EVCNT_TYPE_INTR, NULL, "ar5315", ar5315_miscintrnames[i]);
145 /* make sure we start without any misc interrupts enabled */
146 GETREG(AR5315_SYSREG_ISR);
147 PUTREG(AR5315_SYSREG_IMR, 0);
149 /* make sure we register the MISC interrupt handler */
150 ar531x_cpu_intr_establish(AR5315_CPU_IRQ_MISC, ar531x_miscintr, NULL);
154 void *
155 ar531x_cpu_intr_establish(int intr, int (*func)(void *), void *arg)
157 struct ar531x_intrhand *ih;
158 int s;
160 if ((ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT)) == NULL)
161 return NULL;
163 ih->ih_func = func;
164 ih->ih_arg = arg;
165 ih->ih_irq = intr;
167 if (ih == NULL)
168 return NULL;
170 s = splhigh();
172 LIST_INSERT_HEAD(&ar5315_cpuintrs[intr].intr_l, ih, ih_q);
175 * The MIPS CPU interrupts are enabled at boot time, so they
176 * should pretty much always be ready to go.
179 splx(s);
180 return (ih);
183 void
184 ar531x_cpu_intr_disestablish(void *arg)
186 struct ar531x_intrhand *ih = arg;
187 int s;
189 s = splhigh();
191 LIST_REMOVE(ih, ih_q);
193 splx(s);
194 free(ih, M_DEVBUF);
197 void *
198 ar531x_misc_intr_establish(int irq, int (*func)(void *), void *arg)
200 struct ar531x_intrhand *ih;
201 int first;
202 int s;
204 if ((ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT)) == NULL)
205 return NULL;
207 ih->ih_func = func;
208 ih->ih_arg = arg;
209 ih->ih_irq = irq;
211 if (ih == NULL)
212 return NULL;
214 s = splhigh();
216 first = LIST_EMPTY(&ar5315_miscintrs[irq].intr_l);
218 LIST_INSERT_HEAD(&ar5315_miscintrs[irq].intr_l, ih, ih_q);
220 if (first) {
221 uint32_t mask;
222 mask = GETREG(AR5315_SYSREG_IMR);
223 mask |= (1 << irq);
224 PUTREG(AR5315_SYSREG_IMR, mask);
225 GETREG(AR5315_SYSREG_IMR); /* flush wbuffer */
228 splx(s);
230 return ih;
233 void
234 ar531x_misc_intr_disestablish(void *arg)
236 struct ar531x_intrhand *ih = arg;
237 int s;
239 s = splhigh();
241 LIST_REMOVE(ih, ih_q);
242 if (LIST_EMPTY(&ar5315_miscintrs[ih->ih_irq].intr_l)) {
243 uint32_t mask;
244 mask = GETREG(AR5315_SYSREG_ISR);
245 mask &= ~(1 << ih->ih_irq);
246 PUTREG(AR5315_SYSREG_IMR, mask);
247 GETREG(AR5315_SYSREG_IMR); /* flush wbuffer */
250 splx(s);
251 free(ih, M_DEVBUF);
256 ar531x_miscintr(void *arg)
258 uint32_t isr;
259 int mask;
260 int index;
261 int rv = 0;
262 struct ar531x_intrhand *ih;
264 isr = GETREG(AR5315_SYSREG_ISR);
265 mask = GETREG(AR5315_SYSREG_IMR);
267 for (index = 0; index < NIRQS; index++) {
269 if (isr & mask & (1 << index)) {
270 ar5315_miscintrs[index].intr_count.ev_count++;
271 LIST_FOREACH(ih, &ar5315_miscintrs[index].intr_l, ih_q)
272 rv |= (*ih->ih_func)(ih->ih_arg);
276 return rv;
279 void
280 ar531x_cpuintr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending)
282 uint32_t mask;
283 int index;
284 struct ar531x_intrhand *ih;
286 /* all others get normal handling */
287 for (index = NINTRS - 1; index >= 0; index--) {
288 mask = MIPS_INT_MASK_0 << index;
290 if (ipending & mask) {
291 ar5315_cpuintrs[index].intr_count.ev_count++;
292 LIST_FOREACH(ih, &ar5315_cpuintrs[index].intr_l, ih_q)
293 (*ih->ih_func)(ih->ih_arg);
294 cause &= ~mask;
298 /* re-enable the stuff we processed */
299 _splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK));