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