1 /* $NetBSD: upa.c,v 1.9 2002/05/16 20:05:39 wiz 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 /* #define DEBUG_1 */ 84 85 /* 86 * UPA bus stuff. 87 */ 88 89 #include <sys/param.h> 90 #include <sys/malloc.h> 91 #include <sys/systm.h> 92 #include <sys/device.h> 93 94 #include <machine/bus.h> 95 #include <sparc64/dev/upavar.h> 96 97 #include <machine/autoconf.h> 98 #include <machine/ctlreg.h> 99 #include <machine/cpu.h> 100 101 102 void upareset __P((int)); 103 104 static bus_space_tag_t upa_alloc_bustag __P((struct upa_softc *)); 105 static int upa_get_intr __P((struct upa_softc *, int, int *)); 106 static int upa_bus_mmap __P((bus_space_tag_t, bus_type_t, bus_addr_t, 107 int, bus_space_handle_t *)); 108 static int _upa_bus_map __P(( 109 bus_space_tag_t, 110 bus_type_t, /*slot*/ 111 bus_addr_t, /*offset*/ 112 bus_size_t, /*size*/ 113 int, /*flags*/ 114 vaddr_t, /*preferred virtual address */ 115 bus_space_handle_t *)); 116 static void *upa_intr_establish __P(( 117 bus_space_tag_t, 118 int, /*level*/ 119 int, /*flags*/ 120 int (*) __P((void *)), /*handler*/ 121 void *)); /*handler arg*/ 122 123 124 /* autoconfiguration driver */ 125 int upa_match_mainbus __P((struct device *, struct cfdata *, void *)); 126 void upa_attach_mainbus __P((struct device *, struct device *, void *)); 127 128 struct cfattach upa_ca = { 129 sizeof(struct upa_softc), upa_match, upa_attach 130 }; 131 132 extern struct cfdriver upa_cd; 133 134 135 /* 136 * Print the location of some upa-attached device (called just 137 * before attaching that device). If `upa' is not NULL, the 138 * device was found but not configured; print the upa as well. 139 * Return UNCONF (config_find ignores this if the device was configured). 140 */ 141 int 142 upa_print(args, busname) 143 void *args; 144 const char *busname; 145 { 146 struct upa_attach_args *ua = args; 147 148 if (busname) 149 printf("%s at %s", ua->ua_name, busname); 150 if (ua->ua_interrupts) { 151 int level = ua->ua_pri; 152 struct upa_softc *sc = 153 (struct upa_softc *) ua->ua_bustag->cookie; 154 155 printf(" interrupt %x", ua->ua_interrupts); 156 } 157 return (UNCONF); 158 } 159 160 int 161 upa_match(parent, cf, aux) 162 struct device *parent; 163 struct cfdata *cf; 164 void *aux; 165 { 166 struct mainbus_attach_args *ma = aux; 167 168 return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0); 169 } 170 171 int 172 upa_match_iommu(parent, cf, aux) 173 struct device *parent; 174 struct cfdata *cf; 175 void *aux; 176 { 177 struct iommu_attach_args *ia = aux; 178 179 if (CPU_ISSUN4) 180 return (0); 181 182 return (strcmp(cf->cf_driver->cd_name, ia->iom_name) == 0); 183 } 184 185 int 186 upa_match_xbox(parent, cf, aux) 187 struct device *parent; 188 struct cfdata *cf; 189 void *aux; 190 { 191 struct xbox_attach_args *xa = aux; 192 193 if (CPU_ISSUN4) 194 return (0); 195 196 return (strcmp(cf->cf_driver->cd_name, xa->xa_name) == 0); 197 } 198 199 /* 200 * Attach an Upa. 201 */ 202 void 203 upa_attach_mainbus(parent, self, aux) 204 struct device *parent; 205 struct device *self; 206 void *aux; 207 { 208 struct upa_softc *sc = (struct upa_softc *)self; 209 struct mainbus_attach_args *ma = aux; 210 int node = ma->ma_node; 211 212 /* 213 * XXX there is only one Upa, for now -- do not know how to 214 * address children on others 215 */ 216 if (sc->sc_dev.dv_unit > 0) { 217 printf(" unsupported\n"); 218 return; 219 } 220 221 sc->sc_bustag = ma->ma_bustag; 222 sc->sc_dmatag = ma->ma_dmatag; 223 224 /* Setup interrupt translation tables */ 225 sc->sc_intr2ipl = CPU_ISSUN4C 226 ? intr_upa2ipl_4c 227 : intr_upa2ipl_4m; 228 229 /* 230 * Record clock frequency for synchronous SCSI. 231 * IS THIS THE CORRECT DEFAULT?? 232 */ 233 sc->sc_clockfreq = PROM_getpropint(node, "clock-frequency", 25*1000*1000); 234 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); 235 236 upa_attach(sc, "upa", node, NULL); 237 } 238 239 void 240 upa_attach_iommu(parent, self, aux) 241 struct device *parent; 242 struct device *self; 243 void *aux; 244 { 245 struct upa_softc *sc = (struct upa_softc *)self; 246 struct iommu_attach_args *ia = aux; 247 int node = ia->iom_node; 248 249 sc->sc_bustag = ia->iom_bustag; 250 sc->sc_dmatag = ia->iom_dmatag; 251 252 /* Setup interrupt translation tables */ 253 sc->sc_intr2ipl = CPU_ISSUN4C ? intr_upa2ipl_4c : intr_upa2ipl_4m; 254 255 /* 256 * Record clock frequency for synchronous SCSI. 257 * IS THIS THE CORRECT DEFAULT?? 258 */ 259 sc->sc_clockfreq = PROM_getpropint(node, "clock-frequency", 25*1000*1000); 260 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); 261 262 upa_attach(sc, "upa", node, NULL); 263 } 264 265 void 266 upa_attach_xbox(parent, self, aux) 267 struct device *parent; 268 struct device *self; 269 void *aux; 270 { 271 struct upa_softc *sc = (struct upa_softc *)self; 272 struct xbox_attach_args *xa = aux; 273 int node = xa->xa_node; 274 275 sc->sc_bustag = xa->xa_bustag; 276 sc->sc_dmatag = xa->xa_dmatag; 277 278 /* Setup interrupt translation tables */ 279 sc->sc_intr2ipl = CPU_ISSUN4C ? intr_upa2ipl_4c : intr_upa2ipl_4m; 280 281 /* 282 * Record clock frequency for synchronous SCSI. 283 * IS THIS THE CORRECT DEFAULT?? 284 */ 285 sc->sc_clockfreq = PROM_getpropint(node, "clock-frequency", 25*1000*1000); 286 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); 287 288 upa_attach(sc, "upa", node, NULL); 289 } 290 291 void 292 upa_attach(sc, busname, busnode, specials) 293 struct upa_softc *sc; 294 char *busname; 295 int busnode; 296 const char * const *specials; 297 { 298 int node0, node, error; 299 const char *sp; 300 const char *const *ssp; 301 bus_space_tag_t sbt; 302 struct upa_attach_args ua; 303 304 sbt = upa_alloc_bustag(sc); 305 306 /* 307 * Get the Upa burst transfer size if burst transfers are supported 308 */ 309 sc->sc_burst = PROM_getpropint(busnode, "burst-sizes", 0); 310 311 /* 312 * Collect address translations from the OBP. 313 */ 314 error = PROM_getprop(busnode, "ranges", sizeof(struct rom_range), 315 &sc->sc_nrange, (void **)&sc->sc_range); 316 switch (error) { 317 case 0: 318 break; 319 case ENOENT: 320 /* Fall back to our own `range' construction */ 321 sc->sc_range = upa_translations; 322 sc->sc_nrange = 323 sizeof(upa_translations)/sizeof(upa_translations[0]); 324 break; 325 default: 326 panic("%s: error getting ranges property", sc->sc_dev.dv_xname); 327 } 328 329 /* WARNING -- this stuff needs to be set somewhere */ 330 sc->sc_sysio = (struct sysioreg*) ra->ra_vaddr; /* Use prom mapping for sysio. */ 331 sc->sc_ign = ra->ra_interrupt[0] & INTMAP_IGN; /* Find interrupt group no */ 332 333 334 /* 335 * Setup the iommu. 336 * 337 * The sun4u iommu is part of the UPA controller so we will 338 * deal with it here. We could try to fake a device node so 339 * we can eventually share it with the PCI bus run by psyco, 340 * but I don't want to get into that sort of cruft. 341 */ 342 #ifdef NOTDEF_DEBUG 343 { 344 /* Probe the iommu */ 345 int64_t cr, tsb; 346 347 printf("\niommu regs at: cr=%x tsb=%x flush=%x\n", &sc->sc_sysio->sys_iommu.iommu_cr, 348 &sc->sc_sysio->sys_iommu.iommu_tsb, &sc->sc_sysio->sys_iommu.iommu_flush); 349 cr = sc->sc_sysio->sys_iommu.iommu_cr; 350 tsb = sc->sc_sysio->sys_iommu.iommu_tsb; 351 printf("iommu cr=%x:%x tsb=%x:%x\n", (long)(cr>>32), (long)cr, (long)(tsb>>32), (long)tsb); 352 delay(1000000); /* 1 s */ 353 } 354 #endif 355 356 /* 357 * All IOMMUs will share the same TSB which is allocated in pmap_bootstrap. 358 * 359 * This makes device management easier. 360 */ 361 sc->sc_tsbsize = iotsbsize; 362 sc->sc_tsb = iotsb; 363 sc->sc_ptsb = iotsbp; 364 #if 0 365 /* Need to do 64-bit stores */ 366 sc->sc_sysio->sys_iommu.iommu_cr = (IOMMUCR_TSB1K|IOMMUCR_8KPG|IOMMUCR_EN); 367 sc->sc_sysio->sys_iommu.iommu_tsb = sc->sc_ptsb; 368 #else 369 stxa(&sc->sc_sysio->sys_iommu.iommu_cr,ASI_NUCLEUS,(IOMMUCR_TSB1K|IOMMUCR_8KPG|IOMMUCR_EN)); 370 stxa(&sc->sc_sysio->sys_iommu.iommu_tsb,ASI_NUCLEUS,sc->sc_ptsb); 371 #endif 372 /* 373 * Loop through ROM children, fixing any relative addresses 374 * and then configuring each device. 375 * `specials' is an array of device names that are treated 376 * specially: 377 */ 378 node0 = firstchild(busnode); 379 for (ssp = specials ; ssp != NULL && *(sp = *ssp) != 0; ssp++) { 380 if ((node = findnode(node0, sp)) == 0) { 381 panic("could not find %s amongst %s devices", 382 sp, busname); 383 } 384 385 if (upa_setup_attach_args(sc, sbt, sc->sc_dmatag, 386 node, &ua) != 0) { 387 panic("upa_attach: %s: incomplete", sp); 388 } 389 (void) config_found(&sc->sc_dev, (void *)&ua, upa_print); 390 } 391 392 for (node = node0; node; node = nextsibling(node)) { 393 char *name = PROM_getpropstring(node, "name"); 394 for (ssp = specials, sp = NULL; 395 ssp != NULL && (sp = *ssp) != NULL; 396 ssp++) 397 if (strcmp(name, sp) == 0) 398 break; 399 400 if (sp != NULL) 401 /* Already configured as an "early" device */ 402 continue; 403 404 <<<<<<<<<<<<<< variant A 405 upa_translate(self, &oca); 406 oca.ca_bustype = BUS_UPA; 407 /* Now we need to enable this interrupt if a handler has been registered */ 408 if( config_found(&sc->sc_dev, (void *)&oca, upa_print) != NULL ) 409 for( i=0; i<oca.ca_ra.ra_ninterrupt; i++) { 410 #ifdef IRQEN_DEBUG 411 printf("\nupa: intr[%d]%x: %x\n", i, oca.ca_ra.ra_interrupt[i], 412 intrlev[oca.ca_ra.ra_interrupt[i]]); 413 #endif 414 if( intrlev[oca.ca_ra.ra_interrupt[i]] ) { 415 /* Hunt for proper register UGH! */ 416 #ifdef IRQEN_DEBUG 417 printf("Hunting for IRQ...\n"); 418 #endif 419 for( intrptr=&sc->sc_sysio->scsi_int_map; 420 intrptr < &sc->sc_sysio->reserved_int_map && 421 ((intrmap=*intrptr)&INTMAP_INR) 422 != oca.ca_ra.ra_interrupt[i]; 423 intrptr++); 424 if((intrmap&INTMAP_INR) == 425 oca.ca_ra.ra_interrupt[i]) { 426 #ifdef IRQEN_DEBUG 427 printf("Found %x IRQ as %x:%x in slot\n", 428 oca.ca_ra.ra_interrupt[i], (int)(intrmap>>32), (int)intrmap, 429 intrptr - &sc->sc_sysio->scsi_int_map); 430 #endif 431 /* Enable the interrupt */ 432 intrmap |= INTMAP_V; 433 stxa(intrptr, ASI_NUCLEUS, intrmap); 434 /* Register the map and clear intr registers */ 435 intrlev[oca.ca_ra.ra_interrupt[i]]->ih_map = intrptr; 436 intrlev[oca.ca_ra.ra_interrupt[i]]->ih_clr = 437 &sc->sc_sysio->scsi_clr_int + 438 (intrptr - &sc->sc_sysio->scsi_int_map); 439 } 440 } 441 } 442 #ifdef IRQEN_DEBUG 443 for( i=0; i<140000000; i++); 444 #endif 445 >>>>>>>>>>>>>> variant B 446 if (upa_setup_attach_args(sc, sbt, sc->sc_dmatag, 447 node, bp, &ua) != 0) { 448 printf("upa_attach: %s: incomplete\n", name); 449 continue; 450 } 451 (void) config_found(&sc->sc_dev, (void *)&ua, upa_print); 452 ======= end of combination 453 } 454 } 455 456 int 457 upa_setup_attach_args(sc, bustag, dmatag, node, ua) 458 struct upa_softc *sc; 459 bus_space_tag_t bustag; 460 bus_dma_tag_t dmatag; 461 int node; 462 struct upa_attach_args *ua; 463 { 464 struct rom_reg romreg; 465 int base; 466 int error; 467 468 bzero(ua, sizeof(struct upa_attach_args)); 469 ua->ua_name = PROM_getpropstring(node, "name"); 470 ua->ua_bustag = bustag; 471 ua->ua_dmatag = dmatag; 472 ua->ua_node = node; 473 474 if ((error = PROM_getprop_reg1(node, &romreg)) != 0) 475 return (error); 476 477 /* We pass only the first "reg" property */ 478 base = (int)romreg.rr_paddr; 479 if (UPA_ABS(base)) { 480 ua->ua_slot = UPA_ABS_TO_SLOT(base); 481 ua->ua_offset = UPA_ABS_TO_OFFSET(base); 482 } else { 483 ua->ua_slot = romreg.rr_iospace; 484 ua->ua_offset = base; 485 } 486 ua->ua_size = romreg.rr_len; 487 488 if ((error = upa_get_intr(sc, node, &ua->ua_pri)) != 0) 489 return (error); 490 491 if ((error = PROM_getprop_address1(node, &ua->ua_promvaddr)) != 0) 492 return (error); 493 494 return (0); 495 } 496 497 int 498 _upa_bus_map(t, btype, offset, size, flags, vaddr, hp) 499 bus_space_tag_t t; 500 bus_type_t btype; 501 bus_addr_t offset; 502 bus_size_t size; 503 int flags; 504 vaddr_t vaddr; 505 bus_space_handle_t *hp; 506 { 507 struct upa_softc *sc = t->cookie; 508 int slot = btype; 509 int i; 510 511 for (i = 0; i < sc->sc_nrange; i++) { 512 bus_addr_t paddr; 513 bus_type_t iospace; 514 515 if (sc->sc_range[i].cspace != slot) 516 continue; 517 518 /* We've found the connection to the parent bus */ 519 paddr = sc->sc_range[i].poffset + offset; 520 iospace = sc->sc_range[i].pspace; 521 return (bus_space_map2(sc->sc_bustag, iospace, paddr, 522 size, flags, vaddr, hp)); 523 } 524 525 return (EINVAL); 526 } 527 528 int 529 upa_bus_mmap(t, btype, paddr, flags, hp) 530 bus_space_tag_t t; 531 bus_type_t btype; 532 bus_addr_t paddr; 533 int flags; 534 bus_space_handle_t *hp; 535 { 536 int slot = (int)btype; 537 int offset = (int)paddr; 538 struct upa_softc *sc = t->cookie; 539 int i; 540 541 for (i = 0; i < sc->sc_nrange; i++) { 542 bus_addr_t paddr; 543 bus_addr_t iospace; 544 545 if (sc->sc_range[i].cspace != slot) 546 continue; 547 548 paddr = sc->sc_range[i].poffset + offset; 549 iospace = (bus_addr_t)sc->sc_range[i].pspace; 550 return (bus_space_mmap(sc->sc_bustag, iospace, paddr, 551 flags, hp)); 552 } 553 554 return (-1); 555 } 556 557 558 /* 559 * Each attached device calls upa_establish after it initializes 560 * its upadev portion. 561 */ 562 void 563 upa_establish(sd, dev) 564 register struct upadev *sd; 565 register struct device *dev; 566 { 567 register struct upa_softc *sc; 568 register struct device *curdev; 569 570 /* 571 * We have to look for the upa by name, since it is not necessarily 572 * our immediate parent (i.e. sun4m /iommu/upa/espdma/esp) 573 * We don't just use the device structure of the above-attached 574 * upa, since we might (in the future) support multiple upa's. 575 */ 576 for (curdev = dev->dv_parent; ; curdev = curdev->dv_parent) { 577 if (!curdev || !curdev->dv_xname) 578 panic("upa_establish: can't find upa parent for %s", 579 sd->sd_dev->dv_xname 580 ? sd->sd_dev->dv_xname 581 : "<unknown>" ); 582 583 if (strncmp(curdev->dv_xname, "upa", 4) == 0) 584 break; 585 } 586 sc = (struct upa_softc *) curdev; 587 588 sd->sd_dev = dev; 589 sd->sd_bchain = sc->sc_sbdev; 590 sc->sc_sbdev = sd; 591 } 592 593 /* 594 * Reset the given upa. (???) 595 */ 596 void 597 upareset(upa) 598 int upa; 599 { 600 register struct upadev *sd; 601 struct upa_softc *sc = upa_cd.cd_devs[upa]; 602 struct device *dev; 603 604 printf("reset %s:", sc->sc_dev.dv_xname); 605 for (sd = sc->sc_sbdev; sd != NULL; sd = sd->sd_bchain) { 606 if (sd->sd_reset) { 607 dev = sd->sd_dev; 608 (*sd->sd_reset)(dev); 609 printf(" %s", dev->dv_xname); 610 } 611 } 612 #if 0 613 /* Reload iommu regs */ 614 sc->sc_sysio->sys_iommu.iommu_cr = (IOMMUCR_TSB1K|IOMMUCR_8KPG|IOMMUCR_EN); 615 sc->sc_sysio->sys_iommu.iommu_tsb = sc->sc_ptsb; 616 #else 617 /* Reload iommu regs */ 618 stxa(&sc->sc_sysio->sys_iommu.iommu_cr,ASI_NUCLEUS,(IOMMUCR_TSB1K|IOMMUCR_8KPG|IOMMUCR_EN)); 619 stxa(&sc->sc_sysio->sys_iommu.iommu_tsb,ASI_NUCLEUS,sc->sc_ptsb); 620 #endif 621 } 622 623 /* 624 * Here are the iommu control routines. 625 */ 626 void 627 upa_enter(va, pa) 628 vaddr_t va; 629 paddr_t pa; 630 { 631 struct upa_softc *sc = upa_sc; 632 int64_t tte; 633 634 #ifdef DIAGNOSTIC 635 if (va < sc->sc_dvmabase) 636 panic("upa_enter: va 0x%x not in DVMA space",va); 637 #endif 638 639 #if 1 640 /* Streaming */ 641 tte = MAKEIOTTE(pa, 1, 1, 1); 642 #else 643 /* Consistent */ 644 tte = MAKEIOTTE(pa, 1, 1, 0); 645 #endif 646 647 sc->sc_tsb[IOTSBSLOT(va,sc->sc_tsbsize)] = tte; 648 #if 0 649 sc->sc_sysio->sys_iommu.iommu_flush = va; 650 #else 651 stxa(&sc->sc_sysio->sys_iommu.iommu_flush,ASI_NUCLEUS,va); 652 #endif 653 #ifdef DEBUG_1 654 printf("upa_enter: added xlation va %x pa %x:%x TSB[%x]=%x:%x\n", 655 va, (int)(pa>>32), (int)pa, IOTSBSLOT(va,sc->sc_tsbsize), (int)(tte>>32), (int)tte); 656 #endif 657 } 658 /* 659 * upa_clear: clears mappings created by upa_enter 660 */ 661 void 662 upa_remove(va, len) 663 register vaddr_t va; 664 register u_int len; 665 { 666 register struct upa_softc *sc = upa_sc; 667 668 #ifdef DIAGNOSTIC 669 if (va < sc->sc_dvmabase) 670 panic("upa_remove: va 0x%x not in DVMA space", va); 671 #endif 672 673 while (len > 0) { 674 static volatile int flushdone; 675 int flushtimeout; 676 extern u_int ksegv; 677 extern u_int64_t ksegp; 678 679 /* 680 * Streaming buffer flushes: 681 * 682 * 1 Tell strbuf to flush by storing va to strbuf_pgflush 683 * If we're not on a cache line boundary (64-bits): 684 * 2 Store 0 in flag 685 * 3 Store pointer to flag in flushsync 686 * 4 wait till flushsync becomes 0x1 687 * 688 * If it takes more than .5 sec, something went wrong. 689 */ 690 #if 0 691 sc->sc_sysio->sys_strbuf.strbuf_pgflush = va; 692 #else 693 stxa(&(sc->sc_sysio->sys_strbuf.strbuf_pgflush), ASI_NUCLEUS, va); 694 #endif 695 if( len < NBPG && ((va+len) & 0x3f) ) { 696 flushdone = 0; 697 /* 698 * KLUGE ALERT KLUGE ALERT 699 * 700 * In order not to bother with pmap_extract() to do the vtop 701 * translation, flushdone is a static variable that resides in 702 * the kernel's 4MB locked TTE. This means that this routine 703 * is NOT re-entrant. Since we're single-threaded and poll 704 * on this value, this is currently not a problem. 705 */ 706 #ifdef DEBUG_1 707 printf("upa_remove: flush = %x at va = %x pa = %x\n", flushdone, &flushdone, (long)(((long)&flushdone) - ksegv + ksegp)); 708 #endif 709 #if 0 710 sc->sc_sysio->sys_strbuf.strbuf_flushsync = (long)(((long)&flushdone) - ksegv + ksegp); 711 #else 712 stxa(&sc->sc_sysio->sys_strbuf.strbuf_flushsync, ASI_NUCLEUS, (long)(((long)&flushdone) - ksegv + ksegp)); 713 #endif 714 flushtimeout = 250000000; /* 1 sec on a 250MHz machine */ 715 while( !flushdone && flushtimeout--) membar_sync(); 716 #ifdef DIAGNOSTIC 717 if( !flushdone ) 718 printf("upa_remove: flush timeout %x at %x\n", flushdone, (long)(((long)&flushdone) - ksegv + ksegp)); /* panic? */ 719 #endif 720 } 721 sc->sc_tsb[IOTSBSLOT(va,sc->sc_tsbsize)] = 0; 722 #if 0 723 sc->sc_sysio->sys_iommu.iommu_flush = va; 724 #else 725 stxa(&sc->sc_sysio->sys_iommu.iommu_flush, ASI_NUCLEUS, va); 726 #endif 727 len -= NBPG; 728 va += NBPG; 729 } 730 } 731 732 733 /* 734 * Get interrupt attributes for an Upa device. 735 */ 736 int 737 upa_get_intr(sc, node, ip) 738 struct upa_softc *sc; 739 int node; 740 int *ip; 741 { 742 struct rom_intr *rip; 743 int *ipl; 744 int n; 745 746 /* 747 * The `interrupts' property contains the Upa interrupt level. 748 */ 749 ipl = NULL; 750 if (PROM_getprop(node, "interrupts", sizeof(int), &n, (void **)&ipl) == 0) { 751 *ip = ipl[0]; 752 free(ipl, M_DEVBUF); 753 return (0); 754 } 755 756 /* 757 * Fall back on `intr' property. 758 */ 759 rip = NULL; 760 switch (PROM_getprop(node, "intr", sizeof(*rip), &n, (void **)&rip)) { 761 case 0: 762 *ip = (rip[0].int_pri & 0xf) | UPA_INTR_COMPAT; 763 free(rip, M_DEVBUF); 764 return (0); 765 case ENOENT: 766 *ip = 0; 767 return (0); 768 } 769 770 return (-1); 771 } 772 773 774 /* 775 * Install an interrupt handler for an Upa device. 776 */ 777 void * 778 upa_intr_establish(t, level, flags, handler, arg) 779 bus_space_tag_t t; 780 int level; 781 int flags; 782 int (*handler) __P((void *)); 783 void *arg; 784 { 785 struct upa_softc *sc = t->cookie; 786 struct intrhand *ih; 787 int ipl; 788 789 ih = (struct intrhand *) 790 malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT); 791 if (ih == NULL) 792 return (NULL); 793 794 if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) != 0) 795 ipl = level; 796 else if ((level & UPA_INTR_COMPAT) != 0) 797 ipl = level & ~UPA_INTR_COMPAT; 798 else 799 ipl = sc->sc_intr2ipl[level]; 800 801 ih->ih_fun = handler; 802 ih->ih_arg = arg; 803 intr_establish(ipl, ih); 804 return (ih); 805 } 806 807 static bus_space_tag_t 808 upa_alloc_bustag(sc) 809 struct upa_softc *sc; 810 { 811 bus_space_tag_t sbt; 812 813 sbt = (bus_space_tag_t) 814 malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT); 815 if (sbt == NULL) 816 return (NULL); 817 818 bzero(sbt, sizeof *sbt); 819 sbt->cookie = sc; 820 sbt->parent = sc->sc_bustag; 821 sbt->sparc_bus_map = _upa_bus_map; 822 sbt->sparc_bus_mmap = upa_bus_mmap; 823 sbt->sparc_intr_establish = upa_intr_establish; 824 return (sbt); 825 } 826