ofw_machdep.c revision 215159
164987Smsmith/*- 273050Smsmith * Copyright (C) 1996 Wolfgang Solfrank. 364987Smsmith * Copyright (C) 1996 TooLs GmbH. 464987Smsmith * All rights reserved. 564987Smsmith * 664987Smsmith * Redistribution and use in source and binary forms, with or without 764987Smsmith * modification, are permitted provided that the following conditions 864987Smsmith * are met: 964987Smsmith * 1. Redistributions of source code must retain the above copyright 1064987Smsmith * notice, this list of conditions and the following disclaimer. 1164987Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1264987Smsmith * notice, this list of conditions and the following disclaimer in the 1364987Smsmith * documentation and/or other materials provided with the distribution. 1464987Smsmith * 3. All advertising materials mentioning features or use of this software 1564987Smsmith * must display the following acknowledgement: 1664987Smsmith * This product includes software developed by TooLs GmbH. 1764987Smsmith * 4. The name of TooLs GmbH may not be used to endorse or promote products 1864987Smsmith * derived from this software without specific prior written permission. 1964987Smsmith * 2064987Smsmith * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2164987Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2264987Smsmith * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2364987Smsmith * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2464987Smsmith * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2564987Smsmith * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2664987Smsmith * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2764987Smsmith * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2864987Smsmith * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2964987Smsmith * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3064987Smsmith * 3164987Smsmith * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 3264987Smsmith */ 3364987Smsmith 3464987Smsmith#include <sys/cdefs.h> 3564987Smsmith__FBSDID("$FreeBSD: head/sys/powerpc/aim/ofw_machdep.c 215159 2010-11-12 04:18:19Z nwhitehorn $"); 3664987Smsmith 3779695Smsmith#include <sys/param.h> 3873050Smsmith#include <sys/bus.h> 3973050Smsmith#include <sys/systm.h> 4064987Smsmith#include <sys/conf.h> 4164987Smsmith#include <sys/disk.h> 4264987Smsmith#include <sys/fcntl.h> 4364987Smsmith#include <sys/malloc.h> 4464987Smsmith#include <sys/smp.h> 4564987Smsmith#include <sys/stat.h> 4679695Smsmith 4779695Smsmith#include <net/ethernet.h> 4879695Smsmith 4979695Smsmith#include <dev/ofw/openfirm.h> 5079695Smsmith#include <dev/ofw/ofw_pci.h> 5164987Smsmith#include <dev/ofw/ofw_bus.h> 5279695Smsmith 5364987Smsmith#include <vm/vm.h> 5479695Smsmith#include <vm/vm_param.h> 5579695Smsmith#include <vm/vm_page.h> 5679695Smsmith 5764987Smsmith#include <machine/bus.h> 5873050Smsmith#include <machine/cpu.h> 5964987Smsmith#include <machine/md_var.h> 6064987Smsmith#include <machine/platform.h> 6164987Smsmith#include <machine/ofw_machdep.h> 6279695Smsmith 6379695Smsmith#define OFMEM_REGIONS 32 6479695Smsmithstatic struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3]; 6579695Smsmithstatic struct mem_region OFfree[OFMEM_REGIONS + 3]; 6679695Smsmithstatic int nOFmem; 6779695Smsmith 6879695Smsmithextern register_t ofmsr[5]; 6979695Smsmithextern struct pmap ofw_pmap; 7079695Smsmithstatic int (*ofwcall)(void *); 7179695Smsmithstatic void *fdt; 7279695Smsmithint ofw_real_mode; 7379695Smsmith 7479695Smsmithint ofw_32bit_mode_entry(void *); 7564987Smsmithstatic void ofw_quiesce(void); 7664987Smsmithstatic int openfirmware(void *args); 7764987Smsmith 7864987Smsmith/* 7964987Smsmith * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 8064987Smsmith */ 8164987Smsmithregister_t ofw_sprg0_save; 8264987Smsmith 8364987Smsmithstatic __inline void 8479695Smsmithofw_sprg_prepare(void) 8564987Smsmith{ 8664987Smsmith /* 8764987Smsmith * Assume that interrupt are disabled at this point, or 8864987Smsmith * SPRG1-3 could be trashed 8964987Smsmith */ 9064987Smsmith __asm __volatile("mfsprg0 %0\n\t" 9164987Smsmith "mtsprg0 %1\n\t" 9279695Smsmith "mtsprg1 %2\n\t" 9364987Smsmith "mtsprg2 %3\n\t" 9464987Smsmith "mtsprg3 %4\n\t" 9579695Smsmith : "=&r"(ofw_sprg0_save) 9679695Smsmith : "r"(ofmsr[1]), 9773050Smsmith "r"(ofmsr[2]), 9873050Smsmith "r"(ofmsr[3]), 9979695Smsmith "r"(ofmsr[4])); 10064987Smsmith} 10164987Smsmith 10264987Smsmithstatic __inline void 10379695Smsmithofw_sprg_restore(void) 10479695Smsmith{ 10579695Smsmith /* 10679695Smsmith * Note that SPRG1-3 contents are irrelevant. They are scratch 10779695Smsmith * registers used in the early portion of trap handling when 10879695Smsmith * interrupts are disabled. 10979695Smsmith * 11079695Smsmith * PCPU data cannot be used until this routine is called ! 11179695Smsmith */ 11279695Smsmith __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 11379695Smsmith} 11464987Smsmith 11564987Smsmith/* 11664987Smsmith * Memory region utilities: determine if two regions overlap, 11764987Smsmith * and merge two overlapping regions into one 11864987Smsmith */ 11964987Smsmithstatic int 12064987Smsmithmemr_overlap(struct mem_region *r1, struct mem_region *r2) 12164987Smsmith{ 12264987Smsmith if ((r1->mr_start + r1->mr_size) < r2->mr_start || 12373050Smsmith (r2->mr_start + r2->mr_size) < r1->mr_start) 124110479Sscottl return (FALSE); 12564987Smsmith 12679695Smsmith return (TRUE); 12773050Smsmith} 12873050Smsmith 12973050Smsmithstatic void 13073050Smsmithmemr_merge(struct mem_region *from, struct mem_region *to) 13173050Smsmith{ 13273050Smsmith vm_offset_t end; 133110479Sscottl end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size); 13479695Smsmith to->mr_start = ulmin(from->mr_start, to->mr_start); 13579695Smsmith to->mr_size = end - to->mr_start; 13679695Smsmith} 13779695Smsmith 13879695Smsmithstatic int 13979695Smsmithparse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 14079695Smsmith{ 14179695Smsmith cell_t address_cells, size_cells; 14279695Smsmith cell_t OFmem[4*(OFMEM_REGIONS + 1)]; 14379695Smsmith int sz, i, j; 14479695Smsmith int apple_hack_mode; 14579695Smsmith phandle_t phandle; 14679695Smsmith 14779695Smsmith sz = 0; 14879695Smsmith apple_hack_mode = 0; 14979695Smsmith 15079695Smsmith /* 15179695Smsmith * Get #address-cells from root node, defaulting to 1 if it cannot 15279695Smsmith * be found. 15373050Smsmith */ 15473050Smsmith phandle = OF_finddevice("/"); 15573050Smsmith if (OF_getprop(phandle, "#address-cells", &address_cells, 156111815Sphk sizeof(address_cells)) < sizeof(address_cells)) 157111815Sphk address_cells = 1; 158111815Sphk if (OF_getprop(phandle, "#size-cells", &size_cells, 159111815Sphk sizeof(size_cells)) < sizeof(size_cells)) 160111815Sphk size_cells = 1; 16173050Smsmith 16273050Smsmith /* 16364987Smsmith * On Apple hardware, address_cells is always 1 for "available", 16464987Smsmith * even when it is explicitly set to 2. Then all memory above 4 GB 16564987Smsmith * should be added by hand to the available list. Detect Apple hardware 16664987Smsmith * by seeing if ofw_real_mode is set -- only Apple seems to use 16764987Smsmith * virtual-mode OF. 16864987Smsmith */ 16979695Smsmith if (strcmp(prop, "available") == 0 && !ofw_real_mode) 17079695Smsmith apple_hack_mode = 1; 17179695Smsmith 17279695Smsmith if (apple_hack_mode) 17379695Smsmith address_cells = 1; 17479695Smsmith 17579695Smsmith /* 17679695Smsmith * Get memory. 17779695Smsmith */ 17879695Smsmith if ((node == -1) || (sz = OF_getprop(node, prop, 17979695Smsmith OFmem, sizeof(OFmem[0]) * 4 * OFMEM_REGIONS)) <= 0) 18079695Smsmith panic("Physical memory map not found"); 18179695Smsmith 18279695Smsmith i = 0; 18379695Smsmith j = 0; 18479695Smsmith while (i < sz/sizeof(cell_t)) { 18579695Smsmith #ifndef __powerpc64__ 18664987Smsmith /* On 32-bit PPC, ignore regions starting above 4 GB */ 18779695Smsmith if (address_cells > 1 && OFmem[i] > 0) { 18879695Smsmith i += address_cells + size_cells; 18979695Smsmith continue; 19079695Smsmith } 19179695Smsmith #endif 19279695Smsmith 19379695Smsmith output[j].mr_start = OFmem[i++]; 19479695Smsmith if (address_cells == 2) { 19579695Smsmith #ifdef __powerpc64__ 19679695Smsmith output[j].mr_start <<= 32; 19779695Smsmith #endif 19879695Smsmith output[j].mr_start += OFmem[i++]; 19979695Smsmith } 20079695Smsmith 20179695Smsmith output[j].mr_size = OFmem[i++]; 20279695Smsmith if (size_cells == 2) { 20379695Smsmith #ifdef __powerpc64__ 20479695Smsmith output[j].mr_size <<= 32; 20579695Smsmith #endif 20679695Smsmith output[j].mr_size += OFmem[i++]; 20779695Smsmith } 20879695Smsmith 20979695Smsmith #ifndef __powerpc64__ 21079695Smsmith /* 21179695Smsmith * Check for memory regions extending above 32-bit 21279695Smsmith * memory space, and restrict them to stay there. 21379695Smsmith */ 21464987Smsmith if (((uint64_t)output[j].mr_start + 21564987Smsmith (uint64_t)output[j].mr_size) > 216105215Sphk BUS_SPACE_MAXADDR_32BIT) { 21779695Smsmith output[j].mr_size = BUS_SPACE_MAXADDR_32BIT - 21864987Smsmith output[j].mr_start; 21979695Smsmith } 22079695Smsmith #endif 22164987Smsmith 22264987Smsmith j++; 22364987Smsmith } 22479695Smsmith sz = j*sizeof(output[0]); 22579695Smsmith 22679695Smsmith #ifdef __powerpc64__ 22779695Smsmith if (apple_hack_mode) { 22879695Smsmith /* Add in regions above 4 GB to the available list */ 22979695Smsmith struct mem_region himem[OFMEM_REGIONS]; 23079695Smsmith int hisz; 23164987Smsmith 23279695Smsmith hisz = parse_ofw_memory(node, "reg", himem); 23379695Smsmith for (i = 0; i < hisz/sizeof(himem[0]); i++) { 23479695Smsmith if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) { 23579695Smsmith output[j].mr_start = himem[i].mr_start; 23679695Smsmith output[j].mr_size = himem[i].mr_size; 23779695Smsmith j++; 23864987Smsmith } 23964987Smsmith } 24073050Smsmith sz = j*sizeof(output[0]); 24173050Smsmith } 24273050Smsmith #endif 24364987Smsmith 24464987Smsmith return (sz); 24564987Smsmith} 24664987Smsmith 24764987Smsmith/* 24864987Smsmith * This is called during powerpc_init, before the system is really initialized. 24964987Smsmith * It shall provide the total and the available regions of RAM. 25064987Smsmith * Both lists must have a zero-size entry as terminator. 25164987Smsmith * The available regions need not take the kernel into account, but needs 25264987Smsmith * to provide space for two additional entry beyond the terminating one. 25364987Smsmith */ 25464987Smsmithvoid 25564987Smsmithofw_mem_regions(struct mem_region **memp, int *memsz, 25664987Smsmith struct mem_region **availp, int *availsz) 25764987Smsmith{ 25864987Smsmith phandle_t phandle; 25964987Smsmith int asz, msz, fsz; 26079695Smsmith int i, j; 26164987Smsmith int still_merging; 26264987Smsmith 26379695Smsmith asz = msz = 0; 26464987Smsmith 26573050Smsmith /* 26679695Smsmith * Get memory. 26764987Smsmith */ 26864987Smsmith phandle = OF_finddevice("/memory"); 26964987Smsmith if (phandle == -1) 27064987Smsmith phandle = OF_finddevice("/memory@0"); 27164987Smsmith 27279695Smsmith msz = parse_ofw_memory(phandle, "reg", OFmem); 27364987Smsmith nOFmem = msz / sizeof(struct mem_region); 27464987Smsmith asz = parse_ofw_memory(phandle, "available", OFavail); 27579695Smsmith 27679695Smsmith *memp = OFmem; 27779695Smsmith *memsz = nOFmem; 27879695Smsmith 27979695Smsmith /* 28079695Smsmith * OFavail may have overlapping regions - collapse these 28179695Smsmith * and copy out remaining regions to OFfree 28264987Smsmith */ 28364987Smsmith asz /= sizeof(struct mem_region); 28464987Smsmith do { 28564987Smsmith still_merging = FALSE; 28679695Smsmith for (i = 0; i < asz; i++) { 28764987Smsmith if (OFavail[i].mr_size == 0) 28864987Smsmith continue; 28979695Smsmith for (j = i+1; j < asz; j++) { 29064987Smsmith if (OFavail[j].mr_size == 0) 29164987Smsmith continue; 29279695Smsmith if (memr_overlap(&OFavail[j], &OFavail[i])) { 29364987Smsmith memr_merge(&OFavail[j], &OFavail[i]); 29464987Smsmith /* mark inactive */ 29564987Smsmith OFavail[j].mr_size = 0; 29664987Smsmith still_merging = TRUE; 29764987Smsmith } 29879695Smsmith } 29964987Smsmith } 30064987Smsmith } while (still_merging == TRUE); 30164987Smsmith 30264987Smsmith /* evict inactive ranges */ 30364987Smsmith for (i = 0, fsz = 0; i < asz; i++) { 30464987Smsmith if (OFavail[i].mr_size != 0) { 30564987Smsmith OFfree[fsz] = OFavail[i]; 30679695Smsmith fsz++; 30764987Smsmith } 30864987Smsmith } 30964987Smsmith 31064987Smsmith *availp = OFfree; 31164987Smsmith *availsz = fsz; 31264987Smsmith} 31379695Smsmith 31464987Smsmithvoid 31564987SmsmithOF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 31664987Smsmith{ 31773050Smsmith if (ofmsr[0] & PSL_DR) 31873050Smsmith ofw_real_mode = 0; 31973050Smsmith else 32073050Smsmith ofw_real_mode = 1; 32173050Smsmith 32273050Smsmith ofwcall = NULL; 32373050Smsmith 32464987Smsmith #ifdef __powerpc64__ 32564987Smsmith /* 32664987Smsmith * For PPC64, we need to use some hand-written 327110479Sscottl * asm trampolines to get to OF. 328110479Sscottl */ 329110479Sscottl if (openfirm != NULL) 330110479Sscottl ofwcall = ofw_32bit_mode_entry; 33179695Smsmith #else 33279695Smsmith ofwcall = openfirm; 33379695Smsmith #endif 33479695Smsmith 33579695Smsmith fdt = fdt_ptr; 33679695Smsmith 33779695Smsmith #ifdef FDT_DTB_STATIC 33879695Smsmith /* Check for a statically included blob */ 33979695Smsmith if (fdt == NULL) 34079695Smsmith fdt = &fdt_static_dtb; 34179695Smsmith #endif 34279695Smsmith} 34379695Smsmith 34479695Smsmithboolean_t 34579695SmsmithOF_bootstrap() 34679695Smsmith{ 34779695Smsmith boolean_t status = FALSE; 34879695Smsmith 34979695Smsmith if (ofwcall != NULL) { 35079695Smsmith if (ofw_real_mode) { 35179695Smsmith status = OF_install(OFW_STD_REAL, 0); 35279695Smsmith } else { 35379695Smsmith #ifdef __powerpc64__ 35479695Smsmith status = OF_install(OFW_STD_32BIT, 0); 35579695Smsmith #else 35679695Smsmith status = OF_install(OFW_STD_DIRECT, 0); 35779695Smsmith #endif 35879695Smsmith } 35979695Smsmith 36079695Smsmith if (status != TRUE) 36179695Smsmith return status; 36279695Smsmith 36379695Smsmith OF_init(openfirmware); 36479695Smsmith 36579695Smsmith /* 36679695Smsmith * On some machines, we need to quiesce OF to turn off 36779695Smsmith * background processes. 36879695Smsmith */ 36979695Smsmith ofw_quiesce(); 37079695Smsmith } else if (fdt != NULL) { 37179695Smsmith status = OF_install(OFW_FDT, 0); 37279695Smsmith 37379695Smsmith if (status != TRUE) 37479695Smsmith return status; 37579695Smsmith 37679695Smsmith OF_init(fdt); 37779695Smsmith } 37879695Smsmith 37979695Smsmith return (status); 38079695Smsmith} 38179695Smsmith 38279695Smsmithstatic void 38379695Smsmithofw_quiesce(void) 38479695Smsmith{ 38579695Smsmith phandle_t rootnode; 38679695Smsmith char model[32]; 38779695Smsmith struct { 38879695Smsmith cell_t name; 38979695Smsmith cell_t nargs; 39079695Smsmith cell_t nreturns; 39179695Smsmith } args; 39279695Smsmith 39379695Smsmith /* 39479695Smsmith * Only quiesce Open Firmware on PowerMac11,2 and 12,1. It is 39579695Smsmith * necessary there to shut down a background thread doing fan 39679695Smsmith * management, and is harmful on other machines. 39779695Smsmith * 39879695Smsmith * Note: we don't need to worry about which OF module we are 39979695Smsmith * using since this is called only from very early boot, within 40079695Smsmith * OF's boot context. 40179695Smsmith */ 40279695Smsmith 40379695Smsmith rootnode = OF_finddevice("/"); 40479695Smsmith if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) { 40579695Smsmith if (strcmp(model, "PowerMac11,2") == 0 || 40679695Smsmith strcmp(model, "PowerMac12,1") == 0) { 40779695Smsmith args.name = (cell_t)(uintptr_t)"quiesce"; 40879695Smsmith args.nargs = 0; 40979695Smsmith args.nreturns = 0; 41079695Smsmith openfirmware(&args); 41179695Smsmith } 41279695Smsmith } 41379695Smsmith} 41479695Smsmith 41579695Smsmithstatic int 41679695Smsmithopenfirmware_core(void *args) 41779695Smsmith{ 41879695Smsmith int result; 41979695Smsmith register_t oldmsr; 42079695Smsmith #ifndef __powerpc64__ 42179695Smsmith register_t srsave[16]; 42279695Smsmith u_int i; 42379695Smsmith #endif 42479695Smsmith 42579695Smsmith /* 42679695Smsmith * Turn off exceptions - we really don't want to end up 42779695Smsmith * anywhere unexpected with PCPU set to something strange, 42879695Smsmith * the stack pointer wrong, or the OFW mapping enabled. 42979695Smsmith */ 43079695Smsmith oldmsr = intr_disable(); 43179695Smsmith 43279695Smsmith ofw_sprg_prepare(); 43379695Smsmith 43479695Smsmith #ifndef __powerpc64__ 43579695Smsmith if (pmap_bootstrapped && !ofw_real_mode) { 43679695Smsmith /* 43779695Smsmith * Swap the kernel's address space with Open Firmware's 43879695Smsmith */ 43979695Smsmith 44079695Smsmith for (i = 0; i < 16; i++) { 44179695Smsmith srsave[i] = mfsrin(i << ADDR_SR_SHFT); 44279695Smsmith mtsrin(i << ADDR_SR_SHFT, ofw_pmap.pm_sr[i]); 44379695Smsmith } 44479695Smsmith 44579695Smsmith /* 44679695Smsmith * Clear battable[] translations 44779695Smsmith */ 44879695Smsmith if (!(cpu_features & PPC_FEATURE_64)) { 44979695Smsmith __asm __volatile("mtdbatu 2, %0\n" 45079695Smsmith "mtdbatu 3, %0" : : "r" (0)); 45179695Smsmith } 45279695Smsmith isync(); 45379695Smsmith } 45479695Smsmith #endif 45579695Smsmith 45679695Smsmith result = ofwcall(args); 45779695Smsmith 45879695Smsmith #ifndef __powerpc64__ 45979695Smsmith if (pmap_bootstrapped && !ofw_real_mode) { 46079695Smsmith /* 46179695Smsmith * Restore the kernel's addr space. The isync() doesn;t 46279695Smsmith * work outside the loop unless mtsrin() is open-coded 46379695Smsmith * in an asm statement :( 46479695Smsmith */ 46579695Smsmith 46679695Smsmith for (i = 0; i < 16; i++) { 46779695Smsmith mtsrin(i << ADDR_SR_SHFT, srsave[i]); 46879695Smsmith isync(); 46979695Smsmith } 47079695Smsmith } 47179695Smsmith #endif 47279695Smsmith 47379695Smsmith ofw_sprg_restore(); 47479695Smsmith 47579695Smsmith intr_restore(oldmsr); 47679695Smsmith 47779695Smsmith return (result); 47879695Smsmith} 47979695Smsmith 48079695Smsmith#ifdef SMP 48179695Smsmithstruct ofw_rv_args { 48279695Smsmith void *args; 48379695Smsmith int retval; 48479695Smsmith volatile int in_progress; 48579695Smsmith}; 48679695Smsmith 48779695Smsmithstatic void 48879695Smsmithofw_rendezvous_dispatch(void *xargs) 48979695Smsmith{ 49079695Smsmith struct ofw_rv_args *rv_args = xargs; 49179695Smsmith 49279695Smsmith /* NOTE: Interrupts are disabled here */ 49379695Smsmith 49479695Smsmith if (PCPU_GET(cpuid) == 0) { 49579695Smsmith /* 49679695Smsmith * Execute all OF calls on CPU 0 49779695Smsmith */ 49879695Smsmith rv_args->retval = openfirmware_core(rv_args->args); 49979695Smsmith rv_args->in_progress = 0; 50079695Smsmith } else { 50179695Smsmith /* 50279695Smsmith * Spin with interrupts off on other CPUs while OF has 50379695Smsmith * control of the machine. 50479695Smsmith */ 50579695Smsmith while (rv_args->in_progress) 50679695Smsmith cpu_spinwait(); 50779695Smsmith } 50879695Smsmith} 50979695Smsmith#endif 51079695Smsmith 51179695Smsmithstatic int 51279695Smsmithopenfirmware(void *args) 51364987Smsmith{ 51464987Smsmith int result; 51564987Smsmith #ifdef SMP 51664987Smsmith struct ofw_rv_args rv_args; 51764987Smsmith #endif 51879695Smsmith 51979695Smsmith if (pmap_bootstrapped && ofw_real_mode) 52079695Smsmith args = (void *)pmap_kextract((vm_offset_t)args); 52179695Smsmith 52279695Smsmith #ifdef SMP 52379695Smsmith rv_args.args = args; 52464987Smsmith rv_args.in_progress = 1; 52579695Smsmith smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, 52679695Smsmith smp_no_rendevous_barrier, &rv_args); 52764987Smsmith result = rv_args.retval; 52879695Smsmith #else 52964987Smsmith result = openfirmware_core(args); 53064987Smsmith #endif 53179695Smsmith 53279695Smsmith return (result); 53379695Smsmith} 53464987Smsmith 53564987Smsmithvoid 53664987SmsmithOF_reboot() 53764987Smsmith{ 53864987Smsmith struct { 53964987Smsmith cell_t name; 54064987Smsmith cell_t nargs; 54164987Smsmith cell_t nreturns; 54264987Smsmith cell_t arg; 54379695Smsmith } args; 54479695Smsmith 54564987Smsmith args.name = (cell_t)(uintptr_t)"interpret"; 54664987Smsmith args.nargs = 1; 54779695Smsmith args.nreturns = 0; 54879695Smsmith args.arg = (cell_t)(uintptr_t)"reset-all"; 54979695Smsmith openfirmware_core(&args); /* Don't do rendezvous! */ 55079695Smsmith 55179695Smsmith for (;;); /* just in case */ 55279695Smsmith} 55379695Smsmith 55479695Smsmithvoid 55579695SmsmithOF_getetheraddr(device_t dev, u_char *addr) 55679695Smsmith{ 55779695Smsmith phandle_t node; 55879695Smsmith 55979695Smsmith node = ofw_bus_get_node(dev); 56079695Smsmith OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 56164987Smsmith} 56264987Smsmith 56379695Smsmith/* 56479695Smsmith * Return a bus handle and bus tag that corresponds to the register 56579695Smsmith * numbered regno for the device referenced by the package handle 56679695Smsmith * dev. This function is intended to be used by console drivers in 56779695Smsmith * early boot only. It works by mapping the address of the device's 56879695Smsmith * register in the address space of its parent and recursively walk 56979695Smsmith * the device tree upward this way. 57079695Smsmith */ 57179695Smsmithstatic void 57279695SmsmithOF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip) 57379695Smsmith{ 57479695Smsmith char name[16]; 57579695Smsmith uint32_t addr, size; 57679695Smsmith int pci, res; 57779695Smsmith 57879695Smsmith res = OF_getprop(node, "#address-cells", &addr, sizeof(addr)); 57979695Smsmith if (res == -1) 58079695Smsmith addr = 2; 58179695Smsmith res = OF_getprop(node, "#size-cells", &size, sizeof(size)); 58279695Smsmith if (res == -1) 58379695Smsmith size = 1; 58479695Smsmith pci = 0; 58579695Smsmith if (addr == 3 && size == 2) { 58679695Smsmith res = OF_getprop(node, "name", name, sizeof(name)); 58779695Smsmith if (res != -1) { 58879695Smsmith name[sizeof(name) - 1] = '\0'; 58979695Smsmith pci = (strcmp(name, "pci") == 0) ? 1 : 0; 59079695Smsmith } 59179695Smsmith } 59279695Smsmith if (addrp != NULL) 59379695Smsmith *addrp = addr; 59479695Smsmith if (sizep != NULL) 59579695Smsmith *sizep = size; 59679695Smsmith if (pcip != NULL) 59779695Smsmith *pcip = pci; 59879695Smsmith} 59979695Smsmith 60079695Smsmithint 60179695SmsmithOF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 60279695Smsmith bus_space_handle_t *handle) 60379695Smsmith{ 60479695Smsmith uint32_t cell[32]; 60579695Smsmith bus_addr_t addr, raddr, baddr; 60679695Smsmith bus_size_t size, rsize; 60779695Smsmith uint32_t c, nbridge, naddr, nsize; 60879695Smsmith phandle_t bridge, parent; 60979695Smsmith u_int spc, rspc; 61079695Smsmith int pci, pcib, res; 61179695Smsmith 61279695Smsmith /* Sanity checking. */ 61379695Smsmith if (dev == 0) 61479695Smsmith return (EINVAL); 61579695Smsmith bridge = OF_parent(dev); 61679695Smsmith if (bridge == 0) 61779695Smsmith return (EINVAL); 61879695Smsmith if (regno < 0) 61979695Smsmith return (EINVAL); 62079695Smsmith if (tag == NULL || handle == NULL) 62179695Smsmith return (EINVAL); 62279695Smsmith 62379695Smsmith /* Get the requested register. */ 62479695Smsmith OF_get_addr_props(bridge, &naddr, &nsize, &pci); 62579695Smsmith res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg", 62679695Smsmith cell, sizeof(cell)); 62779695Smsmith if (res == -1) 62879695Smsmith return (ENXIO); 62979695Smsmith if (res % sizeof(cell[0])) 63079695Smsmith return (ENXIO); 63179695Smsmith res /= sizeof(cell[0]); 63279695Smsmith regno *= naddr + nsize; 63379695Smsmith if (regno + naddr + nsize > res) 63479695Smsmith return (EINVAL); 63579695Smsmith spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0; 63679695Smsmith addr = 0; 63779695Smsmith for (c = 0; c < naddr; c++) 63879695Smsmith addr = ((uint64_t)addr << 32) | cell[regno++]; 63979695Smsmith size = 0; 64079695Smsmith for (c = 0; c < nsize; c++) 64179695Smsmith size = ((uint64_t)size << 32) | cell[regno++]; 64279695Smsmith 64379695Smsmith /* 64479695Smsmith * Map the address range in the bridge's decoding window as given 64579695Smsmith * by the "ranges" property. If a node doesn't have such property 64679695Smsmith * then no mapping is done. 64779695Smsmith */ 64879695Smsmith parent = OF_parent(bridge); 64979695Smsmith while (parent != 0) { 65079695Smsmith OF_get_addr_props(parent, &nbridge, NULL, &pcib); 65179695Smsmith res = OF_getprop(bridge, "ranges", cell, sizeof(cell)); 65279695Smsmith if (res == -1) 65379695Smsmith goto next; 65479695Smsmith if (res % sizeof(cell[0])) 65579695Smsmith return (ENXIO); 65679695Smsmith res /= sizeof(cell[0]); 65779695Smsmith regno = 0; 65879695Smsmith while (regno < res) { 65979695Smsmith rspc = (pci) 66079695Smsmith ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 66179695Smsmith : ~0; 66279695Smsmith if (rspc != spc) { 66379695Smsmith regno += naddr + nbridge + nsize; 66479695Smsmith continue; 66579695Smsmith } 66679695Smsmith raddr = 0; 66779695Smsmith for (c = 0; c < naddr; c++) 66879695Smsmith raddr = ((uint64_t)raddr << 32) | cell[regno++]; 66979695Smsmith rspc = (pcib) 67079695Smsmith ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 67179695Smsmith : ~0; 67279695Smsmith baddr = 0; 67379695Smsmith for (c = 0; c < nbridge; c++) 67479695Smsmith baddr = ((uint64_t)baddr << 32) | cell[regno++]; 67579695Smsmith rsize = 0; 67679695Smsmith for (c = 0; c < nsize; c++) 67779695Smsmith rsize = ((uint64_t)rsize << 32) | cell[regno++]; 67879695Smsmith if (addr < raddr || addr >= raddr + rsize) 67979695Smsmith continue; 680105215Sphk addr = addr - raddr + baddr; 68179695Smsmith if (rspc != ~0) 68279695Smsmith spc = rspc; 68379695Smsmith } 68479695Smsmith 68579695Smsmith next: 686108926Sscottl bridge = parent; 687108926Sscottl parent = OF_parent(bridge); 688108926Sscottl OF_get_addr_props(bridge, &naddr, &nsize, &pci); 68979695Smsmith } 69079695Smsmith 69179695Smsmith *tag = &bs_le_tag; 69279695Smsmith return (bus_space_map(*tag, addr, size, 0, handle)); 69379695Smsmith} 69479695Smsmith 69579695Smsmith