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