1fe3b4685SNathan Whitehorn /*- 271e3c308SPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 371e3c308SPedro F. Giffuni * 4fe3b4685SNathan Whitehorn * Copyright (C) 1996 Wolfgang Solfrank. 5fe3b4685SNathan Whitehorn * Copyright (C) 1996 TooLs GmbH. 6fe3b4685SNathan Whitehorn * All rights reserved. 7fe3b4685SNathan Whitehorn * 8fe3b4685SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 9fe3b4685SNathan Whitehorn * modification, are permitted provided that the following conditions 10fe3b4685SNathan Whitehorn * are met: 11fe3b4685SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 12fe3b4685SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 13fe3b4685SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 14fe3b4685SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 15fe3b4685SNathan Whitehorn * documentation and/or other materials provided with the distribution. 16fe3b4685SNathan Whitehorn * 3. All advertising materials mentioning features or use of this software 17fe3b4685SNathan Whitehorn * must display the following acknowledgement: 18fe3b4685SNathan Whitehorn * This product includes software developed by TooLs GmbH. 19fe3b4685SNathan Whitehorn * 4. The name of TooLs GmbH may not be used to endorse or promote products 20fe3b4685SNathan Whitehorn * derived from this software without specific prior written permission. 21fe3b4685SNathan Whitehorn * 22fe3b4685SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23fe3b4685SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24fe3b4685SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25fe3b4685SNathan Whitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26fe3b4685SNathan Whitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27fe3b4685SNathan Whitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28fe3b4685SNathan Whitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29fe3b4685SNathan Whitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30fe3b4685SNathan Whitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31fe3b4685SNathan Whitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32fe3b4685SNathan Whitehorn * 33fe3b4685SNathan Whitehorn * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 34fe3b4685SNathan Whitehorn */ 35fe3b4685SNathan Whitehorn 36fe3b4685SNathan Whitehorn #include <sys/cdefs.h> 37fe3b4685SNathan Whitehorn __FBSDID("$FreeBSD$"); 38fe3b4685SNathan Whitehorn 398c092157SJustin Hibbits #include "opt_platform.h" 40fe3b4685SNathan Whitehorn #include <sys/param.h> 41fe3b4685SNathan Whitehorn #include <sys/bus.h> 42fe3b4685SNathan Whitehorn #include <sys/systm.h> 43fe3b4685SNathan Whitehorn #include <sys/conf.h> 44fe3b4685SNathan Whitehorn #include <sys/disk.h> 45fe3b4685SNathan Whitehorn #include <sys/fcntl.h> 46e2e050c8SConrad Meyer #include <sys/lock.h> 47fe3b4685SNathan Whitehorn #include <sys/malloc.h> 48fe3b4685SNathan Whitehorn #include <sys/smp.h> 49fe3b4685SNathan Whitehorn #include <sys/stat.h> 50b9d056f3SNathan Whitehorn #include <sys/endian.h> 51fe3b4685SNathan Whitehorn 52fe3b4685SNathan Whitehorn #include <net/ethernet.h> 53fe3b4685SNathan Whitehorn 548c092157SJustin Hibbits #include <dev/fdt/fdt_common.h> 55fe3b4685SNathan Whitehorn #include <dev/ofw/openfirm.h> 56fe3b4685SNathan Whitehorn #include <dev/ofw/ofw_pci.h> 57fe3b4685SNathan Whitehorn #include <dev/ofw/ofw_bus.h> 58bc7b9300SIan Lepore #include <dev/ofw/ofw_subr.h> 59fe3b4685SNathan Whitehorn 60fe3b4685SNathan Whitehorn #include <vm/vm.h> 61fe3b4685SNathan Whitehorn #include <vm/vm_param.h> 62fe3b4685SNathan Whitehorn #include <vm/vm_page.h> 6349d9a597SJustin Hibbits #include <vm/vm_phys.h> 64fe3b4685SNathan Whitehorn 65fe3b4685SNathan Whitehorn #include <machine/bus.h> 66fe3b4685SNathan Whitehorn #include <machine/cpu.h> 67fe3b4685SNathan Whitehorn #include <machine/md_var.h> 68fe3b4685SNathan Whitehorn #include <machine/platform.h> 69fe3b4685SNathan Whitehorn #include <machine/ofw_machdep.h> 70f367ffdeSAndreas Tobler #include <machine/trap.h> 71fe3b4685SNathan Whitehorn 72c0650b2fSNathan Whitehorn #include <contrib/libfdt/libfdt.h> 73c0650b2fSNathan Whitehorn 74fd8cf3beSJustin Hibbits #ifdef POWERNV 75fd8cf3beSJustin Hibbits #include <powerpc/powernv/opal.h> 76fd8cf3beSJustin Hibbits #endif 77fd8cf3beSJustin Hibbits 786f489d43SJustin Hibbits static void *fdt; 796f489d43SJustin Hibbits int ofw_real_mode; 806f489d43SJustin Hibbits 81629aa519SNathan Whitehorn #ifdef AIM 82fe3b4685SNathan Whitehorn extern register_t ofmsr[5]; 8317879090SNathan Whitehorn extern void *openfirmware_entry; 84bb808254SNathan Whitehorn char save_trap_init[0x2f00]; /* EXC_LAST */ 85f367ffdeSAndreas Tobler char save_trap_of[0x2f00]; /* EXC_LAST */ 86fe3b4685SNathan Whitehorn 87d8c6808aSNathan Whitehorn int ofwcall(void *); 88fe3b4685SNathan Whitehorn static int openfirmware(void *args); 89fe3b4685SNathan Whitehorn 90f367ffdeSAndreas Tobler __inline void 91f367ffdeSAndreas Tobler ofw_save_trap_vec(char *save_trap_vec) 92f367ffdeSAndreas Tobler { 93f9edb09dSNathan Whitehorn if (!ofw_real_mode || !hw_direct_map) 94f367ffdeSAndreas Tobler return; 95f367ffdeSAndreas Tobler 96f9edb09dSNathan Whitehorn bcopy((void *)PHYS_TO_DMAP(EXC_RST), save_trap_vec, EXC_LAST - EXC_RST); 97f367ffdeSAndreas Tobler } 98f367ffdeSAndreas Tobler 99f367ffdeSAndreas Tobler static __inline void 100f367ffdeSAndreas Tobler ofw_restore_trap_vec(char *restore_trap_vec) 101f367ffdeSAndreas Tobler { 102f9edb09dSNathan Whitehorn if (!ofw_real_mode || !hw_direct_map) 103f367ffdeSAndreas Tobler return; 104f367ffdeSAndreas Tobler 105f9edb09dSNathan Whitehorn bcopy(restore_trap_vec, (void *)PHYS_TO_DMAP(EXC_RST), 106f9edb09dSNathan Whitehorn EXC_LAST - EXC_RST); 107f9edb09dSNathan Whitehorn __syncicache((void *)PHYS_TO_DMAP(EXC_RSVD), EXC_LAST - EXC_RSVD); 108f367ffdeSAndreas Tobler } 1094aa3cee6SNathan Whitehorn 1104aa3cee6SNathan Whitehorn /* 1114aa3cee6SNathan Whitehorn * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 1124aa3cee6SNathan Whitehorn */ 1134aa3cee6SNathan Whitehorn register_t ofw_sprg0_save; 1144aa3cee6SNathan Whitehorn 1154aa3cee6SNathan Whitehorn static __inline void 1164aa3cee6SNathan Whitehorn ofw_sprg_prepare(void) 1174aa3cee6SNathan Whitehorn { 1184aa3cee6SNathan Whitehorn if (ofw_real_mode) 1194aa3cee6SNathan Whitehorn return; 1204aa3cee6SNathan Whitehorn 1214aa3cee6SNathan Whitehorn /* 1224aa3cee6SNathan Whitehorn * Assume that interrupt are disabled at this point, or 1234aa3cee6SNathan Whitehorn * SPRG1-3 could be trashed 1244aa3cee6SNathan Whitehorn */ 12562c6b30eSJustin Hibbits #ifdef __powerpc64__ 12662c6b30eSJustin Hibbits __asm __volatile("mtsprg1 %0\n\t" 12762c6b30eSJustin Hibbits "mtsprg2 %1\n\t" 12862c6b30eSJustin Hibbits "mtsprg3 %2\n\t" 12962c6b30eSJustin Hibbits : 13062c6b30eSJustin Hibbits : "r"(ofmsr[2]), 13162c6b30eSJustin Hibbits "r"(ofmsr[3]), 13262c6b30eSJustin Hibbits "r"(ofmsr[4])); 13362c6b30eSJustin Hibbits #else 1344aa3cee6SNathan Whitehorn __asm __volatile("mfsprg0 %0\n\t" 1354aa3cee6SNathan Whitehorn "mtsprg0 %1\n\t" 1364aa3cee6SNathan Whitehorn "mtsprg1 %2\n\t" 1374aa3cee6SNathan Whitehorn "mtsprg2 %3\n\t" 1384aa3cee6SNathan Whitehorn "mtsprg3 %4\n\t" 1394aa3cee6SNathan Whitehorn : "=&r"(ofw_sprg0_save) 1404aa3cee6SNathan Whitehorn : "r"(ofmsr[1]), 1414aa3cee6SNathan Whitehorn "r"(ofmsr[2]), 1424aa3cee6SNathan Whitehorn "r"(ofmsr[3]), 1434aa3cee6SNathan Whitehorn "r"(ofmsr[4])); 14462c6b30eSJustin Hibbits #endif 1454aa3cee6SNathan Whitehorn } 1464aa3cee6SNathan Whitehorn 1474aa3cee6SNathan Whitehorn static __inline void 1484aa3cee6SNathan Whitehorn ofw_sprg_restore(void) 1494aa3cee6SNathan Whitehorn { 1504aa3cee6SNathan Whitehorn if (ofw_real_mode) 1514aa3cee6SNathan Whitehorn return; 1524aa3cee6SNathan Whitehorn 1534aa3cee6SNathan Whitehorn /* 1544aa3cee6SNathan Whitehorn * Note that SPRG1-3 contents are irrelevant. They are scratch 1554aa3cee6SNathan Whitehorn * registers used in the early portion of trap handling when 1564aa3cee6SNathan Whitehorn * interrupts are disabled. 1574aa3cee6SNathan Whitehorn * 1584aa3cee6SNathan Whitehorn * PCPU data cannot be used until this routine is called ! 1594aa3cee6SNathan Whitehorn */ 16062c6b30eSJustin Hibbits #ifndef __powerpc64__ 1614aa3cee6SNathan Whitehorn __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 16262c6b30eSJustin Hibbits #endif 1634aa3cee6SNathan Whitehorn } 164c7291bdcSNathan Whitehorn #endif 165f367ffdeSAndreas Tobler 166fe3b4685SNathan Whitehorn static int 167fe3b4685SNathan Whitehorn parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 168fe3b4685SNathan Whitehorn { 169fe3b4685SNathan Whitehorn cell_t address_cells, size_cells; 170d8c6808aSNathan Whitehorn cell_t OFmem[4 * PHYS_AVAIL_SZ]; 171fe3b4685SNathan Whitehorn int sz, i, j; 172fe3b4685SNathan Whitehorn phandle_t phandle; 173fe3b4685SNathan Whitehorn 174fe3b4685SNathan Whitehorn sz = 0; 175fe3b4685SNathan Whitehorn 176fe3b4685SNathan Whitehorn /* 177fe3b4685SNathan Whitehorn * Get #address-cells from root node, defaulting to 1 if it cannot 178fe3b4685SNathan Whitehorn * be found. 179fe3b4685SNathan Whitehorn */ 180fe3b4685SNathan Whitehorn phandle = OF_finddevice("/"); 181509142e1SNathan Whitehorn if (OF_getencprop(phandle, "#address-cells", &address_cells, 1828bab0d80SNathan Whitehorn sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 183fe3b4685SNathan Whitehorn address_cells = 1; 184509142e1SNathan Whitehorn if (OF_getencprop(phandle, "#size-cells", &size_cells, 1858bab0d80SNathan Whitehorn sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 186fe3b4685SNathan Whitehorn size_cells = 1; 187fe3b4685SNathan Whitehorn 188fe3b4685SNathan Whitehorn /* 189fe3b4685SNathan Whitehorn * Get memory. 190fe3b4685SNathan Whitehorn */ 191509142e1SNathan Whitehorn if (node == -1 || (sz = OF_getencprop(node, prop, 192d8c6808aSNathan Whitehorn OFmem, sizeof(OFmem))) <= 0) 193fe3b4685SNathan Whitehorn panic("Physical memory map not found"); 194fe3b4685SNathan Whitehorn 195fe3b4685SNathan Whitehorn i = 0; 196fe3b4685SNathan Whitehorn j = 0; 197fe3b4685SNathan Whitehorn while (i < sz/sizeof(cell_t)) { 198fe3b4685SNathan Whitehorn output[j].mr_start = OFmem[i++]; 199fe3b4685SNathan Whitehorn if (address_cells == 2) { 200fe3b4685SNathan Whitehorn output[j].mr_start <<= 32; 201fe3b4685SNathan Whitehorn output[j].mr_start += OFmem[i++]; 202fe3b4685SNathan Whitehorn } 203fe3b4685SNathan Whitehorn 204fe3b4685SNathan Whitehorn output[j].mr_size = OFmem[i++]; 205fe3b4685SNathan Whitehorn if (size_cells == 2) { 206fe3b4685SNathan Whitehorn output[j].mr_size <<= 32; 207fe3b4685SNathan Whitehorn output[j].mr_size += OFmem[i++]; 208fe3b4685SNathan Whitehorn } 209fe3b4685SNathan Whitehorn 210bb7137e1SJustin Hibbits if (output[j].mr_start > BUS_SPACE_MAXADDR) 211bb7137e1SJustin Hibbits continue; 212bb7137e1SJustin Hibbits 213fe3b4685SNathan Whitehorn /* 214bb7137e1SJustin Hibbits * Constrain memory to that which we can access. 215bb7137e1SJustin Hibbits * 32-bit AIM can only reference 32 bits of address currently, 216bb7137e1SJustin Hibbits * but Book-E can access 36 bits. 217fe3b4685SNathan Whitehorn */ 218fe3b4685SNathan Whitehorn if (((uint64_t)output[j].mr_start + 219bb7137e1SJustin Hibbits (uint64_t)output[j].mr_size - 1) > 220bb7137e1SJustin Hibbits BUS_SPACE_MAXADDR) { 221bb7137e1SJustin Hibbits output[j].mr_size = BUS_SPACE_MAXADDR - 222bb7137e1SJustin Hibbits output[j].mr_start + 1; 223fe3b4685SNathan Whitehorn } 224fe3b4685SNathan Whitehorn 225fe3b4685SNathan Whitehorn j++; 226fe3b4685SNathan Whitehorn } 227fe3b4685SNathan Whitehorn 22849d9a597SJustin Hibbits return (j); 22949d9a597SJustin Hibbits } 23049d9a597SJustin Hibbits 23149d9a597SJustin Hibbits static int 23249d9a597SJustin Hibbits parse_numa_ofw_memory(phandle_t node, const char *prop, 23349d9a597SJustin Hibbits struct numa_mem_region *output) 23449d9a597SJustin Hibbits { 23549d9a597SJustin Hibbits cell_t address_cells, size_cells; 23649d9a597SJustin Hibbits cell_t OFmem[4 * PHYS_AVAIL_SZ]; 23749d9a597SJustin Hibbits int sz, i, j; 23849d9a597SJustin Hibbits phandle_t phandle; 23949d9a597SJustin Hibbits 24049d9a597SJustin Hibbits sz = 0; 24149d9a597SJustin Hibbits 24249d9a597SJustin Hibbits /* 24349d9a597SJustin Hibbits * Get #address-cells from root node, defaulting to 1 if it cannot 24449d9a597SJustin Hibbits * be found. 24549d9a597SJustin Hibbits */ 24649d9a597SJustin Hibbits phandle = OF_finddevice("/"); 24749d9a597SJustin Hibbits if (OF_getencprop(phandle, "#address-cells", &address_cells, 24849d9a597SJustin Hibbits sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 24949d9a597SJustin Hibbits address_cells = 1; 25049d9a597SJustin Hibbits if (OF_getencprop(phandle, "#size-cells", &size_cells, 25149d9a597SJustin Hibbits sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 25249d9a597SJustin Hibbits size_cells = 1; 25349d9a597SJustin Hibbits 25449d9a597SJustin Hibbits /* 25549d9a597SJustin Hibbits * Get memory. 25649d9a597SJustin Hibbits */ 25749d9a597SJustin Hibbits if (node == -1 || (sz = OF_getencprop(node, prop, 25849d9a597SJustin Hibbits OFmem, sizeof(OFmem))) <= 0) 25949d9a597SJustin Hibbits panic("Physical memory map not found"); 26049d9a597SJustin Hibbits 26149d9a597SJustin Hibbits i = 0; 26249d9a597SJustin Hibbits j = 0; 26349d9a597SJustin Hibbits while (i < sz/sizeof(cell_t)) { 26449d9a597SJustin Hibbits output[j].mr_start = OFmem[i++]; 26549d9a597SJustin Hibbits if (address_cells == 2) { 26649d9a597SJustin Hibbits output[j].mr_start <<= 32; 26749d9a597SJustin Hibbits output[j].mr_start += OFmem[i++]; 26849d9a597SJustin Hibbits } 26949d9a597SJustin Hibbits output[j].mr_size = OFmem[i++]; 27049d9a597SJustin Hibbits if (size_cells == 2) { 27149d9a597SJustin Hibbits output[j].mr_size <<= 32; 27249d9a597SJustin Hibbits output[j].mr_size += OFmem[i++]; 27349d9a597SJustin Hibbits } 27449d9a597SJustin Hibbits j++; 27549d9a597SJustin Hibbits } 27649d9a597SJustin Hibbits 27749d9a597SJustin Hibbits return (j); 278fe3b4685SNathan Whitehorn } 279fe3b4685SNathan Whitehorn 28035feca37SNathan Whitehorn #ifdef FDT 281b9d056f3SNathan Whitehorn static int 28248f64992SBreno Leitao excise_reserved_regions(struct mem_region *avail, int asz, 28348f64992SBreno Leitao struct mem_region *exclude, int esz) 284b9d056f3SNathan Whitehorn { 285b9d056f3SNathan Whitehorn int i, j, k; 286b9d056f3SNathan Whitehorn 287b9d056f3SNathan Whitehorn for (i = 0; i < asz; i++) { 28848f64992SBreno Leitao for (j = 0; j < esz; j++) { 289b9d056f3SNathan Whitehorn /* 290b9d056f3SNathan Whitehorn * Case 1: Exclusion region encloses complete 291b9d056f3SNathan Whitehorn * available entry. Drop it and move on. 292b9d056f3SNathan Whitehorn */ 29348f64992SBreno Leitao if (exclude[j].mr_start <= avail[i].mr_start && 29448f64992SBreno Leitao exclude[j].mr_start + exclude[j].mr_size >= 295b9d056f3SNathan Whitehorn avail[i].mr_start + avail[i].mr_size) { 296b9d056f3SNathan Whitehorn for (k = i+1; k < asz; k++) 297b9d056f3SNathan Whitehorn avail[k-1] = avail[k]; 298b9d056f3SNathan Whitehorn asz--; 299b9d056f3SNathan Whitehorn i--; /* Repeat some entries */ 300b9d056f3SNathan Whitehorn continue; 301b9d056f3SNathan Whitehorn } 302b9d056f3SNathan Whitehorn 303b9d056f3SNathan Whitehorn /* 304b9d056f3SNathan Whitehorn * Case 2: Exclusion region starts in available entry. 305b9d056f3SNathan Whitehorn * Trim it to where the entry begins and append 306b9d056f3SNathan Whitehorn * a new available entry with the region after 307b9d056f3SNathan Whitehorn * the excluded region, if any. 308b9d056f3SNathan Whitehorn */ 30948f64992SBreno Leitao if (exclude[j].mr_start >= avail[i].mr_start && 31048f64992SBreno Leitao exclude[j].mr_start < avail[i].mr_start + 311b9d056f3SNathan Whitehorn avail[i].mr_size) { 31248f64992SBreno Leitao if (exclude[j].mr_start + exclude[j].mr_size < 313b9d056f3SNathan Whitehorn avail[i].mr_start + avail[i].mr_size) { 314b9d056f3SNathan Whitehorn avail[asz].mr_start = 31548f64992SBreno Leitao exclude[j].mr_start + exclude[j].mr_size; 316b9d056f3SNathan Whitehorn avail[asz].mr_size = avail[i].mr_start + 317b9d056f3SNathan Whitehorn avail[i].mr_size - 318b9d056f3SNathan Whitehorn avail[asz].mr_start; 319b9d056f3SNathan Whitehorn asz++; 320b9d056f3SNathan Whitehorn } 321b9d056f3SNathan Whitehorn 32248f64992SBreno Leitao avail[i].mr_size = exclude[j].mr_start - 323b9d056f3SNathan Whitehorn avail[i].mr_start; 324b9d056f3SNathan Whitehorn } 325b9d056f3SNathan Whitehorn 326b9d056f3SNathan Whitehorn /* 327b9d056f3SNathan Whitehorn * Case 3: Exclusion region ends in available entry. 328b9d056f3SNathan Whitehorn * Move start point to where the exclusion zone ends. 329b9d056f3SNathan Whitehorn * The case of a contained exclusion zone has already 330b9d056f3SNathan Whitehorn * been caught in case 2. 331b9d056f3SNathan Whitehorn */ 33248f64992SBreno Leitao if (exclude[j].mr_start + exclude[j].mr_size >= 33348f64992SBreno Leitao avail[i].mr_start && exclude[j].mr_start + 33448f64992SBreno Leitao exclude[j].mr_size < avail[i].mr_start + 335b9d056f3SNathan Whitehorn avail[i].mr_size) { 336922a3152SNathan Whitehorn avail[i].mr_size += avail[i].mr_start; 337b9d056f3SNathan Whitehorn avail[i].mr_start = 33848f64992SBreno Leitao exclude[j].mr_start + exclude[j].mr_size; 339922a3152SNathan Whitehorn avail[i].mr_size -= avail[i].mr_start; 340b9d056f3SNathan Whitehorn } 341b9d056f3SNathan Whitehorn } 342b9d056f3SNathan Whitehorn } 343b9d056f3SNathan Whitehorn 344b9d056f3SNathan Whitehorn return (asz); 345b9d056f3SNathan Whitehorn } 34648f64992SBreno Leitao 34748f64992SBreno Leitao static int 34848f64992SBreno Leitao excise_initrd_region(struct mem_region *avail, int asz) 34948f64992SBreno Leitao { 35048f64992SBreno Leitao phandle_t chosen; 35148f64992SBreno Leitao uint64_t start, end; 35248f64992SBreno Leitao ssize_t size; 35348f64992SBreno Leitao struct mem_region initrdmap[1]; 3546d645c57SBreno Leitao pcell_t cell[2]; 35548f64992SBreno Leitao 35648f64992SBreno Leitao chosen = OF_finddevice("/chosen"); 35748f64992SBreno Leitao 3586d645c57SBreno Leitao size = OF_getencprop(chosen, "linux,initrd-start", cell, sizeof(cell)); 3596d645c57SBreno Leitao if (size < 0) 3606d645c57SBreno Leitao return (asz); 3616d645c57SBreno Leitao else if (size == 4) 3626d645c57SBreno Leitao start = cell[0]; 3636d645c57SBreno Leitao else if (size == 8) 3646d645c57SBreno Leitao start = (uint64_t)cell[0] << 32 | cell[1]; 3656d645c57SBreno Leitao else { 3666d645c57SBreno Leitao /* Invalid value length */ 3676d645c57SBreno Leitao printf("WARNING: linux,initrd-start must be either 4 or 8 bytes long\n"); 3686d645c57SBreno Leitao return (asz); 3696d645c57SBreno Leitao } 3706d645c57SBreno Leitao 3716d645c57SBreno Leitao size = OF_getencprop(chosen, "linux,initrd-end", cell, sizeof(cell)); 3726d645c57SBreno Leitao if (size < 0) 3736d645c57SBreno Leitao return (asz); 3746d645c57SBreno Leitao else if (size == 4) 3756d645c57SBreno Leitao end = cell[0]; 3766d645c57SBreno Leitao else if (size == 8) 3776d645c57SBreno Leitao end = (uint64_t)cell[0] << 32 | cell[1]; 3786d645c57SBreno Leitao else { 3796d645c57SBreno Leitao /* Invalid value length */ 3806d645c57SBreno Leitao printf("WARNING: linux,initrd-end must be either 4 or 8 bytes long\n"); 3816d645c57SBreno Leitao return (asz); 3826d645c57SBreno Leitao } 3836d645c57SBreno Leitao 3846d645c57SBreno Leitao if (end <= start) 38548f64992SBreno Leitao return (asz); 38648f64992SBreno Leitao 38748f64992SBreno Leitao initrdmap[0].mr_start = start; 38848f64992SBreno Leitao initrdmap[0].mr_size = end - start; 38948f64992SBreno Leitao 39048f64992SBreno Leitao asz = excise_reserved_regions(avail, asz, initrdmap, 1); 39148f64992SBreno Leitao 39248f64992SBreno Leitao return (asz); 39348f64992SBreno Leitao } 39448f64992SBreno Leitao 395fd8cf3beSJustin Hibbits #ifdef POWERNV 396fd8cf3beSJustin Hibbits static int 397fd8cf3beSJustin Hibbits excise_msi_region(struct mem_region *avail, int asz) 398fd8cf3beSJustin Hibbits { 399fd8cf3beSJustin Hibbits uint64_t start, end; 400fd8cf3beSJustin Hibbits struct mem_region initrdmap[1]; 401fd8cf3beSJustin Hibbits 402fd8cf3beSJustin Hibbits /* 403fd8cf3beSJustin Hibbits * This range of physical addresses is used to implement optimized 404fd8cf3beSJustin Hibbits * 32 bit MSI interrupts on POWER9. Exclude it to avoid accidentally 405fd8cf3beSJustin Hibbits * using it for DMA, as this will cause an immediate PHB fence. 406fd8cf3beSJustin Hibbits * While we could theoretically turn off this behavior in the ETU, 407fd8cf3beSJustin Hibbits * doing so would break 32-bit MSI, so just reserve the range in 408fd8cf3beSJustin Hibbits * the physical map instead. 409fd8cf3beSJustin Hibbits * See section 4.4.2.8 of the PHB4 specification. 410fd8cf3beSJustin Hibbits */ 411fd8cf3beSJustin Hibbits start = 0x00000000ffff0000ul; 412fd8cf3beSJustin Hibbits end = 0x00000000fffffffful; 413fd8cf3beSJustin Hibbits 414fd8cf3beSJustin Hibbits initrdmap[0].mr_start = start; 415fd8cf3beSJustin Hibbits initrdmap[0].mr_size = end - start; 416fd8cf3beSJustin Hibbits 417fd8cf3beSJustin Hibbits asz = excise_reserved_regions(avail, asz, initrdmap, 1); 418fd8cf3beSJustin Hibbits 419fd8cf3beSJustin Hibbits return (asz); 420fd8cf3beSJustin Hibbits } 421fd8cf3beSJustin Hibbits #endif 422fd8cf3beSJustin Hibbits 42348f64992SBreno Leitao static int 42448f64992SBreno Leitao excise_fdt_reserved(struct mem_region *avail, int asz) 42548f64992SBreno Leitao { 42648f64992SBreno Leitao struct mem_region fdtmap[32]; 42748f64992SBreno Leitao ssize_t fdtmapsize; 42848f64992SBreno Leitao phandle_t chosen; 42948f64992SBreno Leitao int j, fdtentries; 43048f64992SBreno Leitao 43148f64992SBreno Leitao chosen = OF_finddevice("/chosen"); 43248f64992SBreno Leitao fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); 43348f64992SBreno Leitao 43448f64992SBreno Leitao for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 43548f64992SBreno Leitao fdtmap[j].mr_start = be64toh(fdtmap[j].mr_start) & ~PAGE_MASK; 43648f64992SBreno Leitao fdtmap[j].mr_size = round_page(be64toh(fdtmap[j].mr_size)); 43748f64992SBreno Leitao } 43848f64992SBreno Leitao 43948f64992SBreno Leitao KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap), 44048f64992SBreno Leitao ("Exceeded number of FDT reservations")); 44148f64992SBreno Leitao /* Add a virtual entry for the FDT itself */ 44248f64992SBreno Leitao if (fdt != NULL) { 44348f64992SBreno Leitao fdtmap[j].mr_start = (vm_offset_t)fdt & ~PAGE_MASK; 44448f64992SBreno Leitao fdtmap[j].mr_size = round_page(fdt_totalsize(fdt)); 44548f64992SBreno Leitao fdtmapsize += sizeof(fdtmap[0]); 44648f64992SBreno Leitao } 44748f64992SBreno Leitao 44848f64992SBreno Leitao fdtentries = fdtmapsize/sizeof(fdtmap[0]); 44948f64992SBreno Leitao asz = excise_reserved_regions(avail, asz, fdtmap, fdtentries); 45048f64992SBreno Leitao 45148f64992SBreno Leitao return (asz); 45248f64992SBreno Leitao } 45335feca37SNathan Whitehorn #endif 454b9d056f3SNathan Whitehorn 455fe3b4685SNathan Whitehorn /* 456fe3b4685SNathan Whitehorn * This is called during powerpc_init, before the system is really initialized. 457fe3b4685SNathan Whitehorn * It shall provide the total and the available regions of RAM. 458b9d056f3SNathan Whitehorn * The available regions need not take the kernel into account. 459fe3b4685SNathan Whitehorn */ 460fe3b4685SNathan Whitehorn void 46149d9a597SJustin Hibbits ofw_numa_mem_regions(struct numa_mem_region *memp, int *memsz) 46249d9a597SJustin Hibbits { 46349d9a597SJustin Hibbits phandle_t phandle; 46449d9a597SJustin Hibbits int res, count, msz; 46549d9a597SJustin Hibbits char name[31]; 46649d9a597SJustin Hibbits cell_t associativity[5]; 46749d9a597SJustin Hibbits struct numa_mem_region *curmemp; 46849d9a597SJustin Hibbits 46949d9a597SJustin Hibbits msz = 0; 47049d9a597SJustin Hibbits /* 47149d9a597SJustin Hibbits * Get memory from all the /memory nodes. 47249d9a597SJustin Hibbits */ 47349d9a597SJustin Hibbits for (phandle = OF_child(OF_peer(0)); phandle != 0; 47449d9a597SJustin Hibbits phandle = OF_peer(phandle)) { 47549d9a597SJustin Hibbits if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 47649d9a597SJustin Hibbits continue; 47749d9a597SJustin Hibbits if (strncmp(name, "memory@", strlen("memory@")) != 0) 47849d9a597SJustin Hibbits continue; 47949d9a597SJustin Hibbits 48049d9a597SJustin Hibbits count = parse_numa_ofw_memory(phandle, "reg", &memp[msz]); 48149d9a597SJustin Hibbits if (count == 0) 48249d9a597SJustin Hibbits continue; 48349d9a597SJustin Hibbits curmemp = &memp[msz]; 48449d9a597SJustin Hibbits res = OF_getproplen(phandle, "ibm,associativity"); 48549d9a597SJustin Hibbits if (res <= 0) 48649d9a597SJustin Hibbits continue; 48749d9a597SJustin Hibbits MPASS(count == 1); 48849d9a597SJustin Hibbits OF_getencprop(phandle, "ibm,associativity", 48949d9a597SJustin Hibbits associativity, res); 49049d9a597SJustin Hibbits curmemp->mr_domain = associativity[3] - 1; 49149d9a597SJustin Hibbits if (bootverbose) 49249d9a597SJustin Hibbits printf("%s %#jx-%#jx domain(%ju)\n", 49349d9a597SJustin Hibbits name, (uintmax_t)curmemp->mr_start, 49449d9a597SJustin Hibbits (uintmax_t)curmemp->mr_start + curmemp->mr_size, 49549d9a597SJustin Hibbits (uintmax_t)curmemp->mr_domain); 49649d9a597SJustin Hibbits msz += count; 49749d9a597SJustin Hibbits } 49849d9a597SJustin Hibbits *memsz = msz; 49949d9a597SJustin Hibbits } 50049d9a597SJustin Hibbits /* 50149d9a597SJustin Hibbits * This is called during powerpc_init, before the system is really initialized. 50249d9a597SJustin Hibbits * It shall provide the total and the available regions of RAM. 50349d9a597SJustin Hibbits * The available regions need not take the kernel into account. 50449d9a597SJustin Hibbits */ 50549d9a597SJustin Hibbits void 506c1cb22d7SNathan Whitehorn ofw_mem_regions(struct mem_region *memp, int *memsz, 507c1cb22d7SNathan Whitehorn struct mem_region *availp, int *availsz) 508fe3b4685SNathan Whitehorn { 509fe3b4685SNathan Whitehorn phandle_t phandle; 510c1cb22d7SNathan Whitehorn int asz, msz; 511c1cb22d7SNathan Whitehorn int res; 512d8c6808aSNathan Whitehorn char name[31]; 513fe3b4685SNathan Whitehorn 514fe3b4685SNathan Whitehorn asz = msz = 0; 515fe3b4685SNathan Whitehorn 516fe3b4685SNathan Whitehorn /* 517d8c6808aSNathan Whitehorn * Get memory from all the /memory nodes. 518fe3b4685SNathan Whitehorn */ 519d8c6808aSNathan Whitehorn for (phandle = OF_child(OF_peer(0)); phandle != 0; 520d8c6808aSNathan Whitehorn phandle = OF_peer(phandle)) { 521d8c6808aSNathan Whitehorn if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 522d8c6808aSNathan Whitehorn continue; 523b9d056f3SNathan Whitehorn if (strncmp(name, "memory", sizeof(name)) != 0 && 524b9d056f3SNathan Whitehorn strncmp(name, "memory@", strlen("memory@")) != 0) 525d8c6808aSNathan Whitehorn continue; 526fe3b4685SNathan Whitehorn 527c1cb22d7SNathan Whitehorn res = parse_ofw_memory(phandle, "reg", &memp[msz]); 52849d9a597SJustin Hibbits msz += res; 529876f3b92SJustin Hibbits 530876f3b92SJustin Hibbits /* 531876f3b92SJustin Hibbits * On POWER9 Systems we might have both linux,usable-memory and 532876f3b92SJustin Hibbits * reg properties. 'reg' denotes all available memory, but we 533876f3b92SJustin Hibbits * must use 'linux,usable-memory', a subset, as some memory 534876f3b92SJustin Hibbits * regions are reserved for NVLink. 535876f3b92SJustin Hibbits */ 536876f3b92SJustin Hibbits if (OF_getproplen(phandle, "linux,usable-memory") >= 0) 537876f3b92SJustin Hibbits res = parse_ofw_memory(phandle, "linux,usable-memory", 538876f3b92SJustin Hibbits &availp[asz]); 539c07c77a3SJustin Hibbits else if (OF_getproplen(phandle, "available") >= 0) 540d8c6808aSNathan Whitehorn res = parse_ofw_memory(phandle, "available", 541c1cb22d7SNathan Whitehorn &availp[asz]); 542d8c6808aSNathan Whitehorn else 543c1cb22d7SNathan Whitehorn res = parse_ofw_memory(phandle, "reg", &availp[asz]); 54449d9a597SJustin Hibbits asz += res; 545d8c6808aSNathan Whitehorn } 546d8c6808aSNathan Whitehorn 54735feca37SNathan Whitehorn #ifdef FDT 548b9d056f3SNathan Whitehorn phandle = OF_finddevice("/chosen"); 549b9d056f3SNathan Whitehorn if (OF_hasprop(phandle, "fdtmemreserv")) 550b9d056f3SNathan Whitehorn asz = excise_fdt_reserved(availp, asz); 55148f64992SBreno Leitao 55248f64992SBreno Leitao /* If the kernel is being loaded through kexec, initrd region is listed 55348f64992SBreno Leitao * in /chosen but the region is not marked as reserved, so, we might exclude 55448f64992SBreno Leitao * it here. 55548f64992SBreno Leitao */ 55648f64992SBreno Leitao if (OF_hasprop(phandle, "linux,initrd-start")) 55748f64992SBreno Leitao asz = excise_initrd_region(availp, asz); 55835feca37SNathan Whitehorn #endif 559b9d056f3SNathan Whitehorn 560fd8cf3beSJustin Hibbits #ifdef POWERNV 561fd8cf3beSJustin Hibbits if (opal_check() == 0) 562fd8cf3beSJustin Hibbits asz = excise_msi_region(availp, asz); 563fd8cf3beSJustin Hibbits #endif 564fd8cf3beSJustin Hibbits 565d8c6808aSNathan Whitehorn *memsz = msz; 566c1cb22d7SNathan Whitehorn *availsz = asz; 567fe3b4685SNathan Whitehorn } 568fe3b4685SNathan Whitehorn 569fe3b4685SNathan Whitehorn void 570fe3b4685SNathan Whitehorn OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 571fe3b4685SNathan Whitehorn { 5726f489d43SJustin Hibbits #ifdef AIM 573bb808254SNathan Whitehorn ofmsr[0] = mfmsr(); 574bb808254SNathan Whitehorn #ifdef __powerpc64__ 575bb808254SNathan Whitehorn ofmsr[0] &= ~PSL_SF; 57662c6b30eSJustin Hibbits #else 577bb808254SNathan Whitehorn __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1])); 57862c6b30eSJustin Hibbits #endif 579bb808254SNathan Whitehorn __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2])); 580bb808254SNathan Whitehorn __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3])); 581bb808254SNathan Whitehorn __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4])); 5826f489d43SJustin Hibbits openfirmware_entry = openfirm; 583bb808254SNathan Whitehorn 584fe3b4685SNathan Whitehorn if (ofmsr[0] & PSL_DR) 585fe3b4685SNathan Whitehorn ofw_real_mode = 0; 586fe3b4685SNathan Whitehorn else 587fe3b4685SNathan Whitehorn ofw_real_mode = 1; 588fe3b4685SNathan Whitehorn 5896f489d43SJustin Hibbits ofw_save_trap_vec(save_trap_init); 5906f489d43SJustin Hibbits #else 5916f489d43SJustin Hibbits ofw_real_mode = 1; 5926f489d43SJustin Hibbits #endif 5936f489d43SJustin Hibbits 594fe3b4685SNathan Whitehorn fdt = fdt_ptr; 595fe3b4685SNathan Whitehorn } 596fe3b4685SNathan Whitehorn 597fe3b4685SNathan Whitehorn boolean_t 598fe3b4685SNathan Whitehorn OF_bootstrap() 599fe3b4685SNathan Whitehorn { 600fe3b4685SNathan Whitehorn boolean_t status = FALSE; 6012bfca577SNathan Whitehorn int err = 0; 602fe3b4685SNathan Whitehorn 6036f489d43SJustin Hibbits #ifdef AIM 60417879090SNathan Whitehorn if (openfirmware_entry != NULL) { 605fe3b4685SNathan Whitehorn if (ofw_real_mode) { 606fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_REAL, 0); 607fe3b4685SNathan Whitehorn } else { 608fe3b4685SNathan Whitehorn #ifdef __powerpc64__ 609fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_32BIT, 0); 610fe3b4685SNathan Whitehorn #else 611fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_DIRECT, 0); 612fe3b4685SNathan Whitehorn #endif 613fe3b4685SNathan Whitehorn } 614fe3b4685SNathan Whitehorn 615fe3b4685SNathan Whitehorn if (status != TRUE) 616fe3b4685SNathan Whitehorn return status; 617fe3b4685SNathan Whitehorn 6182bfca577SNathan Whitehorn err = OF_init(openfirmware); 6196f489d43SJustin Hibbits } else 6206f489d43SJustin Hibbits #endif 6216f489d43SJustin Hibbits if (fdt != NULL) { 62235feca37SNathan Whitehorn #ifdef FDT 623f9edb09dSNathan Whitehorn #ifdef AIM 624f9edb09dSNathan Whitehorn bus_space_tag_t fdt_bt; 625f9edb09dSNathan Whitehorn vm_offset_t tmp_fdt_ptr; 626f9edb09dSNathan Whitehorn vm_size_t fdt_size; 627f9edb09dSNathan Whitehorn uintptr_t fdt_va; 628f9edb09dSNathan Whitehorn #endif 629fe3b4685SNathan Whitehorn 630f9edb09dSNathan Whitehorn status = OF_install(OFW_FDT, 0); 631fe3b4685SNathan Whitehorn if (status != TRUE) 632fe3b4685SNathan Whitehorn return status; 633fe3b4685SNathan Whitehorn 634f9edb09dSNathan Whitehorn #ifdef AIM /* AIM-only for now -- Book-E does this remapping in early init */ 635f9edb09dSNathan Whitehorn /* Get the FDT size for mapping if we can */ 636f9edb09dSNathan Whitehorn tmp_fdt_ptr = pmap_early_io_map((vm_paddr_t)fdt, PAGE_SIZE); 637f9edb09dSNathan Whitehorn if (fdt_check_header((void *)tmp_fdt_ptr) != 0) { 638f9edb09dSNathan Whitehorn pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE); 639f9edb09dSNathan Whitehorn return FALSE; 640fe3b4685SNathan Whitehorn } 641f9edb09dSNathan Whitehorn fdt_size = fdt_totalsize((void *)tmp_fdt_ptr); 642f9edb09dSNathan Whitehorn pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE); 643f9edb09dSNathan Whitehorn 644f9edb09dSNathan Whitehorn /* 645f9edb09dSNathan Whitehorn * Map this for real. Use bus_space_map() to take advantage 646f9edb09dSNathan Whitehorn * of its auto-remapping function once the kernel is loaded. 647f9edb09dSNathan Whitehorn * This is a dirty hack, but what we have. 648f9edb09dSNathan Whitehorn */ 649f9edb09dSNathan Whitehorn #ifdef _LITTLE_ENDIAN 650f9edb09dSNathan Whitehorn fdt_bt = &bs_le_tag; 651f9edb09dSNathan Whitehorn #else 652f9edb09dSNathan Whitehorn fdt_bt = &bs_be_tag; 653f9edb09dSNathan Whitehorn #endif 654f9edb09dSNathan Whitehorn bus_space_map(fdt_bt, (vm_paddr_t)fdt, fdt_size, 0, &fdt_va); 655f9edb09dSNathan Whitehorn 656f9edb09dSNathan Whitehorn err = OF_init((void *)fdt_va); 657f9edb09dSNathan Whitehorn #else 658f9edb09dSNathan Whitehorn err = OF_init(fdt); 659f9edb09dSNathan Whitehorn #endif 66035feca37SNathan Whitehorn #endif 661f9edb09dSNathan Whitehorn } 662f9edb09dSNathan Whitehorn 663f9edb09dSNathan Whitehorn #ifdef FDT_DTB_STATIC 664f9edb09dSNathan Whitehorn /* 665f9edb09dSNathan Whitehorn * Check for a statically included blob already in the kernel and 666f9edb09dSNathan Whitehorn * needing no mapping. 667f9edb09dSNathan Whitehorn */ 668f9edb09dSNathan Whitehorn else { 669f9edb09dSNathan Whitehorn status = OF_install(OFW_FDT, 0); 670f9edb09dSNathan Whitehorn if (status != TRUE) 671f9edb09dSNathan Whitehorn return status; 672f9edb09dSNathan Whitehorn err = OF_init(&fdt_static_dtb); 673f9edb09dSNathan Whitehorn } 674f9edb09dSNathan Whitehorn #endif 675fe3b4685SNathan Whitehorn 6762bfca577SNathan Whitehorn if (err != 0) { 6772bfca577SNathan Whitehorn OF_install(NULL, 0); 6782bfca577SNathan Whitehorn status = FALSE; 6792bfca577SNathan Whitehorn } 6802bfca577SNathan Whitehorn 681fe3b4685SNathan Whitehorn return (status); 682fe3b4685SNathan Whitehorn } 683fe3b4685SNathan Whitehorn 6846f489d43SJustin Hibbits #ifdef AIM 6859f706727SNathan Whitehorn void 686fe3b4685SNathan Whitehorn ofw_quiesce(void) 687fe3b4685SNathan Whitehorn { 688fe3b4685SNathan Whitehorn struct { 689fe3b4685SNathan Whitehorn cell_t name; 690fe3b4685SNathan Whitehorn cell_t nargs; 691fe3b4685SNathan Whitehorn cell_t nreturns; 692fe3b4685SNathan Whitehorn } args; 693fe3b4685SNathan Whitehorn 6949f706727SNathan Whitehorn KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 695fe3b4685SNathan Whitehorn 696fe3b4685SNathan Whitehorn args.name = (cell_t)(uintptr_t)"quiesce"; 697fe3b4685SNathan Whitehorn args.nargs = 0; 698fe3b4685SNathan Whitehorn args.nreturns = 0; 699fe3b4685SNathan Whitehorn openfirmware(&args); 700fe3b4685SNathan Whitehorn } 701fe3b4685SNathan Whitehorn 702fe3b4685SNathan Whitehorn static int 703fe3b4685SNathan Whitehorn openfirmware_core(void *args) 704fe3b4685SNathan Whitehorn { 705fe3b4685SNathan Whitehorn int result; 706fe3b4685SNathan Whitehorn register_t oldmsr; 707fe3b4685SNathan Whitehorn 70844d29d47SNathan Whitehorn if (openfirmware_entry == NULL) 70944d29d47SNathan Whitehorn return (-1); 71044d29d47SNathan Whitehorn 711fe3b4685SNathan Whitehorn /* 712fe3b4685SNathan Whitehorn * Turn off exceptions - we really don't want to end up 7134aa3cee6SNathan Whitehorn * anywhere unexpected with PCPU set to something strange 7144aa3cee6SNathan Whitehorn * or the stack pointer wrong. 715fe3b4685SNathan Whitehorn */ 716fe3b4685SNathan Whitehorn oldmsr = intr_disable(); 717fe3b4685SNathan Whitehorn 7184aa3cee6SNathan Whitehorn ofw_sprg_prepare(); 7194aa3cee6SNathan Whitehorn 720f367ffdeSAndreas Tobler /* Save trap vectors */ 721f367ffdeSAndreas Tobler ofw_save_trap_vec(save_trap_of); 722f367ffdeSAndreas Tobler 723f367ffdeSAndreas Tobler /* Restore initially saved trap vectors */ 724f367ffdeSAndreas Tobler ofw_restore_trap_vec(save_trap_init); 725f367ffdeSAndreas Tobler 72695ce4c00SJustin Hibbits #ifndef __powerpc64__ 727fe3b4685SNathan Whitehorn /* 728fe3b4685SNathan Whitehorn * Clear battable[] translations 729fe3b4685SNathan Whitehorn */ 730fe3b4685SNathan Whitehorn if (!(cpu_features & PPC_FEATURE_64)) 731fe3b4685SNathan Whitehorn __asm __volatile("mtdbatu 2, %0\n" 732fe3b4685SNathan Whitehorn "mtdbatu 3, %0" : : "r" (0)); 733fe3b4685SNathan Whitehorn isync(); 734fe3b4685SNathan Whitehorn #endif 735fe3b4685SNathan Whitehorn 736fe3b4685SNathan Whitehorn result = ofwcall(args); 737f367ffdeSAndreas Tobler 738f367ffdeSAndreas Tobler /* Restore trap vecotrs */ 739f367ffdeSAndreas Tobler ofw_restore_trap_vec(save_trap_of); 740f367ffdeSAndreas Tobler 7414aa3cee6SNathan Whitehorn ofw_sprg_restore(); 7424aa3cee6SNathan Whitehorn 743fe3b4685SNathan Whitehorn intr_restore(oldmsr); 744fe3b4685SNathan Whitehorn 745fe3b4685SNathan Whitehorn return (result); 746fe3b4685SNathan Whitehorn } 747fe3b4685SNathan Whitehorn 748fe3b4685SNathan Whitehorn #ifdef SMP 749fe3b4685SNathan Whitehorn struct ofw_rv_args { 750fe3b4685SNathan Whitehorn void *args; 751fe3b4685SNathan Whitehorn int retval; 752fe3b4685SNathan Whitehorn volatile int in_progress; 753fe3b4685SNathan Whitehorn }; 754fe3b4685SNathan Whitehorn 755fe3b4685SNathan Whitehorn static void 756fe3b4685SNathan Whitehorn ofw_rendezvous_dispatch(void *xargs) 757fe3b4685SNathan Whitehorn { 758fe3b4685SNathan Whitehorn struct ofw_rv_args *rv_args = xargs; 759fe3b4685SNathan Whitehorn 760fe3b4685SNathan Whitehorn /* NOTE: Interrupts are disabled here */ 761fe3b4685SNathan Whitehorn 762fe3b4685SNathan Whitehorn if (PCPU_GET(cpuid) == 0) { 763fe3b4685SNathan Whitehorn /* 764fe3b4685SNathan Whitehorn * Execute all OF calls on CPU 0 765fe3b4685SNathan Whitehorn */ 766fe3b4685SNathan Whitehorn rv_args->retval = openfirmware_core(rv_args->args); 767fe3b4685SNathan Whitehorn rv_args->in_progress = 0; 768fe3b4685SNathan Whitehorn } else { 769fe3b4685SNathan Whitehorn /* 770fe3b4685SNathan Whitehorn * Spin with interrupts off on other CPUs while OF has 771fe3b4685SNathan Whitehorn * control of the machine. 772fe3b4685SNathan Whitehorn */ 773fe3b4685SNathan Whitehorn while (rv_args->in_progress) 774fe3b4685SNathan Whitehorn cpu_spinwait(); 775fe3b4685SNathan Whitehorn } 776fe3b4685SNathan Whitehorn } 777fe3b4685SNathan Whitehorn #endif 778fe3b4685SNathan Whitehorn 779fe3b4685SNathan Whitehorn static int 780fe3b4685SNathan Whitehorn openfirmware(void *args) 781fe3b4685SNathan Whitehorn { 782fe3b4685SNathan Whitehorn int result; 783fe3b4685SNathan Whitehorn #ifdef SMP 784fe3b4685SNathan Whitehorn struct ofw_rv_args rv_args; 78544d29d47SNathan Whitehorn #endif 786fe3b4685SNathan Whitehorn 78744d29d47SNathan Whitehorn if (openfirmware_entry == NULL) 78844d29d47SNathan Whitehorn return (-1); 78944d29d47SNathan Whitehorn 79044d29d47SNathan Whitehorn #ifdef SMP 79191419bdaSNathan Whitehorn if (cold) { 79291419bdaSNathan Whitehorn result = openfirmware_core(args); 79391419bdaSNathan Whitehorn } else { 794fe3b4685SNathan Whitehorn rv_args.args = args; 795fe3b4685SNathan Whitehorn rv_args.in_progress = 1; 79691419bdaSNathan Whitehorn smp_rendezvous(smp_no_rendezvous_barrier, 79791419bdaSNathan Whitehorn ofw_rendezvous_dispatch, smp_no_rendezvous_barrier, 79891419bdaSNathan Whitehorn &rv_args); 799fe3b4685SNathan Whitehorn result = rv_args.retval; 80091419bdaSNathan Whitehorn } 801fe3b4685SNathan Whitehorn #else 802fe3b4685SNathan Whitehorn result = openfirmware_core(args); 803fe3b4685SNathan Whitehorn #endif 804fe3b4685SNathan Whitehorn 805fe3b4685SNathan Whitehorn return (result); 806fe3b4685SNathan Whitehorn } 807fe3b4685SNathan Whitehorn 808fe3b4685SNathan Whitehorn void 809fe3b4685SNathan Whitehorn OF_reboot() 810fe3b4685SNathan Whitehorn { 811fe3b4685SNathan Whitehorn struct { 812fe3b4685SNathan Whitehorn cell_t name; 813fe3b4685SNathan Whitehorn cell_t nargs; 814fe3b4685SNathan Whitehorn cell_t nreturns; 815fe3b4685SNathan Whitehorn cell_t arg; 816fe3b4685SNathan Whitehorn } args; 817fe3b4685SNathan Whitehorn 818fe3b4685SNathan Whitehorn args.name = (cell_t)(uintptr_t)"interpret"; 819fe3b4685SNathan Whitehorn args.nargs = 1; 820fe3b4685SNathan Whitehorn args.nreturns = 0; 821fe3b4685SNathan Whitehorn args.arg = (cell_t)(uintptr_t)"reset-all"; 822fe3b4685SNathan Whitehorn openfirmware_core(&args); /* Don't do rendezvous! */ 823fe3b4685SNathan Whitehorn 824fe3b4685SNathan Whitehorn for (;;); /* just in case */ 825fe3b4685SNathan Whitehorn } 826fe3b4685SNathan Whitehorn 827629aa519SNathan Whitehorn #endif /* AIM */ 828629aa519SNathan Whitehorn 829fe3b4685SNathan Whitehorn void 830fe3b4685SNathan Whitehorn OF_getetheraddr(device_t dev, u_char *addr) 831fe3b4685SNathan Whitehorn { 832fe3b4685SNathan Whitehorn phandle_t node; 833fe3b4685SNathan Whitehorn 834fe3b4685SNathan Whitehorn node = ofw_bus_get_node(dev); 835fe3b4685SNathan Whitehorn OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 836fe3b4685SNathan Whitehorn } 837fe3b4685SNathan Whitehorn 838fe3b4685SNathan Whitehorn /* 839fe3b4685SNathan Whitehorn * Return a bus handle and bus tag that corresponds to the register 840fe3b4685SNathan Whitehorn * numbered regno for the device referenced by the package handle 841fe3b4685SNathan Whitehorn * dev. This function is intended to be used by console drivers in 842fe3b4685SNathan Whitehorn * early boot only. It works by mapping the address of the device's 843fe3b4685SNathan Whitehorn * register in the address space of its parent and recursively walk 844fe3b4685SNathan Whitehorn * the device tree upward this way. 845fe3b4685SNathan Whitehorn */ 846fe3b4685SNathan Whitehorn int 847fe3b4685SNathan Whitehorn OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 84845fd1862SAndrew Turner bus_space_handle_t *handle, bus_size_t *sz) 849fe3b4685SNathan Whitehorn { 850bc7b9300SIan Lepore bus_addr_t addr; 851bc7b9300SIan Lepore bus_size_t size; 852bc7b9300SIan Lepore pcell_t pci_hi; 853bc7b9300SIan Lepore int flags, res; 854fe3b4685SNathan Whitehorn 855bc7b9300SIan Lepore res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi); 856bc7b9300SIan Lepore if (res < 0) 857bc7b9300SIan Lepore return (res); 858fe3b4685SNathan Whitehorn 859bc7b9300SIan Lepore if (pci_hi == OFW_PADDR_NOT_PCI) { 86043a581e1SNathan Whitehorn *tag = &bs_be_tag; 861bc7b9300SIan Lepore flags = 0; 862bc7b9300SIan Lepore } else { 86343a581e1SNathan Whitehorn *tag = &bs_le_tag; 864bc7b9300SIan Lepore flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? 865bc7b9300SIan Lepore BUS_SPACE_MAP_PREFETCHABLE: 0; 866fe3b4685SNathan Whitehorn } 867fe3b4685SNathan Whitehorn 86845fd1862SAndrew Turner if (sz != NULL) 86945fd1862SAndrew Turner *sz = size; 87045fd1862SAndrew Turner 871bc7b9300SIan Lepore return (bus_space_map(*tag, addr, size, flags, handle)); 872fe3b4685SNathan Whitehorn } 873fe3b4685SNathan Whitehorn 874