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