xref: /openbsd/sys/arch/sparc64/sparc64/ofw_machdep.c (revision bec25f42)
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 
58 static u_int mmuh = -1, memh = -1;
59 
60 static u_int get_mmu_handle(void);
61 static u_int get_memory_handle(void);
62 
63 static u_int
get_mmu_handle(void)64 get_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 
79 static u_int
get_memory_handle(void)80 get_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  */
99 int
prom_set_trap_table(vaddr_t tba,paddr_t mmfsa)100 prom_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  */
126 paddr_t
prom_vtop(vaddr_t vaddr)127 prom_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  */
177 vaddr_t
prom_claim_virt(vaddr_t vaddr,int len)178 prom_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  */
215 vaddr_t
prom_alloc_virt(int len,int align)216 prom_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  */
252 int
prom_free_virt(vaddr_t vaddr,int len)253 prom_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  */
285 int
prom_unmap_virt(vaddr_t vaddr,int len)286 prom_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  */
317 int
prom_map_phys(paddr_t paddr,off_t size,vaddr_t vaddr,int mode)318 prom_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  */
356 paddr_t
prom_alloc_phys(int len,int align)357 prom_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  */
393 paddr_t
prom_claim_phys(paddr_t phys,int len)394 prom_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  */
434 int
prom_free_phys(paddr_t phys,int len)435 prom_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  */
468 paddr_t
prom_get_msgbuf(int len,int align)469 prom_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 
518 int
prom_itlb_load(int index,u_int64_t data,vaddr_t vaddr)519 prom_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 
552 int
prom_dtlb_load(int index,u_int64_t data,vaddr_t vaddr)553 prom_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  */
590 void
prom_start_cpu(int cpu,void * func,long arg)591 prom_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 
612 void
prom_start_cpu_by_cpuid(int cpu,void * func,long arg)613 prom_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 
640 static u_int stdin = 0;
641 static u_int stdout = 0;
642 
643 int
OF_stdin(void)644 OF_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 
656 int
OF_stdout(void)657 OF_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  */
674 void
prom_printf(const char * fmt,...)675 prom_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 
692 const char *
prom_serengeti_set_console_input(const char * new)693 prom_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 
714 uint64_t
prom_set_sun4v_api_version(uint64_t api_group,uint64_t major,uint64_t minor,uint64_t * supported_minor)715 prom_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 
744 void
prom_sun4v_soft_state_supported(void)745 prom_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
762 int 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  */
772 int
OF_searchprop(int node,char * prop,void * buf,int buflen)773 OF_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  */
791 static int compare_cells (int *cell1, int *cell2, int *mask, int ncells);
792 static int
compare_cells(int * cell1,int * cell2,int * mask,int ncells)793 compare_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  */
810 static int
find_pci_host_node(int node)811 find_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  */
837 int
OF_mapintr(int node,int * interrupt,int validlen,int buflen)838 OF_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", &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", &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", &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