2 * Copyright (C) 1996 Wolfgang Solfrank.
3 * Copyright (C) 1996 TooLs GmbH.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
31 * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
39 #include <sys/systm.h>
42 #include <sys/fcntl.h>
43 #include <sys/malloc.h>
47 #include <net/ethernet.h>
49 #include <dev/ofw/openfirm.h>
50 #include <dev/ofw/ofw_pci.h>
51 #include <dev/ofw/ofw_bus.h>
54 #include <vm/vm_param.h>
55 #include <vm/vm_page.h>
57 #include <machine/bus.h>
58 #include <machine/cpu.h>
59 #include <machine/md_var.h>
60 #include <machine/platform.h>
61 #include <machine/ofw_machdep.h>
63 static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ];
64 static struct mem_region OFfree[PHYS_AVAIL_SZ];
66 extern register_t ofmsr[5];
67 extern void *openfirmware_entry;
72 static int openfirmware(void *args);
75 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
77 register_t ofw_sprg0_save;
80 ofw_sprg_prepare(void)
83 * Assume that interrupt are disabled at this point, or
84 * SPRG1-3 could be trashed
86 __asm __volatile("mfsprg0 %0\n\t"
91 : "=&r"(ofw_sprg0_save)
99 ofw_sprg_restore(void)
102 * Note that SPRG1-3 contents are irrelevant. They are scratch
103 * registers used in the early portion of trap handling when
104 * interrupts are disabled.
106 * PCPU data cannot be used until this routine is called !
108 __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
112 * Memory region utilities: determine if two regions overlap,
113 * and merge two overlapping regions into one
116 memr_overlap(struct mem_region *r1, struct mem_region *r2)
118 if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
119 (r2->mr_start + r2->mr_size) < r1->mr_start)
126 memr_merge(struct mem_region *from, struct mem_region *to)
129 end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
130 to->mr_start = ulmin(from->mr_start, to->mr_start);
131 to->mr_size = end - to->mr_start;
135 * Quick sort callout for comparing memory regions.
137 static int mr_cmp(const void *a, const void *b);
140 mr_cmp(const void *a, const void *b)
142 const struct mem_region *regiona;
143 const struct mem_region *regionb;
147 if (regiona->mr_start < regionb->mr_start)
149 else if (regiona->mr_start > regionb->mr_start)
156 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
158 cell_t address_cells, size_cells;
159 cell_t OFmem[4 * PHYS_AVAIL_SZ];
168 * Get #address-cells from root node, defaulting to 1 if it cannot
171 phandle = OF_finddevice("/");
172 if (OF_getprop(phandle, "#address-cells", &address_cells,
173 sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
175 if (OF_getprop(phandle, "#size-cells", &size_cells,
176 sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
180 * On Apple hardware, address_cells is always 1 for "available",
181 * even when it is explicitly set to 2. Then all memory above 4 GB
182 * should be added by hand to the available list. Detect Apple hardware
183 * by seeing if ofw_real_mode is set -- only Apple seems to use
186 if (strcmp(prop, "available") == 0 && !ofw_real_mode)
195 if (node == -1 || (sz = OF_getprop(node, prop,
196 OFmem, sizeof(OFmem))) <= 0)
197 panic("Physical memory map not found");
201 while (i < sz/sizeof(cell_t)) {
202 #ifndef __powerpc64__
203 /* On 32-bit PPC, ignore regions starting above 4 GB */
204 if (address_cells > 1 && OFmem[i] > 0) {
205 i += address_cells + size_cells;
210 output[j].mr_start = OFmem[i++];
211 if (address_cells == 2) {
213 output[j].mr_start <<= 32;
215 output[j].mr_start += OFmem[i++];
218 output[j].mr_size = OFmem[i++];
219 if (size_cells == 2) {
221 output[j].mr_size <<= 32;
223 output[j].mr_size += OFmem[i++];
226 #ifndef __powerpc64__
228 * Check for memory regions extending above 32-bit
229 * memory space, and restrict them to stay there.
231 if (((uint64_t)output[j].mr_start +
232 (uint64_t)output[j].mr_size) >
233 BUS_SPACE_MAXADDR_32BIT) {
234 output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
241 sz = j*sizeof(output[0]);
244 if (apple_hack_mode) {
245 /* Add in regions above 4 GB to the available list */
246 struct mem_region himem[16];
249 hisz = parse_ofw_memory(node, "reg", himem);
250 for (i = 0; i < hisz/sizeof(himem[0]); i++) {
251 if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
252 output[j].mr_start = himem[i].mr_start;
253 output[j].mr_size = himem[i].mr_size;
257 sz = j*sizeof(output[0]);
265 parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem,
266 struct mem_region *ofavail)
270 int i, idx, len, lasz, lmsz, res;
271 uint32_t lmb_size[2];
272 unsigned long *dmem, flags;
277 phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
279 /* No drconf node, return. */
282 res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size));
286 /* Parse the /ibm,dynamic-memory.
287 The first position gives the # of entries. The next two words
288 reflect the address of the memory block. The next four words are
289 the DRC index, reserved, list index and flags.
290 (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
292 #el Addr DRC-idx res list-idx flags
293 -------------------------------------------------
294 | 4 | 8 | 4 | 4 | 4 | 4 |....
295 -------------------------------------------------
298 len = OF_getproplen(phandle, "ibm,dynamic-memory");
301 /* We have to use a variable length array on the stack
302 since we have very limited stack space.
304 cell_t arr[len/sizeof(cell_t)];
306 res = OF_getprop(phandle, "ibm,dynamic-memory", &arr,
311 /* Number of elements */
315 dmem = (void*)&arr[1];
317 for (i = 0; i < idx; i++) {
321 /* Use region only if available and not reserved. */
322 if ((flags & 0x8) && !(flags & 0x80)) {
323 ofmem[lmsz].mr_start = base;
324 ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
325 ofavail[lasz].mr_start = base;
326 ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
340 * This is called during powerpc_init, before the system is really initialized.
341 * It shall provide the total and the available regions of RAM.
342 * Both lists must have a zero-size entry as terminator.
343 * The available regions need not take the kernel into account, but needs
344 * to provide space for two additional entry beyond the terminating one.
347 ofw_mem_regions(struct mem_region **memp, int *memsz,
348 struct mem_region **availp, int *availsz)
351 vm_offset_t maxphysaddr;
360 * Get memory from all the /memory nodes.
362 for (phandle = OF_child(OF_peer(0)); phandle != 0;
363 phandle = OF_peer(phandle)) {
364 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
366 if (strncmp(name, "memory", sizeof(name)) != 0)
369 res = parse_ofw_memory(phandle, "reg", &OFmem[msz]);
370 msz += res/sizeof(struct mem_region);
371 if (OF_getproplen(phandle, "available") >= 0)
372 res = parse_ofw_memory(phandle, "available",
375 res = parse_ofw_memory(phandle, "reg", &OFavail[asz]);
376 asz += res/sizeof(struct mem_region);
379 /* Check for memory in ibm,dynamic-reconfiguration-memory */
380 parse_drconf_memory(&msz, &asz, OFmem, OFavail);
382 qsort(OFmem, msz, sizeof(*OFmem), mr_cmp);
383 qsort(OFavail, asz, sizeof(*OFavail), mr_cmp);
389 * On some firmwares (SLOF), some memory may be marked available that
390 * doesn't actually exist. This manifests as an extension of the last
391 * available segment past the end of physical memory, so truncate that
395 for (i = 0; i < msz; i++)
396 if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr)
397 maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size;
399 if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr)
400 OFavail[asz - 1].mr_size = maxphysaddr -
401 OFavail[asz - 1].mr_start;
404 * OFavail may have overlapping regions - collapse these
405 * and copy out remaining regions to OFfree
408 still_merging = FALSE;
409 for (i = 0; i < asz; i++) {
410 if (OFavail[i].mr_size == 0)
412 for (j = i+1; j < asz; j++) {
413 if (OFavail[j].mr_size == 0)
415 if (memr_overlap(&OFavail[j], &OFavail[i])) {
416 memr_merge(&OFavail[j], &OFavail[i]);
418 OFavail[j].mr_size = 0;
419 still_merging = TRUE;
423 } while (still_merging == TRUE);
425 /* evict inactive ranges */
426 for (i = 0, fsz = 0; i < asz; i++) {
427 if (OFavail[i].mr_size != 0) {
428 OFfree[fsz] = OFavail[i];
438 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
440 if (ofmsr[0] & PSL_DR)
447 #ifdef FDT_DTB_STATIC
448 /* Check for a statically included blob */
450 fdt = &fdt_static_dtb;
457 boolean_t status = FALSE;
459 if (openfirmware_entry != NULL) {
461 status = OF_install(OFW_STD_REAL, 0);
464 status = OF_install(OFW_STD_32BIT, 0);
466 status = OF_install(OFW_STD_DIRECT, 0);
473 OF_init(openfirmware);
474 } else if (fdt != NULL) {
475 status = OF_install(OFW_FDT, 0);
495 KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up"));
497 args.name = (cell_t)(uintptr_t)"quiesce";
504 openfirmware_core(void *args)
510 * Turn off exceptions - we really don't want to end up
511 * anywhere unexpected with PCPU set to something strange
512 * or the stack pointer wrong.
514 oldmsr = intr_disable();
518 #if defined(AIM) && !defined(__powerpc64__)
520 * Clear battable[] translations
522 if (!(cpu_features & PPC_FEATURE_64))
523 __asm __volatile("mtdbatu 2, %0\n"
524 "mtdbatu 3, %0" : : "r" (0));
528 result = ofwcall(args);
531 intr_restore(oldmsr);
540 volatile int in_progress;
544 ofw_rendezvous_dispatch(void *xargs)
546 struct ofw_rv_args *rv_args = xargs;
548 /* NOTE: Interrupts are disabled here */
550 if (PCPU_GET(cpuid) == 0) {
552 * Execute all OF calls on CPU 0
554 rv_args->retval = openfirmware_core(rv_args->args);
555 rv_args->in_progress = 0;
558 * Spin with interrupts off on other CPUs while OF has
559 * control of the machine.
561 while (rv_args->in_progress)
568 openfirmware(void *args)
572 struct ofw_rv_args rv_args;
575 rv_args.in_progress = 1;
576 smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
577 smp_no_rendevous_barrier, &rv_args);
578 result = rv_args.retval;
580 result = openfirmware_core(args);
596 args.name = (cell_t)(uintptr_t)"interpret";
599 args.arg = (cell_t)(uintptr_t)"reset-all";
600 openfirmware_core(&args); /* Don't do rendezvous! */
602 for (;;); /* just in case */
606 OF_getetheraddr(device_t dev, u_char *addr)
610 node = ofw_bus_get_node(dev);
611 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
615 * Return a bus handle and bus tag that corresponds to the register
616 * numbered regno for the device referenced by the package handle
617 * dev. This function is intended to be used by console drivers in
618 * early boot only. It works by mapping the address of the device's
619 * register in the address space of its parent and recursively walk
620 * the device tree upward this way.
623 OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
629 res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
632 res = OF_getprop(node, "#size-cells", &size, sizeof(size));
636 if (addr == 3 && size == 2) {
637 res = OF_getprop(node, "name", name, sizeof(name));
639 name[sizeof(name) - 1] = '\0';
640 pci = (strcmp(name, "pci") == 0) ? 1 : 0;
652 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
653 bus_space_handle_t *handle)
656 bus_addr_t addr, raddr, baddr;
657 bus_size_t size, rsize;
658 uint32_t c, nbridge, naddr, nsize;
659 phandle_t bridge, parent;
660 u_int spc, rspc, prefetch;
663 /* Sanity checking. */
666 bridge = OF_parent(dev);
671 if (tag == NULL || handle == NULL)
674 /* Get the requested register. */
675 OF_get_addr_props(bridge, &naddr, &nsize, &pci);
676 res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
680 if (res % sizeof(cell[0]))
682 res /= sizeof(cell[0]);
683 regno *= naddr + nsize;
684 if (regno + naddr + nsize > res)
686 spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
687 prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0;
689 for (c = 0; c < naddr; c++)
690 addr = ((uint64_t)addr << 32) | cell[regno++];
692 for (c = 0; c < nsize; c++)
693 size = ((uint64_t)size << 32) | cell[regno++];
696 * Map the address range in the bridge's decoding window as given
697 * by the "ranges" property. If a node doesn't have such property
698 * then no mapping is done.
700 parent = OF_parent(bridge);
701 while (parent != 0) {
702 OF_get_addr_props(parent, &nbridge, NULL, &pcib);
703 res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
706 if (res % sizeof(cell[0]))
708 res /= sizeof(cell[0]);
710 while (regno < res) {
712 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
715 regno += naddr + nbridge + nsize;
719 for (c = 0; c < naddr; c++)
720 raddr = ((uint64_t)raddr << 32) | cell[regno++];
722 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
725 for (c = 0; c < nbridge; c++)
726 baddr = ((uint64_t)baddr << 32) | cell[regno++];
728 for (c = 0; c < nsize; c++)
729 rsize = ((uint64_t)rsize << 32) | cell[regno++];
730 if (addr < raddr || addr >= raddr + rsize)
732 addr = addr - raddr + baddr;
739 parent = OF_parent(bridge);
740 OF_get_addr_props(bridge, &naddr, &nsize, &pci);
744 return (bus_space_map(*tag, addr, size,
745 prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle));