1 /*- 2 * Copyright (C) 1996 Wolfgang Solfrank. 3 * Copyright (C) 1996 TooLs GmbH. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by TooLs GmbH. 17 * 4. The name of TooLs GmbH may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 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/malloc.h> 45 #include <sys/smp.h> 46 #include <sys/stat.h> 47 #include <sys/endian.h> 48 49 #include <net/ethernet.h> 50 51 #include <dev/fdt/fdt_common.h> 52 #include <dev/ofw/openfirm.h> 53 #include <dev/ofw/ofw_pci.h> 54 #include <dev/ofw/ofw_bus.h> 55 56 #include <vm/vm.h> 57 #include <vm/vm_param.h> 58 #include <vm/vm_page.h> 59 60 #include <machine/bus.h> 61 #include <machine/cpu.h> 62 #include <machine/md_var.h> 63 #include <machine/platform.h> 64 #include <machine/ofw_machdep.h> 65 #include <machine/trap.h> 66 67 static void *fdt; 68 int ofw_real_mode; 69 70 #ifdef AIM 71 extern register_t ofmsr[5]; 72 extern void *openfirmware_entry; 73 char save_trap_init[0x2f00]; /* EXC_LAST */ 74 char save_trap_of[0x2f00]; /* EXC_LAST */ 75 76 int ofwcall(void *); 77 static int openfirmware(void *args); 78 79 __inline void 80 ofw_save_trap_vec(char *save_trap_vec) 81 { 82 if (!ofw_real_mode) 83 return; 84 85 bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST); 86 } 87 88 static __inline void 89 ofw_restore_trap_vec(char *restore_trap_vec) 90 { 91 if (!ofw_real_mode) 92 return; 93 94 bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST); 95 __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD); 96 } 97 98 /* 99 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 100 */ 101 register_t ofw_sprg0_save; 102 103 static __inline void 104 ofw_sprg_prepare(void) 105 { 106 if (ofw_real_mode) 107 return; 108 109 /* 110 * Assume that interrupt are disabled at this point, or 111 * SPRG1-3 could be trashed 112 */ 113 __asm __volatile("mfsprg0 %0\n\t" 114 "mtsprg0 %1\n\t" 115 "mtsprg1 %2\n\t" 116 "mtsprg2 %3\n\t" 117 "mtsprg3 %4\n\t" 118 : "=&r"(ofw_sprg0_save) 119 : "r"(ofmsr[1]), 120 "r"(ofmsr[2]), 121 "r"(ofmsr[3]), 122 "r"(ofmsr[4])); 123 } 124 125 static __inline void 126 ofw_sprg_restore(void) 127 { 128 if (ofw_real_mode) 129 return; 130 131 /* 132 * Note that SPRG1-3 contents are irrelevant. They are scratch 133 * registers used in the early portion of trap handling when 134 * interrupts are disabled. 135 * 136 * PCPU data cannot be used until this routine is called ! 137 */ 138 __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 139 } 140 #endif 141 142 static int 143 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 144 { 145 cell_t address_cells, size_cells; 146 cell_t OFmem[4 * PHYS_AVAIL_SZ]; 147 int sz, i, j; 148 phandle_t phandle; 149 150 sz = 0; 151 152 /* 153 * Get #address-cells from root node, defaulting to 1 if it cannot 154 * be found. 155 */ 156 phandle = OF_finddevice("/"); 157 if (OF_getprop(phandle, "#address-cells", &address_cells, 158 sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 159 address_cells = 1; 160 if (OF_getprop(phandle, "#size-cells", &size_cells, 161 sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 162 size_cells = 1; 163 164 /* 165 * Get memory. 166 */ 167 if (node == -1 || (sz = OF_getprop(node, prop, 168 OFmem, sizeof(OFmem))) <= 0) 169 panic("Physical memory map not found"); 170 171 i = 0; 172 j = 0; 173 while (i < sz/sizeof(cell_t)) { 174 #ifndef __powerpc64__ 175 /* On 32-bit PPC, ignore regions starting above 4 GB */ 176 if (address_cells > 1 && OFmem[i] > 0) { 177 i += address_cells + size_cells; 178 continue; 179 } 180 #endif 181 182 output[j].mr_start = OFmem[i++]; 183 if (address_cells == 2) { 184 #ifdef __powerpc64__ 185 output[j].mr_start <<= 32; 186 #endif 187 output[j].mr_start += OFmem[i++]; 188 } 189 190 output[j].mr_size = OFmem[i++]; 191 if (size_cells == 2) { 192 #ifdef __powerpc64__ 193 output[j].mr_size <<= 32; 194 #endif 195 output[j].mr_size += OFmem[i++]; 196 } 197 198 #ifndef __powerpc64__ 199 /* 200 * Check for memory regions extending above 32-bit 201 * memory space, and restrict them to stay there. 202 */ 203 if (((uint64_t)output[j].mr_start + 204 (uint64_t)output[j].mr_size) > 205 BUS_SPACE_MAXADDR_32BIT) { 206 output[j].mr_size = BUS_SPACE_MAXADDR_32BIT - 207 output[j].mr_start; 208 } 209 #endif 210 211 j++; 212 } 213 sz = j*sizeof(output[0]); 214 215 return (sz); 216 } 217 218 static int 219 excise_fdt_reserved(struct mem_region *avail, int asz) 220 { 221 struct { 222 uint64_t address; 223 uint64_t size; 224 } fdtmap[16]; 225 ssize_t fdtmapsize; 226 phandle_t chosen; 227 int i, j, k; 228 229 chosen = OF_finddevice("/chosen"); 230 fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); 231 232 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 233 fdtmap[j].address = be64toh(fdtmap[j].address); 234 fdtmap[j].size = be64toh(fdtmap[j].size); 235 } 236 237 for (i = 0; i < asz; i++) { 238 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 239 /* 240 * Case 1: Exclusion region encloses complete 241 * available entry. Drop it and move on. 242 */ 243 if (fdtmap[j].address <= avail[i].mr_start && 244 fdtmap[j].address + fdtmap[j].size >= 245 avail[i].mr_start + avail[i].mr_size) { 246 for (k = i+1; k < asz; k++) 247 avail[k-1] = avail[k]; 248 asz--; 249 i--; /* Repeat some entries */ 250 continue; 251 } 252 253 /* 254 * Case 2: Exclusion region starts in available entry. 255 * Trim it to where the entry begins and append 256 * a new available entry with the region after 257 * the excluded region, if any. 258 */ 259 if (fdtmap[j].address >= avail[i].mr_start && 260 fdtmap[j].address < avail[i].mr_start + 261 avail[i].mr_size) { 262 if (fdtmap[j].address + fdtmap[j].size < 263 avail[i].mr_start + avail[i].mr_size) { 264 avail[asz].mr_start = 265 fdtmap[j].address + fdtmap[j].size; 266 avail[asz].mr_size = avail[i].mr_start + 267 avail[i].mr_size - 268 avail[asz].mr_start; 269 asz++; 270 } 271 272 avail[i].mr_size = fdtmap[j].address - 273 avail[i].mr_start; 274 } 275 276 /* 277 * Case 3: Exclusion region ends in available entry. 278 * Move start point to where the exclusion zone ends. 279 * The case of a contained exclusion zone has already 280 * been caught in case 2. 281 */ 282 if (fdtmap[j].address + fdtmap[j].size >= 283 avail[i].mr_start && fdtmap[j].address + 284 fdtmap[j].size < avail[i].mr_start + 285 avail[i].mr_size) { 286 avail[i].mr_size += avail[i].mr_start; 287 avail[i].mr_start = 288 fdtmap[j].address + fdtmap[j].size; 289 avail[i].mr_size -= avail[i].mr_start; 290 } 291 } 292 } 293 294 return (asz); 295 } 296 297 /* 298 * This is called during powerpc_init, before the system is really initialized. 299 * It shall provide the total and the available regions of RAM. 300 * The available regions need not take the kernel into account. 301 */ 302 void 303 ofw_mem_regions(struct mem_region *memp, int *memsz, 304 struct mem_region *availp, int *availsz) 305 { 306 phandle_t phandle; 307 int asz, msz; 308 int res; 309 char name[31]; 310 311 asz = msz = 0; 312 313 /* 314 * Get memory from all the /memory nodes. 315 */ 316 for (phandle = OF_child(OF_peer(0)); phandle != 0; 317 phandle = OF_peer(phandle)) { 318 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 319 continue; 320 if (strncmp(name, "memory", sizeof(name)) != 0 && 321 strncmp(name, "memory@", strlen("memory@")) != 0) 322 continue; 323 324 res = parse_ofw_memory(phandle, "reg", &memp[msz]); 325 msz += res/sizeof(struct mem_region); 326 if (OF_getproplen(phandle, "available") >= 0) 327 res = parse_ofw_memory(phandle, "available", 328 &availp[asz]); 329 else 330 res = parse_ofw_memory(phandle, "reg", &availp[asz]); 331 asz += res/sizeof(struct mem_region); 332 } 333 334 phandle = OF_finddevice("/chosen"); 335 if (OF_hasprop(phandle, "fdtmemreserv")) 336 asz = excise_fdt_reserved(availp, asz); 337 338 *memsz = msz; 339 *availsz = asz; 340 } 341 342 void 343 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 344 { 345 #ifdef AIM 346 ofmsr[0] = mfmsr(); 347 #ifdef __powerpc64__ 348 ofmsr[0] &= ~PSL_SF; 349 #endif 350 __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1])); 351 __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2])); 352 __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3])); 353 __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4])); 354 openfirmware_entry = openfirm; 355 356 if (ofmsr[0] & PSL_DR) 357 ofw_real_mode = 0; 358 else 359 ofw_real_mode = 1; 360 361 ofw_save_trap_vec(save_trap_init); 362 #else 363 ofw_real_mode = 1; 364 #endif 365 366 fdt = fdt_ptr; 367 368 #ifdef FDT_DTB_STATIC 369 /* Check for a statically included blob */ 370 if (fdt == NULL) 371 fdt = &fdt_static_dtb; 372 #endif 373 } 374 375 boolean_t 376 OF_bootstrap() 377 { 378 boolean_t status = FALSE; 379 380 #ifdef AIM 381 if (openfirmware_entry != NULL) { 382 if (ofw_real_mode) { 383 status = OF_install(OFW_STD_REAL, 0); 384 } else { 385 #ifdef __powerpc64__ 386 status = OF_install(OFW_STD_32BIT, 0); 387 #else 388 status = OF_install(OFW_STD_DIRECT, 0); 389 #endif 390 } 391 392 if (status != TRUE) 393 return status; 394 395 OF_init(openfirmware); 396 } else 397 #endif 398 if (fdt != NULL) { 399 status = OF_install(OFW_FDT, 0); 400 401 if (status != TRUE) 402 return status; 403 404 OF_init(fdt); 405 OF_interpret("perform-fixup", 0); 406 } 407 408 return (status); 409 } 410 411 #ifdef AIM 412 void 413 ofw_quiesce(void) 414 { 415 struct { 416 cell_t name; 417 cell_t nargs; 418 cell_t nreturns; 419 } args; 420 421 KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 422 423 args.name = (cell_t)(uintptr_t)"quiesce"; 424 args.nargs = 0; 425 args.nreturns = 0; 426 openfirmware(&args); 427 } 428 429 static int 430 openfirmware_core(void *args) 431 { 432 int result; 433 register_t oldmsr; 434 435 if (openfirmware_entry == NULL) 436 return (-1); 437 438 /* 439 * Turn off exceptions - we really don't want to end up 440 * anywhere unexpected with PCPU set to something strange 441 * or the stack pointer wrong. 442 */ 443 oldmsr = intr_disable(); 444 445 ofw_sprg_prepare(); 446 447 /* Save trap vectors */ 448 ofw_save_trap_vec(save_trap_of); 449 450 /* Restore initially saved trap vectors */ 451 ofw_restore_trap_vec(save_trap_init); 452 453 #if defined(AIM) && !defined(__powerpc64__) 454 /* 455 * Clear battable[] translations 456 */ 457 if (!(cpu_features & PPC_FEATURE_64)) 458 __asm __volatile("mtdbatu 2, %0\n" 459 "mtdbatu 3, %0" : : "r" (0)); 460 isync(); 461 #endif 462 463 result = ofwcall(args); 464 465 /* Restore trap vecotrs */ 466 ofw_restore_trap_vec(save_trap_of); 467 468 ofw_sprg_restore(); 469 470 intr_restore(oldmsr); 471 472 return (result); 473 } 474 475 #ifdef SMP 476 struct ofw_rv_args { 477 void *args; 478 int retval; 479 volatile int in_progress; 480 }; 481 482 static void 483 ofw_rendezvous_dispatch(void *xargs) 484 { 485 struct ofw_rv_args *rv_args = xargs; 486 487 /* NOTE: Interrupts are disabled here */ 488 489 if (PCPU_GET(cpuid) == 0) { 490 /* 491 * Execute all OF calls on CPU 0 492 */ 493 rv_args->retval = openfirmware_core(rv_args->args); 494 rv_args->in_progress = 0; 495 } else { 496 /* 497 * Spin with interrupts off on other CPUs while OF has 498 * control of the machine. 499 */ 500 while (rv_args->in_progress) 501 cpu_spinwait(); 502 } 503 } 504 #endif 505 506 static int 507 openfirmware(void *args) 508 { 509 int result; 510 #ifdef SMP 511 struct ofw_rv_args rv_args; 512 #endif 513 514 if (openfirmware_entry == NULL) 515 return (-1); 516 517 #ifdef SMP 518 rv_args.args = args; 519 rv_args.in_progress = 1; 520 smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, 521 smp_no_rendevous_barrier, &rv_args); 522 result = rv_args.retval; 523 #else 524 result = openfirmware_core(args); 525 #endif 526 527 return (result); 528 } 529 530 void 531 OF_reboot() 532 { 533 struct { 534 cell_t name; 535 cell_t nargs; 536 cell_t nreturns; 537 cell_t arg; 538 } args; 539 540 args.name = (cell_t)(uintptr_t)"interpret"; 541 args.nargs = 1; 542 args.nreturns = 0; 543 args.arg = (cell_t)(uintptr_t)"reset-all"; 544 openfirmware_core(&args); /* Don't do rendezvous! */ 545 546 for (;;); /* just in case */ 547 } 548 549 #endif /* AIM */ 550 551 void 552 OF_getetheraddr(device_t dev, u_char *addr) 553 { 554 phandle_t node; 555 556 node = ofw_bus_get_node(dev); 557 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 558 } 559 560 /* 561 * Return a bus handle and bus tag that corresponds to the register 562 * numbered regno for the device referenced by the package handle 563 * dev. This function is intended to be used by console drivers in 564 * early boot only. It works by mapping the address of the device's 565 * register in the address space of its parent and recursively walk 566 * the device tree upward this way. 567 */ 568 static void 569 OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip) 570 { 571 char type[64]; 572 uint32_t addr, size; 573 int pci, res; 574 575 res = OF_getprop(node, "#address-cells", &addr, sizeof(addr)); 576 if (res == -1) 577 addr = 2; 578 res = OF_getprop(node, "#size-cells", &size, sizeof(size)); 579 if (res == -1) 580 size = 1; 581 pci = 0; 582 if (addr == 3 && size == 2) { 583 res = OF_getprop(node, "device_type", type, sizeof(type)); 584 if (res != -1) { 585 type[sizeof(type) - 1] = '\0'; 586 pci = (strcmp(type, "pci") == 0) ? 1 : 0; 587 } 588 } 589 if (addrp != NULL) 590 *addrp = addr; 591 if (sizep != NULL) 592 *sizep = size; 593 if (pcip != NULL) 594 *pcip = pci; 595 } 596 597 int 598 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 599 bus_space_handle_t *handle) 600 { 601 uint32_t cell[32]; 602 bus_addr_t addr, raddr, baddr; 603 bus_size_t size, rsize; 604 uint32_t c, nbridge, naddr, nsize; 605 phandle_t bridge, parent; 606 u_int spc, rspc, prefetch; 607 int pci, pcib, res; 608 609 /* Sanity checking. */ 610 if (dev == 0) 611 return (EINVAL); 612 bridge = OF_parent(dev); 613 if (bridge == 0) 614 return (EINVAL); 615 if (regno < 0) 616 return (EINVAL); 617 if (tag == NULL || handle == NULL) 618 return (EINVAL); 619 620 /* Assume big-endian unless we find a PCI device */ 621 *tag = &bs_be_tag; 622 623 /* Get the requested register. */ 624 OF_get_addr_props(bridge, &naddr, &nsize, &pci); 625 if (pci) 626 *tag = &bs_le_tag; 627 res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg", 628 cell, sizeof(cell)); 629 if (res == -1) 630 return (ENXIO); 631 if (res % sizeof(cell[0])) 632 return (ENXIO); 633 res /= sizeof(cell[0]); 634 regno *= naddr + nsize; 635 if (regno + naddr + nsize > res) 636 return (EINVAL); 637 spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0; 638 prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0; 639 addr = 0; 640 for (c = 0; c < naddr; c++) 641 addr = ((uint64_t)addr << 32) | cell[regno++]; 642 size = 0; 643 for (c = 0; c < nsize; c++) 644 size = ((uint64_t)size << 32) | cell[regno++]; 645 646 /* 647 * Map the address range in the bridge's decoding window as given 648 * by the "ranges" property. If a node doesn't have such property 649 * then no mapping is done. 650 */ 651 parent = OF_parent(bridge); 652 while (parent != 0) { 653 OF_get_addr_props(parent, &nbridge, NULL, &pcib); 654 if (pcib) 655 *tag = &bs_le_tag; 656 res = OF_getprop(bridge, "ranges", cell, sizeof(cell)); 657 if (res == -1) 658 goto next; 659 if (res % sizeof(cell[0])) 660 return (ENXIO); 661 res /= sizeof(cell[0]); 662 regno = 0; 663 while (regno < res) { 664 rspc = (pci) 665 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 666 : ~0; 667 if (rspc != spc) { 668 regno += naddr + nbridge + nsize; 669 continue; 670 } 671 raddr = 0; 672 for (c = 0; c < naddr; c++) 673 raddr = ((uint64_t)raddr << 32) | cell[regno++]; 674 rspc = (pcib) 675 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 676 : ~0; 677 baddr = 0; 678 for (c = 0; c < nbridge; c++) 679 baddr = ((uint64_t)baddr << 32) | cell[regno++]; 680 rsize = 0; 681 for (c = 0; c < nsize; c++) 682 rsize = ((uint64_t)rsize << 32) | cell[regno++]; 683 if (addr < raddr || addr >= raddr + rsize) 684 continue; 685 addr = addr - raddr + baddr; 686 if (rspc != ~0) 687 spc = rspc; 688 } 689 690 next: 691 bridge = parent; 692 parent = OF_parent(bridge); 693 OF_get_addr_props(bridge, &naddr, &nsize, &pci); 694 } 695 696 return (bus_space_map(*tag, addr, size, 697 prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle)); 698 } 699 700