1/* $NetBSD: ofw_machdep.c,v 1.37 2010/02/20 16:46:38 martin 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.37 2010/02/20 16:46:38 martin 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 59static u_int mmuh = -1, memh = -1; 60 61static u_int get_mmu_handle(void); 62static u_int get_memory_handle(void); 63 64static u_int 65get_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\r\n"); 71 return -1; 72 } 73 if (OF_getprop(chosen, "mmu", &mmuh, sizeof(mmuh)) == -1) { 74 prom_printf("get_mmu_handle: cannot get mmuh\r\n"); 75 return -1; 76 } 77 return mmuh; 78} 79 80static u_int 81get_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\r\n"); 87 return -1; 88 } 89 if (OF_getprop(chosen, "memory", &memh, sizeof(memh)) == -1) { 90 prom_printf("get_memory_handle: cannot get memh\r\n"); 91 return -1; 92 } 93 return memh; 94} 95 96 97/* 98 * Point prom to our trap table. This stops the prom from mapping us. 99 */ 100int 101prom_set_trap_table(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/* 118 * Have the prom convert from virtual to physical addresses. 119 * 120 * Only works while the prom is actively mapping us. 121 */ 122paddr_t 123prom_vtop(vaddr_t vaddr) 124{ 125 struct { 126 cell_t name; 127 cell_t nargs; 128 cell_t nreturns; 129 cell_t method; 130 cell_t ihandle; 131 cell_t vaddr; 132 cell_t status; 133 cell_t retaddr; 134 cell_t mode; 135 cell_t phys_hi; 136 cell_t phys_lo; 137 } args; 138 139 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 140 prom_printf("prom_vtop: cannot get mmuh\r\n"); 141 return 0; 142 } 143 args.name = ADR2CELL(&"call-method"); 144 args.nargs = 3; 145 args.nreturns = 5; 146 args.method = ADR2CELL(&"translate"); 147 args.ihandle = HDL2CELL(mmuh); 148 args.vaddr = ADR2CELL(vaddr); 149 if (openfirmware(&args) == -1) 150 return -1; 151#if 0 152 prom_printf("Called \"translate\", mmuh=%x, vaddr=%x, status=%x %x,\r\n retaddr=%x %x, mode=%x %x, phys_hi=%x %x, phys_lo=%x %x\r\n", 153 mmuh, vaddr, (int)(args.status>>32), (int)args.status, (int)(args.retaddr>>32), (int)args.retaddr, 154 (int)(args.mode>>32), (int)args.mode, (int)(args.phys_hi>>32), (int)args.phys_hi, 155 (int)(args.phys_lo>>32), (int)args.phys_lo); 156#endif 157 return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo); 158} 159 160/* 161 * Grab some address space from the prom 162 * 163 * Only works while the prom is actively mapping us. 164 */ 165vaddr_t 166prom_claim_virt(vaddr_t vaddr, int len) 167{ 168 struct { 169 cell_t name; 170 cell_t nargs; 171 cell_t nreturns; 172 cell_t method; 173 cell_t ihandle; 174 cell_t align; 175 cell_t len; 176 cell_t vaddr; 177 cell_t status; 178 cell_t retaddr; 179 } args; 180 181 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 182 prom_printf("prom_claim_virt: cannot get mmuh\r\n"); 183 return 0; 184 } 185 args.name = ADR2CELL(&"call-method"); 186 args.nargs = 5; 187 args.nreturns = 2; 188 args.method = ADR2CELL(&"claim"); 189 args.ihandle = HDL2CELL(mmuh); 190 args.align = 0; 191 args.len = len; 192 args.vaddr = ADR2CELL(vaddr); 193 if (openfirmware(&args) == -1) 194 return -1; 195 return (vaddr_t)args.retaddr; 196} 197 198/* 199 * Request some address space from the prom 200 * 201 * Only works while the prom is actively mapping us. 202 */ 203vaddr_t 204prom_alloc_virt(int len, int align) 205{ 206 struct { 207 cell_t name; 208 cell_t nargs; 209 cell_t nreturns; 210 cell_t method; 211 cell_t ihandle; 212 cell_t align; 213 cell_t len; 214 cell_t status; 215 cell_t retaddr; 216 } args; 217 218 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 219 prom_printf("prom_alloc_virt: cannot get mmuh\r\n"); 220 return -1LL; 221 } 222 args.name = ADR2CELL(&"call-method"); 223 args.nargs = 4; 224 args.nreturns = 2; 225 args.method = ADR2CELL(&"claim"); 226 args.ihandle = HDL2CELL(mmuh); 227 args.align = align; 228 args.len = len; 229 if (openfirmware(&args) != 0) 230 return -1; 231 return (vaddr_t)args.retaddr; 232} 233 234/* 235 * Release some address space to the prom 236 * 237 * Only works while the prom is actively mapping us. 238 */ 239int 240prom_free_virt(vaddr_t vaddr, int len) 241{ 242 struct { 243 cell_t name; 244 cell_t nargs; 245 cell_t nreturns; 246 cell_t method; 247 cell_t ihandle; 248 cell_t len; 249 cell_t vaddr; 250 } args; 251 252 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 253 prom_printf("prom_free_virt: cannot get mmuh\r\n"); 254 return -1; 255 } 256 args.name = ADR2CELL(&"call-method"); 257 args.nargs = 4; 258 args.nreturns = 0; 259 args.method = ADR2CELL(&"release"); 260 args.ihandle = HDL2CELL(mmuh); 261 args.vaddr = ADR2CELL(vaddr); 262 args.len = len; 263 return openfirmware(&args); 264} 265 266 267/* 268 * Unmap some address space 269 * 270 * Only works while the prom is actively mapping us. 271 */ 272int 273prom_unmap_virt(vaddr_t vaddr, int len) 274{ 275 struct { 276 cell_t name; 277 cell_t nargs; 278 cell_t nreturns; 279 cell_t method; 280 cell_t ihandle; 281 cell_t len; 282 cell_t vaddr; 283 } args; 284 285 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 286 prom_printf("prom_unmap_virt: cannot get mmuh\r\n"); 287 return -1; 288 } 289 args.name = ADR2CELL(&"call-method"); 290 args.nargs = 4; 291 args.nreturns = 0; 292 args.method = ADR2CELL(&"unmap"); 293 args.ihandle = HDL2CELL(mmuh); 294 args.vaddr = ADR2CELL(vaddr); 295 args.len = len; 296 return openfirmware(&args); 297} 298 299/* 300 * Have prom map in some memory 301 * 302 * Only works while the prom is actively mapping us. 303 */ 304int 305prom_map_phys(paddr_t paddr, off_t size, vaddr_t vaddr, int mode) 306{ 307 struct { 308 cell_t name; 309 cell_t nargs; 310 cell_t nreturns; 311 cell_t method; 312 cell_t ihandle; 313 cell_t mode; 314 cell_t size; 315 cell_t vaddr; 316 cell_t phys_hi; 317 cell_t phys_lo; 318 cell_t status; 319 cell_t retaddr; 320 } args; 321 322 if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) { 323 prom_printf("prom_map_phys: cannot get mmuh\r\n"); 324 return 0; 325 } 326 args.name = ADR2CELL(&"call-method"); 327 args.nargs = 7; 328 args.nreturns = 1; 329 args.method = ADR2CELL(&"map"); 330 args.ihandle = HDL2CELL(mmuh); 331 args.mode = mode; 332 args.size = size; 333 args.vaddr = ADR2CELL(vaddr); 334 args.phys_hi = HDQ2CELL_HI(paddr); 335 args.phys_lo = HDQ2CELL_LO(paddr); 336 337 if (openfirmware(&args) == -1) 338 return -1; 339 if (args.status) 340 return -1; 341 return (int)args.retaddr; 342} 343 344 345/* 346 * Request some RAM from the prom 347 * 348 * Only works while the prom is actively mapping us. 349 */ 350paddr_t 351prom_alloc_phys(int len, int align) 352{ 353 struct { 354 cell_t name; 355 cell_t nargs; 356 cell_t nreturns; 357 cell_t method; 358 cell_t ihandle; 359 cell_t align; 360 cell_t len; 361 cell_t status; 362 cell_t phys_hi; 363 cell_t phys_lo; 364 } args; 365 366 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 367 prom_printf("prom_alloc_phys: cannot get memh\r\n"); 368 return -1; 369 } 370 args.name = ADR2CELL(&"call-method"); 371 args.nargs = 4; 372 args.nreturns = 3; 373 args.method = ADR2CELL(&"claim"); 374 args.ihandle = HDL2CELL(memh); 375 args.align = align; 376 args.len = len; 377 if (openfirmware(&args) != 0) 378 return -1; 379 return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo); 380} 381 382/* 383 * Request some specific RAM from the prom 384 * 385 * Only works while the prom is actively mapping us. 386 */ 387paddr_t 388prom_claim_phys(paddr_t phys, int len) 389{ 390 struct { 391 cell_t name; 392 cell_t nargs; 393 cell_t nreturns; 394 cell_t method; 395 cell_t ihandle; 396 cell_t align; 397 cell_t len; 398 cell_t phys_hi; 399 cell_t phys_lo; 400 cell_t status; 401 cell_t rphys_hi; 402 cell_t rphys_lo; 403 } args; 404 405 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 406 prom_printf("prom_claim_phys: cannot get memh\r\n"); 407 return -1; 408 } 409 args.name = ADR2CELL(&"call-method"); 410 args.nargs = 6; 411 args.nreturns = 3; 412 args.method = ADR2CELL(&"claim"); 413 args.ihandle = HDL2CELL(memh); 414 args.align = 0; 415 args.len = len; 416 args.phys_hi = HDQ2CELL_HI(phys); 417 args.phys_lo = HDQ2CELL_LO(phys); 418 if (openfirmware(&args) != 0) 419 return -1; 420 return (paddr_t)CELL2HDQ(args.rphys_hi, args.rphys_lo); 421} 422 423/* 424 * Free some RAM to prom 425 * 426 * Only works while the prom is actively mapping us. 427 */ 428int 429prom_free_phys(paddr_t phys, int len) 430{ 431 struct { 432 cell_t name; 433 cell_t nargs; 434 cell_t nreturns; 435 cell_t method; 436 cell_t ihandle; 437 cell_t len; 438 cell_t phys_hi; 439 cell_t phys_lo; 440 } args; 441 442 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 443 prom_printf("prom_free_phys: cannot get memh\r\n"); 444 return -1; 445 } 446 args.name = ADR2CELL(&"call-method"); 447 args.nargs = 5; 448 args.nreturns = 0; 449 args.method = ADR2CELL(&"release"); 450 args.ihandle = HDL2CELL(memh); 451 args.len = len; 452 args.phys_hi = HDQ2CELL_HI(phys); 453 args.phys_lo = HDQ2CELL_LO(phys); 454 return openfirmware(&args); 455} 456 457/* 458 * Get the msgbuf from the prom. Only works once. 459 * 460 * Only works while the prom is actively mapping us. 461 */ 462paddr_t 463prom_get_msgbuf(int len, int align) 464{ 465 struct { 466 cell_t name; 467 cell_t nargs; 468 cell_t nreturns; 469 cell_t method; 470 cell_t ihandle; 471 cell_t align; 472 cell_t len; 473 cell_t id; 474 cell_t status; 475 cell_t phys_hi; 476 cell_t phys_lo; 477 } args; 478 paddr_t addr; 479 int rooth; 480 int is_e250 = 1; 481 482 /* E250s and E450s tend to have buggy PROMs that break on test-method */ 483 /* XXX - need to find the reason why this breaks someday */ 484 if ((rooth = OF_finddevice("/")) != -1) { 485 char name[80]; 486 487 if ((OF_getprop(rooth, "name", &name, sizeof(name))) != -1) { 488 if (strcmp(name, "SUNW,Ultra-250") 489 && strcmp(name, "SUNW,Ultra-4")) 490 is_e250 = 0; 491 } else prom_printf("prom_get_msgbuf: cannot get \"name\"\r\n"); 492 } else prom_printf("prom_get_msgbuf: cannot open root device \r\n"); 493 494 if (memh == -1 && ((memh = get_memory_handle()) == -1)) { 495 prom_printf("prom_get_msgbuf: cannot get memh\r\n"); 496 return -1; 497 } 498 if (is_e250) { 499 prom_printf("prom_get_msgbuf: Cannot recover msgbuf on E250\r\n"); 500 } else if (OF_test("test-method") == 0) { 501 if (OF_test_method(memh, "SUNW,retain") != 0) { 502 args.name = ADR2CELL(&"call-method"); 503 args.nargs = 5; 504 args.nreturns = 3; 505 args.method = ADR2CELL(&"SUNW,retain"); 506 args.id = ADR2CELL(&"msgbuf"); 507 args.ihandle = HDL2CELL(memh); 508 args.len = len; 509 args.align = align; 510 args.status = -1; 511 if (openfirmware(&args) == 0 && args.status == 0) { 512 return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo); 513 } else prom_printf("prom_get_msgbuf: SUNW,retain failed\r\n"); 514 } else prom_printf("prom_get_msgbuf: test-method failed\r\n"); 515 } else prom_printf("prom_get_msgbuf: test failed\r\n"); 516 /* Allocate random memory -- page zero avail?*/ 517 addr = prom_claim_phys(0x000, len); 518 prom_printf("prom_get_msgbuf: allocated new buf at %08x\r\n", (int)addr); 519 if (addr == -1) { 520 prom_printf("prom_get_msgbuf: cannot get allocate physmem\r\n"); 521 return -1; 522 } 523 prom_printf("prom_get_msgbuf: claiming new buf at %08x\r\n", (int)addr); 524 { int i; for (i=0; i<200000000; i++); } 525 return addr; /* Kluge till we go 64-bit */ 526} 527 528#ifdef MULTIPROCESSOR 529/* 530 * Start secondary cpu, arrange 'func' as the entry. 531 */ 532void 533prom_startcpu(u_int cpu, void *func, u_long arg) 534{ 535 static struct { 536 cell_t name; 537 cell_t nargs; 538 cell_t nreturns; 539 cell_t cpu; 540 cell_t func; 541 cell_t arg; 542 } args; 543 544 args.name = ADR2CELL(&"SUNW,start-cpu"); 545 args.nargs = 3; 546 args.nreturns = 0; 547 args.cpu = cpu; 548 args.func = (cell_t)(u_long)func; 549 args.arg = (cell_t)arg; 550 551 openfirmware(&args); 552} 553 554/* 555 * Stop the calling cpu. 556 */ 557void 558prom_stopself(void) 559{ 560 extern void openfirmware_exit(void*); 561 static struct { 562 cell_t name; 563 cell_t nargs; 564 cell_t nreturns; 565 } args; 566 567 args.name = ADR2CELL(&"SUNW,stop-self"); 568 args.nargs = 0; 569 args.nreturns = 0; 570 571 openfirmware_exit(&args); 572 panic("prom_stopself: failed."); 573} 574 575bool 576prom_has_stopself(void) 577{ 578 return OF_test("SUNW,stop-self") == 0; 579} 580 581int 582prom_stop_other(u_int id) 583{ 584 static struct { 585 cell_t name; 586 cell_t nargs; 587 cell_t nreturns; 588 cell_t cpuid; 589 cell_t result; 590 } args; 591 592 args.name = ADR2CELL(&"SUNW,stop-cpu-by-cpuid"); 593 args.nargs = 1; 594 args.nreturns = 1; 595 args.cpuid = id; 596 args.result = 0; 597 598 if (openfirmware(&args) == -1) 599 return -1; 600 return args.result; 601} 602 603bool 604prom_has_stop_other(void) 605{ 606 return OF_test("SUNW,stop-cpu-by-cpuid") == 0; 607} 608#endif 609 610#ifdef DEBUG 611int ofmapintrdebug = 0; 612#define DPRINTF(x) if (ofmapintrdebug) printf x 613#else 614#define DPRINTF(x) 615#endif 616 617 618/* 619 * Recursively hunt for a property. 620 */ 621int 622OF_searchprop(int node, const char *prop, void *sbuf, int buflen) 623{ 624 int len; 625 626 for( ; node; node = OF_parent(node)) { 627 len = OF_getprop(node, prop, sbuf, buflen); 628 if (len >= 0) 629 return (len); 630 } 631 /* Error -- not found */ 632 return (-1); 633} 634 635 636/* 637 * Compare a sequence of cells with a mask, 638 * return 1 if they match and 0 if they don't. 639 */ 640static int compare_cells (int *cell1, int *cell2, int *mask, int ncells); 641static int 642compare_cells(int *cell1, int *cell2, int *mask, int ncells) 643{ 644 int i; 645 646 for (i=0; i<ncells; i++) { 647 DPRINTF(("src %x ^ dest %x -> %x & mask %x -> %x\n", 648 cell1[i], cell2[i], (cell1[i] ^ cell2[i]), 649 mask[i], ((cell1[i] ^ cell2[i]) & mask[i]))); 650 if (((cell1[i] ^ cell2[i]) & mask[i]) != 0) 651 return (0); 652 } 653 return (1); 654} 655 656/* 657 * Find top pci bus host controller for a node. 658 */ 659static int 660find_pci_host_node(int node) 661{ 662 char dev_type[16]; 663 int pch = 0; 664 int len; 665 666 for (; node; node = OF_parent(node)) { 667 len = OF_getprop(node, "device_type", 668 &dev_type, sizeof(dev_type)); 669 if (len <= 0) 670 continue; 671 if (!strcmp(dev_type, "pci")) 672 pch = node; 673 } 674 return pch; 675} 676 677/* 678 * Follow the OFW algorithm and return an interrupt specifier. 679 * 680 * Pass in the interrupt specifier you want mapped and the node 681 * you want it mapped from. validlen is the number of cells in 682 * the interrupt specifier, and buflen is the number of cells in 683 * the buffer. 684 */ 685int 686OF_mapintr(int node, int *interrupt, int validlen, int buflen) 687{ 688 int i, len; 689 int address_cells, size_cells, interrupt_cells, interrupt_map_len; 690 int static_interrupt_map[100]; 691 int interrupt_map_mask[10]; 692 int *interrupt_map = &static_interrupt_map[0]; 693 int maplen = sizeof static_interrupt_map; 694 int *free_map = NULL; 695 int reg[10]; 696 char dev_type[32]; 697 int phc_node; 698 int rc = -1; 699 700 /* Don't need to map OBP interrupt, it's already */ 701 if (*interrupt & 0x20) 702 return validlen; 703 704 /* 705 * If there is no interrupt map in the bus node, we 706 * need to convert the slot address to its parent 707 * bus format, and hunt up the parent bus to see if 708 * we need to remap. 709 * 710 * The specification for interrupt mapping is borken. 711 * You are supposed to query the interrupt parent in 712 * the interrupt-map specification to determine the 713 * number of address and interrupt cells, but we need 714 * to know how many address and interrupt cells to skip 715 * to find the phandle... 716 * 717 */ 718 if ((len = OF_getprop(node, "reg", ®, sizeof(reg))) <= 0) { 719 printf("OF_mapintr: no reg property?\n"); 720 return (-1); 721 } 722 723 phc_node = find_pci_host_node(node); 724 725 for (; node; node = OF_parent(node)) { 726#ifdef DEBUG 727 char name[40]; 728 729 if (ofmapintrdebug) { 730 OF_getprop(node, "name", &name, sizeof(name)); 731 printf("Node %s (%x), host %x\n", name, 732 node, phc_node); 733 } 734#endif 735 736 retry_map: 737 if ((interrupt_map_len = OF_getprop(node, 738 "interrupt-map", interrupt_map, maplen)) <= 0) { 739 740 /* Swizzle interrupt if this is a PCI bridge. */ 741 if (((len = OF_getprop(node, "device_type", &dev_type, 742 sizeof(dev_type))) > 0) && 743 !strcmp(dev_type, "pci") && 744 (node != phc_node)) { 745#ifdef DEBUG 746 int ointerrupt = *interrupt; 747#endif 748 749 *interrupt = ((*interrupt + 750 OFW_PCI_PHYS_HI_DEVICE(reg[0]) - 1) & 3) + 1; 751 DPRINTF(("OF_mapintr: interrupt %x -> %x, reg[0] %x\n", 752 ointerrupt, *interrupt, reg[0])); 753 } 754 755 /* Get reg for next level compare. */ 756 reg[0] = 0; 757 OF_getprop(node, "reg", ®, sizeof(reg)); 758 continue; 759 } 760 if (interrupt_map_len > maplen) { 761 DPRINTF(("interrupt_map_len %d > maplen %d, " 762 "allocating\n", interrupt_map_len, maplen)); 763 KASSERT(!free_map); 764 free_map = malloc(interrupt_map_len, M_DEVBUF, 765 M_NOWAIT); 766 if (!free_map) { 767 interrupt_map_len = sizeof static_interrupt_map; 768 } else { 769 interrupt_map = free_map; 770 maplen = interrupt_map_len; 771 goto retry_map; 772 } 773 } 774 /* Convert from bytes to cells. */ 775 interrupt_map_len = interrupt_map_len/sizeof(int); 776 if ((len = (OF_searchprop(node, "#address-cells", 777 &address_cells, sizeof(address_cells)))) <= 0) { 778 /* How should I know. */ 779 address_cells = 2; 780 } 781 DPRINTF(("#address-cells = %d len %d ", address_cells, len)); 782 if ((len = OF_searchprop(node, "#size-cells", &size_cells, 783 sizeof(size_cells))) <= 0) { 784 /* How should I know. */ 785 size_cells = 2; 786 } 787 DPRINTF(("#size-cells = %d len %d ", size_cells, len)); 788 if ((len = OF_getprop(node, "#interrupt-cells", &interrupt_cells, 789 sizeof(interrupt_cells))) <= 0) { 790 /* How should I know. */ 791 interrupt_cells = 1; 792 } 793 DPRINTF(("#interrupt-cells = %d, len %d\n", interrupt_cells, 794 len)); 795 if ((len = OF_getprop(node, "interrupt-map-mask", &interrupt_map_mask, 796 sizeof(interrupt_map_mask))) <= 0) { 797 /* Create a mask that masks nothing. */ 798 for (i = 0; i<(address_cells + interrupt_cells); i++) 799 interrupt_map_mask[i] = -1; 800 } 801#ifdef DEBUG 802 DPRINTF(("interrupt-map-mask len %d = ", len)); 803 for (i=0; i<(address_cells + interrupt_cells); i++) 804 DPRINTF(("%x.", interrupt_map_mask[i])); 805 DPRINTF(("reg = ")); 806 for (i=0; i<(address_cells); i++) 807 DPRINTF(("%x.", reg[i])); 808 DPRINTF(("interrupts = ")); 809 for (i=0; i<(interrupt_cells); i++) 810 DPRINTF(("%x.", interrupt[i])); 811 812#endif 813 814 /* finally we can attempt the compare */ 815 i = 0; 816 while (i < interrupt_map_len) { 817 int pintr_cells; 818 int *imap = &interrupt_map[i]; 819 int *parent = &imap[address_cells + interrupt_cells]; 820 821#ifdef DEBUG 822 DPRINTF(("\ninterrupt-map addr ")); 823 for (len = 0; len < address_cells; len++) 824 DPRINTF(("%x.", imap[len])); 825 DPRINTF((" intr ")); 826 for (; len < (address_cells+interrupt_cells); len++) 827 DPRINTF(("%x.", imap[len])); 828 DPRINTF(("\nnode %x vs parent %x\n", 829 imap[len], *parent)); 830#endif 831 832 /* Find out how many cells we'll need to skip. */ 833 if ((len = OF_searchprop(*parent, "#interrupt-cells", 834 &pintr_cells, sizeof(pintr_cells))) < 0) { 835 pintr_cells = interrupt_cells; 836 } 837 DPRINTF(("pintr_cells = %d len %d\n", pintr_cells, len)); 838 839 if (compare_cells(imap, reg, 840 interrupt_map_mask, address_cells) && 841 compare_cells(&imap[address_cells], 842 interrupt, 843 &interrupt_map_mask[address_cells], 844 interrupt_cells)) 845 { 846 /* Bingo! */ 847 if (buflen < pintr_cells) { 848 /* Error -- ran out of storage. */ 849 if (free_map) 850 free(free_map, M_DEVBUF); 851 return (-1); 852 } 853 parent++; 854#ifdef DEBUG 855 DPRINTF(("Match! using ")); 856 for (len = 0; len < pintr_cells; len++) 857 DPRINTF(("%x.", parent[len])); 858 DPRINTF(("\n")); 859#endif 860 for (i = 0; i < pintr_cells; i++) 861 interrupt[i] = parent[i]; 862 rc = validlen = pintr_cells; 863 break; 864 } 865 /* Move on to the next interrupt_map entry. */ 866#ifdef DEBUG 867 DPRINTF(("skip %d cells:", 868 address_cells + interrupt_cells + 869 pintr_cells + 1)); 870 for (len = 0; len < (address_cells + 871 interrupt_cells + pintr_cells + 1); len++) 872 DPRINTF(("%x.", imap[len])); 873#endif 874 i += address_cells + interrupt_cells + pintr_cells + 1; 875 } 876 877 /* Get reg for the next level search. */ 878 if ((len = OF_getprop(node, "reg", ®, sizeof(reg))) <= 0) { 879 DPRINTF(("OF_mapintr: no reg property?\n")); 880 continue; 881 } 882 DPRINTF(("reg len %d\n", len)); 883 884 if (free_map) { 885 free(free_map, M_DEVBUF); 886 free_map = NULL; 887 } 888 } 889 return (rc); 890} 891