1 /* $NetBSD: malta_intr.c,v 1.11 2006/02/09 18:03:12 gdamore 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.11 2006/02/09 18:03:12 gdamore Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/device.h> 47 #include <sys/kernel.h> 48 #include <sys/malloc.h> 49 #include <sys/systm.h> 50 51 #include <mips/locore.h> 52 53 #include <evbmips/evbmips/clockvar.h> 54 55 #include <evbmips/malta/maltavar.h> 56 #include <evbmips/malta/pci/pcibvar.h> 57 58 #include <dev/ic/mc146818reg.h> /* for malta_cal_timer() */ 59 60 #include <dev/isa/isavar.h> 61 #include <dev/pci/pciidereg.h> 62 63 /* 64 * This is a mask of bits to clear in the SR when we go to a 65 * given hardware interrupt priority level. 66 */ 67 const uint32_t ipl_sr_bits[_IPL_N] = { 68 0, /* 0: IPL_NONE */ 69 70 MIPS_SOFT_INT_MASK_0, /* 1: IPL_SOFT */ 71 72 MIPS_SOFT_INT_MASK_0, /* 2: IPL_SOFTCLOCK */ 73 74 MIPS_SOFT_INT_MASK_0| 75 MIPS_SOFT_INT_MASK_1, /* 3: IPL_SOFTNET */ 76 77 MIPS_SOFT_INT_MASK_0| 78 MIPS_SOFT_INT_MASK_1, /* 4: IPL_SOFTSERIAL */ 79 80 MIPS_SOFT_INT_MASK_0| 81 MIPS_SOFT_INT_MASK_1| 82 MIPS_INT_MASK_0, /* 5: IPL_BIO */ 83 84 MIPS_SOFT_INT_MASK_0| 85 MIPS_SOFT_INT_MASK_1| 86 MIPS_INT_MASK_0, /* 6: IPL_NET */ 87 88 MIPS_SOFT_INT_MASK_0| 89 MIPS_SOFT_INT_MASK_1| 90 MIPS_INT_MASK_0, /* 7: IPL_{TTY,SERIAL} */ 91 92 MIPS_SOFT_INT_MASK_0| 93 MIPS_SOFT_INT_MASK_1| 94 MIPS_INT_MASK_0| 95 MIPS_INT_MASK_1| 96 MIPS_INT_MASK_2| 97 MIPS_INT_MASK_3| 98 MIPS_INT_MASK_4| 99 MIPS_INT_MASK_5, /* 8: IPL_{CLOCK,HIGH} */ 100 }; 101 102 /* 103 * This is a mask of bits to clear in the SR when we go to a 104 * given software interrupt priority level. 105 * Hardware ipls are port/board specific. 106 */ 107 const uint32_t mips_ipl_si_to_sr[_IPL_NSOFT] = { 108 MIPS_SOFT_INT_MASK_0, /* IPL_SOFT */ 109 MIPS_SOFT_INT_MASK_0, /* IPL_SOFTCLOCK */ 110 MIPS_SOFT_INT_MASK_1, /* IPL_SOFTNET */ 111 MIPS_SOFT_INT_MASK_1, /* IPL_SOFTSERIAL */ 112 }; 113 114 struct malta_cpuintr { 115 LIST_HEAD(, evbmips_intrhand) cintr_list; 116 struct evcnt cintr_count; 117 }; 118 #define NINTRS 5 /* MIPS INT0 - INT4 */ 119 120 struct malta_cpuintr malta_cpuintrs[NINTRS]; 121 const char *malta_cpuintrnames[NINTRS] = { 122 "int 0 (piix4)", 123 "int 1 (smi)", 124 "int 2 (uart)", 125 "int 3 (core hi/gt64120)", 126 "int 4 (core lo)", 127 }; 128 129 static int malta_pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 130 static const char 131 *malta_pci_intr_string(void *, pci_intr_handle_t); 132 static const struct evcnt 133 *malta_pci_intr_evcnt(void *, pci_intr_handle_t); 134 static void *malta_pci_intr_establish(void *, pci_intr_handle_t, int, 135 int (*)(void *), void *); 136 static void malta_pci_intr_disestablish(void *, void *); 137 static void malta_pci_conf_interrupt(void *, int, int, int, int, int *); 138 static void *malta_pciide_compat_intr_establish(void *, struct device *, 139 struct pci_attach_args *, int, int (*)(void *), void *); 140 141 void 142 evbmips_intr_init(void) 143 { 144 struct malta_config *mcp = &malta_configuration; 145 int i; 146 147 for (i = 0; i < NINTRS; i++) { 148 LIST_INIT(&malta_cpuintrs[i].cintr_list); 149 evcnt_attach_dynamic(&malta_cpuintrs[i].cintr_count, 150 EVCNT_TYPE_INTR, NULL, "mips", malta_cpuintrnames[i]); 151 } 152 153 mcp->mc_pc.pc_intr_v = NULL; 154 mcp->mc_pc.pc_intr_map = malta_pci_intr_map; 155 mcp->mc_pc.pc_intr_string = malta_pci_intr_string; 156 mcp->mc_pc.pc_intr_evcnt = malta_pci_intr_evcnt; 157 mcp->mc_pc.pc_intr_establish = malta_pci_intr_establish; 158 mcp->mc_pc.pc_intr_disestablish = malta_pci_intr_disestablish; 159 mcp->mc_pc.pc_conf_interrupt = malta_pci_conf_interrupt; 160 mcp->mc_pc.pc_pciide_compat_intr_establish = 161 malta_pciide_compat_intr_establish; 162 } 163 164 void 165 malta_cal_timer(bus_space_tag_t st, bus_space_handle_t sh) 166 { 167 uint32_t ctrdiff[4], startctr, endctr; 168 uint8_t regc; 169 int i; 170 171 /* Disable interrupts first. */ 172 bus_space_write_1(st, sh, 0, MC_REGB); 173 bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY | 174 MC_REGB_24HR); 175 176 /* Initialize for 16Hz. */ 177 bus_space_write_1(st, sh, 0, MC_REGA); 178 bus_space_write_1(st, sh, 1, MC_BASE_32_KHz | MC_RATE_16_Hz); 179 180 /* Run the loop an extra time to prime the cache. */ 181 for (i = 0; i < 4; i++) { 182 // led_display('h', 'z', '0' + i, ' '); 183 184 /* Enable the interrupt. */ 185 bus_space_write_1(st, sh, 0, MC_REGB); 186 bus_space_write_1(st, sh, 1, MC_REGB_PIE | MC_REGB_SQWE | 187 MC_REGB_BINARY | MC_REGB_24HR); 188 189 /* Go to REGC. */ 190 bus_space_write_1(st, sh, 0, MC_REGC); 191 192 /* Wait for it to happen. */ 193 startctr = mips3_cp0_count_read(); 194 do { 195 regc = bus_space_read_1(st, sh, 1); 196 endctr = mips3_cp0_count_read(); 197 } while ((regc & MC_REGC_IRQF) == 0); 198 199 /* Already ACK'd. */ 200 201 /* Disable. */ 202 bus_space_write_1(st, sh, 0, MC_REGB); 203 bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY | 204 MC_REGB_24HR); 205 206 ctrdiff[i] = endctr - startctr; 207 } 208 209 /* Compute the number of cycles per second. */ 210 curcpu()->ci_cpu_freq = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16/*Hz*/; 211 212 /* Compute the number of ticks for hz. */ 213 curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz; 214 215 /* Compute the delay divisor and reciprical. */ 216 curcpu()->ci_divisor_delay = 217 ((curcpu()->ci_cpu_freq + 500000) / 1000000); 218 MIPS_SET_CI_RECIPRICAL(curcpu()); 219 220 /* 221 * Get correct cpu frequency if the CPU runs at twice the 222 * external/cp0-count frequency. 223 */ 224 if (mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT) 225 curcpu()->ci_cpu_freq *= 2; 226 227 #ifdef DEBUG 228 printf("Timer calibration: %lu cycles/sec [(%u, %u) * 16]\n", 229 curcpu()->ci_cpu_freq, ctrdiff[2], ctrdiff[3]); 230 #endif 231 } 232 233 void * 234 evbmips_intr_establish(int irq, int (*func)(void *), void *arg) 235 { 236 struct evbmips_intrhand *ih; 237 int s; 238 239 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 240 if (ih == NULL) 241 return (NULL); 242 243 ih->ih_func = func; 244 ih->ih_arg = arg; 245 246 s = splhigh(); 247 248 /* 249 * Link it into the tables. 250 */ 251 LIST_INSERT_HEAD(&malta_cpuintrs[0].cintr_list, ih, ih_q); 252 253 /* XXX - should check that MIPS_INT_MASK_0 is set... */ 254 255 splx(s); 256 257 return (ih); 258 } 259 260 void 261 evbmips_intr_disestablish(void *arg) 262 { 263 struct evbmips_intrhand *ih = arg; 264 int s; 265 266 s = splhigh(); 267 268 /* 269 * First, remove it from the table. 270 */ 271 LIST_REMOVE(ih, ih_q); 272 273 /* XXX - disable MIPS_INT_MASK_0 if list is empty? */ 274 275 splx(s); 276 277 free(ih, M_DEVBUF); 278 } 279 280 void 281 evbmips_iointr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending) 282 { 283 struct evbmips_intrhand *ih; 284 285 /* Check for error interrupts (SMI, GT64120) */ 286 if (ipending & (MIPS_INT_MASK_1 | MIPS_INT_MASK_3)) { 287 if (ipending & MIPS_INT_MASK_1) 288 panic("piix4 SMI interrupt"); 289 if (ipending & MIPS_INT_MASK_3) 290 panic("gt64120 error interrupt"); 291 } 292 293 /* 294 * Read the interrupt pending registers, mask them with the 295 * ones we have enabled, and service them in order of decreasing 296 * priority. 297 */ 298 if (ipending & MIPS_INT_MASK_0) { 299 /* All interrupts are gated through MIPS HW interrupt 0 */ 300 malta_cpuintrs[0].cintr_count.ev_count++; 301 LIST_FOREACH(ih, &malta_cpuintrs[0].cintr_list, ih_q) 302 (*ih->ih_func)(ih->ih_arg); 303 cause &= ~MIPS_INT_MASK_0; 304 } 305 306 /* Re-enable anything that we have processed. */ 307 _splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK)); 308 } 309 310 /* 311 * YAMON configures pa_intrline correctly (so far), so we trust it to DTRT 312 * in the future... 313 */ 314 #undef YAMON_IRQ_MAP_BAD 315 316 /* 317 * PCI interrupt support 318 */ 319 static int 320 malta_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 321 { 322 #ifdef YAMON_IRQ_MAP_BAD 323 static const int pciirqmap[12/*device*/][4/*pin*/] = { 324 { -1, -1, -1, 11 }, /* 10: USB */ 325 { 10, -1, -1, -1 }, /* 11: Ethernet */ 326 { 11, -1, -1, -1 }, /* 12: Audio */ 327 { -1, -1, -1, -1 }, /* 13: not used */ 328 { -1, -1, -1, -1 }, /* 14: not used */ 329 { -1, -1, -1, -1 }, /* 15: not used */ 330 { -1, -1, -1, -1 }, /* 16: not used */ 331 { -1, -1, -1, -1 }, /* 17: Core card(?) */ 332 { 10, 10, 11, 11 }, /* 18: PCI Slot 1 */ 333 { 10, 11, 11, 10 }, /* 19: PCI Slot 2 */ 334 { 11, 11, 10, 10 }, /* 20: PCI Slot 3 */ 335 { 11, 10, 10, 11 }, /* 21: PCI Slot 4 */ 336 }; 337 int buspin, device, irq; 338 #else /* !YAMON_IRQ_MAP_BAD */ 339 int buspin; 340 #endif /* !YAMON_IRQ_MAP_BAD */ 341 342 buspin = pa->pa_intrpin; 343 344 if (buspin == 0) { 345 /* No IRQ used. */ 346 return (1); 347 } 348 349 if (buspin > 4) { 350 printf("malta_pci_intr_map: bad interrupt pin %d\n", buspin); 351 return (1); 352 } 353 354 #ifdef YAMON_IRQ_MAP_BAD 355 pci_decompose_tag(pa->pa_pc, pa->pa_intrtag, NULL, &device, NULL); 356 357 if (device < 10 || device > 21) { 358 printf("malta_pci_intr_map: bad device %d\n", device); 359 return (1); 360 } 361 362 irq = pciirqmap[device - 10][buspin - 1]; 363 if (irq == -1) { 364 printf("malta_pci_intr_map: no mapping for device %d pin %d\n", 365 device, buspin); 366 return (1); 367 } 368 369 *ihp = irq; 370 #else /* !YAMON_IRQ_MAP_BAD */ 371 *ihp = pa->pa_intrline; 372 #endif /* !YAMON_IRQ_MAP_BAD */ 373 return (0); 374 } 375 376 static const char * 377 malta_pci_intr_string(void *v, pci_intr_handle_t irq) 378 { 379 380 return (isa_intr_string(pcib_ic, irq)); 381 } 382 383 static const struct evcnt * 384 malta_pci_intr_evcnt(void *v, pci_intr_handle_t irq) 385 { 386 387 return (isa_intr_evcnt(pcib_ic, irq)); 388 } 389 390 static void * 391 malta_pci_intr_establish(void *v, pci_intr_handle_t irq, int level, 392 int (*func)(void *), void *arg) 393 { 394 395 return (isa_intr_establish(pcib_ic, irq, IST_LEVEL, level, func, arg)); 396 } 397 398 static void 399 malta_pci_intr_disestablish(void *v, void *arg) 400 { 401 402 return (isa_intr_disestablish(pcib_ic, arg)); 403 } 404 405 static void 406 malta_pci_conf_interrupt(void *v, int bus, int dev, int func, int swiz, 407 int *iline) 408 { 409 410 /* 411 * We actually don't need to do anything; everything is handled 412 * in pci_intr_map(). 413 */ 414 *iline = 0; 415 } 416 417 void * 418 malta_pciide_compat_intr_establish(void *v, struct device *dev, 419 struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg) 420 { 421 pci_chipset_tag_t pc = pa->pa_pc; 422 void *cookie; 423 int bus, irq; 424 425 pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL); 426 427 /* 428 * If this isn't PCI bus #0, all bets are off. 429 */ 430 if (bus != 0) 431 return (NULL); 432 433 irq = PCIIDE_COMPAT_IRQ(chan); 434 cookie = isa_intr_establish(pcib_ic, irq, IST_EDGE, IPL_BIO, func, arg); 435 if (cookie == NULL) 436 return (NULL); 437 printf("%s: %s channel interrupting at %s\n", dev->dv_xname, 438 PCIIDE_CHANNEL_NAME(chan), malta_pci_intr_string(v, irq)); 439 return (cookie); 440 } 441