ralink_intr.c revision 1.2 1 1.2 matt /* $NetBSD: ralink_intr.c,v 1.2 2011/07/28 15:38:49 matt Exp $ */
2 1.2 matt /*-
3 1.2 matt * Copyright (c) 2011 CradlePoint Technology, Inc.
4 1.2 matt * All rights reserved.
5 1.2 matt *
6 1.2 matt *
7 1.2 matt * Redistribution and use in source and binary forms, with or without
8 1.2 matt * modification, are permitted provided that the following conditions
9 1.2 matt * are met:
10 1.2 matt * 1. Redistributions of source code must retain the above copyright
11 1.2 matt * notice, this list of conditions and the following disclaimer.
12 1.2 matt * 2. Redistributions in binary form must reproduce the above copyright
13 1.2 matt * notice, this list of conditions and the following disclaimer in the
14 1.2 matt * documentation and/or other materials provided with the distribution.
15 1.2 matt *
16 1.2 matt * THIS SOFTWARE IS PROVIDED BY CRADLEPOINT TECHNOLOGY, INC. AND CONTRIBUTORS
17 1.2 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.2 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.2 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
20 1.2 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.2 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.2 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.2 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.2 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.2 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.2 matt * POSSIBILITY OF SUCH DAMAGE.
27 1.2 matt */
28 1.2 matt
29 1.2 matt #define __INTR_PRIVATE
30 1.2 matt
31 1.2 matt #include <sys/cdefs.h>
32 1.2 matt __KERNEL_RCSID(0, "$NetBSD: ralink_intr.c,v 1.2 2011/07/28 15:38:49 matt Exp $");
33 1.2 matt
34 1.2 matt #include <sys/param.h>
35 1.2 matt #include <sys/bus.h>
36 1.2 matt #include <sys/device.h>
37 1.2 matt #include <sys/intr.h>
38 1.2 matt #include <sys/kernel.h>
39 1.2 matt #include <sys/malloc.h>
40 1.2 matt #include <sys/systm.h>
41 1.2 matt
42 1.2 matt #include <mips/locore.h>
43 1.2 matt
44 1.2 matt #include <mips/ralink/ralink_reg.h>
45 1.2 matt #include <mips/ralink/ralink_var.h>
46 1.2 matt
47 1.2 matt static int ra_pic_intr(void *arg);
48 1.2 matt
49 1.2 matt /*
50 1.2 matt * evbmips spl integration:
51 1.2 matt * this is a mask of bits to clear in the SR when we go to a
52 1.2 matt * given hardware interrupt priority level.
53 1.2 matt */
54 1.2 matt static const struct ipl_sr_map ralink_ipl_sr_map = {
55 1.2 matt .sr_bits = {
56 1.2 matt [IPL_NONE] = 0,
57 1.2 matt [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0,
58 1.2 matt [IPL_SOFTBIO] = MIPS_SOFT_INT_MASK_0,
59 1.2 matt [IPL_SOFTNET] = MIPS_SOFT_INT_MASK,
60 1.2 matt [IPL_SOFTSERIAL] = MIPS_SOFT_INT_MASK,
61 1.2 matt [IPL_VM] = MIPS_INT_MASK ^ MIPS_INT_MASK_5,
62 1.2 matt [IPL_SCHED] = MIPS_INT_MASK,
63 1.2 matt [IPL_DDB] = MIPS_INT_MASK,
64 1.2 matt [IPL_HIGH] = MIPS_INT_MASK,
65 1.2 matt },
66 1.2 matt };
67 1.2 matt
68 1.2 matt
69 1.2 matt /*
70 1.2 matt * RT3052 Interrupt Block Definitions
71 1.2 matt *
72 1.2 matt * HW_INT0 - Low Priority Chip Interrupts (Lowest Priority)
73 1.2 matt * HW_INT1 - High Priority Chip Interrupts
74 1.2 matt * HW_INT2 - PCIe/PCI (3883 only)
75 1.2 matt * HW_INT3 - Frame Engine
76 1.2 matt * HW_INT4 - 802.11n NIC
77 1.2 matt * HW_INT5 - Timer Interrupt (Highest Priority)
78 1.2 matt *
79 1.2 matt * HW_INT0 and HW_INT1 can be configured to fire with any of the other
80 1.2 matt * interrupts on chip. They can be masked for either INT0 or INT1
81 1.2 matt * but not both.
82 1.2 matt *
83 1.2 matt * SYSCTL
84 1.2 matt * TIMER0
85 1.2 matt * WDTIMER
86 1.2 matt * ILLACC
87 1.2 matt * PCM
88 1.2 matt * UARTF
89 1.2 matt * PIO
90 1.2 matt * DMA
91 1.2 matt * NAND
92 1.2 matt * PERF
93 1.2 matt * I2S
94 1.2 matt * UARTL
95 1.2 matt * ETHSW
96 1.2 matt * USB
97 1.2 matt */
98 1.2 matt
99 1.2 matt
100 1.2 matt /*
101 1.2 matt * we use 5 MIPS cpu interrupts:
102 1.2 matt * MIPS INT0 .. INT4
103 1.2 matt */
104 1.2 matt #define NCPUINTRS 5
105 1.2 matt
106 1.2 matt struct ra_intr {
107 1.2 matt LIST_HEAD(, evbmips_intrhand) intr_list;
108 1.2 matt struct evcnt intr_evcnt;
109 1.2 matt };
110 1.2 matt
111 1.2 matt /*
112 1.2 matt * ordering for ra_intrtab[] and ra_intr_names[]
113 1.2 matt * corresponds to the RA_IRQ_* definitions
114 1.2 matt * which include the CPU intrs and the PIC intrs
115 1.2 matt */
116 1.2 matt static struct ra_intr ra_intrtab[RA_IRQ_MAX];
117 1.2 matt static const char * const ra_intr_names[RA_IRQ_MAX] = {
118 1.2 matt "intr 0 (lowpri)",
119 1.2 matt "intr 1 (highpri)",
120 1.2 matt "intr 2 (pci)",
121 1.2 matt "intr 3 (frame)",
122 1.2 matt "intr 4 (wlan)",
123 1.2 matt "intr 5 (timer)",
124 1.2 matt "intr 0 (sysctl)",
125 1.2 matt "intr 1 (timer0)",
126 1.2 matt "intr 2 (watchdog)",
127 1.2 matt "intr 3 (illacc)",
128 1.2 matt "intr 4 (pcm)",
129 1.2 matt "intr 5 (uartf)",
130 1.2 matt "intr 6 (gpio)",
131 1.2 matt "intr 7 (dma)",
132 1.2 matt "intr 8 (nand)",
133 1.2 matt "intr 9 (perf)",
134 1.2 matt "intr 10 (i2s)",
135 1.2 matt "intr 12 (uartl)",
136 1.2 matt "intr 17 (ethsw)",
137 1.2 matt "intr 18 (usb)"
138 1.2 matt };
139 1.2 matt
140 1.2 matt /* determine if irq belongs to the PIC */
141 1.2 matt #define PIC_IRQ_P(irq) ((irq) > RA_IRQ_TIMER)
142 1.2 matt
143 1.2 matt /* map the IRQ num to PIC reg bits */
144 1.2 matt static const uint8_t irq2bit[RA_IRQ_MAX] = {
145 1.2 matt -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 17, 18
146 1.2 matt };
147 1.2 matt
148 1.2 matt /* map the PIC reg bits to IRQ num */
149 1.2 matt static const uint8_t bit2irq[19] = {
150 1.2 matt 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 255, 17, 255, 255, 255, 255, 18, 19
151 1.2 matt };
152 1.2 matt
153 1.2 matt
154 1.2 matt
155 1.2 matt static inline uint32_t
156 1.2 matt intctl_read(u_int offset)
157 1.2 matt {
158 1.2 matt return *RA_IOREG_VADDR(RA_INTCTL_BASE, offset);
159 1.2 matt }
160 1.2 matt
161 1.2 matt static inline void
162 1.2 matt intctl_write(u_int offset, uint32_t val)
163 1.2 matt {
164 1.2 matt *RA_IOREG_VADDR(RA_INTCTL_BASE, offset) = val;
165 1.2 matt }
166 1.2 matt
167 1.2 matt
168 1.2 matt void
169 1.2 matt evbmips_intr_init(void)
170 1.2 matt {
171 1.2 matt ipl_sr_map = ralink_ipl_sr_map;
172 1.2 matt
173 1.2 matt for (int irq=0; irq < RA_IRQ_MAX; irq++) {
174 1.2 matt LIST_INIT(&ra_intrtab[irq].intr_list);
175 1.2 matt if (PIC_IRQ_P(irq)) {
176 1.2 matt evcnt_attach_dynamic(&ra_intrtab[irq].intr_evcnt,
177 1.2 matt EVCNT_TYPE_INTR, NULL, "pic",
178 1.2 matt ra_intr_names[irq]);
179 1.2 matt } else {
180 1.2 matt evcnt_attach_dynamic(&ra_intrtab[irq].intr_evcnt,
181 1.2 matt EVCNT_TYPE_INTR, NULL, "cpu0",
182 1.2 matt ra_intr_names[irq]);
183 1.2 matt }
184 1.2 matt }
185 1.2 matt
186 1.2 matt /*
187 1.2 matt * make sure we start without any misc interrupts enabled,
188 1.2 matt * but the block enabled
189 1.2 matt */
190 1.2 matt intctl_write(RA_INTCTL_DISABLE, ~0);
191 1.2 matt intctl_write(RA_INTCTL_ENABLE, INT_GLOBAL);
192 1.2 matt
193 1.2 matt /*
194 1.2 matt * establish the low/high priority cpu interrupts.
195 1.2 matt * note here we pass the value of the priority as the argument
196 1.2 matt * so it is passed to ra_pic_intr() correctly.
197 1.2 matt */
198 1.2 matt ra_intr_establish(RA_IRQ_HIGH, ra_pic_intr,
199 1.2 matt (void *)1, 1);
200 1.2 matt ra_intr_establish(RA_IRQ_LOW, ra_pic_intr,
201 1.2 matt (void *)0, 0);
202 1.2 matt }
203 1.2 matt
204 1.2 matt
205 1.2 matt void *
206 1.2 matt ra_intr_establish(int intr, int (*func)(void *), void *arg, int priority)
207 1.2 matt {
208 1.2 matt struct evbmips_intrhand *ih;
209 1.2 matt
210 1.2 matt if ((ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT)) == NULL) {
211 1.2 matt KASSERTMSG(0, ("%s: cannot malloc intrhand", __func__));
212 1.2 matt return NULL;
213 1.2 matt }
214 1.2 matt
215 1.2 matt ih->ih_func = func;
216 1.2 matt ih->ih_arg = arg;
217 1.2 matt ih->ih_irq = intr;
218 1.2 matt
219 1.2 matt const int s = splhigh();
220 1.2 matt
221 1.2 matt LIST_INSERT_HEAD(&ra_intrtab[intr].intr_list, ih, ih_q);
222 1.2 matt
223 1.2 matt if (PIC_IRQ_P(intr)) {
224 1.2 matt /* irq belongs to the PIC */
225 1.2 matt uint32_t r;
226 1.2 matt r = intctl_read(RA_INTCTL_TYPE);
227 1.2 matt r |= (priority << irq2bit[intr]);
228 1.2 matt intctl_write(RA_INTCTL_TYPE, r);
229 1.2 matt r = intctl_read(RA_INTCTL_ENABLE);
230 1.2 matt r |= (1 << irq2bit[intr]);
231 1.2 matt intctl_write(RA_INTCTL_ENABLE, r);
232 1.2 matt }
233 1.2 matt
234 1.2 matt splx(s);
235 1.2 matt
236 1.2 matt return ih;
237 1.2 matt }
238 1.2 matt
239 1.2 matt void
240 1.2 matt ra_intr_disestablish(void *arg)
241 1.2 matt {
242 1.2 matt struct evbmips_intrhand * const ih = arg;
243 1.2 matt
244 1.2 matt const int s = splhigh();
245 1.2 matt
246 1.2 matt LIST_REMOVE(ih, ih_q);
247 1.2 matt if (PIC_IRQ_P(ih->ih_irq) &&
248 1.2 matt LIST_EMPTY(&ra_intrtab[ih->ih_irq].intr_list)) {
249 1.2 matt uint32_t r;
250 1.2 matt r = intctl_read(RA_INTCTL_DISABLE);
251 1.2 matt r &= ~(1 << irq2bit[ih->ih_irq]);
252 1.2 matt intctl_write(RA_INTCTL_DISABLE, r);
253 1.2 matt }
254 1.2 matt
255 1.2 matt splx(s);
256 1.2 matt
257 1.2 matt free(ih, M_DEVBUF);
258 1.2 matt }
259 1.2 matt
260 1.2 matt /*
261 1.2 matt * ra_pic_intr - service PIC interrupts
262 1.2 matt *
263 1.2 matt * caller handles priority by the calling this function w/ PRI_HIGH first
264 1.2 matt */
265 1.2 matt static int
266 1.2 matt ra_pic_intr(void *arg)
267 1.2 matt {
268 1.2 matt const int priority = (intptr_t)arg;
269 1.2 matt const u_int off = (priority == 0) ?
270 1.2 matt RA_INTCTL_IRQ0STAT : RA_INTCTL_IRQ1STAT;
271 1.2 matt uint32_t pending = intctl_read(off);
272 1.2 matt
273 1.2 matt while (pending != 0) {
274 1.2 matt const u_int bitno = 31 - __builtin_clz(pending);
275 1.2 matt pending ^= (1 << bitno);
276 1.2 matt const int irq = bit2irq[bitno];
277 1.2 matt KASSERT(PIC_IRQ_P(irq));
278 1.2 matt ra_intrtab[irq].intr_evcnt.ev_count++;
279 1.2 matt struct evbmips_intrhand *ih;
280 1.2 matt LIST_FOREACH(ih, &ra_intrtab[irq].intr_list, ih_q)
281 1.2 matt (*ih->ih_func)(ih->ih_arg);
282 1.2 matt }
283 1.2 matt
284 1.2 matt return 1;
285 1.2 matt }
286 1.2 matt
287 1.2 matt /*
288 1.2 matt * evbmips_iointr - process CPU interrupts
289 1.2 matt *
290 1.2 matt * we only see IRQ 4..0 here as IRQ 5 is handled
291 1.2 matt * in the generic MIPS code for the timer
292 1.2 matt */
293 1.2 matt void
294 1.2 matt evbmips_iointr(int ipl, vaddr_t pc, uint32_t ipending)
295 1.2 matt {
296 1.2 matt while (ipending != 0) {
297 1.2 matt const u_int bitno = 31 - __builtin_clz(ipending);
298 1.2 matt ipending ^= (1 << bitno);
299 1.2 matt const int irq = bitno - (31 - __builtin_clz(MIPS_INT_MASK_0));
300 1.2 matt KASSERT(!PIC_IRQ_P(irq));
301 1.2 matt ra_intrtab[irq].intr_evcnt.ev_count++;
302 1.2 matt struct evbmips_intrhand *ih;
303 1.2 matt LIST_FOREACH(ih, &ra_intrtab[irq].intr_list, ih_q)
304 1.2 matt (*ih->ih_func)(ih->ih_arg);
305 1.2 matt }
306 1.2 matt }
307