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