1/*- 2 * Copyright (C) 1996 Wolfgang Solfrank. 3 * Copyright (C) 1996 TooLs GmbH. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by TooLs GmbH. 17 * 4. The name of TooLs GmbH may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: stable/11/sys/powerpc/ofw/ofw_machdep.c 331722 2018-03-29 02:50:57Z eadler $"); 36 37#include "opt_platform.h" 38#include <sys/param.h> 39#include <sys/bus.h> 40#include <sys/systm.h> 41#include <sys/conf.h> 42#include <sys/disk.h> 43#include <sys/fcntl.h> 44#include <sys/malloc.h> 45#include <sys/smp.h> 46#include <sys/stat.h> 47#include <sys/endian.h> 48 49#include <net/ethernet.h> 50 51#include <dev/fdt/fdt_common.h> 52#include <dev/ofw/openfirm.h> 53#include <dev/ofw/ofw_pci.h> 54#include <dev/ofw/ofw_bus.h> 55#include <dev/ofw/ofw_subr.h> 56 57#include <vm/vm.h> 58#include <vm/vm_param.h> 59#include <vm/vm_page.h> 60 61#include <machine/bus.h> 62#include <machine/cpu.h> 63#include <machine/md_var.h> 64#include <machine/platform.h> 65#include <machine/ofw_machdep.h> 66#include <machine/trap.h> 67 68static void *fdt; 69int ofw_real_mode; 70 71#ifdef AIM 72extern register_t ofmsr[5]; 73extern void *openfirmware_entry; 74char save_trap_init[0x2f00]; /* EXC_LAST */ 75char save_trap_of[0x2f00]; /* EXC_LAST */ 76 77int ofwcall(void *); 78static int openfirmware(void *args); 79 80__inline void 81ofw_save_trap_vec(char *save_trap_vec) 82{ 83 if (!ofw_real_mode) 84 return; 85 86 bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST); 87} 88 89static __inline void 90ofw_restore_trap_vec(char *restore_trap_vec) 91{ 92 if (!ofw_real_mode) 93 return; 94 95 bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST); 96 __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD); 97} 98 99/* 100 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 101 */ 102register_t ofw_sprg0_save; 103 104static __inline void 105ofw_sprg_prepare(void) 106{ 107 if (ofw_real_mode) 108 return; 109 110 /* 111 * Assume that interrupt are disabled at this point, or 112 * SPRG1-3 could be trashed 113 */ 114#ifdef __powerpc64__ 115 __asm __volatile("mtsprg1 %0\n\t" 116 "mtsprg2 %1\n\t" 117 "mtsprg3 %2\n\t" 118 : 119 : "r"(ofmsr[2]), 120 "r"(ofmsr[3]), 121 "r"(ofmsr[4])); 122#else 123 __asm __volatile("mfsprg0 %0\n\t" 124 "mtsprg0 %1\n\t" 125 "mtsprg1 %2\n\t" 126 "mtsprg2 %3\n\t" 127 "mtsprg3 %4\n\t" 128 : "=&r"(ofw_sprg0_save) 129 : "r"(ofmsr[1]), 130 "r"(ofmsr[2]), 131 "r"(ofmsr[3]), 132 "r"(ofmsr[4])); 133#endif 134} 135 136static __inline void 137ofw_sprg_restore(void) 138{ 139 if (ofw_real_mode) 140 return; 141 142 /* 143 * Note that SPRG1-3 contents are irrelevant. They are scratch 144 * registers used in the early portion of trap handling when 145 * interrupts are disabled. 146 * 147 * PCPU data cannot be used until this routine is called ! 148 */ 149#ifndef __powerpc64__ 150 __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 151#endif 152} 153#endif 154 155static int 156parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 157{ 158 cell_t address_cells, size_cells; 159 cell_t OFmem[4 * PHYS_AVAIL_SZ]; 160 int sz, i, j; 161 phandle_t phandle; 162 163 sz = 0; 164 165 /* 166 * Get #address-cells from root node, defaulting to 1 if it cannot 167 * be found. 168 */ 169 phandle = OF_finddevice("/"); 170 if (OF_getencprop(phandle, "#address-cells", &address_cells, 171 sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 172 address_cells = 1; 173 if (OF_getencprop(phandle, "#size-cells", &size_cells, 174 sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 175 size_cells = 1; 176 177 /* 178 * Get memory. 179 */ 180 if (node == -1 || (sz = OF_getencprop(node, prop, 181 OFmem, sizeof(OFmem))) <= 0) 182 panic("Physical memory map not found"); 183 184 i = 0; 185 j = 0; 186 while (i < sz/sizeof(cell_t)) { 187 #if !defined(__powerpc64__) && !defined(BOOKE) 188 /* On 32-bit PPC (OEA), ignore regions starting above 4 GB */ 189 if (address_cells > 1 && OFmem[i] > 0) { 190 i += address_cells + size_cells; 191 continue; 192 } 193 #endif 194 195 output[j].mr_start = OFmem[i++]; 196 if (address_cells == 2) { 197 output[j].mr_start <<= 32; 198 output[j].mr_start += OFmem[i++]; 199 } 200 201 output[j].mr_size = OFmem[i++]; 202 if (size_cells == 2) { 203 output[j].mr_size <<= 32; 204 output[j].mr_size += OFmem[i++]; 205 } 206 207 #if !defined(__powerpc64__) && !defined(BOOKE) 208 /* Book-E can support 36-bit addresses. */ 209 /* 210 * Check for memory regions extending above 32-bit 211 * memory space, and restrict them to stay there. 212 */ 213 if (((uint64_t)output[j].mr_start + 214 (uint64_t)output[j].mr_size) > 215 BUS_SPACE_MAXADDR_32BIT) { 216 output[j].mr_size = BUS_SPACE_MAXADDR_32BIT - 217 output[j].mr_start; 218 } 219 #endif 220 221 j++; 222 } 223 sz = j*sizeof(output[0]); 224 225 return (sz); 226} 227 228static int 229excise_fdt_reserved(struct mem_region *avail, int asz) 230{ 231 struct { 232 uint64_t address; 233 uint64_t size; 234 } fdtmap[16]; 235 ssize_t fdtmapsize; 236 phandle_t chosen; 237 int i, j, k; 238 239 chosen = OF_finddevice("/chosen"); 240 fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); 241 242 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 243 fdtmap[j].address = be64toh(fdtmap[j].address); 244 fdtmap[j].size = be64toh(fdtmap[j].size); 245 } 246 247 for (i = 0; i < asz; i++) { 248 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 249 /* 250 * Case 1: Exclusion region encloses complete 251 * available entry. Drop it and move on. 252 */ 253 if (fdtmap[j].address <= avail[i].mr_start && 254 fdtmap[j].address + fdtmap[j].size >= 255 avail[i].mr_start + avail[i].mr_size) { 256 for (k = i+1; k < asz; k++) 257 avail[k-1] = avail[k]; 258 asz--; 259 i--; /* Repeat some entries */ 260 continue; 261 } 262 263 /* 264 * Case 2: Exclusion region starts in available entry. 265 * Trim it to where the entry begins and append 266 * a new available entry with the region after 267 * the excluded region, if any. 268 */ 269 if (fdtmap[j].address >= avail[i].mr_start && 270 fdtmap[j].address < avail[i].mr_start + 271 avail[i].mr_size) { 272 if (fdtmap[j].address + fdtmap[j].size < 273 avail[i].mr_start + avail[i].mr_size) { 274 avail[asz].mr_start = 275 fdtmap[j].address + fdtmap[j].size; 276 avail[asz].mr_size = avail[i].mr_start + 277 avail[i].mr_size - 278 avail[asz].mr_start; 279 asz++; 280 } 281 282 avail[i].mr_size = fdtmap[j].address - 283 avail[i].mr_start; 284 } 285 286 /* 287 * Case 3: Exclusion region ends in available entry. 288 * Move start point to where the exclusion zone ends. 289 * The case of a contained exclusion zone has already 290 * been caught in case 2. 291 */ 292 if (fdtmap[j].address + fdtmap[j].size >= 293 avail[i].mr_start && fdtmap[j].address + 294 fdtmap[j].size < avail[i].mr_start + 295 avail[i].mr_size) { 296 avail[i].mr_size += avail[i].mr_start; 297 avail[i].mr_start = 298 fdtmap[j].address + fdtmap[j].size; 299 avail[i].mr_size -= avail[i].mr_start; 300 } 301 } 302 } 303 304 return (asz); 305} 306 307/* 308 * This is called during powerpc_init, before the system is really initialized. 309 * It shall provide the total and the available regions of RAM. 310 * The available regions need not take the kernel into account. 311 */ 312void 313ofw_mem_regions(struct mem_region *memp, int *memsz, 314 struct mem_region *availp, int *availsz) 315{ 316 phandle_t phandle; 317 int asz, msz; 318 int res; 319 char name[31]; 320 321 asz = msz = 0; 322 323 /* 324 * Get memory from all the /memory nodes. 325 */ 326 for (phandle = OF_child(OF_peer(0)); phandle != 0; 327 phandle = OF_peer(phandle)) { 328 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 329 continue; 330 if (strncmp(name, "memory", sizeof(name)) != 0 && 331 strncmp(name, "memory@", strlen("memory@")) != 0) 332 continue; 333 334 res = parse_ofw_memory(phandle, "reg", &memp[msz]); 335 msz += res/sizeof(struct mem_region); 336 if (OF_getproplen(phandle, "available") >= 0) 337 res = parse_ofw_memory(phandle, "available", 338 &availp[asz]); 339 else 340 res = parse_ofw_memory(phandle, "reg", &availp[asz]); 341 asz += res/sizeof(struct mem_region); 342 } 343 344 phandle = OF_finddevice("/chosen"); 345 if (OF_hasprop(phandle, "fdtmemreserv")) 346 asz = excise_fdt_reserved(availp, asz); 347 348 *memsz = msz; 349 *availsz = asz; 350} 351 352void 353OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 354{ 355#ifdef AIM 356 ofmsr[0] = mfmsr(); 357 #ifdef __powerpc64__ 358 ofmsr[0] &= ~PSL_SF; 359 #else 360 __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1])); 361 #endif 362 __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2])); 363 __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3])); 364 __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4])); 365 openfirmware_entry = openfirm; 366 367 if (ofmsr[0] & PSL_DR) 368 ofw_real_mode = 0; 369 else 370 ofw_real_mode = 1; 371 372 ofw_save_trap_vec(save_trap_init); 373#else 374 ofw_real_mode = 1; 375#endif 376 377 fdt = fdt_ptr; 378 379 #ifdef FDT_DTB_STATIC 380 /* Check for a statically included blob */ 381 if (fdt == NULL) 382 fdt = &fdt_static_dtb; 383 #endif 384} 385 386boolean_t 387OF_bootstrap() 388{ 389 boolean_t status = FALSE; 390 int err = 0; 391 392#ifdef AIM 393 if (openfirmware_entry != NULL) { 394 if (ofw_real_mode) { 395 status = OF_install(OFW_STD_REAL, 0); 396 } else { 397 #ifdef __powerpc64__ 398 status = OF_install(OFW_STD_32BIT, 0); 399 #else 400 status = OF_install(OFW_STD_DIRECT, 0); 401 #endif 402 } 403 404 if (status != TRUE) 405 return status; 406 407 err = OF_init(openfirmware); 408 } else 409#endif 410 if (fdt != NULL) { 411 status = OF_install(OFW_FDT, 0); 412 413 if (status != TRUE) 414 return status; 415 416 err = OF_init(fdt); 417 if (err == 0) 418 OF_interpret("perform-fixup", 0); 419 } 420 421 if (err != 0) { 422 OF_install(NULL, 0); 423 status = FALSE; 424 } 425 426 return (status); 427} 428 429#ifdef AIM 430void 431ofw_quiesce(void) 432{ 433 struct { 434 cell_t name; 435 cell_t nargs; 436 cell_t nreturns; 437 } args; 438 439 KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 440 441 args.name = (cell_t)(uintptr_t)"quiesce"; 442 args.nargs = 0; 443 args.nreturns = 0; 444 openfirmware(&args); 445} 446 447static int 448openfirmware_core(void *args) 449{ 450 int result; 451 register_t oldmsr; 452 453 if (openfirmware_entry == NULL) 454 return (-1); 455 456 /* 457 * Turn off exceptions - we really don't want to end up 458 * anywhere unexpected with PCPU set to something strange 459 * or the stack pointer wrong. 460 */ 461 oldmsr = intr_disable(); 462 463 ofw_sprg_prepare(); 464 465 /* Save trap vectors */ 466 ofw_save_trap_vec(save_trap_of); 467 468 /* Restore initially saved trap vectors */ 469 ofw_restore_trap_vec(save_trap_init); 470 471#if defined(AIM) && !defined(__powerpc64__) 472 /* 473 * Clear battable[] translations 474 */ 475 if (!(cpu_features & PPC_FEATURE_64)) 476 __asm __volatile("mtdbatu 2, %0\n" 477 "mtdbatu 3, %0" : : "r" (0)); 478 isync(); 479#endif 480 481 result = ofwcall(args); 482 483 /* Restore trap vecotrs */ 484 ofw_restore_trap_vec(save_trap_of); 485 486 ofw_sprg_restore(); 487 488 intr_restore(oldmsr); 489 490 return (result); 491} 492 493#ifdef SMP 494struct ofw_rv_args { 495 void *args; 496 int retval; 497 volatile int in_progress; 498}; 499 500static void 501ofw_rendezvous_dispatch(void *xargs) 502{ 503 struct ofw_rv_args *rv_args = xargs; 504 505 /* NOTE: Interrupts are disabled here */ 506 507 if (PCPU_GET(cpuid) == 0) { 508 /* 509 * Execute all OF calls on CPU 0 510 */ 511 rv_args->retval = openfirmware_core(rv_args->args); 512 rv_args->in_progress = 0; 513 } else { 514 /* 515 * Spin with interrupts off on other CPUs while OF has 516 * control of the machine. 517 */ 518 while (rv_args->in_progress) 519 cpu_spinwait(); 520 } 521} 522#endif 523 524static int 525openfirmware(void *args) 526{ 527 int result; 528 #ifdef SMP 529 struct ofw_rv_args rv_args; 530 #endif 531 532 if (openfirmware_entry == NULL) 533 return (-1); 534 535 #ifdef SMP 536 rv_args.args = args; 537 rv_args.in_progress = 1; 538 smp_rendezvous(smp_no_rendezvous_barrier, ofw_rendezvous_dispatch, 539 smp_no_rendezvous_barrier, &rv_args); 540 result = rv_args.retval; 541 #else 542 result = openfirmware_core(args); 543 #endif 544 545 return (result); 546} 547 548void 549OF_reboot() 550{ 551 struct { 552 cell_t name; 553 cell_t nargs; 554 cell_t nreturns; 555 cell_t arg; 556 } args; 557 558 args.name = (cell_t)(uintptr_t)"interpret"; 559 args.nargs = 1; 560 args.nreturns = 0; 561 args.arg = (cell_t)(uintptr_t)"reset-all"; 562 openfirmware_core(&args); /* Don't do rendezvous! */ 563 564 for (;;); /* just in case */ 565} 566 567#endif /* AIM */ 568 569void 570OF_getetheraddr(device_t dev, u_char *addr) 571{ 572 phandle_t node; 573 574 node = ofw_bus_get_node(dev); 575 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 576} 577 578/* 579 * Return a bus handle and bus tag that corresponds to the register 580 * numbered regno for the device referenced by the package handle 581 * dev. This function is intended to be used by console drivers in 582 * early boot only. It works by mapping the address of the device's 583 * register in the address space of its parent and recursively walk 584 * the device tree upward this way. 585 */ 586int 587OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 588 bus_space_handle_t *handle, bus_size_t *sz) 589{ 590 bus_addr_t addr; 591 bus_size_t size; 592 pcell_t pci_hi; 593 int flags, res; 594 595 res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi); 596 if (res < 0) 597 return (res); 598 599 if (pci_hi == OFW_PADDR_NOT_PCI) { 600 *tag = &bs_be_tag; 601 flags = 0; 602 } else { 603 *tag = &bs_le_tag; 604 flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? 605 BUS_SPACE_MAP_PREFETCHABLE: 0; 606 } 607 608 if (sz != NULL) 609 *sz = size; 610 611 return (bus_space_map(*tag, addr, size, flags, handle)); 612} 613 614