1 /* $OpenBSD: sbus.c,v 1.10 2002/02/05 18:34:39 jason Exp $ */ 2 /* $NetBSD: sbus.c,v 1.46 2001/10/07 20:30:41 eeh Exp $ */ 3 4 /*- 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Paul Kranenburg. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Copyright (c) 1992, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * This software was developed by the Computer Systems Engineering group 45 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 46 * contributed to Berkeley. 47 * 48 * All advertising materials mentioning features or use of this software 49 * must display the following acknowledgement: 50 * This product includes software developed by the University of 51 * California, Lawrence Berkeley Laboratory. 52 * 53 * Redistribution and use in source and binary forms, with or without 54 * modification, are permitted provided that the following conditions 55 * are met: 56 * 1. Redistributions of source code must retain the above copyright 57 * notice, this list of conditions and the following disclaimer. 58 * 2. Redistributions in binary form must reproduce the above copyright 59 * notice, this list of conditions and the following disclaimer in the 60 * documentation and/or other materials provided with the distribution. 61 * 3. All advertising materials mentioning features or use of this software 62 * must display the following acknowledgement: 63 * This product includes software developed by the University of 64 * California, Berkeley and its contributors. 65 * 4. Neither the name of the University nor the names of its contributors 66 * may be used to endorse or promote products derived from this software 67 * without specific prior written permission. 68 * 69 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 70 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 71 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 72 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 73 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 74 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 75 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 76 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 77 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 78 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 79 * SUCH DAMAGE. 80 * 81 * @(#)sbus.c 8.1 (Berkeley) 6/11/93 82 */ 83 84 /* 85 * Copyright (c) 1999 Eduardo Horvath 86 * 87 * Redistribution and use in source and binary forms, with or without 88 * modification, are permitted provided that the following conditions 89 * are met: 90 * 1. Redistributions of source code must retain the above copyright 91 * notice, this list of conditions and the following disclaimer. 92 * 93 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 94 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 95 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 96 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 97 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 98 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 99 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 101 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 102 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 103 * SUCH DAMAGE. 104 * 105 */ 106 107 108 /* 109 * Sbus stuff. 110 */ 111 112 #include <sys/param.h> 113 #include <sys/extent.h> 114 #include <sys/malloc.h> 115 #include <sys/systm.h> 116 #include <sys/device.h> 117 #include <sys/reboot.h> 118 119 #include <machine/bus.h> 120 #include <sparc64/sparc64/cache.h> 121 #include <sparc64/dev/iommureg.h> 122 #include <sparc64/dev/iommuvar.h> 123 #include <sparc64/dev/sbusreg.h> 124 #include <dev/sbus/sbusvar.h> 125 126 #include <uvm/uvm_extern.h> 127 128 #include <machine/autoconf.h> 129 #include <machine/cpu.h> 130 #include <machine/sparc64.h> 131 132 #ifdef DEBUG 133 #define SDB_DVMA 0x1 134 #define SDB_INTR 0x2 135 int sbus_debug = 0; 136 #define DPRINTF(l, s) do { if (sbus_debug & l) printf s; } while (0) 137 #else 138 #define DPRINTF(l, s) 139 #endif 140 141 void sbusreset __P((int)); 142 143 static bus_space_tag_t sbus_alloc_bustag __P((struct sbus_softc *)); 144 static bus_dma_tag_t sbus_alloc_dmatag __P((struct sbus_softc *)); 145 static int sbus_get_intr __P((struct sbus_softc *, int, 146 struct sbus_intr **, int *, int)); 147 int sbus_bus_mmap __P((bus_space_tag_t, bus_type_t, bus_addr_t, 148 int, bus_space_handle_t *)); 149 static int sbus_overtemp __P((void *)); 150 static int _sbus_bus_map __P(( 151 bus_space_tag_t, 152 bus_type_t, 153 bus_addr_t, /*offset*/ 154 bus_size_t, /*size*/ 155 int, /*flags*/ 156 vaddr_t, /*preferred virtual address */ 157 bus_space_handle_t *)); 158 static void *sbus_intr_establish __P(( 159 bus_space_tag_t, 160 int, /*Sbus interrupt level*/ 161 int, /*`device class' priority*/ 162 int, /*flags*/ 163 int (*) __P((void *)), /*handler*/ 164 void *)); /*handler arg*/ 165 166 167 /* autoconfiguration driver */ 168 int sbus_match __P((struct device *, void *, void *)); 169 void sbus_attach __P((struct device *, struct device *, void *)); 170 171 172 struct cfattach sbus_ca = { 173 sizeof(struct sbus_softc), sbus_match, sbus_attach 174 }; 175 176 struct cfdriver sbus_cd = { 177 NULL, "sbus", DV_DULL 178 }; 179 180 extern struct cfdriver sbus_cd; 181 182 /* 183 * DVMA routines 184 */ 185 int sbus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *, 186 bus_size_t, struct proc *, int)); 187 void sbus_dmamap_unload __P((bus_dma_tag_t, bus_dmamap_t)); 188 int sbus_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t, 189 bus_dma_segment_t *, int, bus_size_t, int)); 190 void sbus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, bus_addr_t, 191 bus_size_t, int)); 192 int sbus_dmamem_alloc __P((bus_dma_tag_t tag, bus_size_t size, 193 bus_size_t alignment, bus_size_t boundary, 194 bus_dma_segment_t *segs, int nsegs, int *rsegs, 195 int flags)); 196 void sbus_dmamem_free __P((bus_dma_tag_t tag, bus_dma_segment_t *segs, 197 int nsegs)); 198 int sbus_dmamem_map __P((bus_dma_tag_t tag, bus_dma_segment_t *segs, 199 int nsegs, size_t size, caddr_t *kvap, int flags)); 200 void sbus_dmamem_unmap __P((bus_dma_tag_t tag, caddr_t kva, 201 size_t size)); 202 203 /* 204 * Child devices receive the Sbus interrupt level in their attach 205 * arguments. We translate these to CPU IPLs using the following 206 * tables. Note: obio bus interrupt levels are identical to the 207 * processor IPL. 208 * 209 * The second set of tables is used when the Sbus interrupt level 210 * cannot be had from the PROM as an `interrupt' property. We then 211 * fall back on the `intr' property which contains the CPU IPL. 212 */ 213 214 /* Translate Sbus interrupt level to processor IPL */ 215 static int intr_sbus2ipl_4c[] = { 216 0, 1, 2, 3, 5, 7, 8, 9 217 }; 218 static int intr_sbus2ipl_4m[] = { 219 0, 2, 3, 5, 7, 9, 11, 13 220 }; 221 222 /* 223 * This value is or'ed into the attach args' interrupt level cookie 224 * if the interrupt level comes from an `intr' property, i.e. it is 225 * not an Sbus interrupt level. 226 */ 227 #define SBUS_INTR_COMPAT 0x80000000 228 229 230 /* 231 * Print the location of some sbus-attached device (called just 232 * before attaching that device). If `sbus' is not NULL, the 233 * device was found but not configured; print the sbus as well. 234 * Return UNCONF (config_find ignores this if the device was configured). 235 */ 236 int 237 sbus_print(args, busname) 238 void *args; 239 const char *busname; 240 { 241 struct sbus_attach_args *sa = args; 242 int i; 243 244 if (busname) 245 printf("%s at %s", sa->sa_name, busname); 246 printf(" slot %ld offset 0x%lx", (long)sa->sa_slot, 247 (u_long)sa->sa_offset); 248 for (i = 0; i < sa->sa_nintr; i++) { 249 struct sbus_intr *sbi = &sa->sa_intr[i]; 250 251 printf(" vector %lx ipl %ld", 252 (u_long)sbi->sbi_vec, 253 (long)INTLEV(sbi->sbi_pri)); 254 } 255 return (UNCONF); 256 } 257 258 int 259 sbus_match(parent, vcf, aux) 260 struct device *parent; 261 void *vcf; 262 void *aux; 263 { 264 struct cfdata *cf = vcf; 265 struct mainbus_attach_args *ma = aux; 266 267 return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0); 268 } 269 270 /* 271 * Attach an Sbus. 272 */ 273 void 274 sbus_attach(parent, self, aux) 275 struct device *parent; 276 struct device *self; 277 void *aux; 278 { 279 struct sbus_softc *sc = (struct sbus_softc *)self; 280 struct mainbus_attach_args *ma = aux; 281 struct intrhand *ih; 282 int ipl; 283 char *name; 284 int node = ma->ma_node; 285 286 int node0, error; 287 bus_space_tag_t sbt; 288 struct sbus_attach_args sa; 289 290 sc->sc_bustag = ma->ma_bustag; 291 sc->sc_dmatag = ma->ma_dmatag; 292 sc->sc_sysio = (struct sysioreg*)(u_long)ma->ma_address[0]; /* Use prom mapping for sysio. */ 293 sc->sc_ign = ma->ma_interrupts[0] & INTMAP_IGN; /* Find interrupt group no */ 294 295 /* Setup interrupt translation tables */ 296 sc->sc_intr2ipl = CPU_ISSUN4C 297 ? intr_sbus2ipl_4c 298 : intr_sbus2ipl_4m; 299 300 /* 301 * Record clock frequency for synchronous SCSI. 302 * IS THIS THE CORRECT DEFAULT?? 303 */ 304 sc->sc_clockfreq = getpropint(node, "clock-frequency", 25*1000*1000); 305 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); 306 307 sbt = sbus_alloc_bustag(sc); 308 sc->sc_dmatag = sbus_alloc_dmatag(sc); 309 310 /* 311 * Get the SBus burst transfer size if burst transfers are supported 312 */ 313 sc->sc_burst = getpropint(node, "burst-sizes", 0); 314 315 /* 316 * Collect address translations from the OBP. 317 */ 318 error = getprop(node, "ranges", sizeof(struct sbus_range), 319 &sc->sc_nrange, (void **)&sc->sc_range); 320 if (error) 321 panic("%s: error getting ranges property", sc->sc_dev.dv_xname); 322 323 /* initailise the IOMMU */ 324 325 /* punch in our copies */ 326 sc->sc_is.is_bustag = sc->sc_bustag; 327 sc->sc_is.is_iommu = &sc->sc_sysio->sys_iommu; 328 sc->sc_is.is_sb[0] = &sc->sc_sysio->sys_strbuf; 329 sc->sc_is.is_sb[1] = NULL; 330 331 /* give us a nice name.. */ 332 name = (char *)malloc(32, M_DEVBUF, M_NOWAIT); 333 if (name == 0) 334 panic("couldn't malloc iommu name"); 335 snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname); 336 337 iommu_init(name, &sc->sc_is, 0, -1); 338 339 /* Enable the over temp intr */ 340 ih = (struct intrhand *) 341 malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT); 342 if (ih == NULL) 343 panic("couldn't malloc intrhand"); 344 ih->ih_map = &sc->sc_sysio->therm_int_map; 345 ih->ih_clr = NULL; /* &sc->sc_sysio->therm_clr_int; */ 346 ih->ih_fun = sbus_overtemp; 347 ipl = 1; 348 ih->ih_pil = (1<<ipl); 349 ih->ih_number = INTVEC(*(ih->ih_map)); 350 intr_establish(ipl, ih); 351 *(ih->ih_map) |= INTMAP_V; 352 353 /* 354 * Note: the stupid SBUS IOMMU ignores the high bits of an address, so a 355 * NULL DMA pointer will be translated by the first page of the IOTSB. 356 * To avoid bugs we'll alloc and ignore the first entry in the IOTSB. 357 */ 358 { 359 u_long dummy; 360 361 if (extent_alloc_subregion(sc->sc_is.is_dvmamap, 362 sc->sc_is.is_dvmabase, sc->sc_is.is_dvmabase + NBPG, 363 NBPG, NBPG, 0, 0, EX_NOWAIT|EX_BOUNDZERO, 364 (u_long *)&dummy) != 0) 365 panic("sbus iommu: can't toss first dvma page"); 366 } 367 368 /* 369 * Loop through ROM children, fixing any relative addresses 370 * and then configuring each device. 371 * `specials' is an array of device names that are treated 372 * specially: 373 */ 374 node0 = firstchild(node); 375 for (node = node0; node; node = nextsibling(node)) { 376 char *name = getpropstring(node, "name"); 377 378 if (sbus_setup_attach_args(sc, sbt, sc->sc_dmatag, 379 node, &sa) != 0) { 380 printf("sbus_attach: %s: incomplete\n", name); 381 continue; 382 } 383 (void) config_found(&sc->sc_dev, (void *)&sa, sbus_print); 384 sbus_destroy_attach_args(&sa); 385 } 386 } 387 388 int 389 sbus_setup_attach_args(sc, bustag, dmatag, node, sa) 390 struct sbus_softc *sc; 391 bus_space_tag_t bustag; 392 bus_dma_tag_t dmatag; 393 int node; 394 struct sbus_attach_args *sa; 395 { 396 /*struct sbus_reg sbusreg;*/ 397 /*int base;*/ 398 int error; 399 int n; 400 401 bzero(sa, sizeof(struct sbus_attach_args)); 402 error = getprop(node, "name", 1, &n, (void **)&sa->sa_name); 403 if (error != 0) 404 return (error); 405 sa->sa_name[n] = '\0'; 406 407 sa->sa_bustag = bustag; 408 sa->sa_dmatag = dmatag; 409 sa->sa_node = node; 410 sa->sa_frequency = sc->sc_clockfreq; 411 412 error = getprop(node, "reg", sizeof(struct sbus_reg), 413 &sa->sa_nreg, (void **)&sa->sa_reg); 414 if (error != 0) { 415 char buf[32]; 416 if (error != ENOENT || 417 !node_has_property(node, "device_type") || 418 strcmp(getpropstringA(node, "device_type", buf), 419 "hierarchical") != 0) 420 return (error); 421 } 422 for (n = 0; n < sa->sa_nreg; n++) { 423 /* Convert to relative addressing, if necessary */ 424 u_int32_t base = sa->sa_reg[n].sbr_offset; 425 if (SBUS_ABS(base)) { 426 sa->sa_reg[n].sbr_slot = SBUS_ABS_TO_SLOT(base); 427 sa->sa_reg[n].sbr_offset = SBUS_ABS_TO_OFFSET(base); 428 } 429 } 430 431 if ((error = sbus_get_intr(sc, node, &sa->sa_intr, &sa->sa_nintr, 432 sa->sa_slot)) != 0) 433 return (error); 434 435 error = getprop(node, "address", sizeof(u_int32_t), 436 &sa->sa_npromvaddrs, (void **)&sa->sa_promvaddrs); 437 if (error != 0 && error != ENOENT) 438 return (error); 439 440 return (0); 441 } 442 443 void 444 sbus_destroy_attach_args(sa) 445 struct sbus_attach_args *sa; 446 { 447 if (sa->sa_name != NULL) 448 free(sa->sa_name, M_DEVBUF); 449 450 if (sa->sa_nreg != 0) 451 free(sa->sa_reg, M_DEVBUF); 452 453 if (sa->sa_intr) 454 free(sa->sa_intr, M_DEVBUF); 455 456 if (sa->sa_promvaddrs) 457 free((void *)sa->sa_promvaddrs, M_DEVBUF); 458 459 bzero(sa, sizeof(struct sbus_attach_args)); /*DEBUG*/ 460 } 461 462 463 int 464 _sbus_bus_map(t, btype, offset, size, flags, vaddr, hp) 465 bus_space_tag_t t; 466 bus_type_t btype; 467 bus_addr_t offset; 468 bus_size_t size; 469 int flags; 470 vaddr_t vaddr; 471 bus_space_handle_t *hp; 472 { 473 struct sbus_softc *sc = t->cookie; 474 int64_t slot = btype; 475 int i; 476 477 for (i = 0; i < sc->sc_nrange; i++) { 478 bus_addr_t paddr; 479 480 if (sc->sc_range[i].cspace != slot) 481 continue; 482 483 /* We've found the connection to the parent bus */ 484 paddr = sc->sc_range[i].poffset + offset; 485 paddr |= ((bus_addr_t)sc->sc_range[i].pspace<<32); 486 DPRINTF(SDB_DVMA, 487 ("\n_sbus_bus_map: mapping paddr slot %lx offset %lx poffset %lx paddr %lx\n", 488 (long)slot, (long)offset, (long)sc->sc_range[i].poffset, 489 (long)paddr)); 490 return (bus_space_map2(sc->sc_bustag, 0, paddr, 491 size, flags, vaddr, hp)); 492 } 493 494 return (EINVAL); 495 } 496 497 int 498 sbus_bus_mmap(t, btype, paddr, flags, hp) 499 bus_space_tag_t t; 500 bus_type_t btype; 501 bus_addr_t paddr; 502 int flags; 503 bus_space_handle_t *hp; 504 { 505 bus_addr_t offset = paddr; 506 int slot = btype; 507 struct sbus_softc *sc = t->cookie; 508 int i; 509 510 for (i = 0; i < sc->sc_nrange; i++) { 511 bus_addr_t paddr; 512 513 if (sc->sc_range[i].cspace != slot) 514 continue; 515 516 paddr = sc->sc_range[i].poffset + offset; 517 paddr |= ((bus_addr_t)sc->sc_range[i].pspace<<32); 518 *hp = bus_space_mmap(sc->sc_bustag, paddr, 0, 519 VM_PROT_READ|VM_PROT_WRITE, flags); 520 } 521 522 return (*hp == -1 ? -1 : 0); 523 } 524 525 bus_addr_t 526 sbus_bus_addr(t, btype, offset) 527 bus_space_tag_t t; 528 u_int btype; 529 u_int offset; 530 { 531 bus_addr_t baddr; 532 int slot = btype; 533 struct sbus_softc *sc = t->cookie; 534 int i; 535 536 for (i = 0; i < sc->sc_nrange; i++) { 537 if (sc->sc_range[i].cspace != slot) 538 continue; 539 540 baddr = sc->sc_range[i].poffset + offset; 541 baddr |= ((bus_addr_t)sc->sc_range[i].pspace<<32); 542 } 543 544 return (baddr); 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 /* Reload iommu regs */ 603 iommu_reset(&sc->sc_is); 604 } 605 606 /* 607 * Handle an overtemp situation. 608 * 609 * SPARCs have temperature sensors which generate interrupts 610 * if the machine's temperature exceeds a certain threshold. 611 * This handles the interrupt and powers off the machine. 612 * The same needs to be done to PCI controller drivers. 613 */ 614 int 615 sbus_overtemp(arg) 616 void *arg; 617 { 618 /* Should try a clean shutdown first */ 619 printf("DANGER: OVER TEMPERATURE detected\nShutting down...\n"); 620 delay(20); 621 boot(RB_POWERDOWN|RB_HALT); 622 /*NOTREACHED*/ 623 return (1); 624 } 625 626 /* 627 * Get interrupt attributes for an Sbus device. 628 */ 629 int 630 sbus_get_intr(sc, node, ipp, np, slot) 631 struct sbus_softc *sc; 632 int node; 633 struct sbus_intr **ipp; 634 int *np; 635 int slot; 636 { 637 int *ipl; 638 int n, i; 639 char buf[32]; 640 641 /* 642 * The `interrupts' property contains the Sbus interrupt level. 643 */ 644 ipl = NULL; 645 if (getprop(node, "interrupts", sizeof(int), np, (void **)&ipl) == 0) { 646 struct sbus_intr *ip; 647 int pri; 648 649 /* Default to interrupt level 2 -- otherwise unused */ 650 pri = INTLEVENCODE(2); 651 652 /* Change format to an `struct sbus_intr' array */ 653 ip = malloc(*np * sizeof(struct sbus_intr), M_DEVBUF, M_NOWAIT); 654 if (ip == NULL) 655 return (ENOMEM); 656 657 /* 658 * Now things get ugly. We need to take this value which is 659 * the interrupt vector number and encode the IPL into it 660 * somehow. Luckily, the interrupt vector has lots of free 661 * space and we can easily stuff the IPL in there for a while. 662 */ 663 getpropstringA(node, "device_type", buf); 664 if (!buf[0]) 665 getpropstringA(node, "name", buf); 666 667 for (i = 0; intrmap[i].in_class; i++) 668 if (strcmp(intrmap[i].in_class, buf) == 0) { 669 pri = INTLEVENCODE(intrmap[i].in_lev); 670 break; 671 } 672 673 /* 674 * Sbus card devices need the slot number encoded into 675 * the vector as this is generally not done. 676 */ 677 if ((ipl[0] & INTMAP_OBIO) == 0) 678 pri |= slot << 3; 679 680 for (n = 0; n < *np; n++) { 681 /* 682 * We encode vector and priority into sbi_pri so we 683 * can pass them as a unit. This will go away if 684 * sbus_establish ever takes an sbus_intr instead 685 * of an integer level. 686 * Stuff the real vector in sbi_vec. 687 */ 688 689 ip[n].sbi_pri = pri|ipl[n]; 690 ip[n].sbi_vec = ipl[n]; 691 } 692 free(ipl, M_DEVBUF); 693 *ipp = ip; 694 } 695 696 return (0); 697 } 698 699 700 /* 701 * Install an interrupt handler for an Sbus device. 702 */ 703 void * 704 sbus_intr_establish(t, pri, level, flags, handler, arg) 705 bus_space_tag_t t; 706 int pri; 707 int level; 708 int flags; 709 int (*handler) __P((void *)); 710 void *arg; 711 { 712 struct sbus_softc *sc = t->cookie; 713 struct intrhand *ih; 714 int ipl; 715 long vec = pri; 716 717 ih = (struct intrhand *) 718 malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT); 719 if (ih == NULL) 720 return (NULL); 721 722 if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) != 0) 723 ipl = vec; 724 else if ((vec & SBUS_INTR_COMPAT) != 0) 725 ipl = vec & ~SBUS_INTR_COMPAT; 726 else { 727 /* Decode and remove IPL */ 728 ipl = INTLEV(vec); 729 vec = INTVEC(vec); 730 DPRINTF(SDB_INTR, 731 ("\nsbus: intr[%ld]%lx: %lx\nHunting for IRQ...\n", 732 (long)ipl, (long)vec, (u_long)intrlev[vec])); 733 if ((vec & INTMAP_OBIO) == 0) { 734 /* We're in an SBUS slot */ 735 /* Register the map and clear intr registers */ 736 737 int slot = INTSLOT(pri); 738 739 ih->ih_map = &(&sc->sc_sysio->sbus_slot0_int)[slot]; 740 ih->ih_clr = &sc->sc_sysio->sbus0_clr_int[vec]; 741 #ifdef DEBUG 742 if (sbus_debug & SDB_INTR) { 743 int64_t intrmap = *ih->ih_map; 744 745 printf("SBUS %lx IRQ as %llx in slot %d\n", 746 (long)vec, (long long)intrmap, slot); 747 printf("\tmap addr %p clr addr %p\n", 748 ih->ih_map, ih->ih_clr); 749 } 750 #endif 751 /* Enable the interrupt */ 752 vec |= INTMAP_V; 753 /* Insert IGN */ 754 vec |= sc->sc_ign; 755 bus_space_write_8(sc->sc_bustag, 756 (bus_space_handle_t)(u_long)ih->ih_map, 0, vec); 757 } else { 758 int64_t *intrptr = &sc->sc_sysio->scsi_int_map; 759 int64_t intrmap = 0; 760 int i; 761 762 /* Insert IGN */ 763 vec |= sc->sc_ign; 764 for (i = 0; &intrptr[i] <= 765 (int64_t *)&sc->sc_sysio->reserved_int_map && 766 INTVEC(intrmap = intrptr[i]) != INTVEC(vec); i++) 767 ; 768 if (INTVEC(intrmap) == INTVEC(vec)) { 769 DPRINTF(SDB_INTR, 770 ("OBIO %lx IRQ as %lx in slot %d\n", 771 vec, (long)intrmap, i)); 772 /* Register the map and clear intr registers */ 773 ih->ih_map = &intrptr[i]; 774 intrptr = (int64_t *)&sc->sc_sysio->scsi_clr_int; 775 ih->ih_clr = &intrptr[i]; 776 /* Enable the interrupt */ 777 intrmap |= INTMAP_V; 778 bus_space_write_8(sc->sc_bustag, 779 (bus_space_handle_t)(u_long)ih->ih_map, 0, 780 (u_long)intrmap); 781 } else 782 panic("IRQ not found!"); 783 } 784 } 785 #ifdef DEBUG 786 if (sbus_debug & SDB_INTR) { long i; for (i = 0; i < 400000000; i++); } 787 #endif 788 789 ih->ih_fun = handler; 790 ih->ih_arg = arg; 791 ih->ih_number = vec; 792 ih->ih_pil = (1<<ipl); 793 intr_establish(ipl, ih); 794 return (ih); 795 } 796 797 static bus_space_tag_t 798 sbus_alloc_bustag(sc) 799 struct sbus_softc *sc; 800 { 801 bus_space_tag_t sbt; 802 803 sbt = (bus_space_tag_t) 804 malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT); 805 if (sbt == NULL) 806 return (NULL); 807 808 bzero(sbt, sizeof *sbt); 809 sbt->cookie = sc; 810 sbt->parent = sc->sc_bustag; 811 sbt->type = SBUS_BUS_SPACE; 812 sbt->sparc_bus_map = _sbus_bus_map; 813 sbt->sparc_bus_mmap = sc->sc_bustag->sparc_bus_mmap; 814 sbt->sparc_intr_establish = sbus_intr_establish; 815 return (sbt); 816 } 817 818 819 static bus_dma_tag_t 820 sbus_alloc_dmatag(sc) 821 struct sbus_softc *sc; 822 { 823 bus_dma_tag_t sdt, psdt = sc->sc_dmatag; 824 825 sdt = (bus_dma_tag_t) 826 malloc(sizeof(struct sparc_bus_dma_tag), M_DEVBUF, M_NOWAIT); 827 if (sdt == NULL) 828 /* Panic? */ 829 return (psdt); 830 831 sdt->_cookie = sc; 832 sdt->_parent = psdt; 833 #define PCOPY(x) sdt->x = psdt->x 834 PCOPY(_dmamap_create); 835 PCOPY(_dmamap_destroy); 836 sdt->_dmamap_load = sbus_dmamap_load; 837 PCOPY(_dmamap_load_mbuf); 838 PCOPY(_dmamap_load_uio); 839 sdt->_dmamap_load_raw = sbus_dmamap_load_raw; 840 sdt->_dmamap_unload = sbus_dmamap_unload; 841 sdt->_dmamap_sync = sbus_dmamap_sync; 842 sdt->_dmamem_alloc = sbus_dmamem_alloc; 843 sdt->_dmamem_free = sbus_dmamem_free; 844 sdt->_dmamem_map = sbus_dmamem_map; 845 sdt->_dmamem_unmap = sbus_dmamem_unmap; 846 PCOPY(_dmamem_mmap); 847 #undef PCOPY 848 sc->sc_dmatag = sdt; 849 return (sdt); 850 } 851 852 int 853 sbus_dmamap_load(tag, map, buf, buflen, p, flags) 854 bus_dma_tag_t tag; 855 bus_dmamap_t map; 856 void *buf; 857 bus_size_t buflen; 858 struct proc *p; 859 int flags; 860 { 861 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 862 863 return (iommu_dvmamap_load(tag, &sc->sc_is, map, buf, buflen, p, flags)); 864 } 865 866 int 867 sbus_dmamap_load_raw(tag, map, segs, nsegs, size, flags) 868 bus_dma_tag_t tag; 869 bus_dmamap_t map; 870 bus_dma_segment_t *segs; 871 int nsegs; 872 bus_size_t size; 873 int flags; 874 { 875 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 876 877 return (iommu_dvmamap_load_raw(tag, &sc->sc_is, map, segs, nsegs, flags, size)); 878 } 879 880 void 881 sbus_dmamap_unload(tag, map) 882 bus_dma_tag_t tag; 883 bus_dmamap_t map; 884 { 885 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 886 887 iommu_dvmamap_unload(tag, &sc->sc_is, map); 888 } 889 890 void 891 sbus_dmamap_sync(tag, map, offset, len, ops) 892 bus_dma_tag_t tag; 893 bus_dmamap_t map; 894 bus_addr_t offset; 895 bus_size_t len; 896 int ops; 897 { 898 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 899 900 if (ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) { 901 /* Flush the CPU then the IOMMU */ 902 bus_dmamap_sync(tag->_parent, map, offset, len, ops); 903 iommu_dvmamap_sync(tag, &sc->sc_is, map, offset, len, ops); 904 } 905 if (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) { 906 /* Flush the IOMMU then the CPU */ 907 iommu_dvmamap_sync(tag, &sc->sc_is, map, offset, len, ops); 908 bus_dmamap_sync(tag->_parent, map, offset, len, ops); 909 } 910 } 911 912 int 913 sbus_dmamem_alloc(tag, size, alignment, boundary, segs, nsegs, rsegs, flags) 914 bus_dma_tag_t tag; 915 bus_size_t size; 916 bus_size_t alignment; 917 bus_size_t boundary; 918 bus_dma_segment_t *segs; 919 int nsegs; 920 int *rsegs; 921 int flags; 922 { 923 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 924 925 return (iommu_dvmamem_alloc(tag, &sc->sc_is, size, alignment, boundary, 926 segs, nsegs, rsegs, flags)); 927 } 928 929 void 930 sbus_dmamem_free(tag, segs, nsegs) 931 bus_dma_tag_t tag; 932 bus_dma_segment_t *segs; 933 int nsegs; 934 { 935 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 936 937 iommu_dvmamem_free(tag, &sc->sc_is, segs, nsegs); 938 } 939 940 int 941 sbus_dmamem_map(tag, segs, nsegs, size, kvap, flags) 942 bus_dma_tag_t tag; 943 bus_dma_segment_t *segs; 944 int nsegs; 945 size_t size; 946 caddr_t *kvap; 947 int flags; 948 { 949 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 950 951 return (iommu_dvmamem_map(tag, &sc->sc_is, segs, nsegs, size, kvap, flags)); 952 } 953 954 void 955 sbus_dmamem_unmap(tag, kva, size) 956 bus_dma_tag_t tag; 957 caddr_t kva; 958 size_t size; 959 { 960 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 961 962 iommu_dvmamem_unmap(tag, &sc->sc_is, kva, size); 963 } 964