ralink_intr.c revision 1.5 1 1.5 ryo /* $NetBSD: ralink_intr.c,v 1.5 2016/10/05 15:54:58 ryo 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.5 ryo __KERNEL_RCSID(0, "$NetBSD: ralink_intr.c,v 1.5 2016/10/05 15:54:58 ryo 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 struct ra_intr {
100 1.2 matt LIST_HEAD(, evbmips_intrhand) intr_list;
101 1.2 matt struct evcnt intr_evcnt;
102 1.2 matt };
103 1.2 matt
104 1.2 matt /*
105 1.2 matt * ordering for ra_intrtab[] and ra_intr_names[]
106 1.2 matt * corresponds to the RA_IRQ_* definitions
107 1.2 matt * which include the CPU intrs and the PIC intrs
108 1.2 matt */
109 1.2 matt static struct ra_intr ra_intrtab[RA_IRQ_MAX];
110 1.2 matt static const char * const ra_intr_names[RA_IRQ_MAX] = {
111 1.5 ryo /* CPU interrupts */
112 1.5 ryo [RA_IRQ_LOW] = "intr 0 (lowpri)",
113 1.5 ryo [RA_IRQ_HIGH] = "intr 1 (highpri)",
114 1.5 ryo [RA_IRQ_PCI] = "intr 2 (pci)",
115 1.5 ryo [RA_IRQ_FENGINE]= "intr 3 (frame)",
116 1.5 ryo [RA_IRQ_WLAN] = "intr 4 (wlan)",
117 1.5 ryo [RA_IRQ_TIMER] = "intr 5 (timer)",
118 1.5 ryo
119 1.5 ryo /* Interrupt controller */
120 1.5 ryo [RA_IRQ_SYSCTL] = "intc sysctl",
121 1.5 ryo [RA_IRQ_TIMER0] = "intc timer0",
122 1.5 ryo [RA_IRQ_WDOG] = "intc wdog",
123 1.5 ryo [RA_IRQ_ILLACC] = "intc illacc",
124 1.5 ryo [RA_IRQ_PCM] = "intc pcm",
125 1.5 ryo [RA_IRQ_UARTF] = "intc uartf",
126 1.5 ryo [RA_IRQ_PIO] = "intc gpio",
127 1.5 ryo [RA_IRQ_DMA] = "intc dma",
128 1.5 ryo [RA_IRQ_NAND] = "intc nand",
129 1.5 ryo [RA_IRQ_PERF] = "intc pef",
130 1.5 ryo [RA_IRQ_I2S] = "intc i2s",
131 1.5 ryo [RA_IRQ_SPI] = "intc spi",
132 1.5 ryo [RA_IRQ_UARTL] = "intc uartl",
133 1.5 ryo [RA_IRQ_CRYPTO] = "intc crypto",
134 1.5 ryo [RA_IRQ_SDHC] = "intc sdhc",
135 1.5 ryo [RA_IRQ_R2P] = "intc r2p",
136 1.5 ryo [RA_IRQ_ETHSW] = "intc ethsw",
137 1.5 ryo [RA_IRQ_USB] = "intc usb",
138 1.5 ryo [RA_IRQ_UDEV] = "intc udev",
139 1.5 ryo [RA_IRQ_UART1] = "intc uart1",
140 1.5 ryo [RA_IRQ_UART2] = "intc uart2",
141 1.2 matt };
142 1.2 matt
143 1.2 matt /* determine if irq belongs to the PIC */
144 1.2 matt #define PIC_IRQ_P(irq) ((irq) > RA_IRQ_TIMER)
145 1.2 matt
146 1.2 matt /* map the IRQ num to PIC reg bits */
147 1.2 matt static const uint8_t irq2bit[RA_IRQ_MAX] = {
148 1.5 ryo /* CPU interrupts */
149 1.5 ryo [RA_IRQ_LOW] = -1,
150 1.5 ryo [RA_IRQ_HIGH] = -1,
151 1.5 ryo [RA_IRQ_PCI] = -1,
152 1.5 ryo [RA_IRQ_FENGINE]= -1,
153 1.5 ryo [RA_IRQ_WLAN] = -1,
154 1.5 ryo [RA_IRQ_TIMER] = -1,
155 1.5 ryo
156 1.5 ryo /* Interrupt controller */
157 1.5 ryo [RA_IRQ_SYSCTL] = INT_SYSCTL,
158 1.5 ryo [RA_IRQ_TIMER0] = INT_TIMER0,
159 1.5 ryo [RA_IRQ_WDOG] = INT_WDOG,
160 1.5 ryo [RA_IRQ_ILLACC] = INT_ILLACC,
161 1.5 ryo [RA_IRQ_PCM] = INT_PCM,
162 1.5 ryo [RA_IRQ_UARTF] = INT_UARTF,
163 1.5 ryo [RA_IRQ_PIO] = INT_PIO,
164 1.5 ryo [RA_IRQ_DMA] = INT_DMA,
165 1.5 ryo [RA_IRQ_NAND] = INT_NAND,
166 1.5 ryo [RA_IRQ_PERF] = INT_PERF,
167 1.5 ryo [RA_IRQ_I2S] = INT_I2S,
168 1.5 ryo [RA_IRQ_SPI] = INT_SPI,
169 1.5 ryo [RA_IRQ_UARTL] = INT_UARTL,
170 1.5 ryo #ifdef INT_UART1
171 1.5 ryo [RA_IRQ_UART1] = INT_UART1,
172 1.5 ryo #endif
173 1.5 ryo #ifdef INT_UART2
174 1.5 ryo [RA_IRQ_UART2] = INT_UART2,
175 1.5 ryo #endif
176 1.5 ryo [RA_IRQ_CRYPTO] = INT_CRYPTO,
177 1.5 ryo [RA_IRQ_SDHC] = INT_SDHC,
178 1.5 ryo [RA_IRQ_R2P] = INT_R2P,
179 1.5 ryo [RA_IRQ_ETHSW] = INT_ETHSW,
180 1.5 ryo [RA_IRQ_USB] = INT_USB,
181 1.5 ryo [RA_IRQ_UDEV] = INT_UDEV
182 1.2 matt };
183 1.2 matt
184 1.2 matt /* map the PIC reg bits to IRQ num */
185 1.5 ryo static const uint8_t bit2irq[32] = {
186 1.5 ryo [INT_SYSCTL] = RA_IRQ_SYSCTL,
187 1.5 ryo [INT_TIMER0] = RA_IRQ_TIMER0,
188 1.5 ryo [INT_WDOG] = RA_IRQ_WDOG,
189 1.5 ryo [INT_ILLACC] = RA_IRQ_ILLACC,
190 1.5 ryo [INT_PCM] = RA_IRQ_PCM,
191 1.5 ryo [INT_UARTF] = RA_IRQ_UARTF,
192 1.5 ryo [INT_PIO] = RA_IRQ_PIO,
193 1.5 ryo [INT_DMA] = RA_IRQ_DMA,
194 1.5 ryo [INT_NAND] = RA_IRQ_NAND,
195 1.5 ryo [INT_PERF] = RA_IRQ_PERF,
196 1.5 ryo [INT_I2S] = RA_IRQ_I2S,
197 1.5 ryo [INT_SPI] = RA_IRQ_SPI,
198 1.5 ryo [INT_UARTL] = RA_IRQ_UARTL,
199 1.5 ryo #ifdef INT_UART1
200 1.5 ryo [INT_UART1] = RA_IRQ_UART1,
201 1.5 ryo #endif
202 1.5 ryo #ifdef INT_UART2
203 1.5 ryo [INT_UART2] = RA_IRQ_UART2,
204 1.5 ryo #endif
205 1.5 ryo [INT_CRYPTO] = RA_IRQ_CRYPTO,
206 1.5 ryo [INT_SDHC] = RA_IRQ_SDHC,
207 1.5 ryo [INT_R2P] = RA_IRQ_R2P,
208 1.5 ryo [INT_ETHSW] = RA_IRQ_ETHSW,
209 1.5 ryo [INT_USB] = RA_IRQ_USB,
210 1.5 ryo [INT_UDEV] = RA_IRQ_UDEV
211 1.2 matt };
212 1.2 matt
213 1.2 matt
214 1.2 matt
215 1.2 matt static inline uint32_t
216 1.2 matt intctl_read(u_int offset)
217 1.2 matt {
218 1.2 matt return *RA_IOREG_VADDR(RA_INTCTL_BASE, offset);
219 1.2 matt }
220 1.2 matt
221 1.2 matt static inline void
222 1.2 matt intctl_write(u_int offset, uint32_t val)
223 1.2 matt {
224 1.2 matt *RA_IOREG_VADDR(RA_INTCTL_BASE, offset) = val;
225 1.2 matt }
226 1.2 matt
227 1.2 matt
228 1.2 matt void
229 1.2 matt evbmips_intr_init(void)
230 1.2 matt {
231 1.2 matt ipl_sr_map = ralink_ipl_sr_map;
232 1.2 matt
233 1.2 matt for (int irq=0; irq < RA_IRQ_MAX; irq++) {
234 1.2 matt LIST_INIT(&ra_intrtab[irq].intr_list);
235 1.2 matt if (PIC_IRQ_P(irq)) {
236 1.2 matt evcnt_attach_dynamic(&ra_intrtab[irq].intr_evcnt,
237 1.5 ryo EVCNT_TYPE_INTR, NULL, "pic",
238 1.5 ryo ra_intr_names[irq]);
239 1.2 matt } else {
240 1.2 matt evcnt_attach_dynamic(&ra_intrtab[irq].intr_evcnt,
241 1.5 ryo EVCNT_TYPE_INTR, NULL, "cpu0",
242 1.5 ryo ra_intr_names[irq]);
243 1.2 matt }
244 1.2 matt }
245 1.2 matt
246 1.2 matt /*
247 1.2 matt * make sure we start without any misc interrupts enabled,
248 1.2 matt * but the block enabled
249 1.2 matt */
250 1.2 matt intctl_write(RA_INTCTL_DISABLE, ~0);
251 1.5 ryo intctl_write(RA_INTCTL_ENABLE, INT_GLOBAL_EN);
252 1.2 matt
253 1.5 ryo /*
254 1.2 matt * establish the low/high priority cpu interrupts.
255 1.2 matt * note here we pass the value of the priority as the argument
256 1.2 matt * so it is passed to ra_pic_intr() correctly.
257 1.2 matt */
258 1.2 matt ra_intr_establish(RA_IRQ_HIGH, ra_pic_intr,
259 1.2 matt (void *)1, 1);
260 1.2 matt ra_intr_establish(RA_IRQ_LOW, ra_pic_intr,
261 1.2 matt (void *)0, 0);
262 1.2 matt }
263 1.2 matt
264 1.2 matt
265 1.2 matt void *
266 1.2 matt ra_intr_establish(int intr, int (*func)(void *), void *arg, int priority)
267 1.2 matt {
268 1.2 matt struct evbmips_intrhand *ih;
269 1.2 matt
270 1.2 matt if ((ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT)) == NULL) {
271 1.3 jym KASSERTMSG(0, "%s: cannot malloc intrhand", __func__);
272 1.2 matt return NULL;
273 1.2 matt }
274 1.2 matt
275 1.2 matt ih->ih_func = func;
276 1.2 matt ih->ih_arg = arg;
277 1.2 matt ih->ih_irq = intr;
278 1.2 matt
279 1.2 matt const int s = splhigh();
280 1.2 matt
281 1.2 matt LIST_INSERT_HEAD(&ra_intrtab[intr].intr_list, ih, ih_q);
282 1.2 matt
283 1.2 matt if (PIC_IRQ_P(intr)) {
284 1.2 matt /* irq belongs to the PIC */
285 1.2 matt uint32_t r;
286 1.2 matt r = intctl_read(RA_INTCTL_TYPE);
287 1.2 matt r |= (priority << irq2bit[intr]);
288 1.2 matt intctl_write(RA_INTCTL_TYPE, r);
289 1.2 matt r = intctl_read(RA_INTCTL_ENABLE);
290 1.2 matt r |= (1 << irq2bit[intr]);
291 1.2 matt intctl_write(RA_INTCTL_ENABLE, r);
292 1.2 matt }
293 1.2 matt
294 1.2 matt splx(s);
295 1.2 matt
296 1.2 matt return ih;
297 1.2 matt }
298 1.2 matt
299 1.2 matt void
300 1.2 matt ra_intr_disestablish(void *arg)
301 1.2 matt {
302 1.2 matt struct evbmips_intrhand * const ih = arg;
303 1.2 matt
304 1.2 matt const int s = splhigh();
305 1.2 matt
306 1.2 matt LIST_REMOVE(ih, ih_q);
307 1.2 matt if (PIC_IRQ_P(ih->ih_irq) &&
308 1.2 matt LIST_EMPTY(&ra_intrtab[ih->ih_irq].intr_list)) {
309 1.2 matt uint32_t r;
310 1.2 matt r = intctl_read(RA_INTCTL_DISABLE);
311 1.2 matt r &= ~(1 << irq2bit[ih->ih_irq]);
312 1.2 matt intctl_write(RA_INTCTL_DISABLE, r);
313 1.2 matt }
314 1.2 matt
315 1.2 matt splx(s);
316 1.2 matt
317 1.2 matt free(ih, M_DEVBUF);
318 1.2 matt }
319 1.2 matt
320 1.2 matt /*
321 1.2 matt * ra_pic_intr - service PIC interrupts
322 1.2 matt *
323 1.2 matt * caller handles priority by the calling this function w/ PRI_HIGH first
324 1.2 matt */
325 1.2 matt static int
326 1.2 matt ra_pic_intr(void *arg)
327 1.2 matt {
328 1.2 matt const int priority = (intptr_t)arg;
329 1.2 matt const u_int off = (priority == 0) ?
330 1.5 ryo RA_INTCTL_IRQ0STAT : RA_INTCTL_IRQ1STAT;
331 1.2 matt uint32_t pending = intctl_read(off);
332 1.2 matt
333 1.2 matt while (pending != 0) {
334 1.2 matt const u_int bitno = 31 - __builtin_clz(pending);
335 1.2 matt pending ^= (1 << bitno);
336 1.2 matt const int irq = bit2irq[bitno];
337 1.2 matt KASSERT(PIC_IRQ_P(irq));
338 1.2 matt ra_intrtab[irq].intr_evcnt.ev_count++;
339 1.2 matt struct evbmips_intrhand *ih;
340 1.2 matt LIST_FOREACH(ih, &ra_intrtab[irq].intr_list, ih_q)
341 1.2 matt (*ih->ih_func)(ih->ih_arg);
342 1.2 matt }
343 1.2 matt
344 1.2 matt return 1;
345 1.2 matt }
346 1.2 matt
347 1.2 matt /*
348 1.2 matt * evbmips_iointr - process CPU interrupts
349 1.2 matt *
350 1.2 matt * we only see IRQ 4..0 here as IRQ 5 is handled
351 1.2 matt * in the generic MIPS code for the timer
352 1.2 matt */
353 1.2 matt void
354 1.4 skrll evbmips_iointr(int ipl, uint32_t ipending, struct clockframe *cf)
355 1.2 matt {
356 1.2 matt while (ipending != 0) {
357 1.2 matt const u_int bitno = 31 - __builtin_clz(ipending);
358 1.2 matt ipending ^= (1 << bitno);
359 1.2 matt const int irq = bitno - (31 - __builtin_clz(MIPS_INT_MASK_0));
360 1.2 matt KASSERT(!PIC_IRQ_P(irq));
361 1.2 matt ra_intrtab[irq].intr_evcnt.ev_count++;
362 1.2 matt struct evbmips_intrhand *ih;
363 1.2 matt LIST_FOREACH(ih, &ra_intrtab[irq].intr_list, ih_q)
364 1.2 matt (*ih->ih_func)(ih->ih_arg);
365 1.2 matt }
366 1.2 matt }
367