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