1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (C) 1996 Wolfgang Solfrank. 5 * Copyright (C) 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include "opt_platform.h" 40 #include <sys/param.h> 41 #include <sys/bus.h> 42 #include <sys/systm.h> 43 #include <sys/conf.h> 44 #include <sys/disk.h> 45 #include <sys/fcntl.h> 46 #include <sys/lock.h> 47 #include <sys/malloc.h> 48 #include <sys/smp.h> 49 #include <sys/stat.h> 50 #include <sys/endian.h> 51 52 #include <net/ethernet.h> 53 54 #include <dev/fdt/fdt_common.h> 55 #include <dev/ofw/openfirm.h> 56 #include <dev/ofw/ofw_pci.h> 57 #include <dev/ofw/ofw_bus.h> 58 #include <dev/ofw/ofw_subr.h> 59 60 #include <vm/vm.h> 61 #include <vm/vm_param.h> 62 #include <vm/vm_page.h> 63 #include <vm/vm_phys.h> 64 65 #include <machine/bus.h> 66 #include <machine/cpu.h> 67 #include <machine/md_var.h> 68 #include <machine/platform.h> 69 #include <machine/ofw_machdep.h> 70 #include <machine/trap.h> 71 72 #include <contrib/libfdt/libfdt.h> 73 74 #ifdef POWERNV 75 #include <powerpc/powernv/opal.h> 76 #endif 77 78 static void *fdt; 79 int ofw_real_mode; 80 81 #ifdef AIM 82 extern register_t ofmsr[5]; 83 extern void *openfirmware_entry; 84 char save_trap_init[0x2f00]; /* EXC_LAST */ 85 char save_trap_of[0x2f00]; /* EXC_LAST */ 86 87 int ofwcall(void *); 88 static int openfirmware(void *args); 89 90 #pragma clang diagnostic push 91 #pragma clang diagnostic ignored "-Wfortify-source" 92 93 __inline void 94 ofw_save_trap_vec(char *save_trap_vec) 95 { 96 if (!ofw_real_mode || !hw_direct_map) 97 return; 98 99 bcopy((void *)PHYS_TO_DMAP(EXC_RST), save_trap_vec, EXC_LAST - EXC_RST); 100 } 101 102 static __inline void 103 ofw_restore_trap_vec(char *restore_trap_vec) 104 { 105 if (!ofw_real_mode || !hw_direct_map) 106 return; 107 108 bcopy(restore_trap_vec, (void *)PHYS_TO_DMAP(EXC_RST), 109 EXC_LAST - EXC_RST); 110 __syncicache((void *)PHYS_TO_DMAP(EXC_RSVD), EXC_LAST - EXC_RSVD); 111 } 112 113 #pragma clang diagnostic pop 114 115 /* 116 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 117 */ 118 register_t ofw_sprg0_save; 119 120 static __inline void 121 ofw_sprg_prepare(void) 122 { 123 if (ofw_real_mode) 124 return; 125 126 /* 127 * Assume that interrupt are disabled at this point, or 128 * SPRG1-3 could be trashed 129 */ 130 #ifdef __powerpc64__ 131 __asm __volatile("mtsprg1 %0\n\t" 132 "mtsprg2 %1\n\t" 133 "mtsprg3 %2\n\t" 134 : 135 : "r"(ofmsr[2]), 136 "r"(ofmsr[3]), 137 "r"(ofmsr[4])); 138 #else 139 __asm __volatile("mfsprg0 %0\n\t" 140 "mtsprg0 %1\n\t" 141 "mtsprg1 %2\n\t" 142 "mtsprg2 %3\n\t" 143 "mtsprg3 %4\n\t" 144 : "=&r"(ofw_sprg0_save) 145 : "r"(ofmsr[1]), 146 "r"(ofmsr[2]), 147 "r"(ofmsr[3]), 148 "r"(ofmsr[4])); 149 #endif 150 } 151 152 static __inline void 153 ofw_sprg_restore(void) 154 { 155 if (ofw_real_mode) 156 return; 157 158 /* 159 * Note that SPRG1-3 contents are irrelevant. They are scratch 160 * registers used in the early portion of trap handling when 161 * interrupts are disabled. 162 * 163 * PCPU data cannot be used until this routine is called ! 164 */ 165 #ifndef __powerpc64__ 166 __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 167 #endif 168 } 169 #endif 170 171 static int 172 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 173 { 174 cell_t address_cells, size_cells; 175 cell_t OFmem[4 * PHYS_AVAIL_SZ]; 176 int sz, i, j; 177 phandle_t phandle; 178 179 sz = 0; 180 181 /* 182 * Get #address-cells from root node, defaulting to 1 if it cannot 183 * be found. 184 */ 185 phandle = OF_finddevice("/"); 186 if (OF_getencprop(phandle, "#address-cells", &address_cells, 187 sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 188 address_cells = 1; 189 if (OF_getencprop(phandle, "#size-cells", &size_cells, 190 sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 191 size_cells = 1; 192 193 /* 194 * Get memory. 195 */ 196 if (node == -1 || (sz = OF_getencprop(node, prop, 197 OFmem, sizeof(OFmem))) <= 0) 198 panic("Physical memory map not found"); 199 200 i = 0; 201 j = 0; 202 while (i < sz/sizeof(cell_t)) { 203 output[j].mr_start = OFmem[i++]; 204 if (address_cells == 2) { 205 output[j].mr_start <<= 32; 206 output[j].mr_start += OFmem[i++]; 207 } 208 209 output[j].mr_size = OFmem[i++]; 210 if (size_cells == 2) { 211 output[j].mr_size <<= 32; 212 output[j].mr_size += OFmem[i++]; 213 } 214 215 if (output[j].mr_start > BUS_SPACE_MAXADDR) 216 continue; 217 218 /* 219 * Constrain memory to that which we can access. 220 * 32-bit AIM can only reference 32 bits of address currently, 221 * but Book-E can access 36 bits. 222 */ 223 if (((uint64_t)output[j].mr_start + 224 (uint64_t)output[j].mr_size - 1) > 225 BUS_SPACE_MAXADDR) { 226 output[j].mr_size = BUS_SPACE_MAXADDR - 227 output[j].mr_start + 1; 228 } 229 230 j++; 231 } 232 233 return (j); 234 } 235 236 static int 237 parse_numa_ofw_memory(phandle_t node, const char *prop, 238 struct numa_mem_region *output) 239 { 240 cell_t address_cells, size_cells; 241 cell_t OFmem[4 * PHYS_AVAIL_SZ]; 242 int sz, i, j; 243 phandle_t phandle; 244 245 sz = 0; 246 247 /* 248 * Get #address-cells from root node, defaulting to 1 if it cannot 249 * be found. 250 */ 251 phandle = OF_finddevice("/"); 252 if (OF_getencprop(phandle, "#address-cells", &address_cells, 253 sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 254 address_cells = 1; 255 if (OF_getencprop(phandle, "#size-cells", &size_cells, 256 sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 257 size_cells = 1; 258 259 /* 260 * Get memory. 261 */ 262 if (node == -1 || (sz = OF_getencprop(node, prop, 263 OFmem, sizeof(OFmem))) <= 0) 264 panic("Physical memory map not found"); 265 266 i = 0; 267 j = 0; 268 while (i < sz/sizeof(cell_t)) { 269 output[j].mr_start = OFmem[i++]; 270 if (address_cells == 2) { 271 output[j].mr_start <<= 32; 272 output[j].mr_start += OFmem[i++]; 273 } 274 output[j].mr_size = OFmem[i++]; 275 if (size_cells == 2) { 276 output[j].mr_size <<= 32; 277 output[j].mr_size += OFmem[i++]; 278 } 279 j++; 280 } 281 282 return (j); 283 } 284 285 #ifdef FDT 286 static int 287 excise_reserved_regions(struct mem_region *avail, int asz, 288 struct mem_region *exclude, int esz) 289 { 290 int i, j, k; 291 292 for (i = 0; i < asz; i++) { 293 for (j = 0; j < esz; j++) { 294 /* 295 * Case 1: Exclusion region encloses complete 296 * available entry. Drop it and move on. 297 */ 298 if (exclude[j].mr_start <= avail[i].mr_start && 299 exclude[j].mr_start + exclude[j].mr_size >= 300 avail[i].mr_start + avail[i].mr_size) { 301 for (k = i+1; k < asz; k++) 302 avail[k-1] = avail[k]; 303 asz--; 304 i--; /* Repeat some entries */ 305 continue; 306 } 307 308 /* 309 * Case 2: Exclusion region starts in available entry. 310 * Trim it to where the entry begins and append 311 * a new available entry with the region after 312 * the excluded region, if any. 313 */ 314 if (exclude[j].mr_start >= avail[i].mr_start && 315 exclude[j].mr_start < avail[i].mr_start + 316 avail[i].mr_size) { 317 if (exclude[j].mr_start + exclude[j].mr_size < 318 avail[i].mr_start + avail[i].mr_size) { 319 avail[asz].mr_start = 320 exclude[j].mr_start + exclude[j].mr_size; 321 avail[asz].mr_size = avail[i].mr_start + 322 avail[i].mr_size - 323 avail[asz].mr_start; 324 asz++; 325 } 326 327 avail[i].mr_size = exclude[j].mr_start - 328 avail[i].mr_start; 329 } 330 331 /* 332 * Case 3: Exclusion region ends in available entry. 333 * Move start point to where the exclusion zone ends. 334 * The case of a contained exclusion zone has already 335 * been caught in case 2. 336 */ 337 if (exclude[j].mr_start + exclude[j].mr_size >= 338 avail[i].mr_start && exclude[j].mr_start + 339 exclude[j].mr_size < avail[i].mr_start + 340 avail[i].mr_size) { 341 avail[i].mr_size += avail[i].mr_start; 342 avail[i].mr_start = 343 exclude[j].mr_start + exclude[j].mr_size; 344 avail[i].mr_size -= avail[i].mr_start; 345 } 346 } 347 } 348 349 return (asz); 350 } 351 352 static int 353 excise_initrd_region(struct mem_region *avail, int asz) 354 { 355 phandle_t chosen; 356 uint64_t start, end; 357 ssize_t size; 358 struct mem_region initrdmap[1]; 359 pcell_t cell[2]; 360 361 chosen = OF_finddevice("/chosen"); 362 363 size = OF_getencprop(chosen, "linux,initrd-start", cell, sizeof(cell)); 364 if (size < 0) 365 return (asz); 366 else if (size == 4) 367 start = cell[0]; 368 else if (size == 8) 369 start = (uint64_t)cell[0] << 32 | cell[1]; 370 else { 371 /* Invalid value length */ 372 printf("WARNING: linux,initrd-start must be either 4 or 8 bytes long\n"); 373 return (asz); 374 } 375 376 size = OF_getencprop(chosen, "linux,initrd-end", cell, sizeof(cell)); 377 if (size < 0) 378 return (asz); 379 else if (size == 4) 380 end = cell[0]; 381 else if (size == 8) 382 end = (uint64_t)cell[0] << 32 | cell[1]; 383 else { 384 /* Invalid value length */ 385 printf("WARNING: linux,initrd-end must be either 4 or 8 bytes long\n"); 386 return (asz); 387 } 388 389 if (end <= start) 390 return (asz); 391 392 initrdmap[0].mr_start = start; 393 initrdmap[0].mr_size = end - start; 394 395 asz = excise_reserved_regions(avail, asz, initrdmap, 1); 396 397 return (asz); 398 } 399 400 #ifdef POWERNV 401 static int 402 excise_msi_region(struct mem_region *avail, int asz) 403 { 404 uint64_t start, end; 405 struct mem_region initrdmap[1]; 406 407 /* 408 * This range of physical addresses is used to implement optimized 409 * 32 bit MSI interrupts on POWER9. Exclude it to avoid accidentally 410 * using it for DMA, as this will cause an immediate PHB fence. 411 * While we could theoretically turn off this behavior in the ETU, 412 * doing so would break 32-bit MSI, so just reserve the range in 413 * the physical map instead. 414 * See section 4.4.2.8 of the PHB4 specification. 415 */ 416 start = 0x00000000ffff0000ul; 417 end = 0x00000000fffffffful; 418 419 initrdmap[0].mr_start = start; 420 initrdmap[0].mr_size = end - start; 421 422 asz = excise_reserved_regions(avail, asz, initrdmap, 1); 423 424 return (asz); 425 } 426 #endif 427 428 static int 429 excise_fdt_reserved(struct mem_region *avail, int asz) 430 { 431 struct mem_region fdtmap[32]; 432 ssize_t fdtmapsize; 433 phandle_t chosen; 434 int j, fdtentries; 435 436 chosen = OF_finddevice("/chosen"); 437 fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); 438 439 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 440 fdtmap[j].mr_start = be64toh(fdtmap[j].mr_start) & ~PAGE_MASK; 441 fdtmap[j].mr_size = round_page(be64toh(fdtmap[j].mr_size)); 442 } 443 444 KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap), 445 ("Exceeded number of FDT reservations")); 446 /* Add a virtual entry for the FDT itself */ 447 if (fdt != NULL) { 448 fdtmap[j].mr_start = (vm_offset_t)fdt & ~PAGE_MASK; 449 fdtmap[j].mr_size = round_page(fdt_totalsize(fdt)); 450 fdtmapsize += sizeof(fdtmap[0]); 451 } 452 453 fdtentries = fdtmapsize/sizeof(fdtmap[0]); 454 asz = excise_reserved_regions(avail, asz, fdtmap, fdtentries); 455 456 return (asz); 457 } 458 #endif 459 460 /* 461 * This is called during powerpc_init, before the system is really initialized. 462 * It shall provide the total and the available regions of RAM. 463 * The available regions need not take the kernel into account. 464 */ 465 void 466 ofw_numa_mem_regions(struct numa_mem_region *memp, int *memsz) 467 { 468 phandle_t phandle; 469 int res, count, msz; 470 char name[31]; 471 cell_t associativity[5]; 472 struct numa_mem_region *curmemp; 473 474 msz = 0; 475 /* 476 * Get memory from all the /memory nodes. 477 */ 478 for (phandle = OF_child(OF_peer(0)); phandle != 0; 479 phandle = OF_peer(phandle)) { 480 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 481 continue; 482 if (strncmp(name, "memory@", strlen("memory@")) != 0) 483 continue; 484 485 count = parse_numa_ofw_memory(phandle, "reg", &memp[msz]); 486 if (count == 0) 487 continue; 488 curmemp = &memp[msz]; 489 res = OF_getproplen(phandle, "ibm,associativity"); 490 if (res <= 0) 491 continue; 492 MPASS(count == 1); 493 OF_getencprop(phandle, "ibm,associativity", 494 associativity, res); 495 curmemp->mr_domain = associativity[3]; 496 if (bootverbose) 497 printf("%s %#jx-%#jx domain(%ju)\n", 498 name, (uintmax_t)curmemp->mr_start, 499 (uintmax_t)curmemp->mr_start + curmemp->mr_size, 500 (uintmax_t)curmemp->mr_domain); 501 msz += count; 502 } 503 *memsz = msz; 504 } 505 /* 506 * This is called during powerpc_init, before the system is really initialized. 507 * It shall provide the total and the available regions of RAM. 508 * The available regions need not take the kernel into account. 509 */ 510 void 511 ofw_mem_regions(struct mem_region *memp, int *memsz, 512 struct mem_region *availp, int *availsz) 513 { 514 phandle_t phandle; 515 int asz, msz; 516 int res; 517 char name[31]; 518 519 asz = msz = 0; 520 521 /* 522 * Get memory from all the /memory nodes. 523 */ 524 for (phandle = OF_child(OF_peer(0)); phandle != 0; 525 phandle = OF_peer(phandle)) { 526 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 527 continue; 528 if (strncmp(name, "memory", sizeof(name)) != 0 && 529 strncmp(name, "memory@", strlen("memory@")) != 0) 530 continue; 531 532 res = parse_ofw_memory(phandle, "reg", &memp[msz]); 533 msz += res; 534 535 /* 536 * On POWER9 Systems we might have both linux,usable-memory and 537 * reg properties. 'reg' denotes all available memory, but we 538 * must use 'linux,usable-memory', a subset, as some memory 539 * regions are reserved for NVLink. 540 */ 541 if (OF_getproplen(phandle, "linux,usable-memory") >= 0) 542 res = parse_ofw_memory(phandle, "linux,usable-memory", 543 &availp[asz]); 544 else if (OF_getproplen(phandle, "available") >= 0) 545 res = parse_ofw_memory(phandle, "available", 546 &availp[asz]); 547 else 548 res = parse_ofw_memory(phandle, "reg", &availp[asz]); 549 asz += res; 550 } 551 552 #ifdef FDT 553 phandle = OF_finddevice("/chosen"); 554 if (OF_hasprop(phandle, "fdtmemreserv")) 555 asz = excise_fdt_reserved(availp, asz); 556 557 /* If the kernel is being loaded through kexec, initrd region is listed 558 * in /chosen but the region is not marked as reserved, so, we might exclude 559 * it here. 560 */ 561 if (OF_hasprop(phandle, "linux,initrd-start")) 562 asz = excise_initrd_region(availp, asz); 563 #endif 564 565 #ifdef POWERNV 566 if (opal_check() == 0) 567 asz = excise_msi_region(availp, asz); 568 #endif 569 570 *memsz = msz; 571 *availsz = asz; 572 } 573 574 void 575 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 576 { 577 #ifdef AIM 578 ofmsr[0] = mfmsr(); 579 #ifdef __powerpc64__ 580 ofmsr[0] &= ~PSL_SF; 581 #else 582 __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1])); 583 #endif 584 __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2])); 585 __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3])); 586 __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4])); 587 openfirmware_entry = openfirm; 588 589 if (ofmsr[0] & PSL_DR) 590 ofw_real_mode = 0; 591 else 592 ofw_real_mode = 1; 593 594 ofw_save_trap_vec(save_trap_init); 595 #else 596 ofw_real_mode = 1; 597 #endif 598 599 fdt = fdt_ptr; 600 } 601 602 boolean_t 603 OF_bootstrap() 604 { 605 boolean_t status = FALSE; 606 int err = 0; 607 608 #ifdef AIM 609 if (openfirmware_entry != NULL) { 610 if (ofw_real_mode) { 611 status = OF_install(OFW_STD_REAL, 0); 612 } else { 613 #ifdef __powerpc64__ 614 status = OF_install(OFW_STD_32BIT, 0); 615 #else 616 status = OF_install(OFW_STD_DIRECT, 0); 617 #endif 618 } 619 620 if (status != TRUE) 621 return status; 622 623 err = OF_init(openfirmware); 624 } else 625 #endif 626 if (fdt != NULL) { 627 #ifdef FDT 628 #ifdef AIM 629 bus_space_tag_t fdt_bt; 630 vm_offset_t tmp_fdt_ptr; 631 vm_size_t fdt_size; 632 uintptr_t fdt_va; 633 #endif 634 635 status = OF_install(OFW_FDT, 0); 636 if (status != TRUE) 637 return status; 638 639 #ifdef AIM /* AIM-only for now -- Book-E does this remapping in early init */ 640 /* Get the FDT size for mapping if we can */ 641 tmp_fdt_ptr = pmap_early_io_map((vm_paddr_t)fdt, PAGE_SIZE); 642 if (fdt_check_header((void *)tmp_fdt_ptr) != 0) { 643 pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE); 644 return FALSE; 645 } 646 fdt_size = fdt_totalsize((void *)tmp_fdt_ptr); 647 pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE); 648 649 /* 650 * Map this for real. Use bus_space_map() to take advantage 651 * of its auto-remapping function once the kernel is loaded. 652 * This is a dirty hack, but what we have. 653 */ 654 #ifdef _LITTLE_ENDIAN 655 fdt_bt = &bs_le_tag; 656 #else 657 fdt_bt = &bs_be_tag; 658 #endif 659 bus_space_map(fdt_bt, (vm_paddr_t)fdt, fdt_size, 0, &fdt_va); 660 661 err = OF_init((void *)fdt_va); 662 #else 663 err = OF_init(fdt); 664 #endif 665 #endif 666 } 667 668 #ifdef FDT_DTB_STATIC 669 /* 670 * Check for a statically included blob already in the kernel and 671 * needing no mapping. 672 */ 673 else { 674 status = OF_install(OFW_FDT, 0); 675 if (status != TRUE) 676 return status; 677 err = OF_init(&fdt_static_dtb); 678 } 679 #endif 680 681 if (err != 0) { 682 OF_install(NULL, 0); 683 status = FALSE; 684 } 685 686 return (status); 687 } 688 689 #ifdef AIM 690 void 691 ofw_quiesce(void) 692 { 693 struct { 694 cell_t name; 695 cell_t nargs; 696 cell_t nreturns; 697 } args; 698 699 KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 700 701 args.name = (cell_t)(uintptr_t)"quiesce"; 702 args.nargs = 0; 703 args.nreturns = 0; 704 openfirmware(&args); 705 } 706 707 static int 708 openfirmware_core(void *args) 709 { 710 int result; 711 register_t oldmsr; 712 713 if (openfirmware_entry == NULL) 714 return (-1); 715 716 /* 717 * Turn off exceptions - we really don't want to end up 718 * anywhere unexpected with PCPU set to something strange 719 * or the stack pointer wrong. 720 */ 721 oldmsr = intr_disable(); 722 723 ofw_sprg_prepare(); 724 725 /* Save trap vectors */ 726 ofw_save_trap_vec(save_trap_of); 727 728 /* Restore initially saved trap vectors */ 729 ofw_restore_trap_vec(save_trap_init); 730 731 #ifndef __powerpc64__ 732 /* 733 * Clear battable[] translations 734 */ 735 if (!(cpu_features & PPC_FEATURE_64)) 736 __asm __volatile("mtdbatu 2, %0\n" 737 "mtdbatu 3, %0" : : "r" (0)); 738 isync(); 739 #endif 740 741 result = ofwcall(args); 742 743 /* Restore trap vecotrs */ 744 ofw_restore_trap_vec(save_trap_of); 745 746 ofw_sprg_restore(); 747 748 intr_restore(oldmsr); 749 750 return (result); 751 } 752 753 #ifdef SMP 754 struct ofw_rv_args { 755 void *args; 756 int retval; 757 volatile int in_progress; 758 }; 759 760 static void 761 ofw_rendezvous_dispatch(void *xargs) 762 { 763 struct ofw_rv_args *rv_args = xargs; 764 765 /* NOTE: Interrupts are disabled here */ 766 767 if (PCPU_GET(cpuid) == 0) { 768 /* 769 * Execute all OF calls on CPU 0 770 */ 771 rv_args->retval = openfirmware_core(rv_args->args); 772 rv_args->in_progress = 0; 773 } else { 774 /* 775 * Spin with interrupts off on other CPUs while OF has 776 * control of the machine. 777 */ 778 while (rv_args->in_progress) 779 cpu_spinwait(); 780 } 781 } 782 #endif 783 784 static int 785 openfirmware(void *args) 786 { 787 int result; 788 #ifdef SMP 789 struct ofw_rv_args rv_args; 790 #endif 791 792 if (openfirmware_entry == NULL) 793 return (-1); 794 795 #ifdef SMP 796 if (cold) { 797 result = openfirmware_core(args); 798 } else { 799 rv_args.args = args; 800 rv_args.in_progress = 1; 801 smp_rendezvous(smp_no_rendezvous_barrier, 802 ofw_rendezvous_dispatch, smp_no_rendezvous_barrier, 803 &rv_args); 804 result = rv_args.retval; 805 } 806 #else 807 result = openfirmware_core(args); 808 #endif 809 810 return (result); 811 } 812 813 void 814 OF_reboot() 815 { 816 struct { 817 cell_t name; 818 cell_t nargs; 819 cell_t nreturns; 820 cell_t arg; 821 } args; 822 823 args.name = (cell_t)(uintptr_t)"interpret"; 824 args.nargs = 1; 825 args.nreturns = 0; 826 args.arg = (cell_t)(uintptr_t)"reset-all"; 827 openfirmware_core(&args); /* Don't do rendezvous! */ 828 829 for (;;); /* just in case */ 830 } 831 832 #endif /* AIM */ 833 834 void 835 OF_getetheraddr(device_t dev, u_char *addr) 836 { 837 phandle_t node; 838 839 node = ofw_bus_get_node(dev); 840 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 841 } 842 843 /* 844 * Return a bus handle and bus tag that corresponds to the register 845 * numbered regno for the device referenced by the package handle 846 * dev. This function is intended to be used by console drivers in 847 * early boot only. It works by mapping the address of the device's 848 * register in the address space of its parent and recursively walk 849 * the device tree upward this way. 850 */ 851 int 852 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 853 bus_space_handle_t *handle, bus_size_t *sz) 854 { 855 bus_addr_t addr; 856 bus_size_t size; 857 pcell_t pci_hi; 858 int flags, res; 859 860 res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi); 861 if (res < 0) 862 return (res); 863 864 if (pci_hi == OFW_PADDR_NOT_PCI) { 865 *tag = &bs_be_tag; 866 flags = 0; 867 } else { 868 *tag = &bs_le_tag; 869 flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? 870 BUS_SPACE_MAP_PREFETCHABLE: 0; 871 } 872 873 if (sz != NULL) 874 *sz = size; 875 876 return (bus_space_map(*tag, addr, size, flags, handle)); 877 } 878 879