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