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