ralink_intr.c revision 1.7 1 1.7 thorpej /* $NetBSD: ralink_intr.c,v 1.7 2021/01/04 18:14:38 thorpej 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.7 thorpej __KERNEL_RCSID(0, "$NetBSD: ralink_intr.c,v 1.7 2021/01/04 18:14:38 thorpej 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.7 thorpej #include <sys/kmem.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.7 thorpej ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
271 1.2 matt ih->ih_func = func;
272 1.2 matt ih->ih_arg = arg;
273 1.2 matt ih->ih_irq = intr;
274 1.2 matt
275 1.2 matt const int s = splhigh();
276 1.2 matt
277 1.2 matt LIST_INSERT_HEAD(&ra_intrtab[intr].intr_list, ih, ih_q);
278 1.2 matt
279 1.2 matt if (PIC_IRQ_P(intr)) {
280 1.2 matt /* irq belongs to the PIC */
281 1.2 matt uint32_t r;
282 1.2 matt r = intctl_read(RA_INTCTL_TYPE);
283 1.2 matt r |= (priority << irq2bit[intr]);
284 1.2 matt intctl_write(RA_INTCTL_TYPE, r);
285 1.2 matt r = intctl_read(RA_INTCTL_ENABLE);
286 1.2 matt r |= (1 << irq2bit[intr]);
287 1.2 matt intctl_write(RA_INTCTL_ENABLE, r);
288 1.2 matt }
289 1.2 matt
290 1.2 matt splx(s);
291 1.2 matt
292 1.2 matt return ih;
293 1.2 matt }
294 1.2 matt
295 1.2 matt void
296 1.2 matt ra_intr_disestablish(void *arg)
297 1.2 matt {
298 1.2 matt struct evbmips_intrhand * const ih = arg;
299 1.2 matt
300 1.2 matt const int s = splhigh();
301 1.2 matt
302 1.2 matt LIST_REMOVE(ih, ih_q);
303 1.2 matt if (PIC_IRQ_P(ih->ih_irq) &&
304 1.2 matt LIST_EMPTY(&ra_intrtab[ih->ih_irq].intr_list)) {
305 1.2 matt uint32_t r;
306 1.2 matt r = intctl_read(RA_INTCTL_DISABLE);
307 1.2 matt r &= ~(1 << irq2bit[ih->ih_irq]);
308 1.2 matt intctl_write(RA_INTCTL_DISABLE, r);
309 1.2 matt }
310 1.2 matt
311 1.2 matt splx(s);
312 1.2 matt
313 1.7 thorpej kmem_free(ih, sizeof(*ih));
314 1.2 matt }
315 1.2 matt
316 1.2 matt /*
317 1.2 matt * ra_pic_intr - service PIC interrupts
318 1.2 matt *
319 1.2 matt * caller handles priority by the calling this function w/ PRI_HIGH first
320 1.2 matt */
321 1.2 matt static int
322 1.2 matt ra_pic_intr(void *arg)
323 1.2 matt {
324 1.2 matt const int priority = (intptr_t)arg;
325 1.2 matt const u_int off = (priority == 0) ?
326 1.5 ryo RA_INTCTL_IRQ0STAT : RA_INTCTL_IRQ1STAT;
327 1.2 matt uint32_t pending = intctl_read(off);
328 1.2 matt
329 1.2 matt while (pending != 0) {
330 1.2 matt const u_int bitno = 31 - __builtin_clz(pending);
331 1.2 matt pending ^= (1 << bitno);
332 1.2 matt const int irq = bit2irq[bitno];
333 1.2 matt KASSERT(PIC_IRQ_P(irq));
334 1.2 matt ra_intrtab[irq].intr_evcnt.ev_count++;
335 1.2 matt struct evbmips_intrhand *ih;
336 1.2 matt LIST_FOREACH(ih, &ra_intrtab[irq].intr_list, ih_q)
337 1.2 matt (*ih->ih_func)(ih->ih_arg);
338 1.2 matt }
339 1.2 matt
340 1.2 matt return 1;
341 1.2 matt }
342 1.2 matt
343 1.2 matt /*
344 1.2 matt * evbmips_iointr - process CPU interrupts
345 1.2 matt *
346 1.2 matt * we only see IRQ 4..0 here as IRQ 5 is handled
347 1.2 matt * in the generic MIPS code for the timer
348 1.2 matt */
349 1.2 matt void
350 1.4 skrll evbmips_iointr(int ipl, uint32_t ipending, struct clockframe *cf)
351 1.2 matt {
352 1.2 matt while (ipending != 0) {
353 1.2 matt const u_int bitno = 31 - __builtin_clz(ipending);
354 1.2 matt ipending ^= (1 << bitno);
355 1.2 matt const int irq = bitno - (31 - __builtin_clz(MIPS_INT_MASK_0));
356 1.2 matt KASSERT(!PIC_IRQ_P(irq));
357 1.2 matt ra_intrtab[irq].intr_evcnt.ev_count++;
358 1.2 matt struct evbmips_intrhand *ih;
359 1.2 matt LIST_FOREACH(ih, &ra_intrtab[irq].intr_list, ih_q)
360 1.2 matt (*ih->ih_func)(ih->ih_arg);
361 1.2 matt }
362 1.2 matt }
363