1 1.27 thorpej /* $NetBSD: malta_intr.c,v 1.27 2020/11/21 15:36:36 thorpej Exp $ */ 2 1.1 simonb 3 1.1 simonb /* 4 1.1 simonb * Copyright 2001, 2002 Wasabi Systems, Inc. 5 1.1 simonb * All rights reserved. 6 1.1 simonb * 7 1.1 simonb * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc. 8 1.1 simonb * 9 1.1 simonb * Redistribution and use in source and binary forms, with or without 10 1.1 simonb * modification, are permitted provided that the following conditions 11 1.1 simonb * are met: 12 1.1 simonb * 1. Redistributions of source code must retain the above copyright 13 1.1 simonb * notice, this list of conditions and the following disclaimer. 14 1.1 simonb * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 simonb * notice, this list of conditions and the following disclaimer in the 16 1.1 simonb * documentation and/or other materials provided with the distribution. 17 1.1 simonb * 3. All advertising materials mentioning features or use of this software 18 1.1 simonb * must display the following acknowledgement: 19 1.1 simonb * This product includes software developed for the NetBSD Project by 20 1.1 simonb * Wasabi Systems, Inc. 21 1.1 simonb * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 simonb * or promote products derived from this software without specific prior 23 1.1 simonb * written permission. 24 1.1 simonb * 25 1.1 simonb * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 simonb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 simonb * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 simonb * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 simonb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 simonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 simonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 simonb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 simonb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 simonb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 simonb * POSSIBILITY OF SUCH DAMAGE. 36 1.1 simonb */ 37 1.1 simonb 38 1.1 simonb /* 39 1.1 simonb * Platform-specific interrupt support for the MIPS Malta. 40 1.1 simonb */ 41 1.1 simonb 42 1.9 lukem #include <sys/cdefs.h> 43 1.27 thorpej __KERNEL_RCSID(0, "$NetBSD: malta_intr.c,v 1.27 2020/11/21 15:36:36 thorpej Exp $"); 44 1.20 matt 45 1.20 matt #define __INTR_PRIVATE 46 1.1 simonb 47 1.1 simonb #include <sys/param.h> 48 1.1 simonb #include <sys/device.h> 49 1.1 simonb #include <sys/kernel.h> 50 1.27 thorpej #include <sys/kmem.h> 51 1.10 simonb #include <sys/systm.h> 52 1.14 yamt #include <sys/cpu.h> 53 1.1 simonb 54 1.1 simonb #include <mips/locore.h> 55 1.1 simonb 56 1.1 simonb #include <evbmips/malta/maltavar.h> 57 1.1 simonb #include <evbmips/malta/pci/pcibvar.h> 58 1.1 simonb 59 1.1 simonb #include <dev/ic/mc146818reg.h> /* for malta_cal_timer() */ 60 1.1 simonb 61 1.1 simonb #include <dev/isa/isavar.h> 62 1.1 simonb #include <dev/pci/pciidereg.h> 63 1.1 simonb 64 1.1 simonb /* 65 1.1 simonb * This is a mask of bits to clear in the SR when we go to a 66 1.1 simonb * given hardware interrupt priority level. 67 1.1 simonb */ 68 1.20 matt static const struct ipl_sr_map malta_ipl_sr_map = { 69 1.20 matt .sr_bits = { 70 1.20 matt [IPL_NONE] = 0, 71 1.20 matt [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 72 1.20 matt [IPL_SOFTNET] = MIPS_SOFT_INT_MASK, 73 1.20 matt [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0, 74 1.20 matt [IPL_SCHED] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0 75 1.20 matt | MIPS_INT_MASK_5, 76 1.20 matt [IPL_DDB] = MIPS_INT_MASK, 77 1.20 matt [IPL_HIGH] = MIPS_INT_MASK, 78 1.20 matt }, 79 1.1 simonb }; 80 1.1 simonb 81 1.1 simonb struct malta_cpuintr { 82 1.1 simonb LIST_HEAD(, evbmips_intrhand) cintr_list; 83 1.1 simonb struct evcnt cintr_count; 84 1.1 simonb }; 85 1.1 simonb #define NINTRS 5 /* MIPS INT0 - INT4 */ 86 1.1 simonb 87 1.1 simonb struct malta_cpuintr malta_cpuintrs[NINTRS]; 88 1.20 matt const char * const malta_cpuintrnames[NINTRS] = { 89 1.1 simonb "int 0 (piix4)", 90 1.1 simonb "int 1 (smi)", 91 1.1 simonb "int 2 (uart)", 92 1.1 simonb "int 3 (core hi/gt64120)", 93 1.1 simonb "int 4 (core lo)", 94 1.1 simonb }; 95 1.1 simonb 96 1.21 dyoung static int malta_pci_intr_map(const struct pci_attach_args *, 97 1.21 dyoung pci_intr_handle_t *); 98 1.1 simonb static const char 99 1.23 christos *malta_pci_intr_string(void *, pci_intr_handle_t, char *, size_t); 100 1.1 simonb static const struct evcnt 101 1.1 simonb *malta_pci_intr_evcnt(void *, pci_intr_handle_t); 102 1.1 simonb static void *malta_pci_intr_establish(void *, pci_intr_handle_t, int, 103 1.1 simonb int (*)(void *), void *); 104 1.1 simonb static void malta_pci_intr_disestablish(void *, void *); 105 1.1 simonb static void malta_pci_conf_interrupt(void *, int, int, int, int, int *); 106 1.22 chs static void *malta_pciide_compat_intr_establish(void *, device_t, 107 1.21 dyoung const struct pci_attach_args *, int, int (*)(void *), 108 1.21 dyoung void *); 109 1.1 simonb 110 1.1 simonb void 111 1.1 simonb evbmips_intr_init(void) 112 1.1 simonb { 113 1.20 matt struct malta_config * const mcp = &malta_configuration; 114 1.20 matt 115 1.20 matt ipl_sr_map = malta_ipl_sr_map; 116 1.1 simonb 117 1.20 matt for (size_t i = 0; i < NINTRS; i++) { 118 1.1 simonb LIST_INIT(&malta_cpuintrs[i].cintr_list); 119 1.1 simonb evcnt_attach_dynamic(&malta_cpuintrs[i].cintr_count, 120 1.1 simonb EVCNT_TYPE_INTR, NULL, "mips", malta_cpuintrnames[i]); 121 1.1 simonb } 122 1.1 simonb 123 1.1 simonb mcp->mc_pc.pc_intr_v = NULL; 124 1.1 simonb mcp->mc_pc.pc_intr_map = malta_pci_intr_map; 125 1.1 simonb mcp->mc_pc.pc_intr_string = malta_pci_intr_string; 126 1.1 simonb mcp->mc_pc.pc_intr_evcnt = malta_pci_intr_evcnt; 127 1.1 simonb mcp->mc_pc.pc_intr_establish = malta_pci_intr_establish; 128 1.1 simonb mcp->mc_pc.pc_intr_disestablish = malta_pci_intr_disestablish; 129 1.1 simonb mcp->mc_pc.pc_conf_interrupt = malta_pci_conf_interrupt; 130 1.1 simonb mcp->mc_pc.pc_pciide_compat_intr_establish = 131 1.1 simonb malta_pciide_compat_intr_establish; 132 1.1 simonb } 133 1.1 simonb 134 1.1 simonb void 135 1.1 simonb malta_cal_timer(bus_space_tag_t st, bus_space_handle_t sh) 136 1.1 simonb { 137 1.20 matt struct cpu_info * const ci = curcpu(); 138 1.4 simonb uint32_t ctrdiff[4], startctr, endctr; 139 1.11 gdamore uint8_t regc; 140 1.1 simonb int i; 141 1.1 simonb 142 1.1 simonb /* Disable interrupts first. */ 143 1.1 simonb bus_space_write_1(st, sh, 0, MC_REGB); 144 1.1 simonb bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY | 145 1.1 simonb MC_REGB_24HR); 146 1.1 simonb 147 1.1 simonb /* Initialize for 16Hz. */ 148 1.1 simonb bus_space_write_1(st, sh, 0, MC_REGA); 149 1.1 simonb bus_space_write_1(st, sh, 1, MC_BASE_32_KHz | MC_RATE_16_Hz); 150 1.1 simonb 151 1.1 simonb /* Run the loop an extra time to prime the cache. */ 152 1.1 simonb for (i = 0; i < 4; i++) { 153 1.1 simonb // led_display('h', 'z', '0' + i, ' '); 154 1.1 simonb 155 1.1 simonb /* Enable the interrupt. */ 156 1.1 simonb bus_space_write_1(st, sh, 0, MC_REGB); 157 1.1 simonb bus_space_write_1(st, sh, 1, MC_REGB_PIE | MC_REGB_SQWE | 158 1.1 simonb MC_REGB_BINARY | MC_REGB_24HR); 159 1.1 simonb 160 1.1 simonb /* Go to REGC. */ 161 1.1 simonb bus_space_write_1(st, sh, 0, MC_REGC); 162 1.1 simonb 163 1.1 simonb /* Wait for it to happen. */ 164 1.1 simonb startctr = mips3_cp0_count_read(); 165 1.1 simonb do { 166 1.1 simonb regc = bus_space_read_1(st, sh, 1); 167 1.1 simonb endctr = mips3_cp0_count_read(); 168 1.1 simonb } while ((regc & MC_REGC_IRQF) == 0); 169 1.1 simonb 170 1.1 simonb /* Already ACK'd. */ 171 1.1 simonb 172 1.1 simonb /* Disable. */ 173 1.1 simonb bus_space_write_1(st, sh, 0, MC_REGB); 174 1.1 simonb bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY | 175 1.1 simonb MC_REGB_24HR); 176 1.1 simonb 177 1.1 simonb ctrdiff[i] = endctr - startctr; 178 1.1 simonb } 179 1.1 simonb 180 1.1 simonb /* Compute the number of cycles per second. */ 181 1.20 matt ci->ci_cpu_freq = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16/*Hz*/; 182 1.1 simonb 183 1.1 simonb /* Compute the number of ticks for hz. */ 184 1.20 matt ci->ci_cycles_per_hz = (ci->ci_cpu_freq + hz / 2) / hz; 185 1.1 simonb 186 1.19 tsutsui /* Compute the delay divisor. */ 187 1.20 matt ci->ci_divisor_delay = ((ci->ci_cpu_freq + 500000) / 1000000); 188 1.2 simonb 189 1.2 simonb /* 190 1.2 simonb * Get correct cpu frequency if the CPU runs at twice the 191 1.2 simonb * external/cp0-count frequency. 192 1.2 simonb */ 193 1.20 matt ci->ci_cctr_freq = ci->ci_cpu_freq; 194 1.20 matt if (mips_options.mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT) 195 1.20 matt ci->ci_cpu_freq *= 2; 196 1.1 simonb 197 1.1 simonb #ifdef DEBUG 198 1.4 simonb printf("Timer calibration: %lu cycles/sec [(%u, %u) * 16]\n", 199 1.20 matt ci->ci_cpu_freq, ctrdiff[2], ctrdiff[3]); 200 1.1 simonb #endif 201 1.1 simonb } 202 1.1 simonb 203 1.1 simonb void * 204 1.1 simonb evbmips_intr_establish(int irq, int (*func)(void *), void *arg) 205 1.1 simonb { 206 1.1 simonb struct evbmips_intrhand *ih; 207 1.1 simonb int s; 208 1.1 simonb 209 1.27 thorpej ih = kmem_alloc(sizeof(*ih), KM_SLEEP); 210 1.1 simonb ih->ih_func = func; 211 1.1 simonb ih->ih_arg = arg; 212 1.1 simonb 213 1.1 simonb s = splhigh(); 214 1.1 simonb 215 1.1 simonb /* 216 1.1 simonb * Link it into the tables. 217 1.1 simonb */ 218 1.1 simonb LIST_INSERT_HEAD(&malta_cpuintrs[0].cintr_list, ih, ih_q); 219 1.1 simonb 220 1.1 simonb /* XXX - should check that MIPS_INT_MASK_0 is set... */ 221 1.1 simonb 222 1.1 simonb splx(s); 223 1.1 simonb 224 1.1 simonb return (ih); 225 1.1 simonb } 226 1.1 simonb 227 1.1 simonb void 228 1.1 simonb evbmips_intr_disestablish(void *arg) 229 1.1 simonb { 230 1.1 simonb struct evbmips_intrhand *ih = arg; 231 1.1 simonb int s; 232 1.1 simonb 233 1.1 simonb s = splhigh(); 234 1.1 simonb 235 1.1 simonb /* 236 1.1 simonb * First, remove it from the table. 237 1.1 simonb */ 238 1.1 simonb LIST_REMOVE(ih, ih_q); 239 1.1 simonb 240 1.1 simonb /* XXX - disable MIPS_INT_MASK_0 if list is empty? */ 241 1.1 simonb 242 1.1 simonb splx(s); 243 1.1 simonb 244 1.27 thorpej kmem_free(ih, sizeof(*ih)); 245 1.1 simonb } 246 1.1 simonb 247 1.1 simonb void 248 1.25 skrll evbmips_iointr(int ipl, uint32_t ipending, struct clockframe *cf) 249 1.1 simonb { 250 1.1 simonb 251 1.5 simonb /* Check for error interrupts (SMI, GT64120) */ 252 1.1 simonb if (ipending & (MIPS_INT_MASK_1 | MIPS_INT_MASK_3)) { 253 1.1 simonb if (ipending & MIPS_INT_MASK_1) 254 1.1 simonb panic("piix4 SMI interrupt"); 255 1.1 simonb if (ipending & MIPS_INT_MASK_3) 256 1.5 simonb panic("gt64120 error interrupt"); 257 1.1 simonb } 258 1.1 simonb 259 1.1 simonb /* 260 1.1 simonb * Read the interrupt pending registers, mask them with the 261 1.1 simonb * ones we have enabled, and service them in order of decreasing 262 1.1 simonb * priority. 263 1.1 simonb */ 264 1.1 simonb if (ipending & MIPS_INT_MASK_0) { 265 1.20 matt struct evbmips_intrhand *ih; 266 1.1 simonb /* All interrupts are gated through MIPS HW interrupt 0 */ 267 1.1 simonb malta_cpuintrs[0].cintr_count.ev_count++; 268 1.1 simonb LIST_FOREACH(ih, &malta_cpuintrs[0].cintr_list, ih_q) 269 1.1 simonb (*ih->ih_func)(ih->ih_arg); 270 1.1 simonb } 271 1.1 simonb } 272 1.1 simonb 273 1.1 simonb /* 274 1.1 simonb * YAMON configures pa_intrline correctly (so far), so we trust it to DTRT 275 1.1 simonb * in the future... 276 1.1 simonb */ 277 1.1 simonb #undef YAMON_IRQ_MAP_BAD 278 1.1 simonb 279 1.1 simonb /* 280 1.1 simonb * PCI interrupt support 281 1.1 simonb */ 282 1.1 simonb static int 283 1.21 dyoung malta_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) 284 1.1 simonb { 285 1.1 simonb #ifdef YAMON_IRQ_MAP_BAD 286 1.7 simonb static const int pciirqmap[12/*device*/][4/*pin*/] = { 287 1.1 simonb { -1, -1, -1, 11 }, /* 10: USB */ 288 1.1 simonb { 10, -1, -1, -1 }, /* 11: Ethernet */ 289 1.1 simonb { 11, -1, -1, -1 }, /* 12: Audio */ 290 1.1 simonb { -1, -1, -1, -1 }, /* 13: not used */ 291 1.1 simonb { -1, -1, -1, -1 }, /* 14: not used */ 292 1.1 simonb { -1, -1, -1, -1 }, /* 15: not used */ 293 1.1 simonb { -1, -1, -1, -1 }, /* 16: not used */ 294 1.1 simonb { -1, -1, -1, -1 }, /* 17: Core card(?) */ 295 1.1 simonb { 10, 10, 11, 11 }, /* 18: PCI Slot 1 */ 296 1.1 simonb { 10, 11, 11, 10 }, /* 19: PCI Slot 2 */ 297 1.1 simonb { 11, 11, 10, 10 }, /* 20: PCI Slot 3 */ 298 1.1 simonb { 11, 10, 10, 11 }, /* 21: PCI Slot 4 */ 299 1.1 simonb }; 300 1.1 simonb int buspin, device, irq; 301 1.1 simonb #else /* !YAMON_IRQ_MAP_BAD */ 302 1.1 simonb int buspin; 303 1.1 simonb #endif /* !YAMON_IRQ_MAP_BAD */ 304 1.1 simonb 305 1.1 simonb buspin = pa->pa_intrpin; 306 1.1 simonb 307 1.1 simonb if (buspin == 0) { 308 1.1 simonb /* No IRQ used. */ 309 1.1 simonb return (1); 310 1.1 simonb } 311 1.1 simonb 312 1.1 simonb if (buspin > 4) { 313 1.1 simonb printf("malta_pci_intr_map: bad interrupt pin %d\n", buspin); 314 1.1 simonb return (1); 315 1.1 simonb } 316 1.1 simonb 317 1.1 simonb #ifdef YAMON_IRQ_MAP_BAD 318 1.1 simonb pci_decompose_tag(pa->pa_pc, pa->pa_intrtag, NULL, &device, NULL); 319 1.1 simonb 320 1.1 simonb if (device < 10 || device > 21) { 321 1.1 simonb printf("malta_pci_intr_map: bad device %d\n", device); 322 1.1 simonb return (1); 323 1.1 simonb } 324 1.1 simonb 325 1.1 simonb irq = pciirqmap[device - 10][buspin - 1]; 326 1.1 simonb if (irq == -1) { 327 1.1 simonb printf("malta_pci_intr_map: no mapping for device %d pin %d\n", 328 1.1 simonb device, buspin); 329 1.1 simonb return (1); 330 1.1 simonb } 331 1.1 simonb 332 1.1 simonb *ihp = irq; 333 1.1 simonb #else /* !YAMON_IRQ_MAP_BAD */ 334 1.1 simonb *ihp = pa->pa_intrline; 335 1.1 simonb #endif /* !YAMON_IRQ_MAP_BAD */ 336 1.1 simonb return (0); 337 1.1 simonb } 338 1.1 simonb 339 1.1 simonb static const char * 340 1.23 christos malta_pci_intr_string(void *v, pci_intr_handle_t irq, char *buf, size_t len) 341 1.1 simonb { 342 1.1 simonb 343 1.23 christos return isa_intr_string(pcib_ic, irq, buf, len); 344 1.1 simonb } 345 1.1 simonb 346 1.1 simonb static const struct evcnt * 347 1.1 simonb malta_pci_intr_evcnt(void *v, pci_intr_handle_t irq) 348 1.1 simonb { 349 1.1 simonb 350 1.1 simonb return (isa_intr_evcnt(pcib_ic, irq)); 351 1.1 simonb } 352 1.1 simonb 353 1.1 simonb static void * 354 1.1 simonb malta_pci_intr_establish(void *v, pci_intr_handle_t irq, int level, 355 1.1 simonb int (*func)(void *), void *arg) 356 1.1 simonb { 357 1.1 simonb 358 1.1 simonb return (isa_intr_establish(pcib_ic, irq, IST_LEVEL, level, func, arg)); 359 1.1 simonb } 360 1.1 simonb 361 1.1 simonb static void 362 1.1 simonb malta_pci_intr_disestablish(void *v, void *arg) 363 1.1 simonb { 364 1.1 simonb 365 1.1 simonb return (isa_intr_disestablish(pcib_ic, arg)); 366 1.1 simonb } 367 1.1 simonb 368 1.1 simonb static void 369 1.1 simonb malta_pci_conf_interrupt(void *v, int bus, int dev, int func, int swiz, 370 1.1 simonb int *iline) 371 1.1 simonb { 372 1.1 simonb 373 1.1 simonb /* 374 1.1 simonb * We actually don't need to do anything; everything is handled 375 1.1 simonb * in pci_intr_map(). 376 1.1 simonb */ 377 1.1 simonb *iline = 0; 378 1.1 simonb } 379 1.1 simonb 380 1.1 simonb void * 381 1.22 chs malta_pciide_compat_intr_establish(void *v, device_t dev, 382 1.21 dyoung const struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg) 383 1.1 simonb { 384 1.1 simonb pci_chipset_tag_t pc = pa->pa_pc; 385 1.1 simonb void *cookie; 386 1.1 simonb int bus, irq; 387 1.24 christos char buf[PCI_INTRSTR_LEN]; 388 1.1 simonb 389 1.1 simonb pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL); 390 1.1 simonb 391 1.1 simonb /* 392 1.1 simonb * If this isn't PCI bus #0, all bets are off. 393 1.1 simonb */ 394 1.1 simonb if (bus != 0) 395 1.1 simonb return (NULL); 396 1.1 simonb 397 1.1 simonb irq = PCIIDE_COMPAT_IRQ(chan); 398 1.1 simonb cookie = isa_intr_establish(pcib_ic, irq, IST_EDGE, IPL_BIO, func, arg); 399 1.1 simonb if (cookie == NULL) 400 1.1 simonb return (NULL); 401 1.22 chs printf("%s: %s channel interrupting at %s\n", device_xname(dev), 402 1.23 christos PCIIDE_CHANNEL_NAME(chan), malta_pci_intr_string(v, irq, buf, sizeof(buf))); 403 1.1 simonb return (cookie); 404 1.1 simonb } 405