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