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 65extern register_t ofmsr[5]; 66extern void *openfirmware_entry; 67static void *fdt; 68int ofw_real_mode; 69extern char save_trap_init[0x2f00]; /* EXC_LAST */ 70char save_trap_of[0x2f00]; /* EXC_LAST */ 71 72int ofwcall(void *); 73static int openfirmware(void *args); 74 75__inline void 76ofw_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 84static __inline void 85ofw_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 */ 97register_t ofw_sprg0_save; 98 99static __inline void 100ofw_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 121static __inline void 122ofw_sprg_restore(void) 123{ 124#if 0 125 if (ofw_real_mode) 126 return; 127#endif 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 140static int 141parse_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 int apple_hack_mode; 147 phandle_t phandle; 148 149 sz = 0; 150 apple_hack_mode = 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/* 219 * This is called during powerpc_init, before the system is really initialized. 220 * It shall provide the total and the available regions of RAM. 221 * Both lists must have a zero-size entry as terminator. 222 * The available regions need not take the kernel into account, but needs 223 * to provide space for two additional entry beyond the terminating one. 224 */ 225void 226ofw_mem_regions(struct mem_region *memp, int *memsz, 227 struct mem_region *availp, int *availsz) 228{ 229 phandle_t phandle; 230 int asz, msz; 231 int res; 232 char name[31]; 233 234 asz = msz = 0; 235 236 /* 237 * Get memory from all the /memory nodes. 238 */ 239 for (phandle = OF_child(OF_peer(0)); phandle != 0; 240 phandle = OF_peer(phandle)) { 241 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 242 continue; 243 if (strncmp(name, "memory", sizeof(name)) != 0) 244 continue; 245 246 res = parse_ofw_memory(phandle, "reg", &memp[msz]); 247 msz += res/sizeof(struct mem_region); 248 if (OF_getproplen(phandle, "available") >= 0) 249 res = parse_ofw_memory(phandle, "available", 250 &availp[asz]); 251 else 252 res = parse_ofw_memory(phandle, "reg", &availp[asz]); 253 asz += res/sizeof(struct mem_region); 254 } 255 256 *memsz = msz; 257 *availsz = asz; 258} 259 260#ifdef AIM 261void 262OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 263{ 264 if (ofmsr[0] & PSL_DR) 265 ofw_real_mode = 0; 266 else 267 ofw_real_mode = 1; 268 269 fdt = fdt_ptr; 270 271 #ifdef FDT_DTB_STATIC 272 /* Check for a statically included blob */ 273 if (fdt == NULL) 274 fdt = &fdt_static_dtb; 275 #endif 276} 277 278boolean_t 279OF_bootstrap() 280{ 281 boolean_t status = FALSE; 282 283 if (openfirmware_entry != NULL) { 284 if (ofw_real_mode) { 285 status = OF_install(OFW_STD_REAL, 0); 286 } else { 287 #ifdef __powerpc64__ 288 status = OF_install(OFW_STD_32BIT, 0); 289 #else 290 status = OF_install(OFW_STD_DIRECT, 0); 291 #endif 292 } 293 294 if (status != TRUE) 295 return status; 296 297 OF_init(openfirmware); 298 } else if (fdt != NULL) { 299 status = OF_install(OFW_FDT, 0); 300 301 if (status != TRUE) 302 return status; 303 304 OF_init(fdt); 305 } 306 307 return (status); 308} 309 310void 311ofw_quiesce(void) 312{ 313 struct { 314 cell_t name; 315 cell_t nargs; 316 cell_t nreturns; 317 } args; 318 319 KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 320 321 args.name = (cell_t)(uintptr_t)"quiesce"; 322 args.nargs = 0; 323 args.nreturns = 0; 324 openfirmware(&args); 325} 326 327static int 328openfirmware_core(void *args) 329{ 330 int result; 331 register_t oldmsr; 332 333 /* 334 * Turn off exceptions - we really don't want to end up 335 * anywhere unexpected with PCPU set to something strange 336 * or the stack pointer wrong. 337 */ 338 oldmsr = intr_disable(); 339 340 ofw_sprg_prepare(); 341 342 /* Save trap vectors */ 343 ofw_save_trap_vec(save_trap_of); 344 345 /* Restore initially saved trap vectors */ 346 ofw_restore_trap_vec(save_trap_init); 347 348#if defined(AIM) && !defined(__powerpc64__) 349 /* 350 * Clear battable[] translations 351 */ 352 if (!(cpu_features & PPC_FEATURE_64)) 353 __asm __volatile("mtdbatu 2, %0\n" 354 "mtdbatu 3, %0" : : "r" (0)); 355 isync(); 356#endif 357 358 result = ofwcall(args); 359 360 /* Restore trap vecotrs */ 361 ofw_restore_trap_vec(save_trap_of); 362 363 ofw_sprg_restore(); 364 365 intr_restore(oldmsr); 366 367 return (result); 368} 369 370#ifdef SMP 371struct ofw_rv_args { 372 void *args; 373 int retval; 374 volatile int in_progress; 375}; 376 377static void 378ofw_rendezvous_dispatch(void *xargs) 379{ 380 struct ofw_rv_args *rv_args = xargs; 381 382 /* NOTE: Interrupts are disabled here */ 383 384 if (PCPU_GET(cpuid) == 0) { 385 /* 386 * Execute all OF calls on CPU 0 387 */ 388 rv_args->retval = openfirmware_core(rv_args->args); 389 rv_args->in_progress = 0; 390 } else { 391 /* 392 * Spin with interrupts off on other CPUs while OF has 393 * control of the machine. 394 */ 395 while (rv_args->in_progress) 396 cpu_spinwait(); 397 } 398} 399#endif 400 401static int 402openfirmware(void *args) 403{ 404 int result; 405 #ifdef SMP 406 struct ofw_rv_args rv_args; 407 408 rv_args.args = args; 409 rv_args.in_progress = 1; 410 smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, 411 smp_no_rendevous_barrier, &rv_args); 412 result = rv_args.retval; 413 #else 414 result = openfirmware_core(args); 415 #endif 416 417 return (result); 418} 419 420void 421OF_reboot() 422{ 423 struct { 424 cell_t name; 425 cell_t nargs; 426 cell_t nreturns; 427 cell_t arg; 428 } args; 429 430 args.name = (cell_t)(uintptr_t)"interpret"; 431 args.nargs = 1; 432 args.nreturns = 0; 433 args.arg = (cell_t)(uintptr_t)"reset-all"; 434 openfirmware_core(&args); /* Don't do rendezvous! */ 435 436 for (;;); /* just in case */ 437} 438 439#endif /* AIM */ 440 441void 442OF_getetheraddr(device_t dev, u_char *addr) 443{ 444 phandle_t node; 445 446 node = ofw_bus_get_node(dev); 447 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 448} 449 450/* 451 * Return a bus handle and bus tag that corresponds to the register 452 * numbered regno for the device referenced by the package handle 453 * dev. This function is intended to be used by console drivers in 454 * early boot only. It works by mapping the address of the device's 455 * register in the address space of its parent and recursively walk 456 * the device tree upward this way. 457 */ 458static void 459OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip) 460{ 461 char type[64]; 462 uint32_t addr, size; 463 int pci, res; 464 465 res = OF_getprop(node, "#address-cells", &addr, sizeof(addr)); 466 if (res == -1) 467 addr = 2; 468 res = OF_getprop(node, "#size-cells", &size, sizeof(size)); 469 if (res == -1) 470 size = 1; 471 pci = 0; 472 if (addr == 3 && size == 2) { 473 res = OF_getprop(node, "device_type", type, sizeof(type)); 474 if (res != -1) { 475 type[sizeof(type) - 1] = '\0'; 476 pci = (strcmp(type, "pci") == 0) ? 1 : 0; 477 } 478 } 479 if (addrp != NULL) 480 *addrp = addr; 481 if (sizep != NULL) 482 *sizep = size; 483 if (pcip != NULL) 484 *pcip = pci; 485} 486 487int 488OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 489 bus_space_handle_t *handle) 490{ 491 uint32_t cell[32]; 492 bus_addr_t addr, raddr, baddr; 493 bus_size_t size, rsize; 494 uint32_t c, nbridge, naddr, nsize; 495 phandle_t bridge, parent; 496 u_int spc, rspc, prefetch; 497 int pci, pcib, res; 498 499 /* Sanity checking. */ 500 if (dev == 0) 501 return (EINVAL); 502 bridge = OF_parent(dev); 503 if (bridge == 0) 504 return (EINVAL); 505 if (regno < 0) 506 return (EINVAL); 507 if (tag == NULL || handle == NULL) 508 return (EINVAL); 509 510 /* Assume big-endian unless we find a PCI device */ 511 *tag = &bs_be_tag; 512 513 /* Get the requested register. */ 514 OF_get_addr_props(bridge, &naddr, &nsize, &pci); 515 if (pci) 516 *tag = &bs_le_tag; 517 res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg", 518 cell, sizeof(cell)); 519 if (res == -1) 520 return (ENXIO); 521 if (res % sizeof(cell[0])) 522 return (ENXIO); 523 res /= sizeof(cell[0]); 524 regno *= naddr + nsize; 525 if (regno + naddr + nsize > res) 526 return (EINVAL); 527 spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0; 528 prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0; 529 addr = 0; 530 for (c = 0; c < naddr; c++) 531 addr = ((uint64_t)addr << 32) | cell[regno++]; 532 size = 0; 533 for (c = 0; c < nsize; c++) 534 size = ((uint64_t)size << 32) | cell[regno++]; 535 536 /* 537 * Map the address range in the bridge's decoding window as given 538 * by the "ranges" property. If a node doesn't have such property 539 * then no mapping is done. 540 */ 541 parent = OF_parent(bridge); 542 while (parent != 0) { 543 OF_get_addr_props(parent, &nbridge, NULL, &pcib); 544 if (pcib) 545 *tag = &bs_le_tag; 546 res = OF_getprop(bridge, "ranges", cell, sizeof(cell)); 547 if (res == -1) 548 goto next; 549 if (res % sizeof(cell[0])) 550 return (ENXIO); 551 res /= sizeof(cell[0]); 552 regno = 0; 553 while (regno < res) { 554 rspc = (pci) 555 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 556 : ~0; 557 if (rspc != spc) { 558 regno += naddr + nbridge + nsize; 559 continue; 560 } 561 raddr = 0; 562 for (c = 0; c < naddr; c++) 563 raddr = ((uint64_t)raddr << 32) | cell[regno++]; 564 rspc = (pcib) 565 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 566 : ~0; 567 baddr = 0; 568 for (c = 0; c < nbridge; c++) 569 baddr = ((uint64_t)baddr << 32) | cell[regno++]; 570 rsize = 0; 571 for (c = 0; c < nsize; c++) 572 rsize = ((uint64_t)rsize << 32) | cell[regno++]; 573 if (addr < raddr || addr >= raddr + rsize) 574 continue; 575 addr = addr - raddr + baddr; 576 if (rspc != ~0) 577 spc = rspc; 578 } 579 580 next: 581 bridge = parent; 582 parent = OF_parent(bridge); 583 OF_get_addr_props(bridge, &naddr, &nsize, &pci); 584 } 585 586 return (bus_space_map(*tag, addr, size, 587 prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle)); 588} 589 590