1 /* $NetBSD: ralink_intr.c,v 1.3 2011/09/27 01:02:34 jym 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 2011/09/27 01:02:34 jym 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, vaddr_t pc, uint32_t ipending) 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