Home | History | Annotate | Line # | Download | only in sparc64
      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", &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", &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", &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