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