xref: /netbsd-src/sys/arch/powerpc/oea/ofwoea_machdep.c (revision 7b1ec3e3425e0ad9c79424002d6c7918d01d474f)
1 /* $NetBSD: ofwoea_machdep.c,v 1.64 2024/05/28 11:06:07 macallan Exp $ */
2 
3 /*-
4  * Copyright (c) 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Tim Rightnour
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: ofwoea_machdep.c,v 1.64 2024/05/28 11:06:07 macallan Exp $");
34 
35 #include "ksyms.h"
36 #include "wsdisplay.h"
37 
38 #ifdef _KERNEL_OPT
39 #include "opt_ddb.h"
40 #include "opt_kgdb.h"
41 #include "opt_modular.h"
42 #include "opt_multiprocessor.h"
43 #include "opt_oea.h"
44 #include "opt_ofwoea.h"
45 #include "opt_ppcarch.h"
46 #endif
47 
48 #include <sys/param.h>
49 #include <sys/buf.h>
50 #include <sys/boot_flag.h>
51 #include <sys/extent.h>
52 #include <sys/kernel.h>
53 #include <sys/ksyms.h>
54 #include <uvm/uvm_extern.h>
55 
56 #include <dev/ofw/openfirm.h>
57 #include <dev/wscons/wsconsio.h>
58 #include <dev/wscons/wsdisplayvar.h>
59 #include <dev/rasops/rasops.h>
60 #include <dev/wscons/wsdisplay_vconsvar.h>
61 #include <machine/pmap.h>
62 #include <machine/powerpc.h>
63 #include <machine/trap.h>
64 #include <machine/vmparam.h>
65 #include <machine/autoconf.h>
66 #include <sys/bus.h>
67 #include <powerpc/oea/bat.h>
68 #include <powerpc/oea/ofw_rasconsvar.h>
69 #include <powerpc/oea/cpufeat.h>
70 #include <powerpc/include/oea/spr.h>
71 #include <powerpc/ofw_cons.h>
72 #include <powerpc/ofw_machdep.h>
73 #include <powerpc/spr.h>
74 #include <powerpc/pic/picvar.h>
75 
76 #ifdef DDB
77 #include <machine/db_machdep.h>
78 #include <ddb/db_extern.h>
79 #endif
80 
81 #ifdef KGDB
82 #include <sys/kgdb.h>
83 #endif
84 
85 #ifdef ofppc
86 extern struct model_data modeldata;
87 #endif
88 
89 #ifdef OFWOEA_DEBUG
90 #define DPRINTF printf
91 #else
92 #define DPRINTF while (0) printf
93 #endif
94 
95 typedef struct _rangemap {
96 	u_int32_t addr;
97 	u_int32_t size;
98 	int type;
99 } rangemap_t;
100 
101 struct OF_translation ofw_translations[OFW_MAX_TRANSLATIONS];
102 
103 /*
104  * Data structures holding OpenFirmware's translations when running
105  * in virtual-mode.
106  *
107  * When we call into OpenFirmware, we point the calling CPU's
108  * cpu_info::ci_battable at ofw_battable[].  For now, this table
109  * is empty, which will ensure that any DSI exceptions that occur
110  * during the firmware call will not erroneously load kernel BAT
111  * mappings that could clobber the firmware's translations.
112  */
113 struct pmap ofw_pmap;
114 struct bat ofw_battable[BAT_VA2IDX(0xffffffff)+1];
115 
116 char bootpath[256] = "";
117 char model_name[64];
118 #if NKSYMS || defined(DDB) || defined(MODULAR)
119 void *startsym, *endsym;
120 #endif
121 
122 #if PPC_OEA601
123 #define TIMEBASE_FREQ (1000000000)  /* RTC register */
124 #endif
125 
126 #ifdef TIMEBASE_FREQ
127 u_int timebase_freq = TIMEBASE_FREQ;
128 #else
129 u_int timebase_freq = 0;
130 #endif
131 
132 int ofw_quiesce;
133 
134 extern int ofwmsr;
135 extern uint32_t ticks_per_sec;
136 extern uint32_t ns_per_tick;
137 extern uint32_t ticks_per_intr;
138 
139 static void get_timebase_frequency(void);
140 static void init_decrementer(void);
141 
142 static void restore_ofmap(void);
143 
144 void
ofwoea_initppc(u_int startkernel,u_int endkernel,char * args)145 ofwoea_initppc(u_int startkernel, u_int endkernel, char *args)
146 {
147 	register_t scratch;
148 
149 #if NKSYMS || defined(DDB) || defined(MODULAR)
150 	/* get info of kernel symbol table from bootloader */
151 	memcpy(&startsym, args + strlen(args) + 1, sizeof(startsym));
152 	memcpy(&endsym, args + strlen(args) + 1 + sizeof(startsym),
153 	    sizeof(endsym));
154 	if (startsym == NULL || endsym == NULL)
155 	    startsym = endsym = NULL;
156 #endif
157 
158 	/* Parse the args string */
159 	if (args) {
160 		strcpy(bootpath, args);
161 		args = bootpath;
162 		while (*++args && *args != ' ');
163 		if (*args) {
164 			*args++ = 0;
165 			while (*args)
166 				BOOT_FLAG(*args++, boothowto);
167 		}
168 	}
169 
170 	/* if bootpath is still empty, get it from /chosen */
171 	if (bootpath[0] == 0) {
172 		int chs = OF_finddevice("/chosen");
173 		int len;
174 
175 		len = OF_getprop(chs, "bootpath", bootpath, sizeof(bootpath) - 1);
176 		if (len > -1)
177 			bootpath[len] = 0;
178 	}
179 
180 	/* Get the timebase frequency from the firmware. */
181 	get_timebase_frequency();
182 
183 	/* Probe for the console device; it's initialized later. */
184 	ofwoea_cnprobe();
185 
186 	if (ofw_quiesce)
187 		OF_quiesce();
188 
189 	oea_init(pic_ext_intr);
190 
191 	/*
192 	 * Now that we've installed our own exception vectors,
193 	 * ensure that exceptions that happen while running
194 	 * firmware code fall into ours.
195 	 */
196 	ofwmsr &= ~PSL_IP;
197 
198 	/* Initialize bus_space */
199 	ofwoea_bus_space_init();
200 
201 	/* Initialize the console device. */
202 	ofwoea_consinit();
203 
204 	uvm_md_init();
205 
206 	pmap_bootstrap(startkernel, endkernel);
207 
208 /* as far as I can tell, the pmap_setup_seg0 stuff is horribly broken */
209 #if defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
210 #if defined (PMAC_G5)
211 	/* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/
212 	if (oeacpufeat & OEACPU_64_BRIDGE) {
213 		vaddr_t va;
214 		paddr_t pa;
215 		vsize_t size;
216 		int i;
217 
218 		pmap_setup_segment0_map(0, msgbuf_paddr, msgbuf_paddr,
219 		    round_page(MSGBUFSIZE), 0x0);
220 
221 		/* Map OFW code+data */
222 
223 		for (i = 0; i < __arraycount(ofw_translations); i++) {
224 			va = ofw_translations[i].virt;
225 			size = ofw_translations[i].size;
226 			pa = ofw_translations[i].phys;
227 			/* XXX mode */
228 
229 			if (size == 0) {
230 				/* No more, all done! */
231 				break;
232 			}
233 
234 			if (va < 0xff800000)
235 				continue;
236 
237 
238 			for (; va < (ofw_translations[i].virt + size);
239 			    va += PAGE_SIZE, pa += PAGE_SIZE) {
240 				pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL,
241 				    VM_PROT_ALL | PMAP_WIRED);
242 			}
243 		}
244 
245 #if NWSDISPLAY > 0
246 		/* Map video frame buffer */
247 
248 		struct rasops_info *ri = &rascons_console_screen.scr_ri;
249 
250 		if (ri->ri_bits != NULL) {
251 			for (va = (vaddr_t) ri->ri_bits;
252 			    va < round_page((vaddr_t) ri->ri_bits +
253 				ri->ri_height * ri->ri_stride);
254 			    va += PAGE_SIZE) {
255 				pmap_enter(pmap_kernel(), va, va,
256 				    VM_PROT_READ | VM_PROT_WRITE,
257 				    PMAP_NOCACHE | PMAP_WIRED);
258 			}
259 		}
260 #endif
261 	}
262 #elif defined (MAMBO)
263 	/* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/
264 	if (oeacpufeat & OEACPU_64_BRIDGE)
265 		pmap_setup_segment0_map(0, 0xf4000000, 0xf4000000, 0x1000, 0x0);
266 #endif /* PMAC_G5 */
267 #endif /* PPC_OEA64 || PPC_OEA64_BRIDGE */
268 
269 	/* Now enable translation (and machine checks/recoverable interrupts) */
270 	__asm __volatile ("sync; mfmsr %0; ori %0,%0,%1; mtmsr %0; isync"
271 	    : "=r"(scratch)
272 	    : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI));
273 
274 	restore_ofmap();
275 
276 #if NWSDISPLAY > 0
277 	rascons_finalize();
278 #endif
279 
280 #if NKSYMS || defined(DDB) || defined(MODULAR)
281 	ksyms_addsyms_elf((int)((uintptr_t)endsym - (uintptr_t)startsym), startsym, endsym);
282 #endif
283 
284 	/* Kick off the clock. */
285 	init_decrementer();
286 
287 #ifdef DDB
288 	if (boothowto & RB_KDB)
289 		Debugger();
290 #endif
291 }
292 
293 static void
get_timebase_frequency(void)294 get_timebase_frequency(void)
295 {
296 	int qhandle, phandle, node;
297 	char type[32];
298 
299 	if (timebase_freq != 0) {
300 		ticks_per_sec = timebase_freq;
301 		return;
302 	}
303 
304 	node = OF_finddevice("/cpus/@0");
305 	if (node != -1 &&
306 	    OF_getprop(node, "timebase-frequency", &ticks_per_sec,
307 		       sizeof ticks_per_sec) > 0) {
308 		return;
309 	}
310 
311 	node = OF_finddevice("/");
312 	for (qhandle = node; qhandle; qhandle = phandle) {
313 		if (OF_getprop(qhandle, "device_type", type, sizeof type) > 0
314 		    && strcmp(type, "cpu") == 0
315 		    && OF_getprop(qhandle, "timebase-frequency",
316 			&ticks_per_sec, sizeof ticks_per_sec) > 0) {
317 			return;
318 		}
319 		if ((phandle = OF_child(qhandle)))
320 			continue;
321 		while (qhandle) {
322 			if ((phandle = OF_peer(qhandle)))
323 				break;
324 			qhandle = OF_parent(qhandle);
325 		}
326 	}
327 	panic("no cpu node");
328 }
329 
330 static void
init_decrementer(void)331 init_decrementer(void)
332 {
333 	int scratch, msr;
334 
335 	KASSERT(ticks_per_sec != 0);
336 
337 	__asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1"
338 		: "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE));
339 	ns_per_tick = 1000000000 / ticks_per_sec;
340 	ticks_per_intr = ticks_per_sec / hz;
341 	cpu_timebase = ticks_per_sec;
342 
343 #ifdef PPC_OEA601
344 	if ((mfpvr() >> 16) == MPC601)
345 		curcpu()->ci_lasttb = rtc_nanosecs();
346 	else
347 #endif
348 		curcpu()->ci_lasttb = mftbl();
349 
350 	mtspr(SPR_DEC, ticks_per_intr);
351 	mtmsr(msr);
352 }
353 
354 void
restore_ofmap(void)355 restore_ofmap(void)
356 {
357 	vaddr_t va, size;
358 	paddr_t pa;
359 	int i;
360 
361 	pmap_pinit(&ofw_pmap);
362 
363 #ifndef _LP64
364 	ofw_pmap.pm_sr[0] = KERNELN_SEGMENT(0)|SR_PRKEY;
365 	ofw_pmap.pm_sr[KERNEL_SR] = KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY;
366 
367 #ifdef KERNEL2_SR
368 	ofw_pmap.pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT|SR_SUKEY|SR_PRKEY;
369 #endif
370 #endif
371 
372 	for (i = 0; i < __arraycount(ofw_translations); i++) {
373 		va = ofw_translations[i].virt;
374 		size = ofw_translations[i].size;
375 		pa = ofw_translations[i].phys;
376 		/* XXX mode */
377 
378 		if (size == 0) {
379 			/* No more, all done! */
380 			break;
381 		}
382 
383 		if (va < 0xf0000000)	/* XXX */
384 			continue;
385 
386 		/*
387 		 * XXX macallan@
388 		 * My beige G3 throws a DSI trap if we try to map the last page
389 		 * of the 32bit address space. On old world macs the firmware
390 		 * ROM occupies 4MB at 0xffc00000, triggering it when we
391 		 * restore OF translations. This just works around a bug
392 		 * elsewhere in pmap and should go away once fixed there.
393 		 */
394 		if (pa == 0xffc00000 && size == 0x400000)
395 			size = 0x3ff000;
396 
397 		while (size > 0) {
398 			pmap_enter(&ofw_pmap, va, pa, VM_PROT_ALL,
399 			    VM_PROT_ALL|PMAP_WIRED);
400 			pa += PAGE_SIZE;
401 			va += PAGE_SIZE;
402 			size -= PAGE_SIZE;
403 		}
404 	}
405 	pmap_update(&ofw_pmap);
406 }
407 
408 /* we define these partially, as we will fill the rest in later */
409 struct powerpc_bus_space genppc_isa_io_space_tag = {
410 	.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE,
411 	.pbs_base = 0x00000000,
412 };
413 
414 struct powerpc_bus_space genppc_isa_mem_space_tag = {
415 	.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE,
416 	.pbs_base = 0x00000000,
417 };
418 
419 /* This gives us a maximum of 6 PCI busses, assuming both io/mem on each.
420  * Increase if necc.
421  */
422 static char ex_storage[EXSTORAGE_MAX][EXTENT_FIXED_STORAGE_SIZE(EXTMAP_RANGES)]
423 	__attribute__((aligned(8)));
424 
425 
426 static void
find_ranges(int base,rangemap_t * regions,int * cur,int type)427 find_ranges(int base, rangemap_t *regions, int *cur, int type)
428 {
429 	int node, i, len, reclen;
430 	u_int32_t parent_acells, acells, scells, map[160];
431 	char tmp[32];
432 
433 	node = base;
434 	if (OF_getprop(node, "device_type", tmp, sizeof(tmp)) == -1)
435 		goto rec;
436 	if ((type == RANGE_TYPE_PCI || type == RANGE_TYPE_FIRSTPCI) &&
437 	    strcmp("pci", tmp) != 0)
438 		goto rec;
439 	if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) != 0)
440 		goto rec;
441 	if (type == RANGE_TYPE_MACIO && strcmp("memory-controller", tmp) == 0) {
442 		len = OF_getprop(node, "reg", map, sizeof(map));
443 		acells = 1;
444 		scells = 1;
445 	} else {
446 		len = OF_getprop(node, "ranges", map, sizeof(map));
447 	}
448 	if (len == -1)
449 		goto rec;
450 	if (OF_getprop(OF_parent(node), "#address-cells", &parent_acells,
451 	    sizeof(parent_acells)) != sizeof(parent_acells))
452 		parent_acells = 1;
453 	if (OF_getprop(node, "#address-cells", &acells,
454 	    sizeof(acells)) != sizeof(acells))
455 		acells = 3;
456 	if (OF_getprop(node, "#size-cells", &scells,
457 	    sizeof(scells)) != sizeof(scells))
458 		scells = 2;
459 #ifdef ofppc
460 	if (modeldata.ranges_offset == 0)
461 		scells -= 1;
462 #endif
463 	if (type == RANGE_TYPE_ISA)
464 		reclen = 6;
465 	else
466 		reclen = parent_acells + acells + scells;
467 	/*
468 	 * There exist ISA buses with empty ranges properties.  This is
469 	 * known to occur on the Pegasos II machine, and likely others.
470 	 * According to them, that means that the isa bus is a fake bus, and
471 	 * the real maps are the PCI maps of the preceding bus.  To deal
472 	 * with this, we will set cur to -1 and return.
473 	 */
474 	if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) == 0 && len == 0) {
475 		*cur = -1;
476 		DPRINTF("Found empty range in isa bus\n");
477 		return;
478 	}
479 
480 	DPRINTF("found a map reclen=%d cur=%d len=%d\n", reclen, *cur, len);
481 	switch (type) {
482 		case RANGE_TYPE_PCI:
483 		case RANGE_TYPE_FIRSTPCI:
484 			for (i=0; i < len/(4*reclen); i++) {
485 				DPRINTF("FOUND PCI RANGE\n");
486 				regions[*cur].size =
487 				    map[i*reclen + parent_acells + acells + scells - 1];
488 				/* skip ranges of size==0 */
489 				if (regions[*cur].size == 0)
490 					continue;
491 				regions[*cur].type = (map[i*reclen] >> 24) & 0x3;
492 				regions[*cur].addr = map[i*reclen + parent_acells + acells - 1];
493 				(*cur)++;
494 			}
495 			break;
496 		case RANGE_TYPE_ISA:
497 			for (i=0; i < len/(4*reclen); i++) {
498 				if (map[i*reclen] == 1)
499 					regions[*cur].type = RANGE_IO;
500 				else
501 					regions[*cur].type = RANGE_MEM;
502 				DPRINTF("FOUND ISA RANGE TYPE=%d\n",
503 					regions[*cur].type);
504 				regions[*cur].size =
505 				    map[i*reclen + acells + scells];
506 				(*cur)++;
507 			}
508 			break;
509 		case RANGE_TYPE_MACIO:
510 			regions[*cur].type = RANGE_MEM;
511 			if (len == 8) {
512 				regions[*cur].size = map[1];
513 				regions[*cur].addr = map[0];
514 			} else {
515 				regions[*cur].size = map[2];
516 				regions[*cur].addr = map[1];
517 			}
518 			(*cur)++;
519 			break;
520 	}
521 	DPRINTF("returning with CUR=%d\n", *cur);
522 	return;
523 rec:
524 	for (node = OF_child(base); node; node = OF_peer(node)) {
525 		DPRINTF("RECURSE 1 STEP\n");
526 		find_ranges(node, regions, cur, type);
527 		if (*cur == -1)
528 			return;
529 	}
530 }
531 
532 static int
find_lowest_range(rangemap_t * ranges,int nrof,int type)533 find_lowest_range(rangemap_t *ranges, int nrof, int type)
534 {
535 	int i, low = 0;
536 	u_int32_t addr = 0xffffffff;
537 
538 	for (i=0; i < nrof; i++) {
539 		if (ranges[i].type == type && ranges[i].addr != 0 &&
540 		    ranges[i].addr < addr) {
541 			low = i;
542 			addr = ranges[i].addr;
543 		}
544 	}
545 	if (addr == 0xffffffff)
546 		return -1;
547 	return low;
548 }
549 
550 /*
551  * Find a region of memory, and create a bus_space_tag for it.
552  * Notes:
553  * For ISA node is ignored.
554  * node is the starting node.  if -1, we start at / and map everything.
555  */
556 
557 int
ofwoea_map_space(int rangetype,int iomem,int node,struct powerpc_bus_space * tag,const char * name)558 ofwoea_map_space(int rangetype, int iomem, int node,
559     struct powerpc_bus_space *tag, const char *name)
560 {
561 	int i, cur, range, nrofholes, error;
562 	static int exmap=0;
563 	rangemap_t region, holes[32], list[32];
564 
565 	memset(list, 0, sizeof(list));
566 	memset(&region, 0, sizeof(region));
567 	cur = 0;
568 	if (rangetype == RANGE_TYPE_ISA || node == -1)
569 		node = OF_finddevice("/");
570 	if (rangetype == RANGE_TYPE_ISA) {
571 		u_int32_t size = 0;
572 		rangemap_t regions[32];
573 
574 		DPRINTF("LOOKING FOR FIRSTPCI\n");
575 		find_ranges(node, list, &cur, RANGE_TYPE_FIRSTPCI);
576 		range = 0;
577 		DPRINTF("LOOKING FOR ISA\n");
578 		find_ranges(node, regions, &range, RANGE_TYPE_ISA);
579 		if (range == 0 || cur == 0)
580 			return -1; /* no isa stuff found */
581 		/*
582 		 * This may be confusing to some.  The ISA ranges property
583 		 * is supposed to be a set of IO ranges for the ISA bus, but
584 		 * generally, it's just a set of pci devfunc lists that tell
585 		 * you to go look at the parent PCI device for the actual
586 		 * ranges.
587 		 */
588 		if (range == -1) {
589 			/* we found a rangeless isa bus */
590 			if (iomem == RANGE_IO)
591 				size = 0x10000;
592 			else
593 				size = 0x1000000;
594 		}
595 		DPRINTF("found isa stuff\n");
596 		for (i=0; i < range; i++)
597 			if (regions[i].type == iomem)
598 				size = regions[i].size;
599 		if (iomem == RANGE_IO) {
600 			/* the first io range is the one */
601 			for (i=0; i < cur; i++)
602 				if (list[i].type == RANGE_IO && size) {
603 					DPRINTF("found IO\n");
604 					tag->pbs_offset = list[i].addr;
605 					tag->pbs_limit = size;
606 					error = bus_space_init(tag, name,
607 					    ex_storage[exmap],
608 					    sizeof(ex_storage[exmap]));
609 					exmap++;
610 					return error;
611 				}
612 		} else {
613 			for (i=0; i < cur; i++)
614 				if (list[i].type == RANGE_MEM &&
615 				    list[i].size == size) {
616 					DPRINTF("found mem\n");
617 					tag->pbs_offset = list[i].addr;
618 					tag->pbs_limit = size;
619 					error = bus_space_init(tag, name,
620 					    ex_storage[exmap],
621 					    sizeof(ex_storage[exmap]));
622 					exmap++;
623 					return error;
624 				}
625 		}
626 		return -1; /* NO ISA FOUND */
627 	}
628 	find_ranges(node, list, &cur, rangetype);
629 
630 	DPRINTF("cur == %d\n", cur);
631 	/* now list should contain a list of memory regions */
632 	for (i=0; i < cur; i++)
633 		DPRINTF("addr=0x%x size=0x%x type=%d\n", list[i].addr,
634 		    list[i].size, list[i].type);
635 
636 	range = find_lowest_range(list, cur, iomem);
637 	i = 0;
638 	nrofholes = 0;
639 	while (range != -1) {
640 		DPRINTF("range==%d\n", range);
641 		DPRINTF("i==%d\n", i);
642 		if (i == 0) {
643 			memcpy(&region, &list[range], sizeof(rangemap_t));
644 			list[range].addr = 0;
645 			i++;
646 			range = find_lowest_range(list, cur, iomem);
647 			continue;
648 		}
649 		if (region.addr + region.size < list[range].addr) {
650 			/* allocate a hole */
651 			holes[nrofholes].type = iomem;
652 			holes[nrofholes].addr = region.size + region.addr;
653 			holes[nrofholes].size = list[range].addr -
654 			    holes[nrofholes].addr - 1;
655 			nrofholes++;
656 		}
657 		region.size = list[range].size + list[range].addr -
658 		    region.addr;
659 		list[range].addr = 0;
660 		range = find_lowest_range(list, cur, iomem);
661 	}
662 	DPRINTF("RANGE iomem=%d FOUND\n", iomem);
663 	DPRINTF("addr=0x%x size=0x%x type=%d\n", region.addr,
664 		    region.size, region.type);
665 	DPRINTF("HOLES FOUND\n");
666 	for (i=0; i < nrofholes; i++)
667 		DPRINTF("addr=0x%x size=0x%x type=%d\n", holes[i].addr,
668 		    holes[i].size, holes[i].type);
669 	/* AT THIS POINT WE MAP IT */
670 
671 	if ((rangetype == RANGE_TYPE_PCI) || (rangetype == RANGE_TYPE_MACIO)) {
672 		if (exmap == EXSTORAGE_MAX)
673 			panic("Not enough ex_storage space. "
674 			    "Increase EXSTORAGE_MAX");
675 
676 		/* XXX doing this in here might be wrong */
677 		if (iomem == 1) {
678 			/* we map an IO region */
679 			tag->pbs_offset = region.addr;
680 			tag->pbs_base = 0;
681 			tag->pbs_limit = region.size;
682 		} else {
683 			/* ... or a memory region */
684 			tag->pbs_offset = 0;
685 			tag->pbs_base = region.addr;
686 			tag->pbs_limit = region.size + region.addr;
687 		}
688 
689 		error = bus_space_init(tag, name, ex_storage[exmap],
690 		    sizeof(ex_storage[exmap]));
691 		exmap++;
692 		if (error)
693 			panic("ofwoea_bus_space_init: can't init tag %s", name);
694 		for (i=0; i < nrofholes; i++) {
695 			if (holes[i].type == RANGE_IO) {
696 				error = extent_alloc_region(tag->pbs_extent,
697 				    holes[i].addr - tag->pbs_offset,
698 				    holes[i].size, EX_NOWAIT);
699 			} else {
700 				error = extent_alloc_region(tag->pbs_extent,
701 				    holes[i].addr, holes[i].size, EX_NOWAIT);
702 			}
703 			if (error)
704 				panic("ofwoea_bus_space_init: can't block out"
705 				    " reserved space 0x%x-0x%x: error=%d",
706 				    holes[i].addr, holes[i].addr+holes[i].size,
707 				    error);
708 		}
709 		return error;
710 	}
711 	return -1;
712 }
713 
714 void
ofwoea_bus_space_init(void)715 ofwoea_bus_space_init(void)
716 {
717 	int error;
718 
719 	error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_IO, -1,
720 	    &genppc_isa_io_space_tag, "isa-ioport");
721 	if (error > 0)
722 		panic("Could not map ISA IO");
723 
724 	error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_MEM, -1,
725 	    &genppc_isa_mem_space_tag, "isa-iomem");
726 	if (error > 0)
727 		panic("Could not map ISA MEM");
728 }
729