1 /* $Id: ar5315_intr.c,v 1.5 2008/01/07 07:12:06 dyoung Exp $ */
3 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
4 * Copyright (c) 2006 Garrett D'Amore.
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
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.
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 *);
87 LIST_HEAD(, ar531x_intrhand
) intr_l
;
88 struct evcnt intr_count
;
91 const uint32_t ipl_sr_bits
[_IPL_N
] = {
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
|
100 MIPS_INT_MASK_2
, /* 3: IPL_VM */
102 MIPS_INT_MASK
, /* 4: IPL_{SCHED,HIGH} */
105 static const char *ar5315_cpuintrnames
[NINTRS
] = {
111 static const char *ar5315_miscintrnames
[NIRQS
] = {
115 "misc 3 (ahb error)",
116 "misc 4 (apb error)",
123 static struct ar531x_intr ar5315_cpuintrs
[NINTRS
];
124 static struct ar531x_intr ar5315_miscintrs
[NIRQS
];
126 static int ar531x_miscintr(void *);
129 ar531x_intr_init(void)
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
);
155 ar531x_cpu_intr_establish(int intr
, int (*func
)(void *), void *arg
)
157 struct ar531x_intrhand
*ih
;
160 if ((ih
= malloc(sizeof(*ih
), M_DEVBUF
, M_NOWAIT
)) == NULL
)
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.
184 ar531x_cpu_intr_disestablish(void *arg
)
186 struct ar531x_intrhand
*ih
= arg
;
191 LIST_REMOVE(ih
, ih_q
);
198 ar531x_misc_intr_establish(int irq
, int (*func
)(void *), void *arg
)
200 struct ar531x_intrhand
*ih
;
204 if ((ih
= malloc(sizeof(*ih
), M_DEVBUF
, M_NOWAIT
)) == NULL
)
216 first
= LIST_EMPTY(&ar5315_miscintrs
[irq
].intr_l
);
218 LIST_INSERT_HEAD(&ar5315_miscintrs
[irq
].intr_l
, ih
, ih_q
);
222 mask
= GETREG(AR5315_SYSREG_IMR
);
224 PUTREG(AR5315_SYSREG_IMR
, mask
);
225 GETREG(AR5315_SYSREG_IMR
); /* flush wbuffer */
234 ar531x_misc_intr_disestablish(void *arg
)
236 struct ar531x_intrhand
*ih
= arg
;
241 LIST_REMOVE(ih
, ih_q
);
242 if (LIST_EMPTY(&ar5315_miscintrs
[ih
->ih_irq
].intr_l
)) {
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 */
256 ar531x_miscintr(void *arg
)
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
);
280 ar531x_cpuintr(uint32_t status
, uint32_t cause
, uint32_t pc
, uint32_t ipending
)
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
);
298 /* re-enable the stuff we processed */
299 _splset(MIPS_SR_INT_IE
| ((status
& ~cause
) & MIPS_HARD_INT_MASK
));