]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/ofw/ofw_machdep.c
Merge libc++ trunk r338150, and resolve conflicts.
[FreeBSD/FreeBSD.git] / sys / powerpc / ofw / ofw_machdep.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
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  * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
34  */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include "opt_platform.h"
40 #include <sys/param.h>
41 #include <sys/bus.h>
42 #include <sys/systm.h>
43 #include <sys/conf.h>
44 #include <sys/disk.h>
45 #include <sys/fcntl.h>
46 #include <sys/malloc.h>
47 #include <sys/smp.h>
48 #include <sys/stat.h>
49 #include <sys/endian.h>
50
51 #include <net/ethernet.h>
52
53 #include <dev/fdt/fdt_common.h>
54 #include <dev/ofw/openfirm.h>
55 #include <dev/ofw/ofw_pci.h>
56 #include <dev/ofw/ofw_bus.h>
57 #include <dev/ofw/ofw_subr.h>
58
59 #include <vm/vm.h>
60 #include <vm/vm_param.h>
61 #include <vm/vm_page.h>
62
63 #include <machine/bus.h>
64 #include <machine/cpu.h>
65 #include <machine/md_var.h>
66 #include <machine/platform.h>
67 #include <machine/ofw_machdep.h>
68 #include <machine/trap.h>
69
70 #include <contrib/libfdt/libfdt.h>
71
72 static void     *fdt;
73 int             ofw_real_mode;
74
75 #ifdef AIM
76 extern register_t ofmsr[5];
77 extern void     *openfirmware_entry;
78 char            save_trap_init[0x2f00];          /* EXC_LAST */
79 char            save_trap_of[0x2f00];            /* EXC_LAST */
80
81 int             ofwcall(void *);
82 static int      openfirmware(void *args);
83
84 __inline void
85 ofw_save_trap_vec(char *save_trap_vec)
86 {
87         if (!ofw_real_mode || !hw_direct_map)
88                 return;
89
90         bcopy((void *)PHYS_TO_DMAP(EXC_RST), save_trap_vec, EXC_LAST - EXC_RST);
91 }
92
93 static __inline void
94 ofw_restore_trap_vec(char *restore_trap_vec)
95 {
96         if (!ofw_real_mode || !hw_direct_map)
97                 return;
98
99         bcopy(restore_trap_vec, (void *)PHYS_TO_DMAP(EXC_RST),
100             EXC_LAST - EXC_RST);
101         __syncicache((void *)PHYS_TO_DMAP(EXC_RSVD), EXC_LAST - EXC_RSVD);
102 }
103
104 /*
105  * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
106  */
107 register_t      ofw_sprg0_save;
108
109 static __inline void
110 ofw_sprg_prepare(void)
111 {
112         if (ofw_real_mode)
113                 return;
114         
115         /*
116          * Assume that interrupt are disabled at this point, or
117          * SPRG1-3 could be trashed
118          */
119 #ifdef __powerpc64__
120         __asm __volatile("mtsprg1 %0\n\t"
121                          "mtsprg2 %1\n\t"
122                          "mtsprg3 %2\n\t"
123                          :
124                          : "r"(ofmsr[2]),
125                          "r"(ofmsr[3]),
126                          "r"(ofmsr[4]));
127 #else
128         __asm __volatile("mfsprg0 %0\n\t"
129                          "mtsprg0 %1\n\t"
130                          "mtsprg1 %2\n\t"
131                          "mtsprg2 %3\n\t"
132                          "mtsprg3 %4\n\t"
133                          : "=&r"(ofw_sprg0_save)
134                          : "r"(ofmsr[1]),
135                          "r"(ofmsr[2]),
136                          "r"(ofmsr[3]),
137                          "r"(ofmsr[4]));
138 #endif
139 }
140
141 static __inline void
142 ofw_sprg_restore(void)
143 {
144         if (ofw_real_mode)
145                 return;
146         
147         /*
148          * Note that SPRG1-3 contents are irrelevant. They are scratch
149          * registers used in the early portion of trap handling when
150          * interrupts are disabled.
151          *
152          * PCPU data cannot be used until this routine is called !
153          */
154 #ifndef __powerpc64__
155         __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
156 #endif
157 }
158 #endif
159
160 static int
161 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
162 {
163         cell_t address_cells, size_cells;
164         cell_t OFmem[4 * PHYS_AVAIL_SZ];
165         int sz, i, j;
166         phandle_t phandle;
167
168         sz = 0;
169
170         /*
171          * Get #address-cells from root node, defaulting to 1 if it cannot
172          * be found.
173          */
174         phandle = OF_finddevice("/");
175         if (OF_getencprop(phandle, "#address-cells", &address_cells, 
176             sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
177                 address_cells = 1;
178         if (OF_getencprop(phandle, "#size-cells", &size_cells, 
179             sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
180                 size_cells = 1;
181
182         /*
183          * Get memory.
184          */
185         if (node == -1 || (sz = OF_getencprop(node, prop,
186             OFmem, sizeof(OFmem))) <= 0)
187                 panic("Physical memory map not found");
188
189         i = 0;
190         j = 0;
191         while (i < sz/sizeof(cell_t)) {
192                 output[j].mr_start = OFmem[i++];
193                 if (address_cells == 2) {
194                         output[j].mr_start <<= 32;
195                         output[j].mr_start += OFmem[i++];
196                 }
197                         
198                 output[j].mr_size = OFmem[i++];
199                 if (size_cells == 2) {
200                         output[j].mr_size <<= 32;
201                         output[j].mr_size += OFmem[i++];
202                 }
203
204                 if (output[j].mr_start > BUS_SPACE_MAXADDR)
205                         continue;
206
207                 /*
208                  * Constrain memory to that which we can access.
209                  * 32-bit AIM can only reference 32 bits of address currently,
210                  * but Book-E can access 36 bits.
211                  */
212                 if (((uint64_t)output[j].mr_start +
213                     (uint64_t)output[j].mr_size - 1) >
214                     BUS_SPACE_MAXADDR) {
215                         output[j].mr_size = BUS_SPACE_MAXADDR -
216                             output[j].mr_start + 1;
217                 }
218
219                 j++;
220         }
221         sz = j*sizeof(output[0]);
222
223         return (sz);
224 }
225
226 #ifdef FDT
227 static int
228 excise_reserved_regions(struct mem_region *avail, int asz,
229                         struct mem_region *exclude, int esz)
230 {
231         int i, j, k;
232
233         for (i = 0; i < asz; i++) {
234                 for (j = 0; j < esz; j++) {
235                         /*
236                          * Case 1: Exclusion region encloses complete
237                          * available entry. Drop it and move on.
238                          */
239                         if (exclude[j].mr_start <= avail[i].mr_start &&
240                             exclude[j].mr_start + exclude[j].mr_size >=
241                             avail[i].mr_start + avail[i].mr_size) {
242                                 for (k = i+1; k < asz; k++)
243                                         avail[k-1] = avail[k];
244                                 asz--;
245                                 i--; /* Repeat some entries */
246                                 continue;
247                         }
248
249                         /*
250                          * Case 2: Exclusion region starts in available entry.
251                          * Trim it to where the entry begins and append
252                          * a new available entry with the region after
253                          * the excluded region, if any.
254                          */
255                         if (exclude[j].mr_start >= avail[i].mr_start &&
256                             exclude[j].mr_start < avail[i].mr_start +
257                             avail[i].mr_size) {
258                                 if (exclude[j].mr_start + exclude[j].mr_size <
259                                     avail[i].mr_start + avail[i].mr_size) {
260                                         avail[asz].mr_start =
261                                             exclude[j].mr_start + exclude[j].mr_size;
262                                         avail[asz].mr_size = avail[i].mr_start +
263                                              avail[i].mr_size -
264                                              avail[asz].mr_start;
265                                         asz++;
266                                 }
267
268                                 avail[i].mr_size = exclude[j].mr_start -
269                                     avail[i].mr_start;
270                         }
271
272                         /*
273                          * Case 3: Exclusion region ends in available entry.
274                          * Move start point to where the exclusion zone ends.
275                          * The case of a contained exclusion zone has already
276                          * been caught in case 2.
277                          */
278                         if (exclude[j].mr_start + exclude[j].mr_size >=
279                             avail[i].mr_start && exclude[j].mr_start +
280                             exclude[j].mr_size < avail[i].mr_start +
281                             avail[i].mr_size) {
282                                 avail[i].mr_size += avail[i].mr_start;
283                                 avail[i].mr_start =
284                                     exclude[j].mr_start + exclude[j].mr_size;
285                                 avail[i].mr_size -= avail[i].mr_start;
286                         }
287                 }
288         }
289
290         return (asz);
291 }
292
293 static int
294 excise_initrd_region(struct mem_region *avail, int asz)
295 {
296         phandle_t chosen;
297         uint64_t start, end;
298         ssize_t size;
299         struct mem_region initrdmap[1];
300         pcell_t cell[2];
301
302         chosen = OF_finddevice("/chosen");
303
304         size = OF_getencprop(chosen, "linux,initrd-start", cell, sizeof(cell));
305         if (size < 0)
306                 return (asz);
307         else if (size == 4)
308                 start = cell[0];
309         else if (size == 8)
310                 start = (uint64_t)cell[0] << 32 | cell[1];
311         else {
312                 /* Invalid value length */
313                 printf("WARNING: linux,initrd-start must be either 4 or 8 bytes long\n");
314                 return (asz);
315         }
316
317         size = OF_getencprop(chosen, "linux,initrd-end", cell, sizeof(cell));
318         if (size < 0)
319                 return (asz);
320         else if (size == 4)
321                 end = cell[0];
322         else if (size == 8)
323                 end = (uint64_t)cell[0] << 32 | cell[1];
324         else {
325                 /* Invalid value length */
326                 printf("WARNING: linux,initrd-end must be either 4 or 8 bytes long\n");
327                 return (asz);
328         }
329
330         if (end <= start)
331                 return (asz);
332
333         initrdmap[0].mr_start = start;
334         initrdmap[0].mr_size = end - start;
335
336         asz = excise_reserved_regions(avail, asz, initrdmap, 1);
337
338         return (asz);
339 }
340
341 static int
342 excise_fdt_reserved(struct mem_region *avail, int asz)
343 {
344         struct mem_region fdtmap[32];
345         ssize_t fdtmapsize;
346         phandle_t chosen;
347         int j, fdtentries;
348
349         chosen = OF_finddevice("/chosen");
350         fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap));
351
352         for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) {
353                 fdtmap[j].mr_start = be64toh(fdtmap[j].mr_start) & ~PAGE_MASK;
354                 fdtmap[j].mr_size = round_page(be64toh(fdtmap[j].mr_size));
355         }
356
357         KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap),
358             ("Exceeded number of FDT reservations"));
359         /* Add a virtual entry for the FDT itself */
360         if (fdt != NULL) {
361                 fdtmap[j].mr_start = (vm_offset_t)fdt & ~PAGE_MASK;
362                 fdtmap[j].mr_size = round_page(fdt_totalsize(fdt));
363                 fdtmapsize += sizeof(fdtmap[0]);
364         }
365
366         fdtentries = fdtmapsize/sizeof(fdtmap[0]);
367         asz = excise_reserved_regions(avail, asz, fdtmap, fdtentries);
368
369         return (asz);
370 }
371 #endif
372
373 /*
374  * This is called during powerpc_init, before the system is really initialized.
375  * It shall provide the total and the available regions of RAM.
376  * The available regions need not take the kernel into account.
377  */
378 void
379 ofw_mem_regions(struct mem_region *memp, int *memsz,
380                 struct mem_region *availp, int *availsz)
381 {
382         phandle_t phandle;
383         int asz, msz;
384         int res;
385         char name[31];
386
387         asz = msz = 0;
388
389         /*
390          * Get memory from all the /memory nodes.
391          */
392         for (phandle = OF_child(OF_peer(0)); phandle != 0;
393             phandle = OF_peer(phandle)) {
394                 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
395                         continue;
396                 if (strncmp(name, "memory", sizeof(name)) != 0 &&
397                     strncmp(name, "memory@", strlen("memory@")) != 0)
398                         continue;
399
400                 res = parse_ofw_memory(phandle, "reg", &memp[msz]);
401                 msz += res/sizeof(struct mem_region);
402
403                 /*
404                  * On POWER9 Systems we might have both linux,usable-memory and
405                  * reg properties.  'reg' denotes all available memory, but we
406                  * must use 'linux,usable-memory', a subset, as some memory
407                  * regions are reserved for NVLink.
408                  */
409                 if (OF_getproplen(phandle, "linux,usable-memory") >= 0)
410                         res = parse_ofw_memory(phandle, "linux,usable-memory",
411                             &availp[asz]);
412                 else if (OF_getproplen(phandle, "available") >= 0)
413                         res = parse_ofw_memory(phandle, "available",
414                             &availp[asz]);
415                 else
416                         res = parse_ofw_memory(phandle, "reg", &availp[asz]);
417                 asz += res/sizeof(struct mem_region);
418         }
419
420 #ifdef FDT
421         phandle = OF_finddevice("/chosen");
422         if (OF_hasprop(phandle, "fdtmemreserv"))
423                 asz = excise_fdt_reserved(availp, asz);
424
425         /* If the kernel is being loaded through kexec, initrd region is listed
426          * in /chosen but the region is not marked as reserved, so, we might exclude
427          * it here.
428          */
429         if (OF_hasprop(phandle, "linux,initrd-start"))
430                 asz = excise_initrd_region(availp, asz);
431 #endif
432
433         *memsz = msz;
434         *availsz = asz;
435 }
436
437 void
438 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
439 {
440 #ifdef AIM
441         ofmsr[0] = mfmsr();
442         #ifdef __powerpc64__
443         ofmsr[0] &= ~PSL_SF;
444         #else
445         __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1]));
446         #endif
447         __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2]));
448         __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3]));
449         __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4]));
450         openfirmware_entry = openfirm;
451
452         if (ofmsr[0] & PSL_DR)
453                 ofw_real_mode = 0;
454         else
455                 ofw_real_mode = 1;
456
457         ofw_save_trap_vec(save_trap_init);
458 #else
459         ofw_real_mode = 1;
460 #endif
461
462         fdt = fdt_ptr;
463 }
464
465 boolean_t
466 OF_bootstrap()
467 {
468         boolean_t status = FALSE;
469         int err = 0;
470
471 #ifdef AIM
472         if (openfirmware_entry != NULL) {
473                 if (ofw_real_mode) {
474                         status = OF_install(OFW_STD_REAL, 0);
475                 } else {
476                         #ifdef __powerpc64__
477                         status = OF_install(OFW_STD_32BIT, 0);
478                         #else
479                         status = OF_install(OFW_STD_DIRECT, 0);
480                         #endif
481                 }
482
483                 if (status != TRUE)
484                         return status;
485
486                 err = OF_init(openfirmware);
487         } else
488 #endif
489         if (fdt != NULL) {
490 #ifdef FDT
491 #ifdef AIM
492                 bus_space_tag_t fdt_bt;
493                 vm_offset_t tmp_fdt_ptr;
494                 vm_size_t fdt_size;
495                 uintptr_t fdt_va;
496 #endif
497
498                 status = OF_install(OFW_FDT, 0);
499                 if (status != TRUE)
500                         return status;
501
502 #ifdef AIM /* AIM-only for now -- Book-E does this remapping in early init */
503                 /* Get the FDT size for mapping if we can */
504                 tmp_fdt_ptr = pmap_early_io_map((vm_paddr_t)fdt, PAGE_SIZE);
505                 if (fdt_check_header((void *)tmp_fdt_ptr) != 0) {
506                         pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE);
507                         return FALSE;
508                 }
509                 fdt_size = fdt_totalsize((void *)tmp_fdt_ptr);
510                 pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE);
511
512                 /*
513                  * Map this for real. Use bus_space_map() to take advantage
514                  * of its auto-remapping function once the kernel is loaded.
515                  * This is a dirty hack, but what we have.
516                  */
517 #ifdef _LITTLE_ENDIAN
518                 fdt_bt = &bs_le_tag;
519 #else
520                 fdt_bt = &bs_be_tag;
521 #endif
522                 bus_space_map(fdt_bt, (vm_paddr_t)fdt, fdt_size, 0, &fdt_va);
523                  
524                 err = OF_init((void *)fdt_va);
525 #else
526                 err = OF_init(fdt);
527 #endif
528 #endif
529         } 
530
531         #ifdef FDT_DTB_STATIC
532         /*
533          * Check for a statically included blob already in the kernel and
534          * needing no mapping.
535          */
536         else {
537                 status = OF_install(OFW_FDT, 0);
538                 if (status != TRUE)
539                         return status;
540                 err = OF_init(&fdt_static_dtb);
541         }
542         #endif
543
544         if (err != 0) {
545                 OF_install(NULL, 0);
546                 status = FALSE;
547         }
548
549         return (status);
550 }
551
552 #ifdef AIM
553 void
554 ofw_quiesce(void)
555 {
556         struct {
557                 cell_t name;
558                 cell_t nargs;
559                 cell_t nreturns;
560         } args;
561
562         KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up"));
563
564         args.name = (cell_t)(uintptr_t)"quiesce";
565         args.nargs = 0;
566         args.nreturns = 0;
567         openfirmware(&args);
568 }
569
570 static int
571 openfirmware_core(void *args)
572 {
573         int             result;
574         register_t      oldmsr;
575
576         if (openfirmware_entry == NULL)
577                 return (-1);
578
579         /*
580          * Turn off exceptions - we really don't want to end up
581          * anywhere unexpected with PCPU set to something strange
582          * or the stack pointer wrong.
583          */
584         oldmsr = intr_disable();
585
586         ofw_sprg_prepare();
587
588         /* Save trap vectors */
589         ofw_save_trap_vec(save_trap_of);
590
591         /* Restore initially saved trap vectors */
592         ofw_restore_trap_vec(save_trap_init);
593
594 #ifndef __powerpc64__
595         /*
596          * Clear battable[] translations
597          */
598         if (!(cpu_features & PPC_FEATURE_64))
599                 __asm __volatile("mtdbatu 2, %0\n"
600                                  "mtdbatu 3, %0" : : "r" (0));
601         isync();
602 #endif
603
604         result = ofwcall(args);
605
606         /* Restore trap vecotrs */
607         ofw_restore_trap_vec(save_trap_of);
608
609         ofw_sprg_restore();
610
611         intr_restore(oldmsr);
612
613         return (result);
614 }
615
616 #ifdef SMP
617 struct ofw_rv_args {
618         void *args;
619         int retval;
620         volatile int in_progress;
621 };
622
623 static void
624 ofw_rendezvous_dispatch(void *xargs)
625 {
626         struct ofw_rv_args *rv_args = xargs;
627
628         /* NOTE: Interrupts are disabled here */
629
630         if (PCPU_GET(cpuid) == 0) {
631                 /*
632                  * Execute all OF calls on CPU 0
633                  */
634                 rv_args->retval = openfirmware_core(rv_args->args);
635                 rv_args->in_progress = 0;
636         } else {
637                 /*
638                  * Spin with interrupts off on other CPUs while OF has
639                  * control of the machine.
640                  */
641                 while (rv_args->in_progress)
642                         cpu_spinwait();
643         }
644 }
645 #endif
646
647 static int
648 openfirmware(void *args)
649 {
650         int result;
651         #ifdef SMP
652         struct ofw_rv_args rv_args;
653         #endif
654
655         if (openfirmware_entry == NULL)
656                 return (-1);
657
658         #ifdef SMP
659         if (cold) {
660                 result = openfirmware_core(args);
661         } else {
662                 rv_args.args = args;
663                 rv_args.in_progress = 1;
664                 smp_rendezvous(smp_no_rendezvous_barrier,
665                     ofw_rendezvous_dispatch, smp_no_rendezvous_barrier,
666                     &rv_args);
667                 result = rv_args.retval;
668         }
669         #else
670         result = openfirmware_core(args);
671         #endif
672
673         return (result);
674 }
675
676 void
677 OF_reboot()
678 {
679         struct {
680                 cell_t name;
681                 cell_t nargs;
682                 cell_t nreturns;
683                 cell_t arg;
684         } args;
685
686         args.name = (cell_t)(uintptr_t)"interpret";
687         args.nargs = 1;
688         args.nreturns = 0;
689         args.arg = (cell_t)(uintptr_t)"reset-all";
690         openfirmware_core(&args); /* Don't do rendezvous! */
691
692         for (;;);       /* just in case */
693 }
694
695 #endif /* AIM */
696
697 void
698 OF_getetheraddr(device_t dev, u_char *addr)
699 {
700         phandle_t       node;
701
702         node = ofw_bus_get_node(dev);
703         OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
704 }
705
706 /*
707  * Return a bus handle and bus tag that corresponds to the register
708  * numbered regno for the device referenced by the package handle
709  * dev. This function is intended to be used by console drivers in
710  * early boot only. It works by mapping the address of the device's
711  * register in the address space of its parent and recursively walk
712  * the device tree upward this way.
713  */
714 int
715 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
716     bus_space_handle_t *handle, bus_size_t *sz)
717 {
718         bus_addr_t addr;
719         bus_size_t size;
720         pcell_t pci_hi;
721         int flags, res;
722
723         res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi);
724         if (res < 0)
725                 return (res);
726
727         if (pci_hi == OFW_PADDR_NOT_PCI) {
728                 *tag = &bs_be_tag;
729                 flags = 0;
730         } else {
731                 *tag = &bs_le_tag;
732                 flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? 
733                     BUS_SPACE_MAP_PREFETCHABLE: 0;
734         }
735
736         if (sz != NULL)
737                 *sz = size;
738
739         return (bus_space_map(*tag, addr, size, flags, handle));
740 }
741