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