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