1 /* $NetBSD: sbus.c,v 1.49 2002/03/21 00:48:43 eeh 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 * Copyright (c) 1999 Eduardo Horvath 85 * 86 * Redistribution and use in source and binary forms, with or without 87 * modification, are permitted provided that the following conditions 88 * are met: 89 * 1. Redistributions of source code must retain the above copyright 90 * notice, this list of conditions and the following disclaimer. 91 * 92 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 93 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 95 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 96 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 97 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 98 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 99 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 100 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 101 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 102 * SUCH DAMAGE. 103 * 104 */ 105 106 107 /* 108 * Sbus stuff. 109 */ 110 #include "opt_ddb.h" 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_prot.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 static int sbus_overtemp __P((void *)); 148 static int _sbus_bus_map __P(( 149 bus_space_tag_t, 150 bus_addr_t, /*offset*/ 151 bus_size_t, /*size*/ 152 int, /*flags*/ 153 vaddr_t, /* XXX unused -- compat w/sparc */ 154 bus_space_handle_t *)); 155 static void *sbus_intr_establish __P(( 156 bus_space_tag_t, 157 int, /*Sbus interrupt level*/ 158 int, /*`device class' priority*/ 159 int, /*flags*/ 160 int (*) __P((void *)), /*handler*/ 161 void *)); /*handler arg*/ 162 163 164 /* autoconfiguration driver */ 165 int sbus_match __P((struct device *, struct cfdata *, void *)); 166 void sbus_attach __P((struct device *, struct device *, void *)); 167 168 169 struct cfattach sbus_ca = { 170 sizeof(struct sbus_softc), sbus_match, sbus_attach 171 }; 172 173 extern struct cfdriver sbus_cd; 174 175 /* 176 * DVMA routines 177 */ 178 int sbus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *, 179 bus_size_t, struct proc *, int)); 180 void sbus_dmamap_unload __P((bus_dma_tag_t, bus_dmamap_t)); 181 int sbus_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t, 182 bus_dma_segment_t *, int, bus_size_t, int)); 183 void sbus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, bus_addr_t, 184 bus_size_t, int)); 185 int sbus_dmamem_alloc __P((bus_dma_tag_t tag, bus_size_t size, 186 bus_size_t alignment, bus_size_t boundary, 187 bus_dma_segment_t *segs, int nsegs, int *rsegs, 188 int flags)); 189 void sbus_dmamem_free __P((bus_dma_tag_t tag, bus_dma_segment_t *segs, 190 int nsegs)); 191 int sbus_dmamem_map __P((bus_dma_tag_t tag, bus_dma_segment_t *segs, 192 int nsegs, size_t size, caddr_t *kvap, int flags)); 193 void sbus_dmamem_unmap __P((bus_dma_tag_t tag, caddr_t kva, 194 size_t size)); 195 196 /* 197 * Child devices receive the Sbus interrupt level in their attach 198 * arguments. We translate these to CPU IPLs using the following 199 * tables. Note: obio bus interrupt levels are identical to the 200 * processor IPL. 201 * 202 * The second set of tables is used when the Sbus interrupt level 203 * cannot be had from the PROM as an `interrupt' property. We then 204 * fall back on the `intr' property which contains the CPU IPL. 205 */ 206 207 /* 208 * This value is or'ed into the attach args' interrupt level cookie 209 * if the interrupt level comes from an `intr' property, i.e. it is 210 * not an Sbus interrupt level. 211 */ 212 #define SBUS_INTR_COMPAT 0x80000000 213 214 215 /* 216 * Print the location of some sbus-attached device (called just 217 * before attaching that device). If `sbus' is not NULL, the 218 * device was found but not configured; print the sbus as well. 219 * Return UNCONF (config_find ignores this if the device was configured). 220 */ 221 int 222 sbus_print(args, busname) 223 void *args; 224 const char *busname; 225 { 226 struct sbus_attach_args *sa = args; 227 int i; 228 229 if (busname) 230 printf("%s at %s", sa->sa_name, busname); 231 printf(" slot %ld offset 0x%lx", (long)sa->sa_slot, 232 (u_long)sa->sa_offset); 233 for (i = 0; i < sa->sa_nintr; i++) { 234 struct sbus_intr *sbi = &sa->sa_intr[i]; 235 236 printf(" vector %lx ipl %ld", 237 (u_long)sbi->sbi_vec, 238 (long)INTLEV(sbi->sbi_pri)); 239 } 240 return (UNCONF); 241 } 242 243 int 244 sbus_match(parent, cf, aux) 245 struct device *parent; 246 struct cfdata *cf; 247 void *aux; 248 { 249 struct mainbus_attach_args *ma = aux; 250 251 return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0); 252 } 253 254 /* 255 * Attach an Sbus. 256 */ 257 void 258 sbus_attach(parent, self, aux) 259 struct device *parent; 260 struct device *self; 261 void *aux; 262 { 263 struct sbus_softc *sc = (struct sbus_softc *)self; 264 struct mainbus_attach_args *ma = aux; 265 struct intrhand *ih; 266 int ipl; 267 char *name; 268 int node = ma->ma_node; 269 270 int node0, error; 271 bus_space_tag_t sbt; 272 struct sbus_attach_args sa; 273 274 sc->sc_bustag = ma->ma_bustag; 275 sc->sc_dmatag = ma->ma_dmatag; 276 sc->sc_ign = ma->ma_interrupts[0] & INTMAP_IGN; 277 278 /* XXXX Use sysio PROM mappings for interrupt vector regs. */ 279 sparc_promaddr_to_handle(sc->sc_bustag, ma->ma_address[0], &sc->sc_bh); 280 sc->sc_sysio = (struct sysioreg *)bus_space_vaddr(sc->sc_bustag, 281 sc->sc_bh); 282 283 #ifdef _LP64 284 /* 285 * 32-bit kernels use virtual addresses for bus space operations 286 * so we may as well use the prom VA. 287 * 288 * 64-bit kernels use physical addresses for bus space operations 289 * so mapping this in again will reduce TLB thrashing. 290 */ 291 if (bus_space_map(sc->sc_bustag, ma->ma_reg[0].ur_paddr, 292 ma->ma_reg[0].ur_len, 0, &sc->sc_bh) != 0) { 293 printf("%s: cannot map registers\n", self->dv_xname); 294 return; 295 } 296 #endif 297 298 /* 299 * Record clock frequency for synchronous SCSI. 300 * IS THIS THE CORRECT DEFAULT?? 301 */ 302 sc->sc_clockfreq = PROM_getpropint(node, "clock-frequency", 303 25*1000*1000); 304 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); 305 306 sbt = sbus_alloc_bustag(sc); 307 sc->sc_dmatag = sbus_alloc_dmatag(sc); 308 309 /* 310 * Get the SBus burst transfer size if burst transfers are supported 311 */ 312 sc->sc_burst = PROM_getpropint(node, "burst-sizes", 0); 313 314 /* 315 * Collect address translations from the OBP. 316 */ 317 error = PROM_getprop(node, "ranges", sizeof(struct sbus_range), 318 &sc->sc_nrange, (void **)&sc->sc_range); 319 if (error) 320 panic("%s: error getting ranges property", sc->sc_dev.dv_xname); 321 322 /* initialize the IOMMU */ 323 324 /* punch in our copies */ 325 sc->sc_is.is_bustag = sc->sc_bustag; 326 bus_space_subregion(sc->sc_bustag, sc->sc_bh, 327 (vaddr_t)&((struct sysioreg *)NULL)->sys_iommu, 328 sizeof (struct iommureg), &sc->sc_is.is_iommu); 329 bus_space_subregion(sc->sc_bustag, sc->sc_bh, 330 (vaddr_t)&((struct sysioreg *)NULL)->sys_strbuf, 331 sizeof (struct iommu_strbuf), &sc->sc_is.is_sb[0]); 332 sc->sc_is.is_sbvalid[0] = 1; 333 sc->sc_is.is_sbvalid[1] = 0; 334 335 /* give us a nice name.. */ 336 name = (char *)malloc(32, M_DEVBUF, M_NOWAIT); 337 if (name == 0) 338 panic("couldn't malloc iommu name"); 339 snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname); 340 341 iommu_init(name, &sc->sc_is, 0, -1); 342 343 /* Enable the over temp intr */ 344 ih = (struct intrhand *) 345 malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT); 346 ih->ih_map = &sc->sc_sysio->therm_int_map; 347 ih->ih_clr = NULL; /* &sc->sc_sysio->therm_clr_int; */ 348 ih->ih_fun = sbus_overtemp; 349 ipl = 1; 350 ih->ih_pil = (1<<ipl); 351 ih->ih_number = INTVEC(*(ih->ih_map)); 352 intr_establish(ipl, ih); 353 *(ih->ih_map) |= INTMAP_V; 354 355 /* 356 * Note: the stupid SBUS IOMMU ignores the high bits of an address, so a 357 * NULL DMA pointer will be translated by the first page of the IOTSB. 358 * To avoid bugs we'll alloc and ignore the first entry in the IOTSB. 359 */ 360 { 361 u_long dummy; 362 363 if (extent_alloc_subregion(sc->sc_is.is_dvmamap, 364 sc->sc_is.is_dvmabase, sc->sc_is.is_dvmabase + NBPG, NBPG, 365 NBPG, 0, EX_NOWAIT|EX_BOUNDZERO, (u_long *)&dummy) != 0) 366 panic("sbus iommu: can't toss first dvma page"); 367 } 368 369 /* 370 * Loop through ROM children, fixing any relative addresses 371 * and then configuring each device. 372 * `specials' is an array of device names that are treated 373 * specially: 374 */ 375 node0 = firstchild(node); 376 for (node = node0; node; node = nextsibling(node)) { 377 char *name = PROM_getpropstring(node, "name"); 378 379 if (sbus_setup_attach_args(sc, sbt, sc->sc_dmatag, 380 node, &sa) != 0) { 381 printf("sbus_attach: %s: incomplete\n", name); 382 continue; 383 } 384 (void) config_found(&sc->sc_dev, (void *)&sa, sbus_print); 385 sbus_destroy_attach_args(&sa); 386 } 387 } 388 389 int 390 sbus_setup_attach_args(sc, bustag, dmatag, node, sa) 391 struct sbus_softc *sc; 392 bus_space_tag_t bustag; 393 bus_dma_tag_t dmatag; 394 int node; 395 struct sbus_attach_args *sa; 396 { 397 /*struct sbus_reg sbusreg;*/ 398 /*int base;*/ 399 int error; 400 int n; 401 402 bzero(sa, sizeof(struct sbus_attach_args)); 403 error = PROM_getprop(node, "name", 1, &n, (void **)&sa->sa_name); 404 if (error != 0) 405 return (error); 406 sa->sa_name[n] = '\0'; 407 408 sa->sa_bustag = bustag; 409 sa->sa_dmatag = dmatag; 410 sa->sa_node = node; 411 sa->sa_frequency = sc->sc_clockfreq; 412 413 error = PROM_getprop(node, "reg", sizeof(struct sbus_reg), 414 &sa->sa_nreg, (void **)&sa->sa_reg); 415 if (error != 0) { 416 char buf[32]; 417 if (error != ENOENT || 418 !node_has_property(node, "device_type") || 419 strcmp(PROM_getpropstringA(node, "device_type", buf), 420 "hierarchical") != 0) 421 return (error); 422 } 423 for (n = 0; n < sa->sa_nreg; n++) { 424 /* Convert to relative addressing, if necessary */ 425 u_int32_t base = sa->sa_reg[n].sbr_offset; 426 if (SBUS_ABS(base)) { 427 sa->sa_reg[n].sbr_slot = SBUS_ABS_TO_SLOT(base); 428 sa->sa_reg[n].sbr_offset = SBUS_ABS_TO_OFFSET(base); 429 } 430 } 431 432 if ((error = sbus_get_intr(sc, node, &sa->sa_intr, &sa->sa_nintr, 433 sa->sa_slot)) != 0) 434 return (error); 435 436 error = PROM_getprop(node, "address", sizeof(u_int32_t), 437 &sa->sa_npromvaddrs, (void **)&sa->sa_promvaddrs); 438 if (error != 0 && error != ENOENT) 439 return (error); 440 441 return (0); 442 } 443 444 void 445 sbus_destroy_attach_args(sa) 446 struct sbus_attach_args *sa; 447 { 448 if (sa->sa_name != NULL) 449 free(sa->sa_name, M_DEVBUF); 450 451 if (sa->sa_nreg != 0) 452 free(sa->sa_reg, M_DEVBUF); 453 454 if (sa->sa_intr) 455 free(sa->sa_intr, M_DEVBUF); 456 457 if (sa->sa_promvaddrs) 458 free((void *)sa->sa_promvaddrs, M_DEVBUF); 459 460 bzero(sa, sizeof(struct sbus_attach_args)); /*DEBUG*/ 461 } 462 463 464 int 465 _sbus_bus_map(t, addr, size, flags, v, hp) 466 bus_space_tag_t t; 467 bus_addr_t addr; 468 bus_size_t size; 469 int flags; 470 vaddr_t v; 471 bus_space_handle_t *hp; 472 { 473 struct sbus_softc *sc = t->cookie; 474 int64_t slot = BUS_ADDR_IOSPACE(addr); 475 int64_t offset = BUS_ADDR_PADDR(addr); 476 int i; 477 478 for (i = 0; i < sc->sc_nrange; i++) { 479 bus_addr_t paddr; 480 481 if (sc->sc_range[i].cspace != slot) 482 continue; 483 484 /* We've found the connection to the parent bus */ 485 paddr = sc->sc_range[i].poffset + offset; 486 paddr |= ((bus_addr_t)sc->sc_range[i].pspace<<32); 487 DPRINTF(SDB_DVMA, 488 ("\n_sbus_bus_map: mapping paddr slot %lx offset %lx poffset %lx paddr %lx\n", 489 (long)slot, (long)offset, (long)sc->sc_range[i].poffset, 490 (long)paddr)); 491 return (bus_space_map(sc->sc_bustag, paddr, size, flags, hp)); 492 } 493 494 return (EINVAL); 495 } 496 497 498 bus_addr_t 499 sbus_bus_addr(t, btype, offset) 500 bus_space_tag_t t; 501 u_int btype; 502 u_int offset; 503 { 504 bus_addr_t baddr; 505 int slot = btype; 506 struct sbus_softc *sc = t->cookie; 507 int i; 508 509 for (i = 0; i < sc->sc_nrange; i++) { 510 if (sc->sc_range[i].cspace != slot) 511 continue; 512 513 baddr = sc->sc_range[i].poffset + offset; 514 baddr |= ((bus_addr_t)sc->sc_range[i].pspace<<32); 515 } 516 517 return (baddr); 518 } 519 520 521 /* 522 * Each attached device calls sbus_establish after it initializes 523 * its sbusdev portion. 524 */ 525 void 526 sbus_establish(sd, dev) 527 register struct sbusdev *sd; 528 register struct device *dev; 529 { 530 register struct sbus_softc *sc; 531 register struct device *curdev; 532 533 /* 534 * We have to look for the sbus by name, since it is not necessarily 535 * our immediate parent (i.e. sun4m /iommu/sbus/espdma/esp) 536 * We don't just use the device structure of the above-attached 537 * sbus, since we might (in the future) support multiple sbus's. 538 */ 539 for (curdev = dev->dv_parent; ; curdev = curdev->dv_parent) { 540 if (!curdev || !curdev->dv_xname) 541 panic("sbus_establish: can't find sbus parent for %s", 542 sd->sd_dev->dv_xname 543 ? sd->sd_dev->dv_xname 544 : "<unknown>" ); 545 546 if (strncmp(curdev->dv_xname, "sbus", 4) == 0) 547 break; 548 } 549 sc = (struct sbus_softc *) curdev; 550 551 sd->sd_dev = dev; 552 sd->sd_bchain = sc->sc_sbdev; 553 sc->sc_sbdev = sd; 554 } 555 556 /* 557 * Reset the given sbus. 558 */ 559 void 560 sbusreset(sbus) 561 int sbus; 562 { 563 register struct sbusdev *sd; 564 struct sbus_softc *sc = sbus_cd.cd_devs[sbus]; 565 struct device *dev; 566 567 printf("reset %s:", sc->sc_dev.dv_xname); 568 for (sd = sc->sc_sbdev; sd != NULL; sd = sd->sd_bchain) { 569 if (sd->sd_reset) { 570 dev = sd->sd_dev; 571 (*sd->sd_reset)(dev); 572 printf(" %s", dev->dv_xname); 573 } 574 } 575 /* Reload iommu regs */ 576 iommu_reset(&sc->sc_is); 577 } 578 579 /* 580 * Handle an overtemp situation. 581 * 582 * SPARCs have temperature sensors which generate interrupts 583 * if the machine's temperature exceeds a certain threshold. 584 * This handles the interrupt and powers off the machine. 585 * The same needs to be done to PCI controller drivers. 586 */ 587 int 588 sbus_overtemp(arg) 589 void *arg; 590 { 591 /* Should try a clean shutdown first */ 592 printf("DANGER: OVER TEMPERATURE detected\nShutting down...\n"); 593 delay(20); 594 cpu_reboot(RB_POWERDOWN|RB_HALT, NULL); 595 } 596 597 /* 598 * Get interrupt attributes for an Sbus device. 599 */ 600 int 601 sbus_get_intr(sc, node, ipp, np, slot) 602 struct sbus_softc *sc; 603 int node; 604 struct sbus_intr **ipp; 605 int *np; 606 int slot; 607 { 608 int *ipl; 609 int n, i; 610 char buf[32]; 611 612 /* 613 * The `interrupts' property contains the Sbus interrupt level. 614 */ 615 ipl = NULL; 616 if (PROM_getprop(node, "interrupts", sizeof(int), np, (void **)&ipl) == 0) { 617 struct sbus_intr *ip; 618 int pri; 619 620 /* Default to interrupt level 2 -- otherwise unused */ 621 pri = INTLEVENCODE(2); 622 623 /* Change format to an `struct sbus_intr' array */ 624 ip = malloc(*np * sizeof(struct sbus_intr), M_DEVBUF, M_NOWAIT); 625 if (ip == NULL) 626 return (ENOMEM); 627 628 /* 629 * Now things get ugly. We need to take this value which is 630 * the interrupt vector number and encode the IPL into it 631 * somehow. Luckily, the interrupt vector has lots of free 632 * space and we can easily stuff the IPL in there for a while. 633 */ 634 PROM_getpropstringA(node, "device_type", buf); 635 if (!buf[0]) 636 PROM_getpropstringA(node, "name", buf); 637 638 for (i = 0; intrmap[i].in_class; i++) 639 if (strcmp(intrmap[i].in_class, buf) == 0) { 640 pri = INTLEVENCODE(intrmap[i].in_lev); 641 break; 642 } 643 644 /* 645 * Sbus card devices need the slot number encoded into 646 * the vector as this is generally not done. 647 */ 648 if ((ipl[0] & INTMAP_OBIO) == 0) 649 pri |= slot << 3; 650 651 for (n = 0; n < *np; n++) { 652 /* 653 * We encode vector and priority into sbi_pri so we 654 * can pass them as a unit. This will go away if 655 * sbus_establish ever takes an sbus_intr instead 656 * of an integer level. 657 * Stuff the real vector in sbi_vec. 658 */ 659 660 ip[n].sbi_pri = pri|ipl[n]; 661 ip[n].sbi_vec = ipl[n]; 662 } 663 free(ipl, M_DEVBUF); 664 *ipp = ip; 665 } 666 667 return (0); 668 } 669 670 671 /* 672 * Install an interrupt handler for an Sbus device. 673 */ 674 void * 675 sbus_intr_establish(t, pri, level, flags, handler, arg) 676 bus_space_tag_t t; 677 int pri; 678 int level; 679 int flags; 680 int (*handler) __P((void *)); 681 void *arg; 682 { 683 struct sbus_softc *sc = t->cookie; 684 struct intrhand *ih; 685 int ipl; 686 long vec = pri; 687 688 ih = (struct intrhand *) 689 malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT); 690 if (ih == NULL) 691 return (NULL); 692 693 if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) != 0) 694 ipl = vec; 695 else if ((vec & SBUS_INTR_COMPAT) != 0) 696 ipl = vec & ~SBUS_INTR_COMPAT; 697 else { 698 /* Decode and remove IPL */ 699 ipl = INTLEV(vec); 700 vec = INTVEC(vec); 701 DPRINTF(SDB_INTR, 702 ("\nsbus: intr[%ld]%lx: %lx\nHunting for IRQ...\n", 703 (long)ipl, (long)vec, (u_long)intrlev[vec])); 704 if ((vec & INTMAP_OBIO) == 0) { 705 /* We're in an SBUS slot */ 706 /* Register the map and clear intr registers */ 707 708 int slot = INTSLOT(pri); 709 710 ih->ih_map = &(&sc->sc_sysio->sbus_slot0_int)[slot]; 711 ih->ih_clr = &sc->sc_sysio->sbus0_clr_int[vec]; 712 #ifdef DEBUG 713 if (sbus_debug & SDB_INTR) { 714 int64_t intrmap = *ih->ih_map; 715 716 printf("SBUS %lx IRQ as %llx in slot %d\n", 717 (long)vec, (long long)intrmap, slot); 718 printf("\tmap addr %p clr addr %p\n", 719 ih->ih_map, ih->ih_clr); 720 } 721 #endif 722 /* Enable the interrupt */ 723 vec |= INTMAP_V; 724 /* Insert IGN */ 725 vec |= sc->sc_ign; 726 /* XXXX */ 727 *(ih->ih_map) = vec; 728 } else { 729 int64_t *intrptr = &sc->sc_sysio->scsi_int_map; 730 int64_t intrmap = 0; 731 int i; 732 733 /* Insert IGN */ 734 vec |= sc->sc_ign; 735 for (i = 0; &intrptr[i] <= 736 (int64_t *)&sc->sc_sysio->reserved_int_map && 737 INTVEC(intrmap = intrptr[i]) != INTVEC(vec); i++) 738 ; 739 if (INTVEC(intrmap) == INTVEC(vec)) { 740 DPRINTF(SDB_INTR, 741 ("OBIO %lx IRQ as %lx in slot %d\n", 742 vec, (long)intrmap, i)); 743 /* Register the map and clear intr registers */ 744 ih->ih_map = &intrptr[i]; 745 intrptr = (int64_t *)&sc->sc_sysio->scsi_clr_int; 746 ih->ih_clr = &intrptr[i]; 747 /* Enable the interrupt */ 748 intrmap |= INTMAP_V; 749 /* XXXX */ 750 *(ih->ih_map) = intrmap; 751 } else 752 panic("IRQ not found!"); 753 } 754 } 755 #ifdef DEBUG 756 if (sbus_debug & SDB_INTR) { long i; for (i = 0; i < 400000000; i++); } 757 #endif 758 759 ih->ih_fun = handler; 760 ih->ih_arg = arg; 761 ih->ih_number = vec; 762 ih->ih_pil = (1<<ipl); 763 intr_establish(ipl, ih); 764 return (ih); 765 } 766 767 static bus_space_tag_t 768 sbus_alloc_bustag(sc) 769 struct sbus_softc *sc; 770 { 771 bus_space_tag_t sbt; 772 773 sbt = (bus_space_tag_t) 774 malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT); 775 if (sbt == NULL) 776 return (NULL); 777 778 bzero(sbt, sizeof *sbt); 779 sbt->cookie = sc; 780 sbt->parent = sc->sc_bustag; 781 sbt->type = SBUS_BUS_SPACE; 782 sbt->sparc_bus_map = _sbus_bus_map; 783 sbt->sparc_bus_mmap = sc->sc_bustag->sparc_bus_mmap; 784 sbt->sparc_intr_establish = sbus_intr_establish; 785 return (sbt); 786 } 787 788 789 static bus_dma_tag_t 790 sbus_alloc_dmatag(sc) 791 struct sbus_softc *sc; 792 { 793 bus_dma_tag_t sdt, psdt = sc->sc_dmatag; 794 795 sdt = (bus_dma_tag_t) 796 malloc(sizeof(struct sparc_bus_dma_tag), M_DEVBUF, M_NOWAIT); 797 if (sdt == NULL) 798 /* Panic? */ 799 return (psdt); 800 801 sdt->_cookie = sc; 802 sdt->_parent = psdt; 803 #define PCOPY(x) sdt->x = psdt->x 804 PCOPY(_dmamap_create); 805 PCOPY(_dmamap_destroy); 806 sdt->_dmamap_load = sbus_dmamap_load; 807 PCOPY(_dmamap_load_mbuf); 808 PCOPY(_dmamap_load_uio); 809 sdt->_dmamap_load_raw = sbus_dmamap_load_raw; 810 sdt->_dmamap_unload = sbus_dmamap_unload; 811 sdt->_dmamap_sync = sbus_dmamap_sync; 812 sdt->_dmamem_alloc = sbus_dmamem_alloc; 813 sdt->_dmamem_free = sbus_dmamem_free; 814 sdt->_dmamem_map = sbus_dmamem_map; 815 sdt->_dmamem_unmap = sbus_dmamem_unmap; 816 PCOPY(_dmamem_mmap); 817 #undef PCOPY 818 sc->sc_dmatag = sdt; 819 return (sdt); 820 } 821 822 int 823 sbus_dmamap_load(tag, map, buf, buflen, p, flags) 824 bus_dma_tag_t tag; 825 bus_dmamap_t map; 826 void *buf; 827 bus_size_t buflen; 828 struct proc *p; 829 int flags; 830 { 831 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 832 833 return (iommu_dvmamap_load(tag, &sc->sc_is, map, buf, buflen, p, flags)); 834 } 835 836 int 837 sbus_dmamap_load_raw(tag, map, segs, nsegs, size, flags) 838 bus_dma_tag_t tag; 839 bus_dmamap_t map; 840 bus_dma_segment_t *segs; 841 int nsegs; 842 bus_size_t size; 843 int flags; 844 { 845 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 846 847 return (iommu_dvmamap_load_raw(tag, &sc->sc_is, map, segs, nsegs, flags, size)); 848 } 849 850 void 851 sbus_dmamap_unload(tag, map) 852 bus_dma_tag_t tag; 853 bus_dmamap_t map; 854 { 855 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 856 857 iommu_dvmamap_unload(tag, &sc->sc_is, map); 858 } 859 860 void 861 sbus_dmamap_sync(tag, map, offset, len, ops) 862 bus_dma_tag_t tag; 863 bus_dmamap_t map; 864 bus_addr_t offset; 865 bus_size_t len; 866 int ops; 867 { 868 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 869 870 if (ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) { 871 /* Flush the CPU then the IOMMU */ 872 bus_dmamap_sync(tag->_parent, map, offset, len, ops); 873 iommu_dvmamap_sync(tag, &sc->sc_is, map, offset, len, ops); 874 } 875 if (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) { 876 /* Flush the IOMMU then the CPU */ 877 iommu_dvmamap_sync(tag, &sc->sc_is, map, offset, len, ops); 878 bus_dmamap_sync(tag->_parent, map, offset, len, ops); 879 } 880 } 881 882 int 883 sbus_dmamem_alloc(tag, size, alignment, boundary, segs, nsegs, rsegs, flags) 884 bus_dma_tag_t tag; 885 bus_size_t size; 886 bus_size_t alignment; 887 bus_size_t boundary; 888 bus_dma_segment_t *segs; 889 int nsegs; 890 int *rsegs; 891 int flags; 892 { 893 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 894 895 return (iommu_dvmamem_alloc(tag, &sc->sc_is, size, alignment, boundary, 896 segs, nsegs, rsegs, flags)); 897 } 898 899 void 900 sbus_dmamem_free(tag, segs, nsegs) 901 bus_dma_tag_t tag; 902 bus_dma_segment_t *segs; 903 int nsegs; 904 { 905 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 906 907 iommu_dvmamem_free(tag, &sc->sc_is, segs, nsegs); 908 } 909 910 int 911 sbus_dmamem_map(tag, segs, nsegs, size, kvap, flags) 912 bus_dma_tag_t tag; 913 bus_dma_segment_t *segs; 914 int nsegs; 915 size_t size; 916 caddr_t *kvap; 917 int flags; 918 { 919 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 920 921 return (iommu_dvmamem_map(tag, &sc->sc_is, segs, nsegs, size, kvap, flags)); 922 } 923 924 void 925 sbus_dmamem_unmap(tag, kva, size) 926 bus_dma_tag_t tag; 927 caddr_t kva; 928 size_t size; 929 { 930 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie; 931 932 iommu_dvmamem_unmap(tag, &sc->sc_is, kva, size); 933 } 934