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> 46fe3b4685SNathan Whitehorn #include <sys/malloc.h> 47fe3b4685SNathan Whitehorn #include <sys/smp.h> 48fe3b4685SNathan Whitehorn #include <sys/stat.h> 49b9d056f3SNathan Whitehorn #include <sys/endian.h> 50fe3b4685SNathan Whitehorn 51fe3b4685SNathan Whitehorn #include <net/ethernet.h> 52fe3b4685SNathan Whitehorn 538c092157SJustin Hibbits #include <dev/fdt/fdt_common.h> 54fe3b4685SNathan Whitehorn #include <dev/ofw/openfirm.h> 55fe3b4685SNathan Whitehorn #include <dev/ofw/ofw_pci.h> 56fe3b4685SNathan Whitehorn #include <dev/ofw/ofw_bus.h> 57bc7b9300SIan Lepore #include <dev/ofw/ofw_subr.h> 58fe3b4685SNathan Whitehorn 59fe3b4685SNathan Whitehorn #include <vm/vm.h> 60fe3b4685SNathan Whitehorn #include <vm/vm_param.h> 61fe3b4685SNathan Whitehorn #include <vm/vm_page.h> 6249d9a597SJustin Hibbits #include <vm/vm_phys.h> 63fe3b4685SNathan Whitehorn 64fe3b4685SNathan Whitehorn #include <machine/bus.h> 65fe3b4685SNathan Whitehorn #include <machine/cpu.h> 66fe3b4685SNathan Whitehorn #include <machine/md_var.h> 67fe3b4685SNathan Whitehorn #include <machine/platform.h> 68fe3b4685SNathan Whitehorn #include <machine/ofw_machdep.h> 69f367ffdeSAndreas Tobler #include <machine/trap.h> 70fe3b4685SNathan Whitehorn 71c0650b2fSNathan Whitehorn #include <contrib/libfdt/libfdt.h> 72c0650b2fSNathan Whitehorn 73fd8cf3beSJustin Hibbits #ifdef POWERNV 74fd8cf3beSJustin Hibbits #include <powerpc/powernv/opal.h> 75fd8cf3beSJustin Hibbits #endif 76fd8cf3beSJustin Hibbits 776f489d43SJustin Hibbits static void *fdt; 786f489d43SJustin Hibbits int ofw_real_mode; 796f489d43SJustin Hibbits 80629aa519SNathan Whitehorn #ifdef AIM 81fe3b4685SNathan Whitehorn extern register_t ofmsr[5]; 8217879090SNathan Whitehorn extern void *openfirmware_entry; 83bb808254SNathan Whitehorn char save_trap_init[0x2f00]; /* EXC_LAST */ 84f367ffdeSAndreas Tobler char save_trap_of[0x2f00]; /* EXC_LAST */ 85fe3b4685SNathan Whitehorn 86d8c6808aSNathan Whitehorn int ofwcall(void *); 87fe3b4685SNathan Whitehorn static int openfirmware(void *args); 88fe3b4685SNathan Whitehorn 89f367ffdeSAndreas Tobler __inline void 90f367ffdeSAndreas Tobler ofw_save_trap_vec(char *save_trap_vec) 91f367ffdeSAndreas Tobler { 92f9edb09dSNathan Whitehorn if (!ofw_real_mode || !hw_direct_map) 93f367ffdeSAndreas Tobler return; 94f367ffdeSAndreas Tobler 95f9edb09dSNathan Whitehorn bcopy((void *)PHYS_TO_DMAP(EXC_RST), save_trap_vec, EXC_LAST - EXC_RST); 96f367ffdeSAndreas Tobler } 97f367ffdeSAndreas Tobler 98f367ffdeSAndreas Tobler static __inline void 99f367ffdeSAndreas Tobler ofw_restore_trap_vec(char *restore_trap_vec) 100f367ffdeSAndreas Tobler { 101f9edb09dSNathan Whitehorn if (!ofw_real_mode || !hw_direct_map) 102f367ffdeSAndreas Tobler return; 103f367ffdeSAndreas Tobler 104f9edb09dSNathan Whitehorn bcopy(restore_trap_vec, (void *)PHYS_TO_DMAP(EXC_RST), 105f9edb09dSNathan Whitehorn EXC_LAST - EXC_RST); 106f9edb09dSNathan Whitehorn __syncicache((void *)PHYS_TO_DMAP(EXC_RSVD), EXC_LAST - EXC_RSVD); 107f367ffdeSAndreas Tobler } 1084aa3cee6SNathan Whitehorn 1094aa3cee6SNathan Whitehorn /* 1104aa3cee6SNathan Whitehorn * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 1114aa3cee6SNathan Whitehorn */ 1124aa3cee6SNathan Whitehorn register_t ofw_sprg0_save; 1134aa3cee6SNathan Whitehorn 1144aa3cee6SNathan Whitehorn static __inline void 1154aa3cee6SNathan Whitehorn ofw_sprg_prepare(void) 1164aa3cee6SNathan Whitehorn { 1174aa3cee6SNathan Whitehorn if (ofw_real_mode) 1184aa3cee6SNathan Whitehorn return; 1194aa3cee6SNathan Whitehorn 1204aa3cee6SNathan Whitehorn /* 1214aa3cee6SNathan Whitehorn * Assume that interrupt are disabled at this point, or 1224aa3cee6SNathan Whitehorn * SPRG1-3 could be trashed 1234aa3cee6SNathan Whitehorn */ 12462c6b30eSJustin Hibbits #ifdef __powerpc64__ 12562c6b30eSJustin Hibbits __asm __volatile("mtsprg1 %0\n\t" 12662c6b30eSJustin Hibbits "mtsprg2 %1\n\t" 12762c6b30eSJustin Hibbits "mtsprg3 %2\n\t" 12862c6b30eSJustin Hibbits : 12962c6b30eSJustin Hibbits : "r"(ofmsr[2]), 13062c6b30eSJustin Hibbits "r"(ofmsr[3]), 13162c6b30eSJustin Hibbits "r"(ofmsr[4])); 13262c6b30eSJustin Hibbits #else 1334aa3cee6SNathan Whitehorn __asm __volatile("mfsprg0 %0\n\t" 1344aa3cee6SNathan Whitehorn "mtsprg0 %1\n\t" 1354aa3cee6SNathan Whitehorn "mtsprg1 %2\n\t" 1364aa3cee6SNathan Whitehorn "mtsprg2 %3\n\t" 1374aa3cee6SNathan Whitehorn "mtsprg3 %4\n\t" 1384aa3cee6SNathan Whitehorn : "=&r"(ofw_sprg0_save) 1394aa3cee6SNathan Whitehorn : "r"(ofmsr[1]), 1404aa3cee6SNathan Whitehorn "r"(ofmsr[2]), 1414aa3cee6SNathan Whitehorn "r"(ofmsr[3]), 1424aa3cee6SNathan Whitehorn "r"(ofmsr[4])); 14362c6b30eSJustin Hibbits #endif 1444aa3cee6SNathan Whitehorn } 1454aa3cee6SNathan Whitehorn 1464aa3cee6SNathan Whitehorn static __inline void 1474aa3cee6SNathan Whitehorn ofw_sprg_restore(void) 1484aa3cee6SNathan Whitehorn { 1494aa3cee6SNathan Whitehorn if (ofw_real_mode) 1504aa3cee6SNathan Whitehorn return; 1514aa3cee6SNathan Whitehorn 1524aa3cee6SNathan Whitehorn /* 1534aa3cee6SNathan Whitehorn * Note that SPRG1-3 contents are irrelevant. They are scratch 1544aa3cee6SNathan Whitehorn * registers used in the early portion of trap handling when 1554aa3cee6SNathan Whitehorn * interrupts are disabled. 1564aa3cee6SNathan Whitehorn * 1574aa3cee6SNathan Whitehorn * PCPU data cannot be used until this routine is called ! 1584aa3cee6SNathan Whitehorn */ 15962c6b30eSJustin Hibbits #ifndef __powerpc64__ 1604aa3cee6SNathan Whitehorn __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 16162c6b30eSJustin Hibbits #endif 1624aa3cee6SNathan Whitehorn } 163c7291bdcSNathan Whitehorn #endif 164f367ffdeSAndreas Tobler 165fe3b4685SNathan Whitehorn static int 166fe3b4685SNathan Whitehorn parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 167fe3b4685SNathan Whitehorn { 168fe3b4685SNathan Whitehorn cell_t address_cells, size_cells; 169d8c6808aSNathan Whitehorn cell_t OFmem[4 * PHYS_AVAIL_SZ]; 170fe3b4685SNathan Whitehorn int sz, i, j; 171fe3b4685SNathan Whitehorn phandle_t phandle; 172fe3b4685SNathan Whitehorn 173fe3b4685SNathan Whitehorn sz = 0; 174fe3b4685SNathan Whitehorn 175fe3b4685SNathan Whitehorn /* 176fe3b4685SNathan Whitehorn * Get #address-cells from root node, defaulting to 1 if it cannot 177fe3b4685SNathan Whitehorn * be found. 178fe3b4685SNathan Whitehorn */ 179fe3b4685SNathan Whitehorn phandle = OF_finddevice("/"); 180509142e1SNathan Whitehorn if (OF_getencprop(phandle, "#address-cells", &address_cells, 1818bab0d80SNathan Whitehorn sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 182fe3b4685SNathan Whitehorn address_cells = 1; 183509142e1SNathan Whitehorn if (OF_getencprop(phandle, "#size-cells", &size_cells, 1848bab0d80SNathan Whitehorn sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 185fe3b4685SNathan Whitehorn size_cells = 1; 186fe3b4685SNathan Whitehorn 187fe3b4685SNathan Whitehorn /* 188fe3b4685SNathan Whitehorn * Get memory. 189fe3b4685SNathan Whitehorn */ 190509142e1SNathan Whitehorn if (node == -1 || (sz = OF_getencprop(node, prop, 191d8c6808aSNathan Whitehorn OFmem, sizeof(OFmem))) <= 0) 192fe3b4685SNathan Whitehorn panic("Physical memory map not found"); 193fe3b4685SNathan Whitehorn 194fe3b4685SNathan Whitehorn i = 0; 195fe3b4685SNathan Whitehorn j = 0; 196fe3b4685SNathan Whitehorn while (i < sz/sizeof(cell_t)) { 197fe3b4685SNathan Whitehorn output[j].mr_start = OFmem[i++]; 198fe3b4685SNathan Whitehorn if (address_cells == 2) { 199fe3b4685SNathan Whitehorn output[j].mr_start <<= 32; 200fe3b4685SNathan Whitehorn output[j].mr_start += OFmem[i++]; 201fe3b4685SNathan Whitehorn } 202fe3b4685SNathan Whitehorn 203fe3b4685SNathan Whitehorn output[j].mr_size = OFmem[i++]; 204fe3b4685SNathan Whitehorn if (size_cells == 2) { 205fe3b4685SNathan Whitehorn output[j].mr_size <<= 32; 206fe3b4685SNathan Whitehorn output[j].mr_size += OFmem[i++]; 207fe3b4685SNathan Whitehorn } 208fe3b4685SNathan Whitehorn 209bb7137e1SJustin Hibbits if (output[j].mr_start > BUS_SPACE_MAXADDR) 210bb7137e1SJustin Hibbits continue; 211bb7137e1SJustin Hibbits 212fe3b4685SNathan Whitehorn /* 213bb7137e1SJustin Hibbits * Constrain memory to that which we can access. 214bb7137e1SJustin Hibbits * 32-bit AIM can only reference 32 bits of address currently, 215bb7137e1SJustin Hibbits * but Book-E can access 36 bits. 216fe3b4685SNathan Whitehorn */ 217fe3b4685SNathan Whitehorn if (((uint64_t)output[j].mr_start + 218bb7137e1SJustin Hibbits (uint64_t)output[j].mr_size - 1) > 219bb7137e1SJustin Hibbits BUS_SPACE_MAXADDR) { 220bb7137e1SJustin Hibbits output[j].mr_size = BUS_SPACE_MAXADDR - 221bb7137e1SJustin Hibbits output[j].mr_start + 1; 222fe3b4685SNathan Whitehorn } 223fe3b4685SNathan Whitehorn 224fe3b4685SNathan Whitehorn j++; 225fe3b4685SNathan Whitehorn } 226fe3b4685SNathan Whitehorn 22749d9a597SJustin Hibbits return (j); 22849d9a597SJustin Hibbits } 22949d9a597SJustin Hibbits 23049d9a597SJustin Hibbits static int 23149d9a597SJustin Hibbits parse_numa_ofw_memory(phandle_t node, const char *prop, 23249d9a597SJustin Hibbits struct numa_mem_region *output) 23349d9a597SJustin Hibbits { 23449d9a597SJustin Hibbits cell_t address_cells, size_cells; 23549d9a597SJustin Hibbits cell_t OFmem[4 * PHYS_AVAIL_SZ]; 23649d9a597SJustin Hibbits int sz, i, j; 23749d9a597SJustin Hibbits phandle_t phandle; 23849d9a597SJustin Hibbits 23949d9a597SJustin Hibbits sz = 0; 24049d9a597SJustin Hibbits 24149d9a597SJustin Hibbits /* 24249d9a597SJustin Hibbits * Get #address-cells from root node, defaulting to 1 if it cannot 24349d9a597SJustin Hibbits * be found. 24449d9a597SJustin Hibbits */ 24549d9a597SJustin Hibbits phandle = OF_finddevice("/"); 24649d9a597SJustin Hibbits if (OF_getencprop(phandle, "#address-cells", &address_cells, 24749d9a597SJustin Hibbits sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 24849d9a597SJustin Hibbits address_cells = 1; 24949d9a597SJustin Hibbits if (OF_getencprop(phandle, "#size-cells", &size_cells, 25049d9a597SJustin Hibbits sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 25149d9a597SJustin Hibbits size_cells = 1; 25249d9a597SJustin Hibbits 25349d9a597SJustin Hibbits /* 25449d9a597SJustin Hibbits * Get memory. 25549d9a597SJustin Hibbits */ 25649d9a597SJustin Hibbits if (node == -1 || (sz = OF_getencprop(node, prop, 25749d9a597SJustin Hibbits OFmem, sizeof(OFmem))) <= 0) 25849d9a597SJustin Hibbits panic("Physical memory map not found"); 25949d9a597SJustin Hibbits 26049d9a597SJustin Hibbits i = 0; 26149d9a597SJustin Hibbits j = 0; 26249d9a597SJustin Hibbits while (i < sz/sizeof(cell_t)) { 26349d9a597SJustin Hibbits output[j].mr_start = OFmem[i++]; 26449d9a597SJustin Hibbits if (address_cells == 2) { 26549d9a597SJustin Hibbits output[j].mr_start <<= 32; 26649d9a597SJustin Hibbits output[j].mr_start += OFmem[i++]; 26749d9a597SJustin Hibbits } 26849d9a597SJustin Hibbits output[j].mr_size = OFmem[i++]; 26949d9a597SJustin Hibbits if (size_cells == 2) { 27049d9a597SJustin Hibbits output[j].mr_size <<= 32; 27149d9a597SJustin Hibbits output[j].mr_size += OFmem[i++]; 27249d9a597SJustin Hibbits } 27349d9a597SJustin Hibbits j++; 27449d9a597SJustin Hibbits } 27549d9a597SJustin Hibbits 27649d9a597SJustin Hibbits return (j); 277fe3b4685SNathan Whitehorn } 278fe3b4685SNathan Whitehorn 27935feca37SNathan Whitehorn #ifdef FDT 280b9d056f3SNathan Whitehorn static int 28148f64992SBreno Leitao excise_reserved_regions(struct mem_region *avail, int asz, 28248f64992SBreno Leitao struct mem_region *exclude, int esz) 283b9d056f3SNathan Whitehorn { 284b9d056f3SNathan Whitehorn int i, j, k; 285b9d056f3SNathan Whitehorn 286b9d056f3SNathan Whitehorn for (i = 0; i < asz; i++) { 28748f64992SBreno Leitao for (j = 0; j < esz; j++) { 288b9d056f3SNathan Whitehorn /* 289b9d056f3SNathan Whitehorn * Case 1: Exclusion region encloses complete 290b9d056f3SNathan Whitehorn * available entry. Drop it and move on. 291b9d056f3SNathan Whitehorn */ 29248f64992SBreno Leitao if (exclude[j].mr_start <= avail[i].mr_start && 29348f64992SBreno Leitao exclude[j].mr_start + exclude[j].mr_size >= 294b9d056f3SNathan Whitehorn avail[i].mr_start + avail[i].mr_size) { 295b9d056f3SNathan Whitehorn for (k = i+1; k < asz; k++) 296b9d056f3SNathan Whitehorn avail[k-1] = avail[k]; 297b9d056f3SNathan Whitehorn asz--; 298b9d056f3SNathan Whitehorn i--; /* Repeat some entries */ 299b9d056f3SNathan Whitehorn continue; 300b9d056f3SNathan Whitehorn } 301b9d056f3SNathan Whitehorn 302b9d056f3SNathan Whitehorn /* 303b9d056f3SNathan Whitehorn * Case 2: Exclusion region starts in available entry. 304b9d056f3SNathan Whitehorn * Trim it to where the entry begins and append 305b9d056f3SNathan Whitehorn * a new available entry with the region after 306b9d056f3SNathan Whitehorn * the excluded region, if any. 307b9d056f3SNathan Whitehorn */ 30848f64992SBreno Leitao if (exclude[j].mr_start >= avail[i].mr_start && 30948f64992SBreno Leitao exclude[j].mr_start < avail[i].mr_start + 310b9d056f3SNathan Whitehorn avail[i].mr_size) { 31148f64992SBreno Leitao if (exclude[j].mr_start + exclude[j].mr_size < 312b9d056f3SNathan Whitehorn avail[i].mr_start + avail[i].mr_size) { 313b9d056f3SNathan Whitehorn avail[asz].mr_start = 31448f64992SBreno Leitao exclude[j].mr_start + exclude[j].mr_size; 315b9d056f3SNathan Whitehorn avail[asz].mr_size = avail[i].mr_start + 316b9d056f3SNathan Whitehorn avail[i].mr_size - 317b9d056f3SNathan Whitehorn avail[asz].mr_start; 318b9d056f3SNathan Whitehorn asz++; 319b9d056f3SNathan Whitehorn } 320b9d056f3SNathan Whitehorn 32148f64992SBreno Leitao avail[i].mr_size = exclude[j].mr_start - 322b9d056f3SNathan Whitehorn avail[i].mr_start; 323b9d056f3SNathan Whitehorn } 324b9d056f3SNathan Whitehorn 325b9d056f3SNathan Whitehorn /* 326b9d056f3SNathan Whitehorn * Case 3: Exclusion region ends in available entry. 327b9d056f3SNathan Whitehorn * Move start point to where the exclusion zone ends. 328b9d056f3SNathan Whitehorn * The case of a contained exclusion zone has already 329b9d056f3SNathan Whitehorn * been caught in case 2. 330b9d056f3SNathan Whitehorn */ 33148f64992SBreno Leitao if (exclude[j].mr_start + exclude[j].mr_size >= 33248f64992SBreno Leitao avail[i].mr_start && exclude[j].mr_start + 33348f64992SBreno Leitao exclude[j].mr_size < avail[i].mr_start + 334b9d056f3SNathan Whitehorn avail[i].mr_size) { 335922a3152SNathan Whitehorn avail[i].mr_size += avail[i].mr_start; 336b9d056f3SNathan Whitehorn avail[i].mr_start = 33748f64992SBreno Leitao exclude[j].mr_start + exclude[j].mr_size; 338922a3152SNathan Whitehorn avail[i].mr_size -= avail[i].mr_start; 339b9d056f3SNathan Whitehorn } 340b9d056f3SNathan Whitehorn } 341b9d056f3SNathan Whitehorn } 342b9d056f3SNathan Whitehorn 343b9d056f3SNathan Whitehorn return (asz); 344b9d056f3SNathan Whitehorn } 34548f64992SBreno Leitao 34648f64992SBreno Leitao static int 34748f64992SBreno Leitao excise_initrd_region(struct mem_region *avail, int asz) 34848f64992SBreno Leitao { 34948f64992SBreno Leitao phandle_t chosen; 35048f64992SBreno Leitao uint64_t start, end; 35148f64992SBreno Leitao ssize_t size; 35248f64992SBreno Leitao struct mem_region initrdmap[1]; 3536d645c57SBreno Leitao pcell_t cell[2]; 35448f64992SBreno Leitao 35548f64992SBreno Leitao chosen = OF_finddevice("/chosen"); 35648f64992SBreno Leitao 3576d645c57SBreno Leitao size = OF_getencprop(chosen, "linux,initrd-start", cell, sizeof(cell)); 3586d645c57SBreno Leitao if (size < 0) 3596d645c57SBreno Leitao return (asz); 3606d645c57SBreno Leitao else if (size == 4) 3616d645c57SBreno Leitao start = cell[0]; 3626d645c57SBreno Leitao else if (size == 8) 3636d645c57SBreno Leitao start = (uint64_t)cell[0] << 32 | cell[1]; 3646d645c57SBreno Leitao else { 3656d645c57SBreno Leitao /* Invalid value length */ 3666d645c57SBreno Leitao printf("WARNING: linux,initrd-start must be either 4 or 8 bytes long\n"); 3676d645c57SBreno Leitao return (asz); 3686d645c57SBreno Leitao } 3696d645c57SBreno Leitao 3706d645c57SBreno Leitao size = OF_getencprop(chosen, "linux,initrd-end", cell, sizeof(cell)); 3716d645c57SBreno Leitao if (size < 0) 3726d645c57SBreno Leitao return (asz); 3736d645c57SBreno Leitao else if (size == 4) 3746d645c57SBreno Leitao end = cell[0]; 3756d645c57SBreno Leitao else if (size == 8) 3766d645c57SBreno Leitao end = (uint64_t)cell[0] << 32 | cell[1]; 3776d645c57SBreno Leitao else { 3786d645c57SBreno Leitao /* Invalid value length */ 3796d645c57SBreno Leitao printf("WARNING: linux,initrd-end must be either 4 or 8 bytes long\n"); 3806d645c57SBreno Leitao return (asz); 3816d645c57SBreno Leitao } 3826d645c57SBreno Leitao 3836d645c57SBreno Leitao if (end <= start) 38448f64992SBreno Leitao return (asz); 38548f64992SBreno Leitao 38648f64992SBreno Leitao initrdmap[0].mr_start = start; 38748f64992SBreno Leitao initrdmap[0].mr_size = end - start; 38848f64992SBreno Leitao 38948f64992SBreno Leitao asz = excise_reserved_regions(avail, asz, initrdmap, 1); 39048f64992SBreno Leitao 39148f64992SBreno Leitao return (asz); 39248f64992SBreno Leitao } 39348f64992SBreno Leitao 394fd8cf3beSJustin Hibbits #ifdef POWERNV 395fd8cf3beSJustin Hibbits static int 396fd8cf3beSJustin Hibbits excise_msi_region(struct mem_region *avail, int asz) 397fd8cf3beSJustin Hibbits { 398fd8cf3beSJustin Hibbits uint64_t start, end; 399fd8cf3beSJustin Hibbits struct mem_region initrdmap[1]; 400fd8cf3beSJustin Hibbits 401fd8cf3beSJustin Hibbits /* 402fd8cf3beSJustin Hibbits * This range of physical addresses is used to implement optimized 403fd8cf3beSJustin Hibbits * 32 bit MSI interrupts on POWER9. Exclude it to avoid accidentally 404fd8cf3beSJustin Hibbits * using it for DMA, as this will cause an immediate PHB fence. 405fd8cf3beSJustin Hibbits * While we could theoretically turn off this behavior in the ETU, 406fd8cf3beSJustin Hibbits * doing so would break 32-bit MSI, so just reserve the range in 407fd8cf3beSJustin Hibbits * the physical map instead. 408fd8cf3beSJustin Hibbits * See section 4.4.2.8 of the PHB4 specification. 409fd8cf3beSJustin Hibbits */ 410fd8cf3beSJustin Hibbits start = 0x00000000ffff0000ul; 411fd8cf3beSJustin Hibbits end = 0x00000000fffffffful; 412fd8cf3beSJustin Hibbits 413fd8cf3beSJustin Hibbits initrdmap[0].mr_start = start; 414fd8cf3beSJustin Hibbits initrdmap[0].mr_size = end - start; 415fd8cf3beSJustin Hibbits 416fd8cf3beSJustin Hibbits asz = excise_reserved_regions(avail, asz, initrdmap, 1); 417fd8cf3beSJustin Hibbits 418fd8cf3beSJustin Hibbits return (asz); 419fd8cf3beSJustin Hibbits } 420fd8cf3beSJustin Hibbits #endif 421fd8cf3beSJustin Hibbits 42248f64992SBreno Leitao static int 42348f64992SBreno Leitao excise_fdt_reserved(struct mem_region *avail, int asz) 42448f64992SBreno Leitao { 42548f64992SBreno Leitao struct mem_region fdtmap[32]; 42648f64992SBreno Leitao ssize_t fdtmapsize; 42748f64992SBreno Leitao phandle_t chosen; 42848f64992SBreno Leitao int j, fdtentries; 42948f64992SBreno Leitao 43048f64992SBreno Leitao chosen = OF_finddevice("/chosen"); 43148f64992SBreno Leitao fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); 43248f64992SBreno Leitao 43348f64992SBreno Leitao for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 43448f64992SBreno Leitao fdtmap[j].mr_start = be64toh(fdtmap[j].mr_start) & ~PAGE_MASK; 43548f64992SBreno Leitao fdtmap[j].mr_size = round_page(be64toh(fdtmap[j].mr_size)); 43648f64992SBreno Leitao } 43748f64992SBreno Leitao 43848f64992SBreno Leitao KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap), 43948f64992SBreno Leitao ("Exceeded number of FDT reservations")); 44048f64992SBreno Leitao /* Add a virtual entry for the FDT itself */ 44148f64992SBreno Leitao if (fdt != NULL) { 44248f64992SBreno Leitao fdtmap[j].mr_start = (vm_offset_t)fdt & ~PAGE_MASK; 44348f64992SBreno Leitao fdtmap[j].mr_size = round_page(fdt_totalsize(fdt)); 44448f64992SBreno Leitao fdtmapsize += sizeof(fdtmap[0]); 44548f64992SBreno Leitao } 44648f64992SBreno Leitao 44748f64992SBreno Leitao fdtentries = fdtmapsize/sizeof(fdtmap[0]); 44848f64992SBreno Leitao asz = excise_reserved_regions(avail, asz, fdtmap, fdtentries); 44948f64992SBreno Leitao 45048f64992SBreno Leitao return (asz); 45148f64992SBreno Leitao } 45235feca37SNathan Whitehorn #endif 453b9d056f3SNathan Whitehorn 454fe3b4685SNathan Whitehorn /* 455fe3b4685SNathan Whitehorn * This is called during powerpc_init, before the system is really initialized. 456fe3b4685SNathan Whitehorn * It shall provide the total and the available regions of RAM. 457b9d056f3SNathan Whitehorn * The available regions need not take the kernel into account. 458fe3b4685SNathan Whitehorn */ 459fe3b4685SNathan Whitehorn void 46049d9a597SJustin Hibbits ofw_numa_mem_regions(struct numa_mem_region *memp, int *memsz) 46149d9a597SJustin Hibbits { 46249d9a597SJustin Hibbits phandle_t phandle; 46349d9a597SJustin Hibbits int res, count, msz; 46449d9a597SJustin Hibbits char name[31]; 46549d9a597SJustin Hibbits cell_t associativity[5]; 46649d9a597SJustin Hibbits struct numa_mem_region *curmemp; 46749d9a597SJustin Hibbits 46849d9a597SJustin Hibbits msz = 0; 46949d9a597SJustin Hibbits /* 47049d9a597SJustin Hibbits * Get memory from all the /memory nodes. 47149d9a597SJustin Hibbits */ 47249d9a597SJustin Hibbits for (phandle = OF_child(OF_peer(0)); phandle != 0; 47349d9a597SJustin Hibbits phandle = OF_peer(phandle)) { 47449d9a597SJustin Hibbits if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 47549d9a597SJustin Hibbits continue; 47649d9a597SJustin Hibbits if (strncmp(name, "memory@", strlen("memory@")) != 0) 47749d9a597SJustin Hibbits continue; 47849d9a597SJustin Hibbits 47949d9a597SJustin Hibbits count = parse_numa_ofw_memory(phandle, "reg", &memp[msz]); 48049d9a597SJustin Hibbits if (count == 0) 48149d9a597SJustin Hibbits continue; 48249d9a597SJustin Hibbits curmemp = &memp[msz]; 48349d9a597SJustin Hibbits res = OF_getproplen(phandle, "ibm,associativity"); 48449d9a597SJustin Hibbits if (res <= 0) 48549d9a597SJustin Hibbits continue; 48649d9a597SJustin Hibbits MPASS(count == 1); 48749d9a597SJustin Hibbits OF_getencprop(phandle, "ibm,associativity", 48849d9a597SJustin Hibbits associativity, res); 48949d9a597SJustin Hibbits curmemp->mr_domain = associativity[3] - 1; 49049d9a597SJustin Hibbits if (bootverbose) 49149d9a597SJustin Hibbits printf("%s %#jx-%#jx domain(%ju)\n", 49249d9a597SJustin Hibbits name, (uintmax_t)curmemp->mr_start, 49349d9a597SJustin Hibbits (uintmax_t)curmemp->mr_start + curmemp->mr_size, 49449d9a597SJustin Hibbits (uintmax_t)curmemp->mr_domain); 49549d9a597SJustin Hibbits msz += count; 49649d9a597SJustin Hibbits } 49749d9a597SJustin Hibbits *memsz = msz; 49849d9a597SJustin Hibbits } 49949d9a597SJustin Hibbits /* 50049d9a597SJustin Hibbits * This is called during powerpc_init, before the system is really initialized. 50149d9a597SJustin Hibbits * It shall provide the total and the available regions of RAM. 50249d9a597SJustin Hibbits * The available regions need not take the kernel into account. 50349d9a597SJustin Hibbits */ 50449d9a597SJustin Hibbits void 505c1cb22d7SNathan Whitehorn ofw_mem_regions(struct mem_region *memp, int *memsz, 506c1cb22d7SNathan Whitehorn struct mem_region *availp, int *availsz) 507fe3b4685SNathan Whitehorn { 508fe3b4685SNathan Whitehorn phandle_t phandle; 509c1cb22d7SNathan Whitehorn int asz, msz; 510c1cb22d7SNathan Whitehorn int res; 511d8c6808aSNathan Whitehorn char name[31]; 512fe3b4685SNathan Whitehorn 513fe3b4685SNathan Whitehorn asz = msz = 0; 514fe3b4685SNathan Whitehorn 515fe3b4685SNathan Whitehorn /* 516d8c6808aSNathan Whitehorn * Get memory from all the /memory nodes. 517fe3b4685SNathan Whitehorn */ 518d8c6808aSNathan Whitehorn for (phandle = OF_child(OF_peer(0)); phandle != 0; 519d8c6808aSNathan Whitehorn phandle = OF_peer(phandle)) { 520d8c6808aSNathan Whitehorn if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 521d8c6808aSNathan Whitehorn continue; 522b9d056f3SNathan Whitehorn if (strncmp(name, "memory", sizeof(name)) != 0 && 523b9d056f3SNathan Whitehorn strncmp(name, "memory@", strlen("memory@")) != 0) 524d8c6808aSNathan Whitehorn continue; 525fe3b4685SNathan Whitehorn 526c1cb22d7SNathan Whitehorn res = parse_ofw_memory(phandle, "reg", &memp[msz]); 52749d9a597SJustin Hibbits msz += res; 528876f3b92SJustin Hibbits 529876f3b92SJustin Hibbits /* 530876f3b92SJustin Hibbits * On POWER9 Systems we might have both linux,usable-memory and 531876f3b92SJustin Hibbits * reg properties. 'reg' denotes all available memory, but we 532876f3b92SJustin Hibbits * must use 'linux,usable-memory', a subset, as some memory 533876f3b92SJustin Hibbits * regions are reserved for NVLink. 534876f3b92SJustin Hibbits */ 535876f3b92SJustin Hibbits if (OF_getproplen(phandle, "linux,usable-memory") >= 0) 536876f3b92SJustin Hibbits res = parse_ofw_memory(phandle, "linux,usable-memory", 537876f3b92SJustin Hibbits &availp[asz]); 538c07c77a3SJustin Hibbits else if (OF_getproplen(phandle, "available") >= 0) 539d8c6808aSNathan Whitehorn res = parse_ofw_memory(phandle, "available", 540c1cb22d7SNathan Whitehorn &availp[asz]); 541d8c6808aSNathan Whitehorn else 542c1cb22d7SNathan Whitehorn res = parse_ofw_memory(phandle, "reg", &availp[asz]); 54349d9a597SJustin Hibbits asz += res; 544d8c6808aSNathan Whitehorn } 545d8c6808aSNathan Whitehorn 54635feca37SNathan Whitehorn #ifdef FDT 547b9d056f3SNathan Whitehorn phandle = OF_finddevice("/chosen"); 548b9d056f3SNathan Whitehorn if (OF_hasprop(phandle, "fdtmemreserv")) 549b9d056f3SNathan Whitehorn asz = excise_fdt_reserved(availp, asz); 55048f64992SBreno Leitao 55148f64992SBreno Leitao /* If the kernel is being loaded through kexec, initrd region is listed 55248f64992SBreno Leitao * in /chosen but the region is not marked as reserved, so, we might exclude 55348f64992SBreno Leitao * it here. 55448f64992SBreno Leitao */ 55548f64992SBreno Leitao if (OF_hasprop(phandle, "linux,initrd-start")) 55648f64992SBreno Leitao asz = excise_initrd_region(availp, asz); 55735feca37SNathan Whitehorn #endif 558b9d056f3SNathan Whitehorn 559fd8cf3beSJustin Hibbits #ifdef POWERNV 560fd8cf3beSJustin Hibbits if (opal_check() == 0) 561fd8cf3beSJustin Hibbits asz = excise_msi_region(availp, asz); 562fd8cf3beSJustin Hibbits #endif 563fd8cf3beSJustin Hibbits 564d8c6808aSNathan Whitehorn *memsz = msz; 565c1cb22d7SNathan Whitehorn *availsz = asz; 566fe3b4685SNathan Whitehorn } 567fe3b4685SNathan Whitehorn 568fe3b4685SNathan Whitehorn void 569fe3b4685SNathan Whitehorn OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 570fe3b4685SNathan Whitehorn { 5716f489d43SJustin Hibbits #ifdef AIM 572bb808254SNathan Whitehorn ofmsr[0] = mfmsr(); 573bb808254SNathan Whitehorn #ifdef __powerpc64__ 574bb808254SNathan Whitehorn ofmsr[0] &= ~PSL_SF; 57562c6b30eSJustin Hibbits #else 576bb808254SNathan Whitehorn __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1])); 57762c6b30eSJustin Hibbits #endif 578bb808254SNathan Whitehorn __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2])); 579bb808254SNathan Whitehorn __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3])); 580bb808254SNathan Whitehorn __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4])); 5816f489d43SJustin Hibbits openfirmware_entry = openfirm; 582bb808254SNathan Whitehorn 583fe3b4685SNathan Whitehorn if (ofmsr[0] & PSL_DR) 584fe3b4685SNathan Whitehorn ofw_real_mode = 0; 585fe3b4685SNathan Whitehorn else 586fe3b4685SNathan Whitehorn ofw_real_mode = 1; 587fe3b4685SNathan Whitehorn 5886f489d43SJustin Hibbits ofw_save_trap_vec(save_trap_init); 5896f489d43SJustin Hibbits #else 5906f489d43SJustin Hibbits ofw_real_mode = 1; 5916f489d43SJustin Hibbits #endif 5926f489d43SJustin Hibbits 593fe3b4685SNathan Whitehorn fdt = fdt_ptr; 594fe3b4685SNathan Whitehorn } 595fe3b4685SNathan Whitehorn 596fe3b4685SNathan Whitehorn boolean_t 597fe3b4685SNathan Whitehorn OF_bootstrap() 598fe3b4685SNathan Whitehorn { 599fe3b4685SNathan Whitehorn boolean_t status = FALSE; 6002bfca577SNathan Whitehorn int err = 0; 601fe3b4685SNathan Whitehorn 6026f489d43SJustin Hibbits #ifdef AIM 60317879090SNathan Whitehorn if (openfirmware_entry != NULL) { 604fe3b4685SNathan Whitehorn if (ofw_real_mode) { 605fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_REAL, 0); 606fe3b4685SNathan Whitehorn } else { 607fe3b4685SNathan Whitehorn #ifdef __powerpc64__ 608fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_32BIT, 0); 609fe3b4685SNathan Whitehorn #else 610fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_DIRECT, 0); 611fe3b4685SNathan Whitehorn #endif 612fe3b4685SNathan Whitehorn } 613fe3b4685SNathan Whitehorn 614fe3b4685SNathan Whitehorn if (status != TRUE) 615fe3b4685SNathan Whitehorn return status; 616fe3b4685SNathan Whitehorn 6172bfca577SNathan Whitehorn err = OF_init(openfirmware); 6186f489d43SJustin Hibbits } else 6196f489d43SJustin Hibbits #endif 6206f489d43SJustin Hibbits if (fdt != NULL) { 62135feca37SNathan Whitehorn #ifdef FDT 622f9edb09dSNathan Whitehorn #ifdef AIM 623f9edb09dSNathan Whitehorn bus_space_tag_t fdt_bt; 624f9edb09dSNathan Whitehorn vm_offset_t tmp_fdt_ptr; 625f9edb09dSNathan Whitehorn vm_size_t fdt_size; 626f9edb09dSNathan Whitehorn uintptr_t fdt_va; 627f9edb09dSNathan Whitehorn #endif 628fe3b4685SNathan Whitehorn 629f9edb09dSNathan Whitehorn status = OF_install(OFW_FDT, 0); 630fe3b4685SNathan Whitehorn if (status != TRUE) 631fe3b4685SNathan Whitehorn return status; 632fe3b4685SNathan Whitehorn 633f9edb09dSNathan Whitehorn #ifdef AIM /* AIM-only for now -- Book-E does this remapping in early init */ 634f9edb09dSNathan Whitehorn /* Get the FDT size for mapping if we can */ 635f9edb09dSNathan Whitehorn tmp_fdt_ptr = pmap_early_io_map((vm_paddr_t)fdt, PAGE_SIZE); 636f9edb09dSNathan Whitehorn if (fdt_check_header((void *)tmp_fdt_ptr) != 0) { 637f9edb09dSNathan Whitehorn pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE); 638f9edb09dSNathan Whitehorn return FALSE; 639fe3b4685SNathan Whitehorn } 640f9edb09dSNathan Whitehorn fdt_size = fdt_totalsize((void *)tmp_fdt_ptr); 641f9edb09dSNathan Whitehorn pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE); 642f9edb09dSNathan Whitehorn 643f9edb09dSNathan Whitehorn /* 644f9edb09dSNathan Whitehorn * Map this for real. Use bus_space_map() to take advantage 645f9edb09dSNathan Whitehorn * of its auto-remapping function once the kernel is loaded. 646f9edb09dSNathan Whitehorn * This is a dirty hack, but what we have. 647f9edb09dSNathan Whitehorn */ 648f9edb09dSNathan Whitehorn #ifdef _LITTLE_ENDIAN 649f9edb09dSNathan Whitehorn fdt_bt = &bs_le_tag; 650f9edb09dSNathan Whitehorn #else 651f9edb09dSNathan Whitehorn fdt_bt = &bs_be_tag; 652f9edb09dSNathan Whitehorn #endif 653f9edb09dSNathan Whitehorn bus_space_map(fdt_bt, (vm_paddr_t)fdt, fdt_size, 0, &fdt_va); 654f9edb09dSNathan Whitehorn 655f9edb09dSNathan Whitehorn err = OF_init((void *)fdt_va); 656f9edb09dSNathan Whitehorn #else 657f9edb09dSNathan Whitehorn err = OF_init(fdt); 658f9edb09dSNathan Whitehorn #endif 65935feca37SNathan Whitehorn #endif 660f9edb09dSNathan Whitehorn } 661f9edb09dSNathan Whitehorn 662f9edb09dSNathan Whitehorn #ifdef FDT_DTB_STATIC 663f9edb09dSNathan Whitehorn /* 664f9edb09dSNathan Whitehorn * Check for a statically included blob already in the kernel and 665f9edb09dSNathan Whitehorn * needing no mapping. 666f9edb09dSNathan Whitehorn */ 667f9edb09dSNathan Whitehorn else { 668f9edb09dSNathan Whitehorn status = OF_install(OFW_FDT, 0); 669f9edb09dSNathan Whitehorn if (status != TRUE) 670f9edb09dSNathan Whitehorn return status; 671f9edb09dSNathan Whitehorn err = OF_init(&fdt_static_dtb); 672f9edb09dSNathan Whitehorn } 673f9edb09dSNathan Whitehorn #endif 674fe3b4685SNathan Whitehorn 6752bfca577SNathan Whitehorn if (err != 0) { 6762bfca577SNathan Whitehorn OF_install(NULL, 0); 6772bfca577SNathan Whitehorn status = FALSE; 6782bfca577SNathan Whitehorn } 6792bfca577SNathan Whitehorn 680fe3b4685SNathan Whitehorn return (status); 681fe3b4685SNathan Whitehorn } 682fe3b4685SNathan Whitehorn 6836f489d43SJustin Hibbits #ifdef AIM 6849f706727SNathan Whitehorn void 685fe3b4685SNathan Whitehorn ofw_quiesce(void) 686fe3b4685SNathan Whitehorn { 687fe3b4685SNathan Whitehorn struct { 688fe3b4685SNathan Whitehorn cell_t name; 689fe3b4685SNathan Whitehorn cell_t nargs; 690fe3b4685SNathan Whitehorn cell_t nreturns; 691fe3b4685SNathan Whitehorn } args; 692fe3b4685SNathan Whitehorn 6939f706727SNathan Whitehorn KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 694fe3b4685SNathan Whitehorn 695fe3b4685SNathan Whitehorn args.name = (cell_t)(uintptr_t)"quiesce"; 696fe3b4685SNathan Whitehorn args.nargs = 0; 697fe3b4685SNathan Whitehorn args.nreturns = 0; 698fe3b4685SNathan Whitehorn openfirmware(&args); 699fe3b4685SNathan Whitehorn } 700fe3b4685SNathan Whitehorn 701fe3b4685SNathan Whitehorn static int 702fe3b4685SNathan Whitehorn openfirmware_core(void *args) 703fe3b4685SNathan Whitehorn { 704fe3b4685SNathan Whitehorn int result; 705fe3b4685SNathan Whitehorn register_t oldmsr; 706fe3b4685SNathan Whitehorn 70744d29d47SNathan Whitehorn if (openfirmware_entry == NULL) 70844d29d47SNathan Whitehorn return (-1); 70944d29d47SNathan Whitehorn 710fe3b4685SNathan Whitehorn /* 711fe3b4685SNathan Whitehorn * Turn off exceptions - we really don't want to end up 7124aa3cee6SNathan Whitehorn * anywhere unexpected with PCPU set to something strange 7134aa3cee6SNathan Whitehorn * or the stack pointer wrong. 714fe3b4685SNathan Whitehorn */ 715fe3b4685SNathan Whitehorn oldmsr = intr_disable(); 716fe3b4685SNathan Whitehorn 7174aa3cee6SNathan Whitehorn ofw_sprg_prepare(); 7184aa3cee6SNathan Whitehorn 719f367ffdeSAndreas Tobler /* Save trap vectors */ 720f367ffdeSAndreas Tobler ofw_save_trap_vec(save_trap_of); 721f367ffdeSAndreas Tobler 722f367ffdeSAndreas Tobler /* Restore initially saved trap vectors */ 723f367ffdeSAndreas Tobler ofw_restore_trap_vec(save_trap_init); 724f367ffdeSAndreas Tobler 72595ce4c00SJustin Hibbits #ifndef __powerpc64__ 726fe3b4685SNathan Whitehorn /* 727fe3b4685SNathan Whitehorn * Clear battable[] translations 728fe3b4685SNathan Whitehorn */ 729fe3b4685SNathan Whitehorn if (!(cpu_features & PPC_FEATURE_64)) 730fe3b4685SNathan Whitehorn __asm __volatile("mtdbatu 2, %0\n" 731fe3b4685SNathan Whitehorn "mtdbatu 3, %0" : : "r" (0)); 732fe3b4685SNathan Whitehorn isync(); 733fe3b4685SNathan Whitehorn #endif 734fe3b4685SNathan Whitehorn 735fe3b4685SNathan Whitehorn result = ofwcall(args); 736f367ffdeSAndreas Tobler 737f367ffdeSAndreas Tobler /* Restore trap vecotrs */ 738f367ffdeSAndreas Tobler ofw_restore_trap_vec(save_trap_of); 739f367ffdeSAndreas Tobler 7404aa3cee6SNathan Whitehorn ofw_sprg_restore(); 7414aa3cee6SNathan Whitehorn 742fe3b4685SNathan Whitehorn intr_restore(oldmsr); 743fe3b4685SNathan Whitehorn 744fe3b4685SNathan Whitehorn return (result); 745fe3b4685SNathan Whitehorn } 746fe3b4685SNathan Whitehorn 747fe3b4685SNathan Whitehorn #ifdef SMP 748fe3b4685SNathan Whitehorn struct ofw_rv_args { 749fe3b4685SNathan Whitehorn void *args; 750fe3b4685SNathan Whitehorn int retval; 751fe3b4685SNathan Whitehorn volatile int in_progress; 752fe3b4685SNathan Whitehorn }; 753fe3b4685SNathan Whitehorn 754fe3b4685SNathan Whitehorn static void 755fe3b4685SNathan Whitehorn ofw_rendezvous_dispatch(void *xargs) 756fe3b4685SNathan Whitehorn { 757fe3b4685SNathan Whitehorn struct ofw_rv_args *rv_args = xargs; 758fe3b4685SNathan Whitehorn 759fe3b4685SNathan Whitehorn /* NOTE: Interrupts are disabled here */ 760fe3b4685SNathan Whitehorn 761fe3b4685SNathan Whitehorn if (PCPU_GET(cpuid) == 0) { 762fe3b4685SNathan Whitehorn /* 763fe3b4685SNathan Whitehorn * Execute all OF calls on CPU 0 764fe3b4685SNathan Whitehorn */ 765fe3b4685SNathan Whitehorn rv_args->retval = openfirmware_core(rv_args->args); 766fe3b4685SNathan Whitehorn rv_args->in_progress = 0; 767fe3b4685SNathan Whitehorn } else { 768fe3b4685SNathan Whitehorn /* 769fe3b4685SNathan Whitehorn * Spin with interrupts off on other CPUs while OF has 770fe3b4685SNathan Whitehorn * control of the machine. 771fe3b4685SNathan Whitehorn */ 772fe3b4685SNathan Whitehorn while (rv_args->in_progress) 773fe3b4685SNathan Whitehorn cpu_spinwait(); 774fe3b4685SNathan Whitehorn } 775fe3b4685SNathan Whitehorn } 776fe3b4685SNathan Whitehorn #endif 777fe3b4685SNathan Whitehorn 778fe3b4685SNathan Whitehorn static int 779fe3b4685SNathan Whitehorn openfirmware(void *args) 780fe3b4685SNathan Whitehorn { 781fe3b4685SNathan Whitehorn int result; 782fe3b4685SNathan Whitehorn #ifdef SMP 783fe3b4685SNathan Whitehorn struct ofw_rv_args rv_args; 78444d29d47SNathan Whitehorn #endif 785fe3b4685SNathan Whitehorn 78644d29d47SNathan Whitehorn if (openfirmware_entry == NULL) 78744d29d47SNathan Whitehorn return (-1); 78844d29d47SNathan Whitehorn 78944d29d47SNathan Whitehorn #ifdef SMP 79091419bdaSNathan Whitehorn if (cold) { 79191419bdaSNathan Whitehorn result = openfirmware_core(args); 79291419bdaSNathan Whitehorn } else { 793fe3b4685SNathan Whitehorn rv_args.args = args; 794fe3b4685SNathan Whitehorn rv_args.in_progress = 1; 79591419bdaSNathan Whitehorn smp_rendezvous(smp_no_rendezvous_barrier, 79691419bdaSNathan Whitehorn ofw_rendezvous_dispatch, smp_no_rendezvous_barrier, 79791419bdaSNathan Whitehorn &rv_args); 798fe3b4685SNathan Whitehorn result = rv_args.retval; 79991419bdaSNathan Whitehorn } 800fe3b4685SNathan Whitehorn #else 801fe3b4685SNathan Whitehorn result = openfirmware_core(args); 802fe3b4685SNathan Whitehorn #endif 803fe3b4685SNathan Whitehorn 804fe3b4685SNathan Whitehorn return (result); 805fe3b4685SNathan Whitehorn } 806fe3b4685SNathan Whitehorn 807fe3b4685SNathan Whitehorn void 808fe3b4685SNathan Whitehorn OF_reboot() 809fe3b4685SNathan Whitehorn { 810fe3b4685SNathan Whitehorn struct { 811fe3b4685SNathan Whitehorn cell_t name; 812fe3b4685SNathan Whitehorn cell_t nargs; 813fe3b4685SNathan Whitehorn cell_t nreturns; 814fe3b4685SNathan Whitehorn cell_t arg; 815fe3b4685SNathan Whitehorn } args; 816fe3b4685SNathan Whitehorn 817fe3b4685SNathan Whitehorn args.name = (cell_t)(uintptr_t)"interpret"; 818fe3b4685SNathan Whitehorn args.nargs = 1; 819fe3b4685SNathan Whitehorn args.nreturns = 0; 820fe3b4685SNathan Whitehorn args.arg = (cell_t)(uintptr_t)"reset-all"; 821fe3b4685SNathan Whitehorn openfirmware_core(&args); /* Don't do rendezvous! */ 822fe3b4685SNathan Whitehorn 823fe3b4685SNathan Whitehorn for (;;); /* just in case */ 824fe3b4685SNathan Whitehorn } 825fe3b4685SNathan Whitehorn 826629aa519SNathan Whitehorn #endif /* AIM */ 827629aa519SNathan Whitehorn 828fe3b4685SNathan Whitehorn void 829fe3b4685SNathan Whitehorn OF_getetheraddr(device_t dev, u_char *addr) 830fe3b4685SNathan Whitehorn { 831fe3b4685SNathan Whitehorn phandle_t node; 832fe3b4685SNathan Whitehorn 833fe3b4685SNathan Whitehorn node = ofw_bus_get_node(dev); 834fe3b4685SNathan Whitehorn OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 835fe3b4685SNathan Whitehorn } 836fe3b4685SNathan Whitehorn 837fe3b4685SNathan Whitehorn /* 838fe3b4685SNathan Whitehorn * Return a bus handle and bus tag that corresponds to the register 839fe3b4685SNathan Whitehorn * numbered regno for the device referenced by the package handle 840fe3b4685SNathan Whitehorn * dev. This function is intended to be used by console drivers in 841fe3b4685SNathan Whitehorn * early boot only. It works by mapping the address of the device's 842fe3b4685SNathan Whitehorn * register in the address space of its parent and recursively walk 843fe3b4685SNathan Whitehorn * the device tree upward this way. 844fe3b4685SNathan Whitehorn */ 845fe3b4685SNathan Whitehorn int 846fe3b4685SNathan Whitehorn OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 84745fd1862SAndrew Turner bus_space_handle_t *handle, bus_size_t *sz) 848fe3b4685SNathan Whitehorn { 849bc7b9300SIan Lepore bus_addr_t addr; 850bc7b9300SIan Lepore bus_size_t size; 851bc7b9300SIan Lepore pcell_t pci_hi; 852bc7b9300SIan Lepore int flags, res; 853fe3b4685SNathan Whitehorn 854bc7b9300SIan Lepore res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi); 855bc7b9300SIan Lepore if (res < 0) 856bc7b9300SIan Lepore return (res); 857fe3b4685SNathan Whitehorn 858bc7b9300SIan Lepore if (pci_hi == OFW_PADDR_NOT_PCI) { 85943a581e1SNathan Whitehorn *tag = &bs_be_tag; 860bc7b9300SIan Lepore flags = 0; 861bc7b9300SIan Lepore } else { 86243a581e1SNathan Whitehorn *tag = &bs_le_tag; 863bc7b9300SIan Lepore flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? 864bc7b9300SIan Lepore BUS_SPACE_MAP_PREFETCHABLE: 0; 865fe3b4685SNathan Whitehorn } 866fe3b4685SNathan Whitehorn 86745fd1862SAndrew Turner if (sz != NULL) 86845fd1862SAndrew Turner *sz = size; 86945fd1862SAndrew Turner 870bc7b9300SIan Lepore return (bus_space_map(*tag, addr, size, flags, handle)); 871fe3b4685SNathan Whitehorn } 872fe3b4685SNathan Whitehorn 873