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