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