]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/ofw/ofw_machdep.c
MFV r328323,328324:
[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)
88                 return;
89
90         bcopy((void *)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)
97                 return;
98
99         bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST);
100         __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
101 }
102
103 /*
104  * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
105  */
106 register_t      ofw_sprg0_save;
107
108 static __inline void
109 ofw_sprg_prepare(void)
110 {
111         if (ofw_real_mode)
112                 return;
113         
114         /*
115          * Assume that interrupt are disabled at this point, or
116          * SPRG1-3 could be trashed
117          */
118 #ifdef __powerpc64__
119         __asm __volatile("mtsprg1 %0\n\t"
120                          "mtsprg2 %1\n\t"
121                          "mtsprg3 %2\n\t"
122                          :
123                          : "r"(ofmsr[2]),
124                          "r"(ofmsr[3]),
125                          "r"(ofmsr[4]));
126 #else
127         __asm __volatile("mfsprg0 %0\n\t"
128                          "mtsprg0 %1\n\t"
129                          "mtsprg1 %2\n\t"
130                          "mtsprg2 %3\n\t"
131                          "mtsprg3 %4\n\t"
132                          : "=&r"(ofw_sprg0_save)
133                          : "r"(ofmsr[1]),
134                          "r"(ofmsr[2]),
135                          "r"(ofmsr[3]),
136                          "r"(ofmsr[4]));
137 #endif
138 }
139
140 static __inline void
141 ofw_sprg_restore(void)
142 {
143         if (ofw_real_mode)
144                 return;
145         
146         /*
147          * Note that SPRG1-3 contents are irrelevant. They are scratch
148          * registers used in the early portion of trap handling when
149          * interrupts are disabled.
150          *
151          * PCPU data cannot be used until this routine is called !
152          */
153 #ifndef __powerpc64__
154         __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
155 #endif
156 }
157 #endif
158
159 static int
160 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
161 {
162         cell_t address_cells, size_cells;
163         cell_t OFmem[4 * PHYS_AVAIL_SZ];
164         int sz, i, j;
165         phandle_t phandle;
166
167         sz = 0;
168
169         /*
170          * Get #address-cells from root node, defaulting to 1 if it cannot
171          * be found.
172          */
173         phandle = OF_finddevice("/");
174         if (OF_getencprop(phandle, "#address-cells", &address_cells, 
175             sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
176                 address_cells = 1;
177         if (OF_getencprop(phandle, "#size-cells", &size_cells, 
178             sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
179                 size_cells = 1;
180
181         /*
182          * Get memory.
183          */
184         if (node == -1 || (sz = OF_getencprop(node, prop,
185             OFmem, sizeof(OFmem))) <= 0)
186                 panic("Physical memory map not found");
187
188         i = 0;
189         j = 0;
190         while (i < sz/sizeof(cell_t)) {
191                 output[j].mr_start = OFmem[i++];
192                 if (address_cells == 2) {
193                         output[j].mr_start <<= 32;
194                         output[j].mr_start += OFmem[i++];
195                 }
196                         
197                 output[j].mr_size = OFmem[i++];
198                 if (size_cells == 2) {
199                         output[j].mr_size <<= 32;
200                         output[j].mr_size += OFmem[i++];
201                 }
202
203                 if (output[j].mr_start > BUS_SPACE_MAXADDR)
204                         continue;
205
206                 /*
207                  * Constrain memory to that which we can access.
208                  * 32-bit AIM can only reference 32 bits of address currently,
209                  * but Book-E can access 36 bits.
210                  */
211                 if (((uint64_t)output[j].mr_start +
212                     (uint64_t)output[j].mr_size - 1) >
213                     BUS_SPACE_MAXADDR) {
214                         output[j].mr_size = BUS_SPACE_MAXADDR -
215                             output[j].mr_start + 1;
216                 }
217
218                 j++;
219         }
220         sz = j*sizeof(output[0]);
221
222         return (sz);
223 }
224
225 static int
226 excise_fdt_reserved(struct mem_region *avail, int asz)
227 {
228         struct {
229                 uint64_t address;
230                 uint64_t size;
231         } fdtmap[16];
232         ssize_t fdtmapsize;
233         phandle_t chosen;
234         int i, j, k;
235
236         chosen = OF_finddevice("/chosen");
237         fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap));
238
239         for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) {
240                 fdtmap[j].address = be64toh(fdtmap[j].address) & ~PAGE_MASK;
241                 fdtmap[j].size = round_page(be64toh(fdtmap[j].size));
242         }
243
244         KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap),
245             ("Exceeded number of FDT reservations"));
246         /* Add a virtual entry for the FDT itself */
247         if (fdt != NULL) {
248                 fdtmap[j].address = (vm_offset_t)fdt & ~PAGE_MASK;
249                 fdtmap[j].size = round_page(fdt_totalsize(fdt));
250                 fdtmapsize += sizeof(fdtmap[0]);
251         }
252
253         for (i = 0; i < asz; i++) {
254                 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) {
255                         /*
256                          * Case 1: Exclusion region encloses complete
257                          * available entry. Drop it and move on.
258                          */
259                         if (fdtmap[j].address <= avail[i].mr_start &&
260                             fdtmap[j].address + fdtmap[j].size >=
261                             avail[i].mr_start + avail[i].mr_size) {
262                                 for (k = i+1; k < asz; k++)
263                                         avail[k-1] = avail[k];
264                                 asz--;
265                                 i--; /* Repeat some entries */
266                                 continue;
267                         }
268
269                         /*
270                          * Case 2: Exclusion region starts in available entry.
271                          * Trim it to where the entry begins and append
272                          * a new available entry with the region after
273                          * the excluded region, if any.
274                          */
275                         if (fdtmap[j].address >= avail[i].mr_start &&
276                             fdtmap[j].address < avail[i].mr_start +
277                             avail[i].mr_size) {
278                                 if (fdtmap[j].address + fdtmap[j].size < 
279                                     avail[i].mr_start + avail[i].mr_size) {
280                                         avail[asz].mr_start =
281                                             fdtmap[j].address + fdtmap[j].size;
282                                         avail[asz].mr_size = avail[i].mr_start +
283                                              avail[i].mr_size -
284                                              avail[asz].mr_start;
285                                         asz++;
286                                 }
287
288                                 avail[i].mr_size = fdtmap[j].address -
289                                     avail[i].mr_start;
290                         }
291
292                         /*
293                          * Case 3: Exclusion region ends in available entry.
294                          * Move start point to where the exclusion zone ends.
295                          * The case of a contained exclusion zone has already
296                          * been caught in case 2.
297                          */
298                         if (fdtmap[j].address + fdtmap[j].size >=
299                             avail[i].mr_start && fdtmap[j].address +
300                             fdtmap[j].size < avail[i].mr_start +
301                             avail[i].mr_size) {
302                                 avail[i].mr_size += avail[i].mr_start;
303                                 avail[i].mr_start =
304                                     fdtmap[j].address + fdtmap[j].size;
305                                 avail[i].mr_size -= avail[i].mr_start;
306                         }
307                 }
308         }
309
310         return (asz);
311 }
312
313 /*
314  * This is called during powerpc_init, before the system is really initialized.
315  * It shall provide the total and the available regions of RAM.
316  * The available regions need not take the kernel into account.
317  */
318 void
319 ofw_mem_regions(struct mem_region *memp, int *memsz,
320                 struct mem_region *availp, int *availsz)
321 {
322         phandle_t phandle;
323         int asz, msz;
324         int res;
325         char name[31];
326
327         asz = msz = 0;
328
329         /*
330          * Get memory from all the /memory nodes.
331          */
332         for (phandle = OF_child(OF_peer(0)); phandle != 0;
333             phandle = OF_peer(phandle)) {
334                 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
335                         continue;
336                 if (strncmp(name, "memory", sizeof(name)) != 0 &&
337                     strncmp(name, "memory@", strlen("memory@")) != 0)
338                         continue;
339
340                 res = parse_ofw_memory(phandle, "reg", &memp[msz]);
341                 msz += res/sizeof(struct mem_region);
342                 if (OF_getproplen(phandle, "available") >= 0)
343                         res = parse_ofw_memory(phandle, "available",
344                             &availp[asz]);
345                 else
346                         res = parse_ofw_memory(phandle, "reg", &availp[asz]);
347                 asz += res/sizeof(struct mem_region);
348         }
349
350         phandle = OF_finddevice("/chosen");
351         if (OF_hasprop(phandle, "fdtmemreserv"))
352                 asz = excise_fdt_reserved(availp, asz);
353
354         *memsz = msz;
355         *availsz = asz;
356 }
357
358 void
359 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
360 {
361 #ifdef AIM
362         ofmsr[0] = mfmsr();
363         #ifdef __powerpc64__
364         ofmsr[0] &= ~PSL_SF;
365         #else
366         __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1]));
367         #endif
368         __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2]));
369         __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3]));
370         __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4]));
371         openfirmware_entry = openfirm;
372
373         if (ofmsr[0] & PSL_DR)
374                 ofw_real_mode = 0;
375         else
376                 ofw_real_mode = 1;
377
378         ofw_save_trap_vec(save_trap_init);
379 #else
380         ofw_real_mode = 1;
381 #endif
382
383         fdt = fdt_ptr;
384
385         #ifdef FDT_DTB_STATIC
386         /* Check for a statically included blob */
387         if (fdt == NULL)
388                 fdt = &fdt_static_dtb;
389         #endif
390 }
391
392 boolean_t
393 OF_bootstrap()
394 {
395         boolean_t status = FALSE;
396         int err = 0;
397
398 #ifdef AIM
399         if (openfirmware_entry != NULL) {
400                 if (ofw_real_mode) {
401                         status = OF_install(OFW_STD_REAL, 0);
402                 } else {
403                         #ifdef __powerpc64__
404                         status = OF_install(OFW_STD_32BIT, 0);
405                         #else
406                         status = OF_install(OFW_STD_DIRECT, 0);
407                         #endif
408                 }
409
410                 if (status != TRUE)
411                         return status;
412
413                 err = OF_init(openfirmware);
414         } else
415 #endif
416         if (fdt != NULL) {
417                 status = OF_install(OFW_FDT, 0);
418
419                 if (status != TRUE)
420                         return status;
421
422                 err = OF_init(fdt);
423         } 
424
425         if (err != 0) {
426                 OF_install(NULL, 0);
427                 status = FALSE;
428         }
429
430         return (status);
431 }
432
433 #ifdef AIM
434 void
435 ofw_quiesce(void)
436 {
437         struct {
438                 cell_t name;
439                 cell_t nargs;
440                 cell_t nreturns;
441         } args;
442
443         KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up"));
444
445         args.name = (cell_t)(uintptr_t)"quiesce";
446         args.nargs = 0;
447         args.nreturns = 0;
448         openfirmware(&args);
449 }
450
451 static int
452 openfirmware_core(void *args)
453 {
454         int             result;
455         register_t      oldmsr;
456
457         if (openfirmware_entry == NULL)
458                 return (-1);
459
460         /*
461          * Turn off exceptions - we really don't want to end up
462          * anywhere unexpected with PCPU set to something strange
463          * or the stack pointer wrong.
464          */
465         oldmsr = intr_disable();
466
467         ofw_sprg_prepare();
468
469         /* Save trap vectors */
470         ofw_save_trap_vec(save_trap_of);
471
472         /* Restore initially saved trap vectors */
473         ofw_restore_trap_vec(save_trap_init);
474
475 #ifndef __powerpc64__
476         /*
477          * Clear battable[] translations
478          */
479         if (!(cpu_features & PPC_FEATURE_64))
480                 __asm __volatile("mtdbatu 2, %0\n"
481                                  "mtdbatu 3, %0" : : "r" (0));
482         isync();
483 #endif
484
485         result = ofwcall(args);
486
487         /* Restore trap vecotrs */
488         ofw_restore_trap_vec(save_trap_of);
489
490         ofw_sprg_restore();
491
492         intr_restore(oldmsr);
493
494         return (result);
495 }
496
497 #ifdef SMP
498 struct ofw_rv_args {
499         void *args;
500         int retval;
501         volatile int in_progress;
502 };
503
504 static void
505 ofw_rendezvous_dispatch(void *xargs)
506 {
507         struct ofw_rv_args *rv_args = xargs;
508
509         /* NOTE: Interrupts are disabled here */
510
511         if (PCPU_GET(cpuid) == 0) {
512                 /*
513                  * Execute all OF calls on CPU 0
514                  */
515                 rv_args->retval = openfirmware_core(rv_args->args);
516                 rv_args->in_progress = 0;
517         } else {
518                 /*
519                  * Spin with interrupts off on other CPUs while OF has
520                  * control of the machine.
521                  */
522                 while (rv_args->in_progress)
523                         cpu_spinwait();
524         }
525 }
526 #endif
527
528 static int
529 openfirmware(void *args)
530 {
531         int result;
532         #ifdef SMP
533         struct ofw_rv_args rv_args;
534         #endif
535
536         if (openfirmware_entry == NULL)
537                 return (-1);
538
539         #ifdef SMP
540         if (cold) {
541                 result = openfirmware_core(args);
542         } else {
543                 rv_args.args = args;
544                 rv_args.in_progress = 1;
545                 smp_rendezvous(smp_no_rendezvous_barrier,
546                     ofw_rendezvous_dispatch, smp_no_rendezvous_barrier,
547                     &rv_args);
548                 result = rv_args.retval;
549         }
550         #else
551         result = openfirmware_core(args);
552         #endif
553
554         return (result);
555 }
556
557 void
558 OF_reboot()
559 {
560         struct {
561                 cell_t name;
562                 cell_t nargs;
563                 cell_t nreturns;
564                 cell_t arg;
565         } args;
566
567         args.name = (cell_t)(uintptr_t)"interpret";
568         args.nargs = 1;
569         args.nreturns = 0;
570         args.arg = (cell_t)(uintptr_t)"reset-all";
571         openfirmware_core(&args); /* Don't do rendezvous! */
572
573         for (;;);       /* just in case */
574 }
575
576 #endif /* AIM */
577
578 void
579 OF_getetheraddr(device_t dev, u_char *addr)
580 {
581         phandle_t       node;
582
583         node = ofw_bus_get_node(dev);
584         OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
585 }
586
587 /*
588  * Return a bus handle and bus tag that corresponds to the register
589  * numbered regno for the device referenced by the package handle
590  * dev. This function is intended to be used by console drivers in
591  * early boot only. It works by mapping the address of the device's
592  * register in the address space of its parent and recursively walk
593  * the device tree upward this way.
594  */
595 int
596 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
597     bus_space_handle_t *handle, bus_size_t *sz)
598 {
599         bus_addr_t addr;
600         bus_size_t size;
601         pcell_t pci_hi;
602         int flags, res;
603
604         res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi);
605         if (res < 0)
606                 return (res);
607
608         if (pci_hi == OFW_PADDR_NOT_PCI) {
609                 *tag = &bs_be_tag;
610                 flags = 0;
611         } else {
612                 *tag = &bs_le_tag;
613                 flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? 
614                     BUS_SPACE_MAP_PREFETCHABLE: 0;
615         }
616
617         if (sz != NULL)
618                 *sz = size;
619
620         return (bus_space_map(*tag, addr, size, flags, handle));
621 }
622