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