1 /* $NetBSD: sbus.c,v 1.48 2002/08/25 17:54:58 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1992, 1993 41 * The Regents of the University of California. All rights reserved. 42 * 43 * This software was developed by the Computer Systems Engineering group 44 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 45 * contributed to Berkeley. 46 * 47 * All advertising materials mentioning features or use of this software 48 * must display the following acknowledgement: 49 * This product includes software developed by the University of 50 * California, Lawrence Berkeley Laboratory. 51 * 52 * Redistribution and use in source and binary forms, with or without 53 * modification, are permitted provided that the following conditions 54 * are met: 55 * 1. Redistributions of source code must retain the above copyright 56 * notice, this list of conditions and the following disclaimer. 57 * 2. Redistributions in binary form must reproduce the above copyright 58 * notice, this list of conditions and the following disclaimer in the 59 * documentation and/or other materials provided with the distribution. 60 * 3. All advertising materials mentioning features or use of this software 61 * must display the following acknowledgement: 62 * This product includes software developed by the University of 63 * California, Berkeley and its contributors. 64 * 4. Neither the name of the University nor the names of its contributors 65 * may be used to endorse or promote products derived from this software 66 * without specific prior written permission. 67 * 68 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 69 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 70 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 71 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 72 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 73 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 74 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 75 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 76 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 77 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 78 * SUCH DAMAGE. 79 * 80 * @(#)sbus.c 8.1 (Berkeley) 6/11/93 81 */ 82 83 /* 84 * Sbus stuff. 85 */ 86 87 #include <sys/param.h> 88 #include <sys/malloc.h> 89 #include <sys/kernel.h> 90 #include <sys/systm.h> 91 #include <sys/device.h> 92 93 #include <uvm/uvm_extern.h> 94 95 #include <machine/autoconf.h> 96 #include <machine/bus.h> 97 #include <sparc/dev/sbusreg.h> 98 #include <dev/sbus/sbusvar.h> 99 #include <dev/sbus/xboxvar.h> 100 101 #include <sparc/sparc/iommuvar.h> 102 103 void sbusreset __P((int)); 104 105 static bus_space_tag_t sbus_alloc_bustag __P((struct sbus_softc *)); 106 static int sbus_get_intr __P((struct sbus_softc *, int, 107 struct openprom_intr **, int *)); 108 static void *sbus_intr_establish __P(( 109 bus_space_tag_t, 110 int, /*Sbus interrupt level*/ 111 int, /*`device class' priority*/ 112 int, /*flags*/ 113 int (*) __P((void *)), /*handler*/ 114 void *)); /*handler arg*/ 115 116 117 /* autoconfiguration driver */ 118 int sbus_match_mainbus __P((struct device *, struct cfdata *, void *)); 119 int sbus_match_iommu __P((struct device *, struct cfdata *, void *)); 120 int sbus_match_xbox __P((struct device *, struct cfdata *, void *)); 121 void sbus_attach_mainbus __P((struct device *, struct device *, void *)); 122 void sbus_attach_iommu __P((struct device *, struct device *, void *)); 123 void sbus_attach_xbox __P((struct device *, struct device *, void *)); 124 125 static int sbus_error __P((void)); 126 int (*sbuserr_handler) __P((void)); 127 128 struct cfattach sbus_mainbus_ca = { 129 sizeof(struct sbus_softc), sbus_match_mainbus, sbus_attach_mainbus 130 }; 131 struct cfattach sbus_iommu_ca = { 132 sizeof(struct sbus_softc), sbus_match_iommu, sbus_attach_iommu 133 }; 134 struct cfattach sbus_xbox_ca = { 135 sizeof(struct sbus_softc), sbus_match_xbox, sbus_attach_xbox 136 }; 137 138 extern struct cfdriver sbus_cd; 139 140 /* The "primary" Sbus */ 141 struct sbus_softc *sbus_sc; 142 143 /* If the PROM does not provide the `ranges' property, we make up our own */ 144 struct openprom_range sbus_translations[] = { 145 /* Assume a maximum of 4 Sbus slots, all mapped to on-board io space */ 146 { 0, 0, PMAP_OBIO, SBUS_ADDR(0,0), 1 << 25 }, 147 { 1, 0, PMAP_OBIO, SBUS_ADDR(1,0), 1 << 25 }, 148 { 2, 0, PMAP_OBIO, SBUS_ADDR(2,0), 1 << 25 }, 149 { 3, 0, PMAP_OBIO, SBUS_ADDR(3,0), 1 << 25 } 150 }; 151 152 /* 153 * Child devices receive the Sbus interrupt level in their attach 154 * arguments. We translate these to CPU IPLs using the following 155 * tables. Note: obio bus interrupt levels are identical to the 156 * processor IPL. 157 * 158 * The second set of tables is used when the Sbus interrupt level 159 * cannot be had from the PROM as an `interrupt' property. We then 160 * fall back on the `intr' property which contains the CPU IPL. 161 */ 162 163 /* Translate Sbus interrupt level to processor IPL */ 164 static int intr_sbus2ipl_4c[] = { 165 0, 1, 2, 3, 5, 7, 8, 9 166 }; 167 static int intr_sbus2ipl_4m[] = { 168 0, 2, 3, 5, 7, 9, 11, 13 169 }; 170 171 /* 172 * This value is or'ed into the attach args' interrupt level cookie 173 * if the interrupt level comes from an `intr' property, i.e. it is 174 * not an Sbus interrupt level. 175 */ 176 #define SBUS_INTR_COMPAT 0x80000000 177 178 179 /* 180 * Print the location of some sbus-attached device (called just 181 * before attaching that device). If `sbus' is not NULL, the 182 * device was found but not configured; print the sbus as well. 183 * Return UNCONF (config_find ignores this if the device was configured). 184 */ 185 int 186 sbus_print(args, busname) 187 void *args; 188 const char *busname; 189 { 190 struct sbus_attach_args *sa = args; 191 int i; 192 193 if (busname) 194 printf("%s at %s", sa->sa_name, busname); 195 printf(" slot %d offset 0x%x", sa->sa_slot, sa->sa_offset); 196 for (i = 0; i < sa->sa_nintr; i++) { 197 u_int32_t level = sa->sa_intr[i].oi_pri; 198 struct sbus_softc *sc = 199 (struct sbus_softc *) sa->sa_bustag->cookie; 200 201 printf(" level %d", level & ~SBUS_INTR_COMPAT); 202 if ((level & SBUS_INTR_COMPAT) == 0) { 203 int ipl = sc->sc_intr2ipl[level]; 204 if (ipl != level) 205 printf(" (ipl %d)", ipl); 206 } 207 } 208 return (UNCONF); 209 } 210 211 int 212 sbus_match_mainbus(parent, cf, aux) 213 struct device *parent; 214 struct cfdata *cf; 215 void *aux; 216 { 217 struct mainbus_attach_args *ma = aux; 218 219 if (CPU_ISSUN4) 220 return (0); 221 222 return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0); 223 } 224 225 int 226 sbus_match_iommu(parent, cf, aux) 227 struct device *parent; 228 struct cfdata *cf; 229 void *aux; 230 { 231 struct iommu_attach_args *ia = aux; 232 233 if (CPU_ISSUN4) 234 return (0); 235 236 return (strcmp(cf->cf_driver->cd_name, ia->iom_name) == 0); 237 } 238 239 int 240 sbus_match_xbox(parent, cf, aux) 241 struct device *parent; 242 struct cfdata *cf; 243 void *aux; 244 { 245 struct xbox_attach_args *xa = aux; 246 247 if (CPU_ISSUN4) 248 return (0); 249 250 return (strcmp(cf->cf_driver->cd_name, xa->xa_name) == 0); 251 } 252 253 /* 254 * Attach an Sbus. 255 */ 256 void 257 sbus_attach_mainbus(parent, self, aux) 258 struct device *parent; 259 struct device *self; 260 void *aux; 261 { 262 struct sbus_softc *sc = (struct sbus_softc *)self; 263 struct mainbus_attach_args *ma = aux; 264 int node = ma->ma_node; 265 266 /* 267 * XXX there is only one Sbus, for now -- do not know how to 268 * address children on others 269 */ 270 if (sc->sc_dev.dv_unit > 0) { 271 printf(" unsupported\n"); 272 return; 273 } 274 275 sc->sc_bustag = ma->ma_bustag; 276 sc->sc_dmatag = ma->ma_dmatag; 277 278 #if 0 /* sbus at mainbus (sun4c): `reg' prop is not control space */ 279 if (ma->ma_size == 0) 280 printf("%s: no Sbus registers", self->dv_xname); 281 282 if (bus_space_map(ma->ma_bustag, 283 ma->ma_paddr, 284 ma->ma_size, 285 BUS_SPACE_MAP_LINEAR, 286 &sc->sc_bh) != 0) { 287 panic("%s: can't map sbusbusreg", self->dv_xname); 288 } 289 #endif 290 291 /* Setup interrupt translation tables */ 292 sc->sc_intr2ipl = CPU_ISSUN4C 293 ? intr_sbus2ipl_4c 294 : intr_sbus2ipl_4m; 295 296 /* 297 * Record clock frequency for synchronous SCSI. 298 * IS THIS THE CORRECT DEFAULT?? 299 */ 300 sc->sc_clockfreq = PROM_getpropint(node, "clock-frequency", 25*1000*1000); 301 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); 302 303 sbus_sc = sc; 304 sbus_attach_common(sc, "sbus", node, NULL); 305 } 306 307 308 void 309 sbus_attach_iommu(parent, self, aux) 310 struct device *parent; 311 struct device *self; 312 void *aux; 313 { 314 struct sbus_softc *sc = (struct sbus_softc *)self; 315 struct iommu_attach_args *ia = aux; 316 int node = ia->iom_node; 317 318 sc->sc_bustag = ia->iom_bustag; 319 sc->sc_dmatag = ia->iom_dmatag; 320 321 if (ia->iom_nreg == 0) 322 panic("%s: no Sbus registers", self->dv_xname); 323 324 if (bus_space_map(ia->iom_bustag, 325 BUS_ADDR(ia->iom_reg[0].oa_space, 326 ia->iom_reg[0].oa_base), 327 (bus_size_t)ia->iom_reg[0].oa_size, 328 BUS_SPACE_MAP_LINEAR, 329 &sc->sc_bh) != 0) { 330 panic("%s: can't map sbusbusreg", self->dv_xname); 331 } 332 333 /* Setup interrupt translation tables */ 334 sc->sc_intr2ipl = CPU_ISSUN4C ? intr_sbus2ipl_4c : intr_sbus2ipl_4m; 335 336 /* 337 * Record clock frequency for synchronous SCSI. 338 * IS THIS THE CORRECT DEFAULT?? 339 */ 340 sc->sc_clockfreq = PROM_getpropint(node, "clock-frequency", 25*1000*1000); 341 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); 342 343 sbus_sc = sc; 344 sbuserr_handler = sbus_error; 345 sbus_attach_common(sc, "sbus", node, NULL); 346 } 347 348 void 349 sbus_attach_xbox(parent, self, aux) 350 struct device *parent; 351 struct device *self; 352 void *aux; 353 { 354 struct sbus_softc *sc = (struct sbus_softc *)self; 355 struct xbox_attach_args *xa = aux; 356 int node = xa->xa_node; 357 358 sc->sc_bustag = xa->xa_bustag; 359 sc->sc_dmatag = xa->xa_dmatag; 360 361 /* Setup interrupt translation tables */ 362 sc->sc_intr2ipl = CPU_ISSUN4C ? intr_sbus2ipl_4c : intr_sbus2ipl_4m; 363 364 /* 365 * Record clock frequency for synchronous SCSI. 366 * IS THIS THE CORRECT DEFAULT?? 367 */ 368 sc->sc_clockfreq = PROM_getpropint(node, "clock-frequency", 25*1000*1000); 369 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); 370 371 sbus_attach_common(sc, "sbus", node, NULL); 372 } 373 374 void 375 sbus_attach_common(sc, busname, busnode, specials) 376 struct sbus_softc *sc; 377 char *busname; 378 int busnode; 379 const char * const *specials; 380 { 381 int node0, node, error; 382 const char *sp; 383 const char *const *ssp; 384 bus_space_tag_t sbt; 385 struct sbus_attach_args sa; 386 387 sbt = sbus_alloc_bustag(sc); 388 389 /* 390 * Get the SBus burst transfer size if burst transfers are supported 391 */ 392 sc->sc_burst = PROM_getpropint(busnode, "burst-sizes", 0); 393 394 395 if (CPU_ISSUN4M) { 396 /* 397 * Some models (e.g. SS20) erroneously report 64-bit 398 * burst capability. We mask it out here for all SUN4Ms, 399 * since probably no member of that class supports 400 * 64-bit Sbus bursts. 401 */ 402 sc->sc_burst &= ~SBUS_BURST_64; 403 } 404 405 /* 406 * Collect address translations from the OBP. 407 */ 408 error = PROM_getprop(busnode, "ranges", sizeof(struct rom_range), 409 &sbt->nranges, (void **) &sbt->ranges); 410 switch (error) { 411 case 0: 412 break; 413 case ENOENT: 414 /* Fall back to our own `range' construction */ 415 sbt->ranges = sbus_translations; 416 sbt->nranges = 417 sizeof(sbus_translations)/sizeof(sbus_translations[0]); 418 break; 419 default: 420 panic("%s: error getting ranges property", sc->sc_dev.dv_xname); 421 } 422 423 /* 424 * Loop through ROM children, fixing any relative addresses 425 * and then configuring each device. 426 * `specials' is an array of device names that are treated 427 * specially: 428 */ 429 node0 = firstchild(busnode); 430 for (ssp = specials ; ssp != NULL && *(sp = *ssp) != 0; ssp++) { 431 if ((node = findnode(node0, sp)) == 0) { 432 panic("could not find %s amongst %s devices", 433 sp, busname); 434 } 435 436 if (sbus_setup_attach_args(sc, sbt, sc->sc_dmatag, 437 node, &sa) != 0) { 438 panic("sbus_attach: %s: incomplete", sp); 439 } 440 (void) config_found(&sc->sc_dev, (void *)&sa, sbus_print); 441 sbus_destroy_attach_args(&sa); 442 } 443 444 for (node = node0; node; node = nextsibling(node)) { 445 char *name = PROM_getpropstring(node, "name"); 446 for (ssp = specials, sp = NULL; 447 ssp != NULL && (sp = *ssp) != NULL; 448 ssp++) 449 if (strcmp(name, sp) == 0) 450 break; 451 452 if (sp != NULL) 453 /* Already configured as an "early" device */ 454 continue; 455 456 if (sbus_setup_attach_args(sc, sbt, sc->sc_dmatag, 457 node, &sa) != 0) { 458 printf("sbus_attach: %s: incomplete\n", name); 459 continue; 460 } 461 (void) config_found(&sc->sc_dev, (void *)&sa, sbus_print); 462 sbus_destroy_attach_args(&sa); 463 } 464 } 465 466 int 467 sbus_setup_attach_args(sc, bustag, dmatag, node, sa) 468 struct sbus_softc *sc; 469 bus_space_tag_t bustag; 470 bus_dma_tag_t dmatag; 471 int node; 472 struct sbus_attach_args *sa; 473 { 474 int n, error; 475 476 bzero(sa, sizeof(struct sbus_attach_args)); 477 error = PROM_getprop(node, "name", 1, &n, (void **)&sa->sa_name); 478 if (error != 0) 479 return (error); 480 sa->sa_name[n] = '\0'; 481 482 sa->sa_bustag = bustag; 483 sa->sa_dmatag = dmatag; 484 sa->sa_node = node; 485 sa->sa_frequency = sc->sc_clockfreq; 486 487 error = PROM_getprop(node, "reg", sizeof(struct openprom_addr), 488 &sa->sa_nreg, (void **)&sa->sa_reg); 489 if (error != 0) { 490 char buf[32]; 491 if (error != ENOENT || 492 !node_has_property(node, "device_type") || 493 strcmp(PROM_getpropstringA(node, "device_type", buf, sizeof buf), 494 "hierarchical") != 0) 495 return (error); 496 } 497 for (n = 0; n < sa->sa_nreg; n++) { 498 /* Convert to relative addressing, if necessary */ 499 u_int32_t base = sa->sa_reg[n].oa_base; 500 if (SBUS_ABS(base)) { 501 sa->sa_reg[n].oa_space = SBUS_ABS_TO_SLOT(base); 502 sa->sa_reg[n].oa_base = SBUS_ABS_TO_OFFSET(base); 503 } 504 } 505 506 if ((error = sbus_get_intr(sc, node, &sa->sa_intr, &sa->sa_nintr)) != 0) 507 return (error); 508 509 error = PROM_getprop(node, "address", sizeof(u_int32_t), 510 &sa->sa_npromvaddrs, (void **)&sa->sa_promvaddrs); 511 if (error != 0 && error != ENOENT) 512 return (error); 513 514 return (0); 515 } 516 517 void 518 sbus_destroy_attach_args(sa) 519 struct sbus_attach_args *sa; 520 { 521 if (sa->sa_name != NULL) 522 free(sa->sa_name, M_DEVBUF); 523 524 if (sa->sa_nreg != 0) 525 free(sa->sa_reg, M_DEVBUF); 526 527 if (sa->sa_intr) 528 free(sa->sa_intr, M_DEVBUF); 529 530 if (sa->sa_promvaddrs) 531 free(sa->sa_promvaddrs, M_DEVBUF); 532 533 bzero(sa, sizeof(struct sbus_attach_args));/*DEBUG*/ 534 } 535 536 bus_addr_t 537 sbus_bus_addr(t, btype, offset) 538 bus_space_tag_t t; 539 u_int btype; 540 u_int offset; 541 { 542 543 /* XXX: sbus_bus_addr should be g/c'ed */ 544 return (BUS_ADDR(btype, offset)); 545 } 546 547 548 /* 549 * Each attached device calls sbus_establish after it initializes 550 * its sbusdev portion. 551 */ 552 void 553 sbus_establish(sd, dev) 554 register struct sbusdev *sd; 555 register struct device *dev; 556 { 557 register struct sbus_softc *sc; 558 register struct device *curdev; 559 560 /* 561 * We have to look for the sbus by name, since it is not necessarily 562 * our immediate parent (i.e. sun4m /iommu/sbus/espdma/esp) 563 * We don't just use the device structure of the above-attached 564 * sbus, since we might (in the future) support multiple sbus's. 565 */ 566 for (curdev = dev->dv_parent; ; curdev = curdev->dv_parent) { 567 if (!curdev || !curdev->dv_xname) 568 panic("sbus_establish: can't find sbus parent for %s", 569 sd->sd_dev->dv_xname 570 ? sd->sd_dev->dv_xname 571 : "<unknown>" ); 572 573 if (strncmp(curdev->dv_xname, "sbus", 4) == 0) 574 break; 575 } 576 sc = (struct sbus_softc *) curdev; 577 578 sd->sd_dev = dev; 579 sd->sd_bchain = sc->sc_sbdev; 580 sc->sc_sbdev = sd; 581 } 582 583 /* 584 * Reset the given sbus. (???) 585 */ 586 void 587 sbusreset(sbus) 588 int sbus; 589 { 590 register struct sbusdev *sd; 591 struct sbus_softc *sc = sbus_cd.cd_devs[sbus]; 592 struct device *dev; 593 594 printf("reset %s:", sc->sc_dev.dv_xname); 595 for (sd = sc->sc_sbdev; sd != NULL; sd = sd->sd_bchain) { 596 if (sd->sd_reset) { 597 dev = sd->sd_dev; 598 (*sd->sd_reset)(dev); 599 printf(" %s", dev->dv_xname); 600 } 601 } 602 } 603 604 605 /* 606 * Get interrupt attributes for an Sbus device. 607 */ 608 int 609 sbus_get_intr(sc, node, ipp, np) 610 struct sbus_softc *sc; 611 int node; 612 struct openprom_intr **ipp; 613 int *np; 614 { 615 int error, n; 616 u_int32_t *ipl = NULL; 617 618 /* 619 * The `interrupts' property contains the Sbus interrupt level. 620 */ 621 if (PROM_getprop(node, "interrupts", sizeof(int), np, 622 (void **)&ipl) == 0) { 623 /* Change format to an `struct openprom_intr' array */ 624 struct openprom_intr *ip; 625 ip = malloc(*np * sizeof(struct openprom_intr), M_DEVBUF, 626 M_NOWAIT); 627 if (ip == NULL) { 628 free(ipl, M_DEVBUF); 629 return (ENOMEM); 630 } 631 for (n = 0; n < *np; n++) { 632 ip[n].oi_pri = ipl[n]; 633 ip[n].oi_vec = 0; 634 } 635 free(ipl, M_DEVBUF); 636 *ipp = ip; 637 return (0); 638 } 639 640 /* 641 * Fall back on `intr' property. 642 */ 643 *ipp = NULL; 644 error = PROM_getprop(node, "intr", sizeof(struct openprom_intr), 645 np, (void **)ipp); 646 switch (error) { 647 case 0: 648 for (n = *np; n-- > 0;) { 649 (*ipp)[n].oi_pri &= 0xf; 650 (*ipp)[n].oi_pri |= SBUS_INTR_COMPAT; 651 } 652 break; 653 case ENOENT: 654 error = 0; 655 break; 656 } 657 658 return (error); 659 } 660 661 662 /* 663 * Install an interrupt handler for an Sbus device. 664 */ 665 void * 666 sbus_intr_establish(t, pri, level, flags, handler, arg) 667 bus_space_tag_t t; 668 int pri; 669 int level; 670 int flags; 671 int (*handler) __P((void *)); 672 void *arg; 673 { 674 struct sbus_softc *sc = t->cookie; 675 struct intrhand *ih; 676 int pil; 677 678 ih = (struct intrhand *) 679 malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT); 680 if (ih == NULL) 681 return (NULL); 682 683 /* 684 * Translate Sbus interrupt priority to CPU interrupt level 685 */ 686 if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) != 0) 687 pil = pri; 688 else if ((pri & SBUS_INTR_COMPAT) != 0) 689 pil = pri & ~SBUS_INTR_COMPAT; 690 else 691 pil = sc->sc_intr2ipl[pri]; 692 693 ih->ih_fun = handler; 694 ih->ih_arg = arg; 695 if ((flags & BUS_INTR_ESTABLISH_FASTTRAP) != 0) 696 intr_fasttrap(pil, (void (*)__P((void)))handler); 697 else 698 intr_establish(pil, ih); 699 return (ih); 700 } 701 702 static bus_space_tag_t 703 sbus_alloc_bustag(sc) 704 struct sbus_softc *sc; 705 { 706 bus_space_tag_t sbt; 707 708 sbt = (bus_space_tag_t) 709 malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT); 710 if (sbt == NULL) 711 return (NULL); 712 713 bzero(sbt, sizeof *sbt); 714 sbt->cookie = sc; 715 sbt->parent = sc->sc_bustag; 716 sbt->sparc_bus_map = sc->sc_bustag->sparc_bus_map; 717 sbt->sparc_bus_mmap = sc->sc_bustag->sparc_bus_mmap; 718 sbt->sparc_intr_establish = sbus_intr_establish; 719 return (sbt); 720 } 721 722 int 723 sbus_error() 724 { 725 struct sbus_softc *sc = sbus_sc; 726 bus_space_handle_t bh = sc->sc_bh; 727 u_int32_t afsr, afva; 728 char bits[64]; 729 static int straytime, nstray; 730 int timesince; 731 732 afsr = bus_space_read_4(sc->sc_bustag, bh, SBUS_AFSR_REG); 733 afva = bus_space_read_4(sc->sc_bustag, bh, SBUS_AFAR_REG); 734 printf("sbus error:\n\tAFSR %s\n", 735 bitmask_snprintf(afsr, SBUS_AFSR_BITS, bits, sizeof(bits))); 736 printf("\taddress: 0x%x%x\n", afsr & SBUS_AFSR_PAH, afva); 737 738 /* For now, do the same dance as on stray interrupts */ 739 timesince = time.tv_sec - straytime; 740 if (timesince <= 10) { 741 if (++nstray > 9) 742 panic("too many SBus errors"); 743 } else { 744 straytime = time.tv_sec; 745 nstray = 1; 746 } 747 748 /* Unlock registers and clear interrupt */ 749 bus_space_write_4(sc->sc_bustag, bh, SBUS_AFSR_REG, afsr); 750 751 return (0); 752 } 753