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