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