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