ofw_machdep.c revision 215067
1139825Simp/*- 277957Sbenno * Copyright (C) 1996 Wolfgang Solfrank. 377957Sbenno * Copyright (C) 1996 TooLs GmbH. 477957Sbenno * All rights reserved. 577957Sbenno * 677957Sbenno * Redistribution and use in source and binary forms, with or without 777957Sbenno * modification, are permitted provided that the following conditions 877957Sbenno * are met: 977957Sbenno * 1. Redistributions of source code must retain the above copyright 1077957Sbenno * notice, this list of conditions and the following disclaimer. 1177957Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1277957Sbenno * notice, this list of conditions and the following disclaimer in the 1377957Sbenno * documentation and/or other materials provided with the distribution. 1477957Sbenno * 3. All advertising materials mentioning features or use of this software 1577957Sbenno * must display the following acknowledgement: 1677957Sbenno * This product includes software developed by TooLs GmbH. 1777957Sbenno * 4. The name of TooLs GmbH may not be used to endorse or promote products 1877957Sbenno * derived from this software without specific prior written permission. 1977957Sbenno * 2077957Sbenno * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2177957Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2277957Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2377957Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2477957Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2577957Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2677957Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2777957Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2877957Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2977957Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3077957Sbenno * 3177957Sbenno * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 3277957Sbenno */ 3377957Sbenno 34113038Sobrien#include <sys/cdefs.h> 35113038Sobrien__FBSDID("$FreeBSD: head/sys/powerpc/aim/ofw_machdep.c 215067 2010-11-09 23:53:47Z nwhitehorn $"); 3677957Sbenno 3777957Sbenno#include <sys/param.h> 3877957Sbenno#include <sys/bus.h> 3977957Sbenno#include <sys/systm.h> 4077957Sbenno#include <sys/conf.h> 4177957Sbenno#include <sys/disk.h> 4277957Sbenno#include <sys/fcntl.h> 4377957Sbenno#include <sys/malloc.h> 44208364Snwhitehorn#include <sys/smp.h> 4577957Sbenno#include <sys/stat.h> 4677957Sbenno 4799665Sbenno#include <net/ethernet.h> 4899665Sbenno 4977957Sbenno#include <dev/ofw/openfirm.h> 50165151Smarcel#include <dev/ofw/ofw_pci.h> 51183882Snwhitehorn#include <dev/ofw/ofw_bus.h> 5277957Sbenno 5390643Sbenno#include <vm/vm.h> 5490643Sbenno#include <vm/vm_param.h> 5590643Sbenno#include <vm/vm_page.h> 5690643Sbenno 57160714Smarcel#include <machine/bus.h> 58199886Snwhitehorn#include <machine/cpu.h> 59160714Smarcel#include <machine/md_var.h> 60192067Snwhitehorn#include <machine/platform.h> 6199030Sbenno#include <machine/ofw_machdep.h> 6277957Sbenno 6377957Sbenno#define OFMEM_REGIONS 32 6477957Sbennostatic struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3]; 65123370Sgrehanstatic struct mem_region OFfree[OFMEM_REGIONS + 3]; 66209975Snwhitehornstatic int nOFmem; 6777957Sbenno 68151891Sgrehanextern register_t ofmsr[5]; 6990643Sbennoextern struct pmap ofw_pmap; 7077957Sbennostatic int (*ofwcall)(void *); 71186347Snwhitehornstatic void *fdt; 72186347Snwhitehornint ofw_real_mode; 7377957Sbenno 74209975Snwhitehornint ofw_32bit_mode_entry(void *); 75208172Snwhitehornstatic void ofw_quiesce(void); 76186347Snwhitehornstatic int openfirmware(void *args); 77186347Snwhitehorn 7877957Sbenno/* 79151891Sgrehan * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 80151891Sgrehan */ 81151891Sgrehanregister_t ofw_sprg0_save; 82151891Sgrehan 83151891Sgrehanstatic __inline void 84151891Sgrehanofw_sprg_prepare(void) 85151891Sgrehan{ 86151891Sgrehan /* 87151891Sgrehan * Assume that interrupt are disabled at this point, or 88151891Sgrehan * SPRG1-3 could be trashed 89151891Sgrehan */ 90151891Sgrehan __asm __volatile("mfsprg0 %0\n\t" 91151891Sgrehan "mtsprg0 %1\n\t" 92151891Sgrehan "mtsprg1 %2\n\t" 93151891Sgrehan "mtsprg2 %3\n\t" 94151891Sgrehan "mtsprg3 %4\n\t" 95151891Sgrehan : "=&r"(ofw_sprg0_save) 96151891Sgrehan : "r"(ofmsr[1]), 97151891Sgrehan "r"(ofmsr[2]), 98151891Sgrehan "r"(ofmsr[3]), 99151891Sgrehan "r"(ofmsr[4])); 100151891Sgrehan} 101151891Sgrehan 102151891Sgrehanstatic __inline void 103151891Sgrehanofw_sprg_restore(void) 104151891Sgrehan{ 105151891Sgrehan /* 106151891Sgrehan * Note that SPRG1-3 contents are irrelevant. They are scratch 107151891Sgrehan * registers used in the early portion of trap handling when 108151891Sgrehan * interrupts are disabled. 109151891Sgrehan * 110151891Sgrehan * PCPU data cannot be used until this routine is called ! 111151891Sgrehan */ 112151891Sgrehan __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 113151891Sgrehan} 114151891Sgrehan 115151891Sgrehan/* 116123370Sgrehan * Memory region utilities: determine if two regions overlap, 117123370Sgrehan * and merge two overlapping regions into one 118123370Sgrehan */ 119123370Sgrehanstatic int 120123370Sgrehanmemr_overlap(struct mem_region *r1, struct mem_region *r2) 121123370Sgrehan{ 122123370Sgrehan if ((r1->mr_start + r1->mr_size) < r2->mr_start || 123123370Sgrehan (r2->mr_start + r2->mr_size) < r1->mr_start) 124123370Sgrehan return (FALSE); 125123370Sgrehan 126123370Sgrehan return (TRUE); 127123370Sgrehan} 128123370Sgrehan 129123370Sgrehanstatic void 130123370Sgrehanmemr_merge(struct mem_region *from, struct mem_region *to) 131123370Sgrehan{ 132209975Snwhitehorn vm_offset_t end; 133209975Snwhitehorn end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size); 134209975Snwhitehorn to->mr_start = ulmin(from->mr_start, to->mr_start); 135123370Sgrehan to->mr_size = end - to->mr_start; 136123370Sgrehan} 137123370Sgrehan 138209975Snwhitehornstatic int 139209975Snwhitehornparse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 14077957Sbenno{ 141209975Snwhitehorn cell_t address_cells, size_cells; 142209975Snwhitehorn cell_t OFmem[4*(OFMEM_REGIONS + 1)]; 143209975Snwhitehorn int sz, i, j; 144209975Snwhitehorn int apple_hack_mode; 145190681Snwhitehorn phandle_t phandle; 146190681Snwhitehorn 147209975Snwhitehorn sz = 0; 148209975Snwhitehorn apple_hack_mode = 0; 149190681Snwhitehorn 150190681Snwhitehorn /* 151190681Snwhitehorn * Get #address-cells from root node, defaulting to 1 if it cannot 152190681Snwhitehorn * be found. 153190681Snwhitehorn */ 154190681Snwhitehorn phandle = OF_finddevice("/"); 155190681Snwhitehorn if (OF_getprop(phandle, "#address-cells", &address_cells, 156190681Snwhitehorn sizeof(address_cells)) < sizeof(address_cells)) 157190681Snwhitehorn address_cells = 1; 158209975Snwhitehorn if (OF_getprop(phandle, "#size-cells", &size_cells, 159209975Snwhitehorn sizeof(size_cells)) < sizeof(size_cells)) 160209975Snwhitehorn size_cells = 1; 161209975Snwhitehorn 162209975Snwhitehorn /* 163209975Snwhitehorn * On Apple hardware, address_cells is always 1 for "available", 164209975Snwhitehorn * even when it is explicitly set to 2. Then all memory above 4 GB 165209975Snwhitehorn * should be added by hand to the available list. Detect Apple hardware 166209975Snwhitehorn * by seeing if ofw_real_mode is set -- only Apple seems to use 167209975Snwhitehorn * virtual-mode OF. 168209975Snwhitehorn */ 169209975Snwhitehorn if (strcmp(prop, "available") == 0 && !ofw_real_mode) 170209975Snwhitehorn apple_hack_mode = 1; 17177957Sbenno 172209975Snwhitehorn if (apple_hack_mode) 173209975Snwhitehorn address_cells = 1; 174209975Snwhitehorn 17577957Sbenno /* 17677957Sbenno * Get memory. 17777957Sbenno */ 178209975Snwhitehorn if ((node == -1) || (sz = OF_getprop(node, prop, 179209975Snwhitehorn OFmem, sizeof(OFmem[0]) * 4 * OFMEM_REGIONS)) <= 0) 180209975Snwhitehorn panic("Physical memory map not found"); 181190681Snwhitehorn 182209975Snwhitehorn i = 0; 183209975Snwhitehorn j = 0; 184209975Snwhitehorn while (i < sz/sizeof(cell_t)) { 185209975Snwhitehorn #ifndef __powerpc64__ 186209975Snwhitehorn /* On 32-bit PPC, ignore regions starting above 4 GB */ 187209975Snwhitehorn if (address_cells > 1 && OFmem[i] > 0) { 188209975Snwhitehorn i += address_cells + size_cells; 189209975Snwhitehorn continue; 190190681Snwhitehorn } 191209975Snwhitehorn #endif 192190681Snwhitehorn 193209975Snwhitehorn output[j].mr_start = OFmem[i++]; 194209975Snwhitehorn if (address_cells == 2) { 195209975Snwhitehorn #ifdef __powerpc64__ 196209975Snwhitehorn output[j].mr_start <<= 32; 197209975Snwhitehorn #endif 198209975Snwhitehorn output[j].mr_start += OFmem[i++]; 199190681Snwhitehorn } 200209975Snwhitehorn 201209975Snwhitehorn output[j].mr_size = OFmem[i++]; 202209975Snwhitehorn if (size_cells == 2) { 203209975Snwhitehorn #ifdef __powerpc64__ 204209975Snwhitehorn output[j].mr_size <<= 32; 205209975Snwhitehorn #endif 206209975Snwhitehorn output[j].mr_size += OFmem[i++]; 207209975Snwhitehorn } 208190681Snwhitehorn 209209975Snwhitehorn #ifndef __powerpc64__ 210209975Snwhitehorn /* 211209975Snwhitehorn * Check for memory regions extending above 32-bit 212209975Snwhitehorn * memory space, and restrict them to stay there. 213209975Snwhitehorn */ 214209975Snwhitehorn if (((uint64_t)output[j].mr_start + 215209975Snwhitehorn (uint64_t)output[j].mr_size) > 216209975Snwhitehorn BUS_SPACE_MAXADDR_32BIT) { 217209975Snwhitehorn output[j].mr_size = BUS_SPACE_MAXADDR_32BIT - 218209975Snwhitehorn output[j].mr_start; 219209975Snwhitehorn } 220209975Snwhitehorn #endif 221190681Snwhitehorn 222209975Snwhitehorn j++; 223209975Snwhitehorn } 224209975Snwhitehorn sz = j*sizeof(output[0]); 225209975Snwhitehorn 226209975Snwhitehorn #ifdef __powerpc64__ 227209975Snwhitehorn if (apple_hack_mode) { 228209975Snwhitehorn /* Add in regions above 4 GB to the available list */ 229209975Snwhitehorn struct mem_region himem[OFMEM_REGIONS]; 230209975Snwhitehorn int hisz; 231209975Snwhitehorn 232209975Snwhitehorn hisz = parse_ofw_memory(node, "reg", himem); 233209975Snwhitehorn for (i = 0; i < hisz/sizeof(himem[0]); i++) { 234209975Snwhitehorn if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) { 235209975Snwhitehorn output[j].mr_start = himem[i].mr_start; 236209975Snwhitehorn output[j].mr_size = himem[i].mr_size; 237209975Snwhitehorn j++; 238190681Snwhitehorn } 239190681Snwhitehorn } 240209975Snwhitehorn sz = j*sizeof(output[0]); 241190681Snwhitehorn } 242209975Snwhitehorn #endif 243190681Snwhitehorn 244209975Snwhitehorn return (sz); 245209975Snwhitehorn} 246209975Snwhitehorn 247209975Snwhitehorn/* 248209975Snwhitehorn * This is called during powerpc_init, before the system is really initialized. 249209975Snwhitehorn * It shall provide the total and the available regions of RAM. 250209975Snwhitehorn * Both lists must have a zero-size entry as terminator. 251209975Snwhitehorn * The available regions need not take the kernel into account, but needs 252209975Snwhitehorn * to provide space for two additional entry beyond the terminating one. 253209975Snwhitehorn */ 254209975Snwhitehornvoid 255209975Snwhitehornofw_mem_regions(struct mem_region **memp, int *memsz, 256209975Snwhitehorn struct mem_region **availp, int *availsz) 257209975Snwhitehorn{ 258209975Snwhitehorn phandle_t phandle; 259209975Snwhitehorn int asz, msz, fsz; 260209975Snwhitehorn int i, j; 261209975Snwhitehorn int still_merging; 262209975Snwhitehorn 263209975Snwhitehorn asz = msz = 0; 264209975Snwhitehorn 265209975Snwhitehorn /* 266209975Snwhitehorn * Get memory. 267209975Snwhitehorn */ 268209975Snwhitehorn phandle = OF_finddevice("/memory"); 269209975Snwhitehorn if (phandle == -1) 270209975Snwhitehorn phandle = OF_finddevice("/memory@0"); 271209975Snwhitehorn 272209975Snwhitehorn msz = parse_ofw_memory(phandle, "reg", OFmem); 273209975Snwhitehorn nOFmem = msz / sizeof(struct mem_region); 274209975Snwhitehorn asz = parse_ofw_memory(phandle, "available", OFavail); 275209975Snwhitehorn 27677957Sbenno *memp = OFmem; 277209975Snwhitehorn *memsz = nOFmem; 278190681Snwhitehorn 279123370Sgrehan /* 280123370Sgrehan * OFavail may have overlapping regions - collapse these 281123370Sgrehan * and copy out remaining regions to OFfree 282123370Sgrehan */ 283123370Sgrehan asz /= sizeof(struct mem_region); 284123370Sgrehan do { 285123370Sgrehan still_merging = FALSE; 286123370Sgrehan for (i = 0; i < asz; i++) { 287123370Sgrehan if (OFavail[i].mr_size == 0) 288123370Sgrehan continue; 289123370Sgrehan for (j = i+1; j < asz; j++) { 290123370Sgrehan if (OFavail[j].mr_size == 0) 291123370Sgrehan continue; 292123370Sgrehan if (memr_overlap(&OFavail[j], &OFavail[i])) { 293123370Sgrehan memr_merge(&OFavail[j], &OFavail[i]); 294123370Sgrehan /* mark inactive */ 295123370Sgrehan OFavail[j].mr_size = 0; 296123370Sgrehan still_merging = TRUE; 297123370Sgrehan } 298123370Sgrehan } 299123370Sgrehan } 300123370Sgrehan } while (still_merging == TRUE); 301123370Sgrehan 302123370Sgrehan /* evict inactive ranges */ 303123370Sgrehan for (i = 0, fsz = 0; i < asz; i++) { 304123370Sgrehan if (OFavail[i].mr_size != 0) { 305123370Sgrehan OFfree[fsz] = OFavail[i]; 306123370Sgrehan fsz++; 307123370Sgrehan } 308123370Sgrehan } 309123370Sgrehan 310123370Sgrehan *availp = OFfree; 311123370Sgrehan *availsz = fsz; 31277957Sbenno} 31377957Sbenno 31477957Sbennovoid 315186347SnwhitehornOF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 31677957Sbenno{ 317186347Snwhitehorn if (ofmsr[0] & PSL_DR) 318186347Snwhitehorn ofw_real_mode = 0; 319186347Snwhitehorn else 320186347Snwhitehorn ofw_real_mode = 1; 32177957Sbenno 322209975Snwhitehorn ofwcall = NULL; 323209975Snwhitehorn 324209975Snwhitehorn #ifdef __powerpc64__ 325209975Snwhitehorn /* 326209975Snwhitehorn * For PPC64, we need to use some hand-written 327209975Snwhitehorn * asm trampolines to get to OF. 328209975Snwhitehorn */ 329209975Snwhitehorn if (openfirm != NULL) 330209975Snwhitehorn ofwcall = ofw_32bit_mode_entry; 331209975Snwhitehorn #else 332209975Snwhitehorn ofwcall = openfirm; 333209975Snwhitehorn #endif 334209975Snwhitehorn 335186347Snwhitehorn fdt = fdt_ptr; 336215067Snwhitehorn 337215067Snwhitehorn #ifdef FDT_DTB_STATIC 338215067Snwhitehorn /* Check for a statically included blob */ 339215067Snwhitehorn if (fdt == NULL) 340215067Snwhitehorn fdt = &fdt_static_dtb; 341215067Snwhitehorn #endif 34277957Sbenno} 34377957Sbenno 344186347Snwhitehornboolean_t 345186347SnwhitehornOF_bootstrap() 346186347Snwhitehorn{ 347186347Snwhitehorn boolean_t status = FALSE; 348186347Snwhitehorn 349186347Snwhitehorn if (ofwcall != NULL) { 350209975Snwhitehorn if (ofw_real_mode) { 351186347Snwhitehorn status = OF_install(OFW_STD_REAL, 0); 352209975Snwhitehorn } else { 353209975Snwhitehorn #ifdef __powerpc64__ 354209975Snwhitehorn status = OF_install(OFW_STD_32BIT, 0); 355209975Snwhitehorn #else 356186347Snwhitehorn status = OF_install(OFW_STD_DIRECT, 0); 357209975Snwhitehorn #endif 358209975Snwhitehorn } 359186347Snwhitehorn 360186347Snwhitehorn if (status != TRUE) 361186347Snwhitehorn return status; 362186347Snwhitehorn 363186347Snwhitehorn OF_init(openfirmware); 364208152Snwhitehorn 365208152Snwhitehorn /* 366208152Snwhitehorn * On some machines, we need to quiesce OF to turn off 367208152Snwhitehorn * background processes. 368208152Snwhitehorn */ 369208172Snwhitehorn ofw_quiesce(); 370215067Snwhitehorn } else if (fdt != NULL) { 371186347Snwhitehorn status = OF_install(OFW_FDT, 0); 372186347Snwhitehorn 373186347Snwhitehorn if (status != TRUE) 374186347Snwhitehorn return status; 375186347Snwhitehorn 376186347Snwhitehorn OF_init(fdt); 377186347Snwhitehorn } 378186347Snwhitehorn 379186347Snwhitehorn return (status); 380186347Snwhitehorn} 381186347Snwhitehorn 382208172Snwhitehornstatic void 383208172Snwhitehornofw_quiesce(void) 384208172Snwhitehorn{ 385208172Snwhitehorn phandle_t rootnode; 386208172Snwhitehorn char model[32]; 387208172Snwhitehorn struct { 388208172Snwhitehorn cell_t name; 389208172Snwhitehorn cell_t nargs; 390208172Snwhitehorn cell_t nreturns; 391208172Snwhitehorn } args; 392208172Snwhitehorn 393208172Snwhitehorn /* 394208172Snwhitehorn * Only quiesce Open Firmware on PowerMac11,2 and 12,1. It is 395208172Snwhitehorn * necessary there to shut down a background thread doing fan 396208172Snwhitehorn * management, and is harmful on other machines. 397208172Snwhitehorn * 398208172Snwhitehorn * Note: we don't need to worry about which OF module we are 399208172Snwhitehorn * using since this is called only from very early boot, within 400208172Snwhitehorn * OF's boot context. 401208172Snwhitehorn */ 402208172Snwhitehorn 403208172Snwhitehorn rootnode = OF_finddevice("/"); 404208172Snwhitehorn if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) { 405208172Snwhitehorn if (strcmp(model, "PowerMac11,2") == 0 || 406208172Snwhitehorn strcmp(model, "PowerMac12,1") == 0) { 407208172Snwhitehorn args.name = (cell_t)(uintptr_t)"quiesce"; 408208172Snwhitehorn args.nargs = 0; 409208172Snwhitehorn args.nreturns = 0; 410208172Snwhitehorn openfirmware(&args); 411208172Snwhitehorn } 412208172Snwhitehorn } 413208172Snwhitehorn} 414208172Snwhitehorn 415186347Snwhitehornstatic int 416208364Snwhitehornopenfirmware_core(void *args) 41777957Sbenno{ 418209975Snwhitehorn int result; 419209975Snwhitehorn register_t oldmsr; 420209975Snwhitehorn #ifndef __powerpc64__ 421209975Snwhitehorn register_t srsave[16]; 422209975Snwhitehorn u_int i; 423209975Snwhitehorn #endif 42477957Sbenno 425209975Snwhitehorn /* 426209975Snwhitehorn * Turn off exceptions - we really don't want to end up 427209975Snwhitehorn * anywhere unexpected with PCPU set to something strange, 428209975Snwhitehorn * the stack pointer wrong, or the OFW mapping enabled. 429209975Snwhitehorn */ 430209975Snwhitehorn oldmsr = intr_disable(); 43177957Sbenno 432151891Sgrehan ofw_sprg_prepare(); 433151891Sgrehan 434209975Snwhitehorn #ifndef __powerpc64__ 435186347Snwhitehorn if (pmap_bootstrapped && !ofw_real_mode) { 43699030Sbenno /* 437133862Smarius * Swap the kernel's address space with Open Firmware's 43899030Sbenno */ 439209975Snwhitehorn 44099030Sbenno for (i = 0; i < 16; i++) { 44199030Sbenno srsave[i] = mfsrin(i << ADDR_SR_SHFT); 44299030Sbenno mtsrin(i << ADDR_SR_SHFT, ofw_pmap.pm_sr[i]); 44399030Sbenno } 444103602Sgrehan 445103602Sgrehan /* 446103602Sgrehan * Clear battable[] translations 447103602Sgrehan */ 448199886Snwhitehorn if (!(cpu_features & PPC_FEATURE_64)) { 449190681Snwhitehorn __asm __volatile("mtdbatu 2, %0\n" 450190681Snwhitehorn "mtdbatu 3, %0" : : "r" (0)); 451190681Snwhitehorn } 45299030Sbenno isync(); 45399030Sbenno } 454209975Snwhitehorn #endif 45577957Sbenno 456151891Sgrehan result = ofwcall(args); 457151891Sgrehan 458209975Snwhitehorn #ifndef __powerpc64__ 459186347Snwhitehorn if (pmap_bootstrapped && !ofw_real_mode) { 46099030Sbenno /* 46199030Sbenno * Restore the kernel's addr space. The isync() doesn;t 46299030Sbenno * work outside the loop unless mtsrin() is open-coded 46399030Sbenno * in an asm statement :( 46499030Sbenno */ 465209975Snwhitehorn 46699030Sbenno for (i = 0; i < 16; i++) { 46799030Sbenno mtsrin(i << ADDR_SR_SHFT, srsave[i]); 46899030Sbenno isync(); 46999030Sbenno } 47099030Sbenno } 471209975Snwhitehorn #endif 47299030Sbenno 473151891Sgrehan ofw_sprg_restore(); 474151891Sgrehan 475209975Snwhitehorn intr_restore(oldmsr); 47677957Sbenno 477208364Snwhitehorn return (result); 478208364Snwhitehorn} 479208364Snwhitehorn 480208364Snwhitehorn#ifdef SMP 481208364Snwhitehornstruct ofw_rv_args { 482208364Snwhitehorn void *args; 483208364Snwhitehorn int retval; 484208364Snwhitehorn volatile int in_progress; 485208364Snwhitehorn}; 486208364Snwhitehorn 487208364Snwhitehornstatic void 488208364Snwhitehornofw_rendezvous_dispatch(void *xargs) 489208364Snwhitehorn{ 490208364Snwhitehorn struct ofw_rv_args *rv_args = xargs; 491208364Snwhitehorn 492208364Snwhitehorn /* NOTE: Interrupts are disabled here */ 493208364Snwhitehorn 494208364Snwhitehorn if (PCPU_GET(cpuid) == 0) { 495208364Snwhitehorn /* 496208364Snwhitehorn * Execute all OF calls on CPU 0 497208364Snwhitehorn */ 498208364Snwhitehorn rv_args->retval = openfirmware_core(rv_args->args); 499208364Snwhitehorn rv_args->in_progress = 0; 500208364Snwhitehorn } else { 501208364Snwhitehorn /* 502208364Snwhitehorn * Spin with interrupts off on other CPUs while OF has 503208364Snwhitehorn * control of the machine. 504208364Snwhitehorn */ 505208364Snwhitehorn while (rv_args->in_progress) 506208364Snwhitehorn cpu_spinwait(); 507208364Snwhitehorn } 508208364Snwhitehorn} 509208364Snwhitehorn#endif 510208364Snwhitehorn 511208364Snwhitehornstatic int 512208364Snwhitehornopenfirmware(void *args) 513208364Snwhitehorn{ 514208364Snwhitehorn int result; 515208364Snwhitehorn #ifdef SMP 516208364Snwhitehorn struct ofw_rv_args rv_args; 517208364Snwhitehorn #endif 518208364Snwhitehorn 519208364Snwhitehorn if (pmap_bootstrapped && ofw_real_mode) 520208364Snwhitehorn args = (void *)pmap_kextract((vm_offset_t)args); 521208364Snwhitehorn 522208364Snwhitehorn #ifdef SMP 523208364Snwhitehorn rv_args.args = args; 524208364Snwhitehorn rv_args.in_progress = 1; 525208364Snwhitehorn smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, 526208364Snwhitehorn smp_no_rendevous_barrier, &rv_args); 527208364Snwhitehorn result = rv_args.retval; 528208364Snwhitehorn #else 529208364Snwhitehorn result = openfirmware_core(args); 530208364Snwhitehorn #endif 531208364Snwhitehorn 53277957Sbenno return (result); 53377957Sbenno} 53477957Sbenno 53577957Sbennovoid 536212054SnwhitehornOF_reboot() 537123353Sgallatin{ 538212054Snwhitehorn struct { 539212054Snwhitehorn cell_t name; 540212054Snwhitehorn cell_t nargs; 541212054Snwhitehorn cell_t nreturns; 542212054Snwhitehorn cell_t arg; 543212054Snwhitehorn } args; 544123353Sgallatin 545212054Snwhitehorn args.name = (cell_t)(uintptr_t)"interpret"; 546212054Snwhitehorn args.nargs = 1; 547212054Snwhitehorn args.nreturns = 0; 548212054Snwhitehorn args.arg = (cell_t)(uintptr_t)"reset-all"; 549212054Snwhitehorn openfirmware_core(&args); /* Don't do rendezvous! */ 550123353Sgallatin 551123353Sgallatin for (;;); /* just in case */ 552123353Sgallatin} 553123353Sgallatin 554123353Sgallatinvoid 55599665SbennoOF_getetheraddr(device_t dev, u_char *addr) 55699665Sbenno{ 55799665Sbenno phandle_t node; 55899665Sbenno 559183882Snwhitehorn node = ofw_bus_get_node(dev); 56099665Sbenno OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 56199665Sbenno} 562133855Sssouhlal 563160714Smarcel/* 564165151Smarcel * Return a bus handle and bus tag that corresponds to the register 565165151Smarcel * numbered regno for the device referenced by the package handle 566165151Smarcel * dev. This function is intended to be used by console drivers in 567165151Smarcel * early boot only. It works by mapping the address of the device's 568165151Smarcel * register in the address space of its parent and recursively walk 569165151Smarcel * the device tree upward this way. 570160714Smarcel */ 571165151Smarcelstatic void 572165151SmarcelOF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip) 573165151Smarcel{ 574165151Smarcel char name[16]; 575165151Smarcel uint32_t addr, size; 576165151Smarcel int pci, res; 577165151Smarcel 578165151Smarcel res = OF_getprop(node, "#address-cells", &addr, sizeof(addr)); 579165151Smarcel if (res == -1) 580165151Smarcel addr = 2; 581165151Smarcel res = OF_getprop(node, "#size-cells", &size, sizeof(size)); 582165151Smarcel if (res == -1) 583165151Smarcel size = 1; 584165151Smarcel pci = 0; 585165151Smarcel if (addr == 3 && size == 2) { 586165151Smarcel res = OF_getprop(node, "name", name, sizeof(name)); 587165151Smarcel if (res != -1) { 588165151Smarcel name[sizeof(name) - 1] = '\0'; 589165151Smarcel pci = (strcmp(name, "pci") == 0) ? 1 : 0; 590165151Smarcel } 591165151Smarcel } 592165151Smarcel if (addrp != NULL) 593165151Smarcel *addrp = addr; 594165151Smarcel if (sizep != NULL) 595165151Smarcel *sizep = size; 596165151Smarcel if (pcip != NULL) 597165151Smarcel *pcip = pci; 598165151Smarcel} 599165151Smarcel 600133855Sssouhlalint 601165151SmarcelOF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 602160714Smarcel bus_space_handle_t *handle) 603160714Smarcel{ 604165151Smarcel uint32_t cell[32]; 605165151Smarcel bus_addr_t addr, raddr, baddr; 606165151Smarcel bus_size_t size, rsize; 607165151Smarcel uint32_t c, nbridge, naddr, nsize; 608165151Smarcel phandle_t bridge, parent; 609165151Smarcel u_int spc, rspc; 610165151Smarcel int pci, pcib, res; 611160714Smarcel 612165151Smarcel /* Sanity checking. */ 613165151Smarcel if (dev == 0) 614165151Smarcel return (EINVAL); 615165151Smarcel bridge = OF_parent(dev); 616165151Smarcel if (bridge == 0) 617165151Smarcel return (EINVAL); 618165151Smarcel if (regno < 0) 619165151Smarcel return (EINVAL); 620165151Smarcel if (tag == NULL || handle == NULL) 621165151Smarcel return (EINVAL); 622165151Smarcel 623165151Smarcel /* Get the requested register. */ 624165151Smarcel OF_get_addr_props(bridge, &naddr, &nsize, &pci); 625165151Smarcel res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg", 626165151Smarcel cell, sizeof(cell)); 627165151Smarcel if (res == -1) 628165151Smarcel return (ENXIO); 629165151Smarcel if (res % sizeof(cell[0])) 630165151Smarcel return (ENXIO); 631165151Smarcel res /= sizeof(cell[0]); 632165151Smarcel regno *= naddr + nsize; 633165151Smarcel if (regno + naddr + nsize > res) 634165151Smarcel return (EINVAL); 635165151Smarcel spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0; 636165151Smarcel addr = 0; 637165151Smarcel for (c = 0; c < naddr; c++) 638165151Smarcel addr = ((uint64_t)addr << 32) | cell[regno++]; 639165151Smarcel size = 0; 640165151Smarcel for (c = 0; c < nsize; c++) 641165151Smarcel size = ((uint64_t)size << 32) | cell[regno++]; 642165151Smarcel 643165151Smarcel /* 644165151Smarcel * Map the address range in the bridge's decoding window as given 645165151Smarcel * by the "ranges" property. If a node doesn't have such property 646165151Smarcel * then no mapping is done. 647165151Smarcel */ 648165151Smarcel parent = OF_parent(bridge); 649165151Smarcel while (parent != 0) { 650165151Smarcel OF_get_addr_props(parent, &nbridge, NULL, &pcib); 651165151Smarcel res = OF_getprop(bridge, "ranges", cell, sizeof(cell)); 652165151Smarcel if (res == -1) 653165151Smarcel goto next; 654165151Smarcel if (res % sizeof(cell[0])) 655165151Smarcel return (ENXIO); 656165151Smarcel res /= sizeof(cell[0]); 657165151Smarcel regno = 0; 658165151Smarcel while (regno < res) { 659165151Smarcel rspc = (pci) 660165151Smarcel ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 661165151Smarcel : ~0; 662165151Smarcel if (rspc != spc) { 663165151Smarcel regno += naddr + nbridge + nsize; 664165151Smarcel continue; 665165151Smarcel } 666165151Smarcel raddr = 0; 667165151Smarcel for (c = 0; c < naddr; c++) 668165151Smarcel raddr = ((uint64_t)raddr << 32) | cell[regno++]; 669165151Smarcel rspc = (pcib) 670165151Smarcel ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 671165151Smarcel : ~0; 672165151Smarcel baddr = 0; 673165151Smarcel for (c = 0; c < nbridge; c++) 674165151Smarcel baddr = ((uint64_t)baddr << 32) | cell[regno++]; 675165151Smarcel rsize = 0; 676165151Smarcel for (c = 0; c < nsize; c++) 677165151Smarcel rsize = ((uint64_t)rsize << 32) | cell[regno++]; 678165151Smarcel if (addr < raddr || addr >= raddr + rsize) 679165151Smarcel continue; 680165151Smarcel addr = addr - raddr + baddr; 681165151Smarcel if (rspc != ~0) 682165151Smarcel spc = rspc; 683165151Smarcel } 684165151Smarcel 685165151Smarcel next: 686165151Smarcel bridge = parent; 687165151Smarcel parent = OF_parent(bridge); 688165151Smarcel OF_get_addr_props(bridge, &naddr, &nsize, &pci); 689165151Smarcel } 690165151Smarcel 691174782Smarcel *tag = &bs_le_tag; 692165151Smarcel return (bus_space_map(*tag, addr, size, 0, handle)); 693160714Smarcel} 694160714Smarcel 695160714Smarcelint 696133855Sssouhlalmem_valid(vm_offset_t addr, int len) 697133855Sssouhlal{ 698133855Sssouhlal int i; 699133855Sssouhlal 700209975Snwhitehorn for (i = 0; i < nOFmem; i++) 701133855Sssouhlal if ((addr >= OFmem[i].mr_start) 702133855Sssouhlal && (addr + len < OFmem[i].mr_start + OFmem[i].mr_size)) 703133855Sssouhlal return (0); 704133855Sssouhlal 705133855Sssouhlal return (EFAULT); 706133855Sssouhlal} 707190681Snwhitehorn 708