1/*-
2 * Copyright (C) 1996 Wolfgang Solfrank.
3 * Copyright (C) 1996 TooLs GmbH.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by TooLs GmbH.
17 * 4. The name of TooLs GmbH may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD$");
36
37#include <sys/param.h>
38#include <sys/bus.h>
39#include <sys/systm.h>
40#include <sys/conf.h>
41#include <sys/disk.h>
42#include <sys/fcntl.h>
43#include <sys/malloc.h>
44#include <sys/smp.h>
45#include <sys/stat.h>
46
47#include <net/ethernet.h>
48
49#include <dev/ofw/openfirm.h>
50#include <dev/ofw/ofw_pci.h>
51#include <dev/ofw/ofw_bus.h>
52
53#include <vm/vm.h>
54#include <vm/vm_param.h>
55#include <vm/vm_page.h>
56
57#include <machine/bus.h>
58#include <machine/cpu.h>
59#include <machine/md_var.h>
60#include <machine/platform.h>
61#include <machine/ofw_machdep.h>
62
63static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ];
64static struct mem_region OFfree[PHYS_AVAIL_SZ];
65
66extern register_t ofmsr[5];
67extern void	*openfirmware_entry;
68static void	*fdt;
69int		ofw_real_mode;
70
71int		ofwcall(void *);
72static int	openfirmware(void *args);
73
74/*
75 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
76 */
77register_t	ofw_sprg0_save;
78
79static __inline void
80ofw_sprg_prepare(void)
81{
82	/*
83	 * Assume that interrupt are disabled at this point, or
84	 * SPRG1-3 could be trashed
85	 */
86	__asm __volatile("mfsprg0 %0\n\t"
87			 "mtsprg0 %1\n\t"
88	    		 "mtsprg1 %2\n\t"
89	    		 "mtsprg2 %3\n\t"
90			 "mtsprg3 %4\n\t"
91			 : "=&r"(ofw_sprg0_save)
92			 : "r"(ofmsr[1]),
93			 "r"(ofmsr[2]),
94			 "r"(ofmsr[3]),
95			 "r"(ofmsr[4]));
96}
97
98static __inline void
99ofw_sprg_restore(void)
100{
101	/*
102	 * Note that SPRG1-3 contents are irrelevant. They are scratch
103	 * registers used in the early portion of trap handling when
104	 * interrupts are disabled.
105	 *
106	 * PCPU data cannot be used until this routine is called !
107	 */
108	__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
109}
110
111/*
112 * Memory region utilities: determine if two regions overlap,
113 * and merge two overlapping regions into one
114 */
115static int
116memr_overlap(struct mem_region *r1, struct mem_region *r2)
117{
118	if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
119	    (r2->mr_start + r2->mr_size) < r1->mr_start)
120		return (FALSE);
121
122	return (TRUE);
123}
124
125static void
126memr_merge(struct mem_region *from, struct mem_region *to)
127{
128	vm_offset_t end;
129	end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
130	to->mr_start = ulmin(from->mr_start, to->mr_start);
131	to->mr_size = end - to->mr_start;
132}
133
134/*
135 * Quick sort callout for comparing memory regions.
136 */
137static int	mr_cmp(const void *a, const void *b);
138
139static int
140mr_cmp(const void *a, const void *b)
141{
142	const struct	mem_region *regiona;
143	const struct	mem_region *regionb;
144
145	regiona = a;
146	regionb = b;
147	if (regiona->mr_start < regionb->mr_start)
148		return (-1);
149	else if (regiona->mr_start > regionb->mr_start)
150		return (1);
151	else
152		return (0);
153}
154
155static int
156parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
157{
158	cell_t address_cells, size_cells;
159	cell_t OFmem[4 * PHYS_AVAIL_SZ];
160	int sz, i, j;
161	int apple_hack_mode;
162	phandle_t phandle;
163
164	sz = 0;
165	apple_hack_mode = 0;
166
167	/*
168	 * Get #address-cells from root node, defaulting to 1 if it cannot
169	 * be found.
170	 */
171	phandle = OF_finddevice("/");
172	if (OF_getprop(phandle, "#address-cells", &address_cells,
173	    sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
174		address_cells = 1;
175	if (OF_getprop(phandle, "#size-cells", &size_cells,
176	    sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
177		size_cells = 1;
178
179	/*
180	 * On Apple hardware, address_cells is always 1 for "available",
181	 * even when it is explicitly set to 2. Then all memory above 4 GB
182	 * should be added by hand to the available list. Detect Apple hardware
183	 * by seeing if ofw_real_mode is set -- only Apple seems to use
184	 * virtual-mode OF.
185	 */
186	if (strcmp(prop, "available") == 0 && !ofw_real_mode)
187		apple_hack_mode = 1;
188
189	if (apple_hack_mode)
190		address_cells = 1;
191
192	/*
193	 * Get memory.
194	 */
195	if (node == -1 || (sz = OF_getprop(node, prop,
196	    OFmem, sizeof(OFmem))) <= 0)
197		panic("Physical memory map not found");
198
199	i = 0;
200	j = 0;
201	while (i < sz/sizeof(cell_t)) {
202	      #ifndef __powerpc64__
203		/* On 32-bit PPC, ignore regions starting above 4 GB */
204		if (address_cells > 1 && OFmem[i] > 0) {
205			i += address_cells + size_cells;
206			continue;
207		}
208	      #endif
209
210		output[j].mr_start = OFmem[i++];
211		if (address_cells == 2) {
212			#ifdef __powerpc64__
213			output[j].mr_start <<= 32;
214			#endif
215			output[j].mr_start += OFmem[i++];
216		}
217
218		output[j].mr_size = OFmem[i++];
219		if (size_cells == 2) {
220			#ifdef __powerpc64__
221			output[j].mr_size <<= 32;
222			#endif
223			output[j].mr_size += OFmem[i++];
224		}
225
226	      #ifndef __powerpc64__
227		/*
228		 * Check for memory regions extending above 32-bit
229		 * memory space, and restrict them to stay there.
230		 */
231		if (((uint64_t)output[j].mr_start +
232		    (uint64_t)output[j].mr_size) >
233		    BUS_SPACE_MAXADDR_32BIT) {
234			output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
235			    output[j].mr_start;
236		}
237	      #endif
238
239		j++;
240	}
241	sz = j*sizeof(output[0]);
242
243	#ifdef __powerpc64__
244	if (apple_hack_mode) {
245		/* Add in regions above 4 GB to the available list */
246		struct mem_region himem[16];
247		int hisz;
248
249		hisz = parse_ofw_memory(node, "reg", himem);
250		for (i = 0; i < hisz/sizeof(himem[0]); i++) {
251			if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
252				output[j].mr_start = himem[i].mr_start;
253				output[j].mr_size = himem[i].mr_size;
254				j++;
255			}
256		}
257		sz = j*sizeof(output[0]);
258	}
259	#endif
260
261	return (sz);
262}
263
264static int
265parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem,
266		    struct mem_region *ofavail)
267{
268	phandle_t phandle;
269	vm_offset_t base;
270	int i, idx, len, lasz, lmsz, res;
271	uint32_t lmb_size[2];
272	unsigned long *dmem, flags;
273
274	lmsz = *msz;
275	lasz = *asz;
276
277	phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
278	if (phandle == -1)
279		/* No drconf node, return. */
280		return (0);
281
282	res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size));
283	if (res == -1)
284		return (0);
285
286	/* Parse the /ibm,dynamic-memory.
287	   The first position gives the # of entries. The next two words
288 	   reflect the address of the memory block. The next four words are
289	   the DRC index, reserved, list index and flags.
290	   (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
291
292	    #el  Addr   DRC-idx  res   list-idx  flags
293	   -------------------------------------------------
294	   | 4 |   8   |   4   |   4   |   4   |   4   |....
295	   -------------------------------------------------
296	*/
297
298	len = OF_getproplen(phandle, "ibm,dynamic-memory");
299	if (len > 0) {
300
301		/* We have to use a variable length array on the stack
302		   since we have very limited stack space.
303		*/
304		cell_t arr[len/sizeof(cell_t)];
305
306		res = OF_getprop(phandle, "ibm,dynamic-memory", &arr,
307				 sizeof(arr));
308		if (res == -1)
309			return (0);
310
311		/* Number of elements */
312		idx = arr[0];
313
314		/* First address. */
315		dmem = (void*)&arr[1];
316
317		for (i = 0; i < idx; i++) {
318			base = *dmem;
319			dmem += 2;
320			flags = *dmem;
321			/* Use region only if available and not reserved. */
322			if ((flags & 0x8) && !(flags & 0x80)) {
323				ofmem[lmsz].mr_start = base;
324				ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
325				ofavail[lasz].mr_start = base;
326				ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
327				lmsz++;
328				lasz++;
329			}
330			dmem++;
331		}
332	}
333
334	*msz = lmsz;
335	*asz = lasz;
336
337	return (1);
338}
339/*
340 * This is called during powerpc_init, before the system is really initialized.
341 * It shall provide the total and the available regions of RAM.
342 * Both lists must have a zero-size entry as terminator.
343 * The available regions need not take the kernel into account, but needs
344 * to provide space for two additional entry beyond the terminating one.
345 */
346void
347ofw_mem_regions(struct mem_region **memp, int *memsz,
348		struct mem_region **availp, int *availsz)
349{
350	phandle_t phandle;
351	vm_offset_t maxphysaddr;
352	int asz, msz, fsz;
353	int i, j, res;
354	int still_merging;
355	char name[31];
356
357	asz = msz = 0;
358
359	/*
360	 * Get memory from all the /memory nodes.
361	 */
362	for (phandle = OF_child(OF_peer(0)); phandle != 0;
363	    phandle = OF_peer(phandle)) {
364		if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
365			continue;
366		if (strncmp(name, "memory", sizeof(name)) != 0)
367			continue;
368
369		res = parse_ofw_memory(phandle, "reg", &OFmem[msz]);
370		msz += res/sizeof(struct mem_region);
371		if (OF_getproplen(phandle, "available") >= 0)
372			res = parse_ofw_memory(phandle, "available",
373			    &OFavail[asz]);
374		else
375			res = parse_ofw_memory(phandle, "reg", &OFavail[asz]);
376		asz += res/sizeof(struct mem_region);
377	}
378
379	/* Check for memory in ibm,dynamic-reconfiguration-memory */
380	parse_drconf_memory(&msz, &asz, OFmem, OFavail);
381
382	qsort(OFmem, msz, sizeof(*OFmem), mr_cmp);
383	qsort(OFavail, asz, sizeof(*OFavail), mr_cmp);
384
385	*memp = OFmem;
386	*memsz = msz;
387
388	/*
389	 * On some firmwares (SLOF), some memory may be marked available that
390	 * doesn't actually exist. This manifests as an extension of the last
391	 * available segment past the end of physical memory, so truncate that
392	 * one.
393	 */
394	maxphysaddr = 0;
395	for (i = 0; i < msz; i++)
396		if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr)
397			maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size;
398
399	if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr)
400		OFavail[asz - 1].mr_size = maxphysaddr -
401		    OFavail[asz - 1].mr_start;
402
403	/*
404	 * OFavail may have overlapping regions - collapse these
405	 * and copy out remaining regions to OFfree
406	 */
407	do {
408		still_merging = FALSE;
409		for (i = 0; i < asz; i++) {
410			if (OFavail[i].mr_size == 0)
411				continue;
412			for (j = i+1; j < asz; j++) {
413				if (OFavail[j].mr_size == 0)
414					continue;
415				if (memr_overlap(&OFavail[j], &OFavail[i])) {
416					memr_merge(&OFavail[j], &OFavail[i]);
417					/* mark inactive */
418					OFavail[j].mr_size = 0;
419					still_merging = TRUE;
420				}
421			}
422		}
423	} while (still_merging == TRUE);
424
425	/* evict inactive ranges */
426	for (i = 0, fsz = 0; i < asz; i++) {
427		if (OFavail[i].mr_size != 0) {
428			OFfree[fsz] = OFavail[i];
429			fsz++;
430		}
431	}
432
433	*availp = OFfree;
434	*availsz = fsz;
435}
436
437void
438OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
439{
440	if (ofmsr[0] & PSL_DR)
441		ofw_real_mode = 0;
442	else
443		ofw_real_mode = 1;
444
445	fdt = fdt_ptr;
446
447	#ifdef FDT_DTB_STATIC
448	/* Check for a statically included blob */
449	if (fdt == NULL)
450		fdt = &fdt_static_dtb;
451	#endif
452}
453
454boolean_t
455OF_bootstrap()
456{
457	boolean_t status = FALSE;
458
459	if (openfirmware_entry != NULL) {
460		if (ofw_real_mode) {
461			status = OF_install(OFW_STD_REAL, 0);
462		} else {
463			#ifdef __powerpc64__
464			status = OF_install(OFW_STD_32BIT, 0);
465			#else
466			status = OF_install(OFW_STD_DIRECT, 0);
467			#endif
468		}
469
470		if (status != TRUE)
471			return status;
472
473		OF_init(openfirmware);
474	} else if (fdt != NULL) {
475		status = OF_install(OFW_FDT, 0);
476
477		if (status != TRUE)
478			return status;
479
480		OF_init(fdt);
481	}
482
483	return (status);
484}
485
486void
487ofw_quiesce(void)
488{
489	struct {
490		cell_t name;
491		cell_t nargs;
492		cell_t nreturns;
493	} args;
494
495	KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up"));
496
497	args.name = (cell_t)(uintptr_t)"quiesce";
498	args.nargs = 0;
499	args.nreturns = 0;
500	openfirmware(&args);
501}
502
503static int
504openfirmware_core(void *args)
505{
506	int		result;
507	register_t	oldmsr;
508
509	/*
510	 * Turn off exceptions - we really don't want to end up
511	 * anywhere unexpected with PCPU set to something strange
512	 * or the stack pointer wrong.
513	 */
514	oldmsr = intr_disable();
515
516	ofw_sprg_prepare();
517
518#if defined(AIM) && !defined(__powerpc64__)
519	/*
520	 * Clear battable[] translations
521	 */
522	if (!(cpu_features & PPC_FEATURE_64))
523		__asm __volatile("mtdbatu 2, %0\n"
524				 "mtdbatu 3, %0" : : "r" (0));
525	isync();
526#endif
527
528	result = ofwcall(args);
529	ofw_sprg_restore();
530
531	intr_restore(oldmsr);
532
533	return (result);
534}
535
536#ifdef SMP
537struct ofw_rv_args {
538	void *args;
539	int retval;
540	volatile int in_progress;
541};
542
543static void
544ofw_rendezvous_dispatch(void *xargs)
545{
546	struct ofw_rv_args *rv_args = xargs;
547
548	/* NOTE: Interrupts are disabled here */
549
550	if (PCPU_GET(cpuid) == 0) {
551		/*
552		 * Execute all OF calls on CPU 0
553		 */
554		rv_args->retval = openfirmware_core(rv_args->args);
555		rv_args->in_progress = 0;
556	} else {
557		/*
558		 * Spin with interrupts off on other CPUs while OF has
559		 * control of the machine.
560		 */
561		while (rv_args->in_progress)
562			cpu_spinwait();
563	}
564}
565#endif
566
567static int
568openfirmware(void *args)
569{
570	int result;
571	#ifdef SMP
572	struct ofw_rv_args rv_args;
573
574	rv_args.args = args;
575	rv_args.in_progress = 1;
576	smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
577	    smp_no_rendevous_barrier, &rv_args);
578	result = rv_args.retval;
579	#else
580	result = openfirmware_core(args);
581	#endif
582
583	return (result);
584}
585
586void
587OF_reboot()
588{
589	struct {
590		cell_t name;
591		cell_t nargs;
592		cell_t nreturns;
593		cell_t arg;
594	} args;
595
596	args.name = (cell_t)(uintptr_t)"interpret";
597	args.nargs = 1;
598	args.nreturns = 0;
599	args.arg = (cell_t)(uintptr_t)"reset-all";
600	openfirmware_core(&args); /* Don't do rendezvous! */
601
602	for (;;);	/* just in case */
603}
604
605void
606OF_getetheraddr(device_t dev, u_char *addr)
607{
608	phandle_t	node;
609
610	node = ofw_bus_get_node(dev);
611	OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
612}
613
614/*
615 * Return a bus handle and bus tag that corresponds to the register
616 * numbered regno for the device referenced by the package handle
617 * dev. This function is intended to be used by console drivers in
618 * early boot only. It works by mapping the address of the device's
619 * register in the address space of its parent and recursively walk
620 * the device tree upward this way.
621 */
622static void
623OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
624{
625	char name[16];
626	uint32_t addr, size;
627	int pci, res;
628
629	res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
630	if (res == -1)
631		addr = 2;
632	res = OF_getprop(node, "#size-cells", &size, sizeof(size));
633	if (res == -1)
634		size = 1;
635	pci = 0;
636	if (addr == 3 && size == 2) {
637		res = OF_getprop(node, "name", name, sizeof(name));
638		if (res != -1) {
639			name[sizeof(name) - 1] = '\0';
640			pci = (strcmp(name, "pci") == 0) ? 1 : 0;
641		}
642	}
643	if (addrp != NULL)
644		*addrp = addr;
645	if (sizep != NULL)
646		*sizep = size;
647	if (pcip != NULL)
648		*pcip = pci;
649}
650
651int
652OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
653    bus_space_handle_t *handle)
654{
655	uint32_t cell[32];
656	bus_addr_t addr, raddr, baddr;
657	bus_size_t size, rsize;
658	uint32_t c, nbridge, naddr, nsize;
659	phandle_t bridge, parent;
660	u_int spc, rspc, prefetch;
661	int pci, pcib, res;
662
663	/* Sanity checking. */
664	if (dev == 0)
665		return (EINVAL);
666	bridge = OF_parent(dev);
667	if (bridge == 0)
668		return (EINVAL);
669	if (regno < 0)
670		return (EINVAL);
671	if (tag == NULL || handle == NULL)
672		return (EINVAL);
673
674	/* Get the requested register. */
675	OF_get_addr_props(bridge, &naddr, &nsize, &pci);
676	res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
677	    cell, sizeof(cell));
678	if (res == -1)
679		return (ENXIO);
680	if (res % sizeof(cell[0]))
681		return (ENXIO);
682	res /= sizeof(cell[0]);
683	regno *= naddr + nsize;
684	if (regno + naddr + nsize > res)
685		return (EINVAL);
686	spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
687	prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0;
688	addr = 0;
689	for (c = 0; c < naddr; c++)
690		addr = ((uint64_t)addr << 32) | cell[regno++];
691	size = 0;
692	for (c = 0; c < nsize; c++)
693		size = ((uint64_t)size << 32) | cell[regno++];
694
695	/*
696	 * Map the address range in the bridge's decoding window as given
697	 * by the "ranges" property. If a node doesn't have such property
698	 * then no mapping is done.
699	 */
700	parent = OF_parent(bridge);
701	while (parent != 0) {
702		OF_get_addr_props(parent, &nbridge, NULL, &pcib);
703		res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
704		if (res == -1)
705			goto next;
706		if (res % sizeof(cell[0]))
707			return (ENXIO);
708		res /= sizeof(cell[0]);
709		regno = 0;
710		while (regno < res) {
711			rspc = (pci)
712			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
713			    : ~0;
714			if (rspc != spc) {
715				regno += naddr + nbridge + nsize;
716				continue;
717			}
718			raddr = 0;
719			for (c = 0; c < naddr; c++)
720				raddr = ((uint64_t)raddr << 32) | cell[regno++];
721			rspc = (pcib)
722			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
723			    : ~0;
724			baddr = 0;
725			for (c = 0; c < nbridge; c++)
726				baddr = ((uint64_t)baddr << 32) | cell[regno++];
727			rsize = 0;
728			for (c = 0; c < nsize; c++)
729				rsize = ((uint64_t)rsize << 32) | cell[regno++];
730			if (addr < raddr || addr >= raddr + rsize)
731				continue;
732			addr = addr - raddr + baddr;
733			if (rspc != ~0)
734				spc = rspc;
735		}
736
737	next:
738		bridge = parent;
739		parent = OF_parent(bridge);
740		OF_get_addr_props(bridge, &naddr, &nsize, &pci);
741	}
742
743	*tag = &bs_le_tag;
744	return (bus_space_map(*tag, addr, size,
745	    prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle));
746}
747
748