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", ®, sizeof(reg))) <= 0) {
871 printf("OF_mapintr: no reg property?\n");
872 return (-1);
873 }
874
875 phc_node = find_pci_host_node(node);
876 while (node) {
877 #ifdef DEBUG
878 char name[40];
879
880 if (ofmapintrdebug) {
881 OF_getprop(node, "name", &name, sizeof(name));
882 printf("Node %s (%x), host %x\n", name,
883 node, phc_node);
884 }
885 #endif
886
887 if ((interrupt_map_len = OF_getprop(node,
888 "interrupt-map", &interrupt_map,
889 sizeof(interrupt_map))) <= 0) {
890
891 /* Swizzle interrupt if this is a PCI bridge. */
892 if (((len = OF_getprop(node, "device_type", &dev_type,
893 sizeof(dev_type))) > 0) &&
894 (strcmp(dev_type, "pci") == 0 ||
895 strcmp(dev_type, "pciex") == 0) &&
896 (node != phc_node)) {
897 *interrupt = ((*interrupt +
898 OFW_PCI_PHYS_HI_DEVICE(reg[0]) - 1) & 3) + 1;
899 DPRINTF(("OF_mapintr: interrupt %x, reg[0] %x\n",
900 *interrupt, reg[0]));
901 }
902
903 /* Get reg for next level compare. */
904 reg[0] = 0;
905 OF_getprop(node, "reg", ®, sizeof(reg));
906
907 node = OF_parent(node);
908 continue;
909 }
910 /* Convert from bytes to cells. */
911 interrupt_map_len = interrupt_map_len/sizeof(int);
912 if ((len = (OF_searchprop(node, "#address-cells", &address_cells,
913 sizeof(address_cells)))) <= 0) {
914 /* How should I know. */
915 address_cells = 2;
916 }
917 DPRINTF(("#address-cells = %d len %d", address_cells, len));
918 if ((len = OF_searchprop(node, "#size-cells", &size_cells,
919 sizeof(size_cells))) <= 0) {
920 /* How should I know. */
921 size_cells = 2;
922 }
923 DPRINTF(("#size-cells = %d len %d", size_cells, len));
924 if ((len = OF_getprop(node, "#interrupt-cells", &interrupt_cells,
925 sizeof(interrupt_cells))) <= 0) {
926 /* How should I know. */
927 interrupt_cells = 1;
928 }
929 DPRINTF(("#interrupt-cells = %d, len %d\n", interrupt_cells,
930 len));
931 if ((len = OF_getprop(node, "interrupt-map-mask", &interrupt_map_mask,
932 sizeof(interrupt_map_mask))) <= 0) {
933 /* Create a mask that masks nothing. */
934 for (i = 0; i<(address_cells + interrupt_cells); i++)
935 interrupt_map_mask[i] = -1;
936 }
937 #ifdef DEBUG
938 DPRINTF(("interrupt-map-mask len %d = ", len));
939 for (i=0; i<(address_cells + interrupt_cells); i++)
940 DPRINTF(("%x.", interrupt_map_mask[i]));
941 DPRINTF(("reg = "));
942 for (i=0; i<(address_cells); i++)
943 DPRINTF(("%x.", reg[i]));
944 DPRINTF(("interrupts = "));
945 for (i=0; i<(interrupt_cells); i++)
946 DPRINTF(("%x.", interrupt[i]));
947
948 #endif
949
950 /* Finally we can attempt the compare. */
951 i = 0;
952 while (i < interrupt_map_len + address_cells + interrupt_cells) {
953 int pintr_cells;
954 int *imap = &interrupt_map[i];
955 int *parent = &imap[address_cells + interrupt_cells];
956
957 #ifdef DEBUG
958 DPRINTF(("\ninterrupt-map addr (a %d, i %d p %p) ", address_cells, interrupt_cells, parent));
959 for (len=0; len<address_cells; len++)
960 DPRINTF(("%x.", imap[len]));
961 DPRINTF((" intr "));
962 for (; len<(address_cells+interrupt_cells); len++)
963 DPRINTF(("%x.", imap[len]));
964 DPRINTF(("\nnode %x vs parent %x\n",
965 imap[len], *parent));
966 #endif
967
968 /* Find out how many cells we'll need to skip. */
969 if ((len = OF_searchprop(*parent, "#interrupt-cells",
970 &pintr_cells, sizeof(pintr_cells))) < 0) {
971 pintr_cells = interrupt_cells;
972 }
973 DPRINTF(("pintr_cells = %d len %d\n", pintr_cells, len));
974
975 if (compare_cells(imap, reg,
976 interrupt_map_mask, address_cells) &&
977 compare_cells(&imap[address_cells],
978 interrupt,
979 &interrupt_map_mask[address_cells],
980 interrupt_cells))
981 {
982 /* Bingo! */
983 if (buflen < pintr_cells) {
984 /* Error -- ran out of storage. */
985 return (-1);
986 }
987 node = *parent;
988 parent++;
989 #ifdef DEBUG
990 DPRINTF(("Match! using "));
991 for (len=0; len<pintr_cells; len++)
992 DPRINTF(("%x.", parent[len]));
993 #endif
994 for (i=0; i<pintr_cells; i++)
995 interrupt[i] = parent[i];
996 rc = validlen = pintr_cells;
997 if (node == phc_node)
998 return (rc);
999 break;
1000 }
1001 /* Move on to the next interrupt_map entry. */
1002 #ifdef DEBUG
1003 DPRINTF(("skip %d cells:",
1004 address_cells + interrupt_cells +
1005 pintr_cells + 1));
1006 for (len=0; len<(address_cells +
1007 interrupt_cells + pintr_cells + 1); len++)
1008 DPRINTF(("%x.", imap[len]));
1009 #endif
1010 i += address_cells + interrupt_cells + pintr_cells + 1;
1011 }
1012
1013 /* Get reg for the next level search. */
1014 if ((len = OF_getprop(node, "reg", ®, sizeof(reg))) <= 0)
1015 DPRINTF(("OF_mapintr: no reg property?\n"));
1016 else
1017 DPRINTF(("reg len %d\n", len));
1018
1019 node = OF_parent(node);
1020 }
1021 return (rc);
1022 }
1023