xref: /netbsd-src/sys/arch/sparc64/sparc64/ofw_machdep.c (revision 25ac767b16abfd17c10eb9c6ebbc1a6681d6d2eb)
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
get_mmu_handle(void)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
get_memory_handle(void)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
prom_set_trap_table_sun4u(vaddr_t tba)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
prom_set_trap_table_sun4v(vaddr_t tba,paddr_t mmfsa)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
prom_vtop(vaddr_t vaddr)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
prom_claim_virt(vaddr_t vaddr,int len)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
prom_alloc_virt(int len,int align)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
prom_free_virt(vaddr_t vaddr,int len)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
prom_unmap_virt(vaddr_t vaddr,int len)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
prom_map_phys(paddr_t paddr,off_t size,vaddr_t vaddr,int mode)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
prom_alloc_phys(int len,int align)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
prom_claim_phys(paddr_t phys,int len)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
prom_free_phys(paddr_t phys,int len)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
prom_get_msgbuf(int len,int align)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
prom_startcpu(u_int cpu,void * func,u_long arg)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
prom_startcpu_by_cpuid(u_int cpu,void * func,u_long arg)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
prom_stopself(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
prom_has_stopself(void)612 prom_has_stopself(void)
613 {
614 	return OF_test("SUNW,stop-self") == 0;
615 }
616 
617 int
prom_stop_other(u_int id)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
prom_has_stop_other(void)640 prom_has_stop_other(void)
641 {
642 	return OF_test("SUNW,stop-cpu-by-cpuid") == 0;
643 }
644 #endif
645 
646 uint64_t
prom_set_sun4v_api_version(uint64_t api_group,uint64_t major,uint64_t minor,uint64_t * supported_minor)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
prom_get_sun4v_api_version(uint64_t api_group,uint64_t * major,uint64_t * minor)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
prom_sun4v_soft_state_supported(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
OF_searchprop(int node,const char * prop,void * sbuf,int buflen)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
compare_cells(int * cell1,int * cell2,int * mask,int ncells)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
find_pci_host_node(int node)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
OF_mapintr(int node,int * interrupt,int validlen,int buflen)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