1 /* $NetBSD: ofw_machdep.c,v 1.51 2022/05/14 07:11:23 hgutch Exp $ */ 2 3 /* 4 * Copyright (C) 1996 Wolfgang Solfrank. 5 * Copyright (C) 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "opt_multiprocessor.h" 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: ofw_machdep.c,v 1.51 2022/05/14 07:11:23 hgutch Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/buf.h> 41 #include <sys/conf.h> 42 #include <sys/device.h> 43 #include <sys/disk.h> 44 #include <sys/disklabel.h> 45 #include <sys/fcntl.h> 46 #include <sys/ioctl.h> 47 #include <sys/kprintf.h> 48 #include <sys/malloc.h> 49 #include <sys/stat.h> 50 #include <sys/systm.h> 51 52 #include <machine/openfirm.h> 53 #include <machine/promlib.h> 54 55 #include <dev/ofw/ofw_pci.h> 56 57 #include <machine/sparc64.h> 58 59 static u_int mmuh = -1, memh = -1; 60 61 static u_int get_mmu_handle(void); 62 static u_int get_memory_handle(void); 63 64 static u_int 65 get_mmu_handle(void) 66 { 67 u_int chosen; 68 69 if ((chosen = OF_finddevice("/chosen")) == -1) { 70 prom_printf("get_mmu_handle: cannot get /chosen\n"); 71 return -1; 72 } 73 if (OF_getprop(chosen, "mmu", &mmuh, sizeof(mmuh)) == -1) { 74 prom_printf("get_mmu_handle: cannot get mmuh\n"); 75 return -1; 76 } 77 return mmuh; 78 } 79 80 static u_int 81 get_memory_handle(void) 82 { 83 u_int chosen; 84 85 if ((chosen = OF_finddevice("/chosen")) == -1) { 86 prom_printf("get_memory_handle: cannot get /chosen\n"); 87 return -1; 88 } 89 if (OF_getprop(chosen, "memory", &memh, sizeof(memh)) == -1) { 90 prom_printf("get_memory_handle: cannot get memh\n"); 91 return -1; 92 } 93 return memh; 94 } 95 96 97 /* 98 * Point prom to our sun4u trap table. This stops the prom from mapping us. 99 */ 100 int 101 prom_set_trap_table_sun4u(vaddr_t tba) 102 { 103 struct { 104 cell_t name; 105 cell_t nargs; 106 cell_t nreturns; 107 cell_t tba; 108 } args; 109 110 args.name = ADR2CELL(&"SUNW,set-trap-table"); 111 args.nargs = 1; 112 args.nreturns = 0; 113 args.tba = ADR2CELL(tba); 114 return openfirmware(&args); 115 } 116 117 #ifdef SUN4V 118 /* 119 * Point prom to our sun4v trap table. This stops the prom from mapping us. 120 */ 121 int 122 prom_set_trap_table_sun4v(vaddr_t tba, paddr_t mmfsa) 123 { 124 struct { 125 cell_t name; 126 cell_t nargs; 127 cell_t nreturns; 128 cell_t tba; 129 cell_t mmfsa; 130 } args; 131 132 args.name = ADR2CELL("SUNW,set-trap-table"); 133 args.nargs = 2; 134 args.nreturns = 0; 135 args.tba = ADR2CELL(tba); 136 args.mmfsa = ADR2CELL(mmfsa); 137 return openfirmware(&args); 138 } 139 #endif 140 141 /* 142 * Have the prom convert from virtual to physical addresses. 143 * 144 * Only works while the prom is actively mapping us. 145 */ 146 paddr_t 147 prom_vtop(vaddr_t vaddr) 148 { 149 struct { 150 cell_t name; 151 cell_t nargs; 152 cell_t nreturns; 153 cell_t method; 154 cell_t ihandle; 155 cell_t vaddr; 156 cell_t status; 157 cell_t retaddr; 158 cell_t mode; 159 cell_t phys_hi; 160 cell_t phys_lo; 161 } args; 162 163 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 164 prom_printf("prom_vtop: cannot get mmuh\n"); 165 return 0; 166 } 167 args.name = ADR2CELL(&"call-method"); 168 args.nargs = 3; 169 args.nreturns = 5; 170 args.method = ADR2CELL(&"translate"); 171 args.ihandle = HDL2CELL(mmuh); 172 args.vaddr = ADR2CELL(vaddr); 173 if (openfirmware(&args) == -1) 174 return -1; 175 #if 0 176 prom_printf("Called \"translate\", mmuh=%x, vaddr=%x, status=%x %x,\n retaddr=%x %x, mode=%x %x, phys_hi=%x %x, phys_lo=%x %x\n", 177 mmuh, vaddr, (int)(args.status>>32), (int)args.status, (int)(args.retaddr>>32), (int)args.retaddr, 178 (int)(args.mode>>32), (int)args.mode, (int)(args.phys_hi>>32), (int)args.phys_hi, 179 (int)(args.phys_lo>>32), (int)args.phys_lo); 180 #endif 181 return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo); 182 } 183 184 /* 185 * Grab some address space from the prom 186 * 187 * Only works while the prom is actively mapping us. 188 */ 189 vaddr_t 190 prom_claim_virt(vaddr_t vaddr, int len) 191 { 192 struct { 193 cell_t name; 194 cell_t nargs; 195 cell_t nreturns; 196 cell_t method; 197 cell_t ihandle; 198 cell_t align; 199 cell_t len; 200 cell_t vaddr; 201 cell_t status; 202 cell_t retaddr; 203 } args; 204 205 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 206 prom_printf("prom_claim_virt: cannot get mmuh\n"); 207 return 0; 208 } 209 args.name = ADR2CELL(&"call-method"); 210 args.nargs = 5; 211 args.nreturns = 2; 212 args.method = ADR2CELL(&"claim"); 213 args.ihandle = HDL2CELL(mmuh); 214 args.align = 0; 215 args.len = len; 216 args.vaddr = ADR2CELL(vaddr); 217 if (openfirmware(&args) == -1) 218 return -1; 219 return (vaddr_t)args.retaddr; 220 } 221 222 /* 223 * Request some address space from the prom 224 * 225 * Only works while the prom is actively mapping us. 226 */ 227 vaddr_t 228 prom_alloc_virt(int len, int align) 229 { 230 struct { 231 cell_t name; 232 cell_t nargs; 233 cell_t nreturns; 234 cell_t method; 235 cell_t ihandle; 236 cell_t align; 237 cell_t len; 238 cell_t status; 239 cell_t retaddr; 240 } args; 241 242 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 243 prom_printf("prom_alloc_virt: cannot get mmuh\n"); 244 return -1LL; 245 } 246 args.name = ADR2CELL(&"call-method"); 247 args.nargs = 4; 248 args.nreturns = 2; 249 args.method = ADR2CELL(&"claim"); 250 args.ihandle = HDL2CELL(mmuh); 251 args.align = align; 252 args.len = len; 253 if (openfirmware(&args) != 0) 254 return -1; 255 return (vaddr_t)args.retaddr; 256 } 257 258 /* 259 * Release some address space to the prom 260 * 261 * Only works while the prom is actively mapping us. 262 */ 263 int 264 prom_free_virt(vaddr_t vaddr, int len) 265 { 266 struct { 267 cell_t name; 268 cell_t nargs; 269 cell_t nreturns; 270 cell_t method; 271 cell_t ihandle; 272 cell_t len; 273 cell_t vaddr; 274 } args; 275 276 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 277 prom_printf("prom_free_virt: cannot get mmuh\n"); 278 return -1; 279 } 280 args.name = ADR2CELL(&"call-method"); 281 args.nargs = 4; 282 args.nreturns = 0; 283 args.method = ADR2CELL(&"release"); 284 args.ihandle = HDL2CELL(mmuh); 285 args.vaddr = ADR2CELL(vaddr); 286 args.len = len; 287 return openfirmware(&args); 288 } 289 290 291 /* 292 * Unmap some address space 293 * 294 * Only works while the prom is actively mapping us. 295 */ 296 int 297 prom_unmap_virt(vaddr_t vaddr, int len) 298 { 299 struct { 300 cell_t name; 301 cell_t nargs; 302 cell_t nreturns; 303 cell_t method; 304 cell_t ihandle; 305 cell_t len; 306 cell_t vaddr; 307 } args; 308 309 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 310 prom_printf("prom_unmap_virt: cannot get mmuh\n"); 311 return -1; 312 } 313 args.name = ADR2CELL(&"call-method"); 314 args.nargs = 4; 315 args.nreturns = 0; 316 args.method = ADR2CELL(&"unmap"); 317 args.ihandle = HDL2CELL(mmuh); 318 args.vaddr = ADR2CELL(vaddr); 319 args.len = len; 320 return openfirmware(&args); 321 } 322 323 /* 324 * Have prom map in some memory 325 * 326 * Only works while the prom is actively mapping us. 327 */ 328 int 329 prom_map_phys(paddr_t paddr, off_t size, vaddr_t vaddr, int mode) 330 { 331 struct { 332 cell_t name; 333 cell_t nargs; 334 cell_t nreturns; 335 cell_t method; 336 cell_t ihandle; 337 cell_t mode; 338 cell_t size; 339 cell_t vaddr; 340 cell_t phys_hi; 341 cell_t phys_lo; 342 } args; 343 344 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 345 prom_printf("prom_map_phys: cannot get mmuh\n"); 346 return 0; 347 } 348 args.name = ADR2CELL(&"call-method"); 349 args.nargs = 7; 350 args.nreturns = 0; 351 args.method = ADR2CELL(&"map"); 352 args.ihandle = HDL2CELL(mmuh); 353 args.mode = mode; 354 args.size = size; 355 args.vaddr = ADR2CELL(vaddr); 356 args.phys_hi = HDQ2CELL_HI(paddr); 357 args.phys_lo = HDQ2CELL_LO(paddr); 358 359 if (openfirmware(&args) == -1) 360 return -1; 361 return 0; 362 } 363 364 365 /* 366 * Request some RAM from the prom 367 * 368 * Only works while the prom is actively mapping us. 369 */ 370 paddr_t 371 prom_alloc_phys(int len, int align) 372 { 373 struct { 374 cell_t name; 375 cell_t nargs; 376 cell_t nreturns; 377 cell_t method; 378 cell_t ihandle; 379 cell_t align; 380 cell_t len; 381 cell_t status; 382 cell_t phys_hi; 383 cell_t phys_lo; 384 } args; 385 386 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 387 prom_printf("prom_alloc_phys: cannot get memh\n"); 388 return -1; 389 } 390 args.name = ADR2CELL(&"call-method"); 391 args.nargs = 4; 392 args.nreturns = 3; 393 args.method = ADR2CELL(&"claim"); 394 args.ihandle = HDL2CELL(memh); 395 args.align = align; 396 args.len = len; 397 if (openfirmware(&args) != 0) 398 return -1; 399 return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo); 400 } 401 402 /* 403 * Request some specific RAM from the prom 404 * 405 * Only works while the prom is actively mapping us. 406 */ 407 paddr_t 408 prom_claim_phys(paddr_t phys, int len) 409 { 410 struct { 411 cell_t name; 412 cell_t nargs; 413 cell_t nreturns; 414 cell_t method; 415 cell_t ihandle; 416 cell_t align; 417 cell_t len; 418 cell_t phys_hi; 419 cell_t phys_lo; 420 cell_t status; 421 cell_t rphys_hi; 422 cell_t rphys_lo; 423 } args; 424 425 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 426 prom_printf("prom_claim_phys: cannot get memh\n"); 427 return -1; 428 } 429 args.name = ADR2CELL(&"call-method"); 430 args.nargs = 6; 431 args.nreturns = 3; 432 args.method = ADR2CELL(&"claim"); 433 args.ihandle = HDL2CELL(memh); 434 args.align = 0; 435 args.len = len; 436 args.phys_hi = HDQ2CELL_HI(phys); 437 args.phys_lo = HDQ2CELL_LO(phys); 438 if (openfirmware(&args) != 0) 439 return -1; 440 return (paddr_t)CELL2HDQ(args.rphys_hi, args.rphys_lo); 441 } 442 443 /* 444 * Free some RAM to prom 445 * 446 * Only works while the prom is actively mapping us. 447 */ 448 int 449 prom_free_phys(paddr_t phys, int len) 450 { 451 struct { 452 cell_t name; 453 cell_t nargs; 454 cell_t nreturns; 455 cell_t method; 456 cell_t ihandle; 457 cell_t len; 458 cell_t phys_hi; 459 cell_t phys_lo; 460 } args; 461 462 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 463 prom_printf("prom_free_phys: cannot get memh\n"); 464 return -1; 465 } 466 args.name = ADR2CELL(&"call-method"); 467 args.nargs = 5; 468 args.nreturns = 0; 469 args.method = ADR2CELL(&"release"); 470 args.ihandle = HDL2CELL(memh); 471 args.len = len; 472 args.phys_hi = HDQ2CELL_HI(phys); 473 args.phys_lo = HDQ2CELL_LO(phys); 474 return openfirmware(&args); 475 } 476 477 /* 478 * Get the msgbuf from the prom. Only works once. 479 * 480 * Only works while the prom is actively mapping us. 481 */ 482 paddr_t 483 prom_get_msgbuf(int len, int align) 484 { 485 struct { 486 cell_t name; 487 cell_t nargs; 488 cell_t nreturns; 489 cell_t method; 490 cell_t ihandle; 491 cell_t align; 492 cell_t len; 493 cell_t id; 494 cell_t status; 495 cell_t phys_hi; 496 cell_t phys_lo; 497 } args; 498 paddr_t addr; 499 500 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 501 prom_printf("prom_get_msgbuf: cannot get memh\n"); 502 return -1; 503 } 504 if (OF_test("test-method") == 0) { 505 if (OF_test_method(OF_instance_to_package(memh), 506 "SUNW,retain") == 0) { 507 args.name = ADR2CELL(&"call-method"); 508 args.nargs = 5; 509 args.nreturns = 3; 510 args.method = ADR2CELL(&"SUNW,retain"); 511 args.id = ADR2CELL(&"msgbuf"); 512 args.ihandle = HDL2CELL(memh); 513 args.len = len; 514 args.align = align; 515 args.status = -1; 516 if (openfirmware(&args) == 0 && args.status == 0) { 517 return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo); 518 } else prom_printf("prom_get_msgbuf: SUNW,retain failed\n"); 519 } else prom_printf("prom_get_msgbuf: test-method failed\n"); 520 } else prom_printf("prom_get_msgbuf: test failed\n"); 521 /* Allocate random memory -- page zero avail?*/ 522 addr = prom_claim_phys(0x000, len); 523 prom_printf("prom_get_msgbuf: allocated new buf at %08x\n", (int)addr); 524 if (addr == -1) { 525 prom_printf("prom_get_msgbuf: cannot get allocate physmem\n"); 526 return -1; 527 } 528 prom_printf("prom_get_msgbuf: claiming new buf at %08x\n", (int)addr); 529 { int i; for (i=0; i<200000000; i++); } 530 return addr; /* Kluge till we go 64-bit */ 531 } 532 533 #ifdef MULTIPROCESSOR 534 /* 535 * Start secondary cpu identified by node, arrange 'func' as the entry. 536 */ 537 void 538 prom_startcpu(u_int cpu, void *func, u_long arg) 539 { 540 static struct { 541 cell_t name; 542 cell_t nargs; 543 cell_t nreturns; 544 cell_t cpu; 545 cell_t func; 546 cell_t arg; 547 } args; 548 549 args.name = ADR2CELL(&"SUNW,start-cpu"); 550 args.nargs = 3; 551 args.nreturns = 0; 552 args.cpu = cpu; 553 args.func = (cell_t)(u_long)func; 554 args.arg = (cell_t)arg; 555 556 openfirmware(&args); 557 } 558 559 /* 560 * Start secondary cpu identified by cpuid, arrange 'func' as the entry. 561 * Returns -1 in case the openfirmware method is not available. 562 * Otherwise the result value from the openfirmware call is returned. 563 */ 564 int 565 prom_startcpu_by_cpuid(u_int cpu, void *func, u_long arg) 566 { 567 static struct { 568 cell_t name; 569 cell_t nargs; 570 cell_t nreturns; 571 cell_t cpu; 572 cell_t func; 573 cell_t arg; 574 cell_t status; 575 } args; 576 577 if (OF_test("SUNW,start-cpu-by-cpuid") != 0) 578 return -1; 579 580 args.name = ADR2CELL("SUNW,start-cpu-by-cpuid"); 581 args.nargs = 3; 582 args.nreturns = 1; 583 args.cpu = cpu; 584 args.func = ADR2CELL(func); 585 args.arg = arg; 586 587 return openfirmware(&args); 588 } 589 590 /* 591 * Stop the calling cpu. 592 */ 593 void 594 prom_stopself(void) 595 { 596 extern void openfirmware_exit(void*); 597 static struct { 598 cell_t name; 599 cell_t nargs; 600 cell_t nreturns; 601 } args; 602 603 args.name = ADR2CELL(&"SUNW,stop-self"); 604 args.nargs = 0; 605 args.nreturns = 0; 606 607 openfirmware_exit(&args); 608 panic("prom_stopself: failed."); 609 } 610 611 bool 612 prom_has_stopself(void) 613 { 614 return OF_test("SUNW,stop-self") == 0; 615 } 616 617 int 618 prom_stop_other(u_int id) 619 { 620 static struct { 621 cell_t name; 622 cell_t nargs; 623 cell_t nreturns; 624 cell_t cpuid; 625 cell_t result; 626 } args; 627 628 args.name = ADR2CELL(&"SUNW,stop-cpu-by-cpuid"); 629 args.nargs = 1; 630 args.nreturns = 1; 631 args.cpuid = id; 632 args.result = 0; 633 634 if (openfirmware(&args) == -1) 635 return -1; 636 return args.result; 637 } 638 639 bool 640 prom_has_stop_other(void) 641 { 642 return OF_test("SUNW,stop-cpu-by-cpuid") == 0; 643 } 644 #endif 645 646 uint64_t 647 prom_set_sun4v_api_version(uint64_t api_group, uint64_t major, 648 uint64_t minor, uint64_t *supported_minor) 649 { 650 static struct { 651 cell_t name; 652 cell_t nargs; 653 cell_t nreturns; 654 cell_t api_group; 655 cell_t major; 656 cell_t minor; 657 cell_t status; 658 cell_t supported_minor; 659 } args; 660 661 args.name = ADR2CELL("SUNW,set-sun4v-api-version"); 662 args.nargs = 3; 663 args.nreturns = 2; 664 args.api_group = api_group; 665 args.major = major; 666 args.minor = minor; 667 args.status = -1; 668 args.supported_minor = -1; 669 670 openfirmware(&args); 671 672 *supported_minor = args.supported_minor; 673 return (uint64_t)args.status; 674 } 675 #if 1 676 uint64_t 677 prom_get_sun4v_api_version(uint64_t api_group, uint64_t* major, uint64_t* minor) 678 { 679 static struct { 680 cell_t name; 681 cell_t nargs; 682 cell_t nreturns; 683 cell_t api_group; 684 cell_t status; 685 cell_t major; 686 cell_t minor; 687 } args; 688 689 args.name = ADR2CELL("SUNW,get-sun4v-api-version"); 690 args.nargs = 1; 691 args.nreturns = 3; 692 args.api_group = api_group; 693 args.status = -1; 694 args.major = -1; 695 args.minor = -1; 696 697 openfirmware(&args); 698 699 *major = args.major; 700 *minor = args.minor; 701 return (uint64_t)args.status; 702 } 703 #endif 704 void 705 prom_sun4v_soft_state_supported(void) 706 { 707 static struct { 708 cell_t name; 709 cell_t nargs; 710 cell_t nreturns; 711 } args; 712 713 args.name = ADR2CELL("SUNW,soft-state-supported"); 714 args.nargs = 0; 715 args.nreturns = 0; 716 717 openfirmware(&args); 718 } 719 720 #ifdef DEBUG 721 int ofmapintrdebug = 0; 722 #define DPRINTF(x) if (ofmapintrdebug) printf x 723 #else 724 #define DPRINTF(x) 725 #endif 726 727 728 /* 729 * Recursively hunt for a property. 730 */ 731 int 732 OF_searchprop(int node, const char *prop, void *sbuf, int buflen) 733 { 734 int len; 735 736 for( ; node; node = OF_parent(node)) { 737 len = OF_getprop(node, prop, sbuf, buflen); 738 if (len >= 0) 739 return (len); 740 } 741 /* Error -- not found */ 742 return (-1); 743 } 744 745 746 /* 747 * Compare a sequence of cells with a mask, 748 * return 1 if they match and 0 if they don't. 749 */ 750 static int compare_cells (int *cell1, int *cell2, int *mask, int ncells); 751 static int 752 compare_cells(int *cell1, int *cell2, int *mask, int ncells) 753 { 754 int i; 755 756 for (i=0; i<ncells; i++) { 757 DPRINTF(("src %x ^ dest %x -> %x & mask %x -> %x\n", 758 cell1[i], cell2[i], (cell1[i] ^ cell2[i]), 759 mask[i], ((cell1[i] ^ cell2[i]) & mask[i]))); 760 if (((cell1[i] ^ cell2[i]) & mask[i]) != 0) 761 return (0); 762 } 763 return (1); 764 } 765 766 /* 767 * Find top pci bus host controller for a node. 768 */ 769 static int 770 find_pci_host_node(int node) 771 { 772 char dev_type[16]; 773 int pch = 0; 774 int len; 775 776 for (; node; node = OF_parent(node)) { 777 len = OF_getprop(node, "device_type", 778 &dev_type, sizeof(dev_type)); 779 if (len <= 0) 780 continue; 781 if (!strcmp(dev_type, "pci") || 782 !strcmp(dev_type, "pciex")) 783 pch = node; 784 } 785 return pch; 786 } 787 788 /* 789 * Follow the OFW algorithm and return an interrupt specifier. 790 * 791 * Pass in the interrupt specifier you want mapped and the node 792 * you want it mapped from. validlen is the number of cells in 793 * the interrupt specifier, and buflen is the number of cells in 794 * the buffer. 795 */ 796 int 797 OF_mapintr(int node, int *interrupt, int validlen, int buflen) 798 { 799 int i, len; 800 int address_cells, size_cells, interrupt_cells, interrupt_map_len; 801 int static_interrupt_map[256]; 802 int interrupt_map_mask[10]; 803 int *interrupt_map = &static_interrupt_map[0]; 804 int maplen = sizeof static_interrupt_map; 805 int *free_map = NULL; 806 int reg[10]; 807 char dev_type[32]; 808 int phc_node; 809 int rc = -1; 810 811 phc_node = find_pci_host_node(node); 812 813 /* 814 * On machines with psycho PCI controllers, we don't need to map 815 * interrupts if they are already fully specified (0x20 to 0x3f 816 * for onboard devices and IGN 0x7c0 for psycho0/psycho1). 817 */ 818 if (*interrupt & 0x20 || *interrupt & 0x7c0) { 819 char model[40]; 820 821 if (OF_getprop(phc_node, "model", &model, sizeof(model)) > 10 822 && !strcmp(model, "SUNW,psycho")) { 823 DPRINTF(("OF_mapintr: interrupt %x already mapped\n", 824 *interrupt)); 825 return validlen; 826 } 827 } 828 829 /* 830 * If there is no interrupt map in the bus node, we 831 * need to convert the slot address to its parent 832 * bus format, and hunt up the parent bus to see if 833 * we need to remap. 834 * 835 * The specification for interrupt mapping is borken. 836 * You are supposed to query the interrupt parent in 837 * the interrupt-map specification to determine the 838 * number of address and interrupt cells, but we need 839 * to know how many address and interrupt cells to skip 840 * to find the phandle... 841 * 842 */ 843 if ((len = OF_getprop(node, "reg", ®, sizeof(reg))) <= 0) { 844 printf("OF_mapintr: no reg property?\n"); 845 return (-1); 846 } 847 848 while (node) { 849 #ifdef DEBUG 850 char name[40]; 851 852 if (ofmapintrdebug) { 853 OF_getprop(node, "name", &name, sizeof(name)); 854 printf("Node %s (%x), host %x\n", name, 855 node, phc_node); 856 } 857 #endif 858 859 retry_map: 860 if ((interrupt_map_len = OF_getprop(node, 861 "interrupt-map", interrupt_map, maplen)) <= 0) { 862 863 /* Swizzle interrupt if this is a PCI bridge. */ 864 if (((len = OF_getprop(node, "device_type", &dev_type, 865 sizeof(dev_type))) > 0) && 866 (!strcmp(dev_type, "pci") || 867 !strcmp(dev_type, "pciex")) && 868 (node != phc_node)) { 869 #ifdef DEBUG 870 int ointerrupt = *interrupt; 871 #endif 872 873 *interrupt = ((*interrupt + 874 OFW_PCI_PHYS_HI_DEVICE(reg[0]) - 1) & 3) + 1; 875 DPRINTF(("OF_mapintr: interrupt %x -> %x, reg[0] %x\n", 876 ointerrupt, *interrupt, reg[0])); 877 } 878 879 /* Get reg for next level compare. */ 880 reg[0] = 0; 881 OF_getprop(node, "reg", ®, sizeof(reg)); 882 883 node = OF_parent(node); 884 continue; 885 } 886 if (interrupt_map_len > maplen) { 887 DPRINTF(("interrupt_map_len %d > maplen %d, " 888 "allocating\n", interrupt_map_len, maplen)); 889 KASSERT(!free_map); 890 free_map = malloc(interrupt_map_len, M_DEVBUF, 891 M_NOWAIT); 892 if (!free_map) { 893 interrupt_map_len = sizeof static_interrupt_map; 894 } else { 895 interrupt_map = free_map; 896 maplen = interrupt_map_len; 897 goto retry_map; 898 } 899 } 900 /* Convert from bytes to cells. */ 901 interrupt_map_len = interrupt_map_len/sizeof(int); 902 if ((len = (OF_searchprop(node, "#address-cells", 903 &address_cells, sizeof(address_cells)))) <= 0) { 904 /* How should I know. */ 905 address_cells = 2; 906 } 907 DPRINTF(("#address-cells = %d len %d ", address_cells, len)); 908 if ((len = OF_searchprop(node, "#size-cells", &size_cells, 909 sizeof(size_cells))) <= 0) { 910 /* How should I know. */ 911 size_cells = 2; 912 } 913 DPRINTF(("#size-cells = %d len %d ", size_cells, len)); 914 if ((len = OF_getprop(node, "#interrupt-cells", &interrupt_cells, 915 sizeof(interrupt_cells))) <= 0) { 916 /* How should I know. */ 917 interrupt_cells = 1; 918 } 919 DPRINTF(("#interrupt-cells = %d, len %d\n", interrupt_cells, 920 len)); 921 if ((len = OF_getprop(node, "interrupt-map-mask", &interrupt_map_mask, 922 sizeof(interrupt_map_mask))) <= 0) { 923 /* Create a mask that masks nothing. */ 924 for (i = 0; i<(address_cells + interrupt_cells); i++) 925 interrupt_map_mask[i] = -1; 926 } 927 #ifdef DEBUG 928 DPRINTF(("interrupt-map-mask len %d = ", len)); 929 for (i=0; i<(address_cells + interrupt_cells); i++) 930 DPRINTF(("%x.", interrupt_map_mask[i])); 931 DPRINTF(("reg = ")); 932 for (i=0; i<(address_cells); i++) 933 DPRINTF(("%x.", reg[i])); 934 DPRINTF(("interrupts = ")); 935 for (i=0; i<(interrupt_cells); i++) 936 DPRINTF(("%x.", interrupt[i])); 937 938 #endif 939 940 /* finally we can attempt the compare */ 941 i = 0; 942 while (i < interrupt_map_len + address_cells + interrupt_cells) { 943 int pintr_cells; 944 int *imap = &interrupt_map[i]; 945 int *parent = &imap[address_cells + interrupt_cells]; 946 947 #ifdef DEBUG 948 DPRINTF(("\ninterrupt-map addr ")); 949 for (len = 0; len < address_cells; len++) 950 DPRINTF(("%x.", imap[len])); 951 DPRINTF((" intr ")); 952 for (; len < (address_cells+interrupt_cells); len++) 953 DPRINTF(("%x.", imap[len])); 954 DPRINTF(("\nnode %x vs parent %x\n", 955 imap[len], *parent)); 956 #endif 957 958 /* Find out how many cells we'll need to skip. */ 959 if ((len = OF_searchprop(*parent, "#interrupt-cells", 960 &pintr_cells, sizeof(pintr_cells))) < 0) { 961 pintr_cells = interrupt_cells; 962 } 963 DPRINTF(("pintr_cells = %d len %d\n", pintr_cells, len)); 964 965 if (compare_cells(imap, reg, 966 interrupt_map_mask, address_cells) && 967 compare_cells(&imap[address_cells], 968 interrupt, 969 &interrupt_map_mask[address_cells], 970 interrupt_cells)) 971 { 972 /* Bingo! */ 973 if (buflen < pintr_cells) { 974 /* Error -- ran out of storage. */ 975 if (free_map) 976 free(free_map, M_DEVBUF); 977 return (-1); 978 } 979 node = *parent; 980 parent++; 981 #ifdef DEBUG 982 DPRINTF(("Match! using ")); 983 for (len = 0; len < pintr_cells; len++) 984 DPRINTF(("%x.", parent[len])); 985 DPRINTF(("\n")); 986 #endif 987 for (i = 0; i < pintr_cells; i++) 988 interrupt[i] = parent[i]; 989 rc = validlen = pintr_cells; 990 if (node == phc_node) 991 return(rc); 992 break; 993 } 994 /* Move on to the next interrupt_map entry. */ 995 #ifdef DEBUG 996 DPRINTF(("skip %d cells:", 997 address_cells + interrupt_cells + 998 pintr_cells + 1)); 999 for (len = 0; len < (address_cells + 1000 interrupt_cells + pintr_cells + 1); len++) 1001 DPRINTF(("%x.", imap[len])); 1002 #endif 1003 i += address_cells + interrupt_cells + pintr_cells + 1; 1004 } 1005 1006 /* Get reg for the next level search. */ 1007 if ((len = OF_getprop(node, "reg", ®, sizeof(reg))) <= 0) { 1008 DPRINTF(("OF_mapintr: no reg property?\n")); 1009 } else { 1010 DPRINTF(("reg len %d\n", len)); 1011 } 1012 1013 if (free_map) { 1014 free(free_map, M_DEVBUF); 1015 free_map = NULL; 1016 } 1017 node = OF_parent(node); 1018 } 1019 return (rc); 1020 } 1021