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