]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/ofw/ofw_machdep.c
Restore packaging subdir to enable running unmodified configure script.
[FreeBSD/FreeBSD.git] / sys / powerpc / ofw / ofw_machdep.c
1 /*-
2  * Copyright (C) 1996 Wolfgang Solfrank.
3  * Copyright (C) 1996 TooLs GmbH.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by TooLs GmbH.
17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/systm.h>
40 #include <sys/conf.h>
41 #include <sys/disk.h>
42 #include <sys/fcntl.h>
43 #include <sys/malloc.h>
44 #include <sys/smp.h>
45 #include <sys/stat.h>
46 #include <sys/endian.h>
47
48 #include <net/ethernet.h>
49
50 #include <dev/ofw/openfirm.h>
51 #include <dev/ofw/ofw_pci.h>
52 #include <dev/ofw/ofw_bus.h>
53
54 #include <vm/vm.h>
55 #include <vm/vm_param.h>
56 #include <vm/vm_page.h>
57
58 #include <machine/bus.h>
59 #include <machine/cpu.h>
60 #include <machine/md_var.h>
61 #include <machine/platform.h>
62 #include <machine/ofw_machdep.h>
63 #include <machine/trap.h>
64
65 #ifdef AIM
66 extern register_t ofmsr[5];
67 extern void     *openfirmware_entry;
68 static void     *fdt;
69 int             ofw_real_mode;
70 char            save_trap_init[0x2f00];          /* EXC_LAST */
71 char            save_trap_of[0x2f00];            /* EXC_LAST */
72
73 int             ofwcall(void *);
74 static int      openfirmware(void *args);
75
76 __inline void
77 ofw_save_trap_vec(char *save_trap_vec)
78 {
79         if (!ofw_real_mode)
80                 return;
81
82         bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST);
83 }
84
85 static __inline void
86 ofw_restore_trap_vec(char *restore_trap_vec)
87 {
88         if (!ofw_real_mode)
89                 return;
90
91         bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST);
92         __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
93 }
94
95 /*
96  * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
97  */
98 register_t      ofw_sprg0_save;
99
100 static __inline void
101 ofw_sprg_prepare(void)
102 {
103         if (ofw_real_mode)
104                 return;
105         
106         /*
107          * Assume that interrupt are disabled at this point, or
108          * SPRG1-3 could be trashed
109          */
110         __asm __volatile("mfsprg0 %0\n\t"
111                          "mtsprg0 %1\n\t"
112                          "mtsprg1 %2\n\t"
113                          "mtsprg2 %3\n\t"
114                          "mtsprg3 %4\n\t"
115                          : "=&r"(ofw_sprg0_save)
116                          : "r"(ofmsr[1]),
117                          "r"(ofmsr[2]),
118                          "r"(ofmsr[3]),
119                          "r"(ofmsr[4]));
120 }
121
122 static __inline void
123 ofw_sprg_restore(void)
124 {
125         if (ofw_real_mode)
126                 return;
127         
128         /*
129          * Note that SPRG1-3 contents are irrelevant. They are scratch
130          * registers used in the early portion of trap handling when
131          * interrupts are disabled.
132          *
133          * PCPU data cannot be used until this routine is called !
134          */
135         __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
136 }
137 #endif
138
139 static int
140 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
141 {
142         cell_t address_cells, size_cells;
143         cell_t OFmem[4 * PHYS_AVAIL_SZ];
144         int sz, i, j;
145         phandle_t phandle;
146
147         sz = 0;
148
149         /*
150          * Get #address-cells from root node, defaulting to 1 if it cannot
151          * be found.
152          */
153         phandle = OF_finddevice("/");
154         if (OF_getprop(phandle, "#address-cells", &address_cells, 
155             sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
156                 address_cells = 1;
157         if (OF_getprop(phandle, "#size-cells", &size_cells, 
158             sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
159                 size_cells = 1;
160
161         /*
162          * Get memory.
163          */
164         if (node == -1 || (sz = OF_getprop(node, prop,
165             OFmem, sizeof(OFmem))) <= 0)
166                 panic("Physical memory map not found");
167
168         i = 0;
169         j = 0;
170         while (i < sz/sizeof(cell_t)) {
171               #ifndef __powerpc64__
172                 /* On 32-bit PPC, ignore regions starting above 4 GB */
173                 if (address_cells > 1 && OFmem[i] > 0) {
174                         i += address_cells + size_cells;
175                         continue;
176                 }
177               #endif
178
179                 output[j].mr_start = OFmem[i++];
180                 if (address_cells == 2) {
181                         #ifdef __powerpc64__
182                         output[j].mr_start <<= 32;
183                         #endif
184                         output[j].mr_start += OFmem[i++];
185                 }
186                         
187                 output[j].mr_size = OFmem[i++];
188                 if (size_cells == 2) {
189                         #ifdef __powerpc64__
190                         output[j].mr_size <<= 32;
191                         #endif
192                         output[j].mr_size += OFmem[i++];
193                 }
194
195               #ifndef __powerpc64__
196                 /*
197                  * Check for memory regions extending above 32-bit
198                  * memory space, and restrict them to stay there.
199                  */
200                 if (((uint64_t)output[j].mr_start +
201                     (uint64_t)output[j].mr_size) >
202                     BUS_SPACE_MAXADDR_32BIT) {
203                         output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
204                             output[j].mr_start;
205                 }
206               #endif
207
208                 j++;
209         }
210         sz = j*sizeof(output[0]);
211
212         return (sz);
213 }
214
215 static int
216 excise_fdt_reserved(struct mem_region *avail, int asz)
217 {
218         struct {
219                 uint64_t address;
220                 uint64_t size;
221         } fdtmap[16];
222         ssize_t fdtmapsize;
223         phandle_t chosen;
224         int i, j, k;
225
226         chosen = OF_finddevice("/chosen");
227         fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap));
228
229         for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) {
230                 fdtmap[j].address = be64toh(fdtmap[j].address);
231                 fdtmap[j].size = be64toh(fdtmap[j].size);
232         }
233
234         for (i = 0; i < asz; i++) {
235                 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) {
236                         /*
237                          * Case 1: Exclusion region encloses complete
238                          * available entry. Drop it and move on.
239                          */
240                         if (fdtmap[j].address <= avail[i].mr_start &&
241                             fdtmap[j].address + fdtmap[j].size >=
242                             avail[i].mr_start + avail[i].mr_size) {
243                                 for (k = i+1; k < asz; k++)
244                                         avail[k-1] = avail[k];
245                                 asz--;
246                                 i--; /* Repeat some entries */
247                                 continue;
248                         }
249
250                         /*
251                          * Case 2: Exclusion region starts in available entry.
252                          * Trim it to where the entry begins and append
253                          * a new available entry with the region after
254                          * the excluded region, if any.
255                          */
256                         if (fdtmap[j].address >= avail[i].mr_start &&
257                             fdtmap[j].address < avail[i].mr_start +
258                             avail[i].mr_size) {
259                                 if (fdtmap[j].address + fdtmap[j].size < 
260                                     avail[i].mr_start + avail[i].mr_size) {
261                                         avail[asz].mr_start =
262                                             fdtmap[j].address + fdtmap[j].size;
263                                         avail[asz].mr_size = avail[i].mr_start +
264                                              avail[i].mr_size -
265                                              avail[asz].mr_start;
266                                         asz++;
267                                 }
268
269                                 avail[i].mr_size = fdtmap[j].address -
270                                     avail[i].mr_start;
271                         }
272
273                         /*
274                          * Case 3: Exclusion region ends in available entry.
275                          * Move start point to where the exclusion zone ends.
276                          * The case of a contained exclusion zone has already
277                          * been caught in case 2.
278                          */
279                         if (fdtmap[j].address + fdtmap[j].size >=
280                             avail[i].mr_start && fdtmap[j].address +
281                             fdtmap[j].size < avail[i].mr_start +
282                             avail[i].mr_size) {
283                                 avail[i].mr_size += avail[i].mr_start;
284                                 avail[i].mr_start =
285                                     fdtmap[j].address + fdtmap[j].size;
286                                 avail[i].mr_size -= avail[i].mr_start;
287                         }
288                 }
289         }
290
291         return (asz);
292 }
293
294 /*
295  * This is called during powerpc_init, before the system is really initialized.
296  * It shall provide the total and the available regions of RAM.
297  * The available regions need not take the kernel into account.
298  */
299 void
300 ofw_mem_regions(struct mem_region *memp, int *memsz,
301                 struct mem_region *availp, int *availsz)
302 {
303         phandle_t phandle;
304         int asz, msz;
305         int res;
306         char name[31];
307
308         asz = msz = 0;
309
310         /*
311          * Get memory from all the /memory nodes.
312          */
313         for (phandle = OF_child(OF_peer(0)); phandle != 0;
314             phandle = OF_peer(phandle)) {
315                 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
316                         continue;
317                 if (strncmp(name, "memory", sizeof(name)) != 0 &&
318                     strncmp(name, "memory@", strlen("memory@")) != 0)
319                         continue;
320
321                 res = parse_ofw_memory(phandle, "reg", &memp[msz]);
322                 msz += res/sizeof(struct mem_region);
323                 if (OF_getproplen(phandle, "available") >= 0)
324                         res = parse_ofw_memory(phandle, "available",
325                             &availp[asz]);
326                 else
327                         res = parse_ofw_memory(phandle, "reg", &availp[asz]);
328                 asz += res/sizeof(struct mem_region);
329         }
330
331         phandle = OF_finddevice("/chosen");
332         if (OF_hasprop(phandle, "fdtmemreserv"))
333                 asz = excise_fdt_reserved(availp, asz);
334
335         *memsz = msz;
336         *availsz = asz;
337 }
338
339 #ifdef AIM
340 void
341 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
342 {
343         ofmsr[0] = mfmsr();
344         #ifdef __powerpc64__
345         ofmsr[0] &= ~PSL_SF;
346         #endif
347         __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1]));
348         __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2]));
349         __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3]));
350         __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4]));
351
352         if (ofmsr[0] & PSL_DR)
353                 ofw_real_mode = 0;
354         else
355                 ofw_real_mode = 1;
356
357         fdt = fdt_ptr;
358         openfirmware_entry = openfirm;
359
360         #ifdef FDT_DTB_STATIC
361         /* Check for a statically included blob */
362         if (fdt == NULL)
363                 fdt = &fdt_static_dtb;
364         #endif
365
366         ofw_save_trap_vec(save_trap_init);
367 }
368
369 boolean_t
370 OF_bootstrap()
371 {
372         boolean_t status = FALSE;
373
374         if (openfirmware_entry != NULL) {
375                 if (ofw_real_mode) {
376                         status = OF_install(OFW_STD_REAL, 0);
377                 } else {
378                         #ifdef __powerpc64__
379                         status = OF_install(OFW_STD_32BIT, 0);
380                         #else
381                         status = OF_install(OFW_STD_DIRECT, 0);
382                         #endif
383                 }
384
385                 if (status != TRUE)
386                         return status;
387
388                 OF_init(openfirmware);
389         } else if (fdt != NULL) {
390                 status = OF_install(OFW_FDT, 0);
391
392                 if (status != TRUE)
393                         return status;
394
395                 OF_init(fdt);
396         } 
397
398         return (status);
399 }
400
401 void
402 ofw_quiesce(void)
403 {
404         struct {
405                 cell_t name;
406                 cell_t nargs;
407                 cell_t nreturns;
408         } args;
409
410         KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up"));
411
412         args.name = (cell_t)(uintptr_t)"quiesce";
413         args.nargs = 0;
414         args.nreturns = 0;
415         openfirmware(&args);
416 }
417
418 static int
419 openfirmware_core(void *args)
420 {
421         int             result;
422         register_t      oldmsr;
423
424         if (openfirmware_entry == NULL)
425                 return (-1);
426
427         /*
428          * Turn off exceptions - we really don't want to end up
429          * anywhere unexpected with PCPU set to something strange
430          * or the stack pointer wrong.
431          */
432         oldmsr = intr_disable();
433
434         ofw_sprg_prepare();
435
436         /* Save trap vectors */
437         ofw_save_trap_vec(save_trap_of);
438
439         /* Restore initially saved trap vectors */
440         ofw_restore_trap_vec(save_trap_init);
441
442 #if defined(AIM) && !defined(__powerpc64__)
443         /*
444          * Clear battable[] translations
445          */
446         if (!(cpu_features & PPC_FEATURE_64))
447                 __asm __volatile("mtdbatu 2, %0\n"
448                                  "mtdbatu 3, %0" : : "r" (0));
449         isync();
450 #endif
451
452         result = ofwcall(args);
453
454         /* Restore trap vecotrs */
455         ofw_restore_trap_vec(save_trap_of);
456
457         ofw_sprg_restore();
458
459         intr_restore(oldmsr);
460
461         return (result);
462 }
463
464 #ifdef SMP
465 struct ofw_rv_args {
466         void *args;
467         int retval;
468         volatile int in_progress;
469 };
470
471 static void
472 ofw_rendezvous_dispatch(void *xargs)
473 {
474         struct ofw_rv_args *rv_args = xargs;
475
476         /* NOTE: Interrupts are disabled here */
477
478         if (PCPU_GET(cpuid) == 0) {
479                 /*
480                  * Execute all OF calls on CPU 0
481                  */
482                 rv_args->retval = openfirmware_core(rv_args->args);
483                 rv_args->in_progress = 0;
484         } else {
485                 /*
486                  * Spin with interrupts off on other CPUs while OF has
487                  * control of the machine.
488                  */
489                 while (rv_args->in_progress)
490                         cpu_spinwait();
491         }
492 }
493 #endif
494
495 static int
496 openfirmware(void *args)
497 {
498         int result;
499         #ifdef SMP
500         struct ofw_rv_args rv_args;
501         #endif
502
503         if (openfirmware_entry == NULL)
504                 return (-1);
505
506         #ifdef SMP
507         rv_args.args = args;
508         rv_args.in_progress = 1;
509         smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
510             smp_no_rendevous_barrier, &rv_args);
511         result = rv_args.retval;
512         #else
513         result = openfirmware_core(args);
514         #endif
515
516         return (result);
517 }
518
519 void
520 OF_reboot()
521 {
522         struct {
523                 cell_t name;
524                 cell_t nargs;
525                 cell_t nreturns;
526                 cell_t arg;
527         } args;
528
529         args.name = (cell_t)(uintptr_t)"interpret";
530         args.nargs = 1;
531         args.nreturns = 0;
532         args.arg = (cell_t)(uintptr_t)"reset-all";
533         openfirmware_core(&args); /* Don't do rendezvous! */
534
535         for (;;);       /* just in case */
536 }
537
538 #endif /* AIM */
539
540 void
541 OF_getetheraddr(device_t dev, u_char *addr)
542 {
543         phandle_t       node;
544
545         node = ofw_bus_get_node(dev);
546         OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
547 }
548
549 /*
550  * Return a bus handle and bus tag that corresponds to the register
551  * numbered regno for the device referenced by the package handle
552  * dev. This function is intended to be used by console drivers in
553  * early boot only. It works by mapping the address of the device's
554  * register in the address space of its parent and recursively walk
555  * the device tree upward this way.
556  */
557 static void
558 OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
559 {
560         char type[64];
561         uint32_t addr, size;
562         int pci, res;
563
564         res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
565         if (res == -1)
566                 addr = 2;
567         res = OF_getprop(node, "#size-cells", &size, sizeof(size));
568         if (res == -1)
569                 size = 1;
570         pci = 0;
571         if (addr == 3 && size == 2) {
572                 res = OF_getprop(node, "device_type", type, sizeof(type));
573                 if (res != -1) {
574                         type[sizeof(type) - 1] = '\0';
575                         pci = (strcmp(type, "pci") == 0) ? 1 : 0;
576                 }
577         }
578         if (addrp != NULL)
579                 *addrp = addr;
580         if (sizep != NULL)
581                 *sizep = size;
582         if (pcip != NULL)
583                 *pcip = pci;
584 }
585
586 int
587 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
588     bus_space_handle_t *handle)
589 {
590         uint32_t cell[32];
591         bus_addr_t addr, raddr, baddr;
592         bus_size_t size, rsize;
593         uint32_t c, nbridge, naddr, nsize;
594         phandle_t bridge, parent;
595         u_int spc, rspc, prefetch;
596         int pci, pcib, res;
597
598         /* Sanity checking. */
599         if (dev == 0)
600                 return (EINVAL);
601         bridge = OF_parent(dev);
602         if (bridge == 0)
603                 return (EINVAL);
604         if (regno < 0)
605                 return (EINVAL);
606         if (tag == NULL || handle == NULL)
607                 return (EINVAL);
608
609         /* Assume big-endian unless we find a PCI device */
610         *tag = &bs_be_tag;
611
612         /* Get the requested register. */
613         OF_get_addr_props(bridge, &naddr, &nsize, &pci);
614         if (pci)
615                 *tag = &bs_le_tag;
616         res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
617             cell, sizeof(cell));
618         if (res == -1)
619                 return (ENXIO);
620         if (res % sizeof(cell[0]))
621                 return (ENXIO);
622         res /= sizeof(cell[0]);
623         regno *= naddr + nsize;
624         if (regno + naddr + nsize > res)
625                 return (EINVAL);
626         spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
627         prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0;
628         addr = 0;
629         for (c = 0; c < naddr; c++)
630                 addr = ((uint64_t)addr << 32) | cell[regno++];
631         size = 0;
632         for (c = 0; c < nsize; c++)
633                 size = ((uint64_t)size << 32) | cell[regno++];
634
635         /*
636          * Map the address range in the bridge's decoding window as given
637          * by the "ranges" property. If a node doesn't have such property
638          * then no mapping is done.
639          */
640         parent = OF_parent(bridge);
641         while (parent != 0) {
642                 OF_get_addr_props(parent, &nbridge, NULL, &pcib);
643                 if (pcib)
644                         *tag = &bs_le_tag;
645                 res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
646                 if (res == -1)
647                         goto next;
648                 if (res % sizeof(cell[0]))
649                         return (ENXIO);
650                 res /= sizeof(cell[0]);
651                 regno = 0;
652                 while (regno < res) {
653                         rspc = (pci)
654                             ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
655                             : ~0;
656                         if (rspc != spc) {
657                                 regno += naddr + nbridge + nsize;
658                                 continue;
659                         }
660                         raddr = 0;
661                         for (c = 0; c < naddr; c++)
662                                 raddr = ((uint64_t)raddr << 32) | cell[regno++];
663                         rspc = (pcib)
664                             ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
665                             : ~0;
666                         baddr = 0;
667                         for (c = 0; c < nbridge; c++)
668                                 baddr = ((uint64_t)baddr << 32) | cell[regno++];
669                         rsize = 0;
670                         for (c = 0; c < nsize; c++)
671                                 rsize = ((uint64_t)rsize << 32) | cell[regno++];
672                         if (addr < raddr || addr >= raddr + rsize)
673                                 continue;
674                         addr = addr - raddr + baddr;
675                         if (rspc != ~0)
676                                 spc = rspc;
677                 }
678
679         next:
680                 bridge = parent;
681                 parent = OF_parent(bridge);
682                 OF_get_addr_props(bridge, &naddr, &nsize, &pci);
683         }
684
685         return (bus_space_map(*tag, addr, size,
686             prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle));
687 }
688