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