ofw_machdep.c revision 259235
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: stable/10/sys/powerpc/ofw/ofw_machdep.c 259235 2013-12-11 22:36:20Z andreast $"); 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 64static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ]; 65static struct mem_region OFfree[PHYS_AVAIL_SZ]; 66 67static int apple_hacks; 68 69#ifdef AIM 70extern register_t ofmsr[5]; 71extern void *openfirmware_entry; 72static void *fdt; 73int ofw_real_mode; 74extern char save_trap_init[0x2f00]; /* EXC_LAST */ 75char save_trap_of[0x2f00]; /* EXC_LAST */ 76 77int ofwcall(void *); 78static int openfirmware(void *args); 79 80__inline void 81ofw_save_trap_vec(char *save_trap_vec) 82{ 83 if (apple_hacks) 84 return; 85 86 bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST); 87} 88 89static __inline void 90ofw_restore_trap_vec(char *restore_trap_vec) 91{ 92 if (apple_hacks) 93 return; 94 95 bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST); 96 __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD); 97} 98 99/* 100 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 101 */ 102register_t ofw_sprg0_save; 103 104static __inline void 105ofw_sprg_prepare(void) 106{ 107 if (!apple_hacks) 108 return; 109 110 /* 111 * Assume that interrupt are disabled at this point, or 112 * SPRG1-3 could be trashed 113 */ 114 __asm __volatile("mfsprg0 %0\n\t" 115 "mtsprg0 %1\n\t" 116 "mtsprg1 %2\n\t" 117 "mtsprg2 %3\n\t" 118 "mtsprg3 %4\n\t" 119 : "=&r"(ofw_sprg0_save) 120 : "r"(ofmsr[1]), 121 "r"(ofmsr[2]), 122 "r"(ofmsr[3]), 123 "r"(ofmsr[4])); 124} 125 126static __inline void 127ofw_sprg_restore(void) 128{ 129 if (!apple_hacks) 130 return; 131 132 /* 133 * Note that SPRG1-3 contents are irrelevant. They are scratch 134 * registers used in the early portion of trap handling when 135 * interrupts are disabled. 136 * 137 * PCPU data cannot be used until this routine is called ! 138 */ 139 __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 140} 141#endif 142 143/* 144 * Memory region utilities: determine if two regions overlap, 145 * and merge two overlapping regions into one 146 */ 147static int 148memr_overlap(struct mem_region *r1, struct mem_region *r2) 149{ 150 if ((r1->mr_start + r1->mr_size) < r2->mr_start || 151 (r2->mr_start + r2->mr_size) < r1->mr_start) 152 return (FALSE); 153 154 return (TRUE); 155} 156 157static void 158memr_merge(struct mem_region *from, struct mem_region *to) 159{ 160 vm_offset_t end; 161 end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size); 162 to->mr_start = ulmin(from->mr_start, to->mr_start); 163 to->mr_size = end - to->mr_start; 164} 165 166/* 167 * Quick sort callout for comparing memory regions. 168 */ 169static int mr_cmp(const void *a, const void *b); 170 171static int 172mr_cmp(const void *a, const void *b) 173{ 174 const struct mem_region *regiona; 175 const struct mem_region *regionb; 176 177 regiona = a; 178 regionb = b; 179 if (regiona->mr_start < regionb->mr_start) 180 return (-1); 181 else if (regiona->mr_start > regionb->mr_start) 182 return (1); 183 else 184 return (0); 185} 186 187static int 188parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 189{ 190 cell_t address_cells, size_cells; 191 cell_t OFmem[4 * PHYS_AVAIL_SZ]; 192 int sz, i, j; 193 int apple_hack_mode; 194 phandle_t phandle; 195 196 sz = 0; 197 apple_hack_mode = 0; 198 199 /* 200 * Get #address-cells from root node, defaulting to 1 if it cannot 201 * be found. 202 */ 203 phandle = OF_finddevice("/"); 204 if (OF_getprop(phandle, "#address-cells", &address_cells, 205 sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 206 address_cells = 1; 207 if (OF_getprop(phandle, "#size-cells", &size_cells, 208 sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 209 size_cells = 1; 210 211 /* 212 * On Apple hardware, address_cells is always 1 for "available", 213 * even when it is explicitly set to 2. All memory above 4 GB 214 * also needs to be added by hand to the available list. 215 */ 216 if (strcmp(prop, "available") == 0 && apple_hacks) 217 address_cells = 1; 218 219 /* 220 * Get memory. 221 */ 222 if (node == -1 || (sz = OF_getprop(node, prop, 223 OFmem, sizeof(OFmem))) <= 0) 224 panic("Physical memory map not found"); 225 226 i = 0; 227 j = 0; 228 while (i < sz/sizeof(cell_t)) { 229 #ifndef __powerpc64__ 230 /* On 32-bit PPC, ignore regions starting above 4 GB */ 231 if (address_cells > 1 && OFmem[i] > 0) { 232 i += address_cells + size_cells; 233 continue; 234 } 235 #endif 236 237 output[j].mr_start = OFmem[i++]; 238 if (address_cells == 2) { 239 #ifdef __powerpc64__ 240 output[j].mr_start <<= 32; 241 #endif 242 output[j].mr_start += OFmem[i++]; 243 } 244 245 output[j].mr_size = OFmem[i++]; 246 if (size_cells == 2) { 247 #ifdef __powerpc64__ 248 output[j].mr_size <<= 32; 249 #endif 250 output[j].mr_size += OFmem[i++]; 251 } 252 253 #ifndef __powerpc64__ 254 /* 255 * Check for memory regions extending above 32-bit 256 * memory space, and restrict them to stay there. 257 */ 258 if (((uint64_t)output[j].mr_start + 259 (uint64_t)output[j].mr_size) > 260 BUS_SPACE_MAXADDR_32BIT) { 261 output[j].mr_size = BUS_SPACE_MAXADDR_32BIT - 262 output[j].mr_start; 263 } 264 #endif 265 266 j++; 267 } 268 sz = j*sizeof(output[0]); 269 270 #ifdef __powerpc64__ 271 if (strcmp(prop, "available") == 0 && apple_hacks) { 272 /* Add in regions above 4 GB to the available list */ 273 struct mem_region himem[16]; 274 int hisz; 275 276 hisz = parse_ofw_memory(node, "reg", himem); 277 for (i = 0; i < hisz/sizeof(himem[0]); i++) { 278 if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) { 279 output[j].mr_start = himem[i].mr_start; 280 output[j].mr_size = himem[i].mr_size; 281 j++; 282 } 283 } 284 sz = j*sizeof(output[0]); 285 } 286 #endif 287 288 return (sz); 289} 290 291static int 292parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem, 293 struct mem_region *ofavail) 294{ 295 phandle_t phandle; 296 vm_offset_t base; 297 int i, idx, len, lasz, lmsz, res; 298 uint32_t lmb_size[2]; 299 unsigned long *dmem, flags; 300 301 lmsz = *msz; 302 lasz = *asz; 303 304 phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory"); 305 if (phandle == -1) 306 /* No drconf node, return. */ 307 return (0); 308 309 res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size)); 310 if (res == -1) 311 return (0); 312 printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20); 313 314 /* Parse the /ibm,dynamic-memory. 315 The first position gives the # of entries. The next two words 316 reflect the address of the memory block. The next four words are 317 the DRC index, reserved, list index and flags. 318 (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) 319 320 #el Addr DRC-idx res list-idx flags 321 ------------------------------------------------- 322 | 4 | 8 | 4 | 4 | 4 | 4 |.... 323 ------------------------------------------------- 324 */ 325 326 len = OF_getproplen(phandle, "ibm,dynamic-memory"); 327 if (len > 0) { 328 329 /* We have to use a variable length array on the stack 330 since we have very limited stack space. 331 */ 332 cell_t arr[len/sizeof(cell_t)]; 333 334 res = OF_getprop(phandle, "ibm,dynamic-memory", &arr, 335 sizeof(arr)); 336 if (res == -1) 337 return (0); 338 339 /* Number of elements */ 340 idx = arr[0]; 341 342 /* First address. */ 343 dmem = (void*)&arr[1]; 344 345 for (i = 0; i < idx; i++) { 346 base = *dmem; 347 dmem += 2; 348 flags = *dmem; 349 /* Use region only if available and not reserved. */ 350 if ((flags & 0x8) && !(flags & 0x80)) { 351 ofmem[lmsz].mr_start = base; 352 ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; 353 ofavail[lasz].mr_start = base; 354 ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; 355 lmsz++; 356 lasz++; 357 } 358 dmem++; 359 } 360 } 361 362 *msz = lmsz; 363 *asz = lasz; 364 365 return (1); 366} 367/* 368 * This is called during powerpc_init, before the system is really initialized. 369 * It shall provide the total and the available regions of RAM. 370 * Both lists must have a zero-size entry as terminator. 371 * The available regions need not take the kernel into account, but needs 372 * to provide space for two additional entry beyond the terminating one. 373 */ 374void 375ofw_mem_regions(struct mem_region **memp, int *memsz, 376 struct mem_region **availp, int *availsz) 377{ 378 phandle_t phandle; 379 vm_offset_t maxphysaddr; 380 int asz, msz, fsz; 381 int i, j, res; 382 int still_merging; 383 char name[31]; 384 385 asz = msz = 0; 386 387 /* 388 * Get memory from all the /memory nodes. 389 */ 390 for (phandle = OF_child(OF_peer(0)); phandle != 0; 391 phandle = OF_peer(phandle)) { 392 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 393 continue; 394 if (strncmp(name, "memory", sizeof(name)) != 0) 395 continue; 396 397 res = parse_ofw_memory(phandle, "reg", &OFmem[msz]); 398 msz += res/sizeof(struct mem_region); 399 if (OF_getproplen(phandle, "available") >= 0) 400 res = parse_ofw_memory(phandle, "available", 401 &OFavail[asz]); 402 else 403 res = parse_ofw_memory(phandle, "reg", &OFavail[asz]); 404 asz += res/sizeof(struct mem_region); 405 } 406 407 /* Check for memory in ibm,dynamic-reconfiguration-memory */ 408 parse_drconf_memory(&msz, &asz, OFmem, OFavail); 409 410 qsort(OFmem, msz, sizeof(*OFmem), mr_cmp); 411 qsort(OFavail, asz, sizeof(*OFavail), mr_cmp); 412 413 *memp = OFmem; 414 *memsz = msz; 415 416 /* 417 * On some firmwares (SLOF), some memory may be marked available that 418 * doesn't actually exist. This manifests as an extension of the last 419 * available segment past the end of physical memory, so truncate that 420 * one. 421 */ 422 maxphysaddr = 0; 423 for (i = 0; i < msz; i++) 424 if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr) 425 maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size; 426 427 if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr) 428 OFavail[asz - 1].mr_size = maxphysaddr - 429 OFavail[asz - 1].mr_start; 430 431 /* 432 * OFavail may have overlapping regions - collapse these 433 * and copy out remaining regions to OFfree 434 */ 435 do { 436 still_merging = FALSE; 437 for (i = 0; i < asz; i++) { 438 if (OFavail[i].mr_size == 0) 439 continue; 440 for (j = i+1; j < asz; j++) { 441 if (OFavail[j].mr_size == 0) 442 continue; 443 if (memr_overlap(&OFavail[j], &OFavail[i])) { 444 memr_merge(&OFavail[j], &OFavail[i]); 445 /* mark inactive */ 446 OFavail[j].mr_size = 0; 447 still_merging = TRUE; 448 } 449 } 450 } 451 } while (still_merging == TRUE); 452 453 /* evict inactive ranges */ 454 for (i = 0, fsz = 0; i < asz; i++) { 455 if (OFavail[i].mr_size != 0) { 456 OFfree[fsz] = OFavail[i]; 457 fsz++; 458 } 459 } 460 461 *availp = OFfree; 462 *availsz = fsz; 463} 464 465#ifdef AIM 466void 467OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 468{ 469 if (ofmsr[0] & PSL_DR) 470 ofw_real_mode = 0; 471 else 472 ofw_real_mode = 1; 473 474 fdt = fdt_ptr; 475 476 #ifdef FDT_DTB_STATIC 477 /* Check for a statically included blob */ 478 if (fdt == NULL) 479 fdt = &fdt_static_dtb; 480 #endif 481} 482 483boolean_t 484OF_bootstrap() 485{ 486 boolean_t status = FALSE; 487 488 if (openfirmware_entry != NULL) { 489 if (ofw_real_mode) { 490 status = OF_install(OFW_STD_REAL, 0); 491 } else { 492 #ifdef __powerpc64__ 493 status = OF_install(OFW_STD_32BIT, 0); 494 #else 495 status = OF_install(OFW_STD_DIRECT, 0); 496 #endif 497 } 498 499 if (status != TRUE) 500 return status; 501 502 OF_init(openfirmware); 503 } else if (fdt != NULL) { 504 status = OF_install(OFW_FDT, 0); 505 506 if (status != TRUE) 507 return status; 508 509 OF_init(fdt); 510 } 511 512 /* Apple firmware has some bugs. Check for a "mac-io" alias. */ 513 apple_hacks = (OF_finddevice("mac-io") != -1) ? 1 : 0; 514 515 return (status); 516} 517 518void 519ofw_quiesce(void) 520{ 521 struct { 522 cell_t name; 523 cell_t nargs; 524 cell_t nreturns; 525 } args; 526 527 KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 528 529 args.name = (cell_t)(uintptr_t)"quiesce"; 530 args.nargs = 0; 531 args.nreturns = 0; 532 openfirmware(&args); 533} 534 535static int 536openfirmware_core(void *args) 537{ 538 int result; 539 register_t oldmsr; 540 541 /* 542 * Turn off exceptions - we really don't want to end up 543 * anywhere unexpected with PCPU set to something strange 544 * or the stack pointer wrong. 545 */ 546 oldmsr = intr_disable(); 547 548 ofw_sprg_prepare(); 549 550 /* Save trap vectors */ 551 ofw_save_trap_vec(save_trap_of); 552 553 /* Restore initially saved trap vectors */ 554 ofw_restore_trap_vec(save_trap_init); 555 556#if defined(AIM) && !defined(__powerpc64__) 557 /* 558 * Clear battable[] translations 559 */ 560 if (!(cpu_features & PPC_FEATURE_64)) 561 __asm __volatile("mtdbatu 2, %0\n" 562 "mtdbatu 3, %0" : : "r" (0)); 563 isync(); 564#endif 565 566 result = ofwcall(args); 567 568 /* Restore trap vecotrs */ 569 ofw_restore_trap_vec(save_trap_of); 570 571 ofw_sprg_restore(); 572 573 intr_restore(oldmsr); 574 575 return (result); 576} 577 578#ifdef SMP 579struct ofw_rv_args { 580 void *args; 581 int retval; 582 volatile int in_progress; 583}; 584 585static void 586ofw_rendezvous_dispatch(void *xargs) 587{ 588 struct ofw_rv_args *rv_args = xargs; 589 590 /* NOTE: Interrupts are disabled here */ 591 592 if (PCPU_GET(cpuid) == 0) { 593 /* 594 * Execute all OF calls on CPU 0 595 */ 596 rv_args->retval = openfirmware_core(rv_args->args); 597 rv_args->in_progress = 0; 598 } else { 599 /* 600 * Spin with interrupts off on other CPUs while OF has 601 * control of the machine. 602 */ 603 while (rv_args->in_progress) 604 cpu_spinwait(); 605 } 606} 607#endif 608 609static int 610openfirmware(void *args) 611{ 612 int result; 613 #ifdef SMP 614 struct ofw_rv_args rv_args; 615 616 rv_args.args = args; 617 rv_args.in_progress = 1; 618 smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, 619 smp_no_rendevous_barrier, &rv_args); 620 result = rv_args.retval; 621 #else 622 result = openfirmware_core(args); 623 #endif 624 625 return (result); 626} 627 628void 629OF_reboot() 630{ 631 struct { 632 cell_t name; 633 cell_t nargs; 634 cell_t nreturns; 635 cell_t arg; 636 } args; 637 638 args.name = (cell_t)(uintptr_t)"interpret"; 639 args.nargs = 1; 640 args.nreturns = 0; 641 args.arg = (cell_t)(uintptr_t)"reset-all"; 642 openfirmware_core(&args); /* Don't do rendezvous! */ 643 644 for (;;); /* just in case */ 645} 646 647#endif /* AIM */ 648 649void 650OF_getetheraddr(device_t dev, u_char *addr) 651{ 652 phandle_t node; 653 654 node = ofw_bus_get_node(dev); 655 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 656} 657 658/* 659 * Return a bus handle and bus tag that corresponds to the register 660 * numbered regno for the device referenced by the package handle 661 * dev. This function is intended to be used by console drivers in 662 * early boot only. It works by mapping the address of the device's 663 * register in the address space of its parent and recursively walk 664 * the device tree upward this way. 665 */ 666static void 667OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip) 668{ 669 char type[64]; 670 uint32_t addr, size; 671 int pci, res; 672 673 res = OF_getprop(node, "#address-cells", &addr, sizeof(addr)); 674 if (res == -1) 675 addr = 2; 676 res = OF_getprop(node, "#size-cells", &size, sizeof(size)); 677 if (res == -1) 678 size = 1; 679 pci = 0; 680 if (addr == 3 && size == 2) { 681 res = OF_getprop(node, "device_type", type, sizeof(type)); 682 if (res != -1) { 683 type[sizeof(type) - 1] = '\0'; 684 pci = (strcmp(type, "pci") == 0) ? 1 : 0; 685 } 686 } 687 if (addrp != NULL) 688 *addrp = addr; 689 if (sizep != NULL) 690 *sizep = size; 691 if (pcip != NULL) 692 *pcip = pci; 693} 694 695int 696OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 697 bus_space_handle_t *handle) 698{ 699 uint32_t cell[32]; 700 bus_addr_t addr, raddr, baddr; 701 bus_size_t size, rsize; 702 uint32_t c, nbridge, naddr, nsize; 703 phandle_t bridge, parent; 704 u_int spc, rspc, prefetch; 705 int pci, pcib, res; 706 707 /* Sanity checking. */ 708 if (dev == 0) 709 return (EINVAL); 710 bridge = OF_parent(dev); 711 if (bridge == 0) 712 return (EINVAL); 713 if (regno < 0) 714 return (EINVAL); 715 if (tag == NULL || handle == NULL) 716 return (EINVAL); 717 718 /* Assume big-endian unless we find a PCI device */ 719 *tag = &bs_be_tag; 720 721 /* Get the requested register. */ 722 OF_get_addr_props(bridge, &naddr, &nsize, &pci); 723 if (pci) 724 *tag = &bs_le_tag; 725 res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg", 726 cell, sizeof(cell)); 727 if (res == -1) 728 return (ENXIO); 729 if (res % sizeof(cell[0])) 730 return (ENXIO); 731 res /= sizeof(cell[0]); 732 regno *= naddr + nsize; 733 if (regno + naddr + nsize > res) 734 return (EINVAL); 735 spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0; 736 prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0; 737 addr = 0; 738 for (c = 0; c < naddr; c++) 739 addr = ((uint64_t)addr << 32) | cell[regno++]; 740 size = 0; 741 for (c = 0; c < nsize; c++) 742 size = ((uint64_t)size << 32) | cell[regno++]; 743 744 /* 745 * Map the address range in the bridge's decoding window as given 746 * by the "ranges" property. If a node doesn't have such property 747 * then no mapping is done. 748 */ 749 parent = OF_parent(bridge); 750 while (parent != 0) { 751 OF_get_addr_props(parent, &nbridge, NULL, &pcib); 752 if (pcib) 753 *tag = &bs_le_tag; 754 res = OF_getprop(bridge, "ranges", cell, sizeof(cell)); 755 if (res == -1) 756 goto next; 757 if (res % sizeof(cell[0])) 758 return (ENXIO); 759 res /= sizeof(cell[0]); 760 regno = 0; 761 while (regno < res) { 762 rspc = (pci) 763 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 764 : ~0; 765 if (rspc != spc) { 766 regno += naddr + nbridge + nsize; 767 continue; 768 } 769 raddr = 0; 770 for (c = 0; c < naddr; c++) 771 raddr = ((uint64_t)raddr << 32) | cell[regno++]; 772 rspc = (pcib) 773 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 774 : ~0; 775 baddr = 0; 776 for (c = 0; c < nbridge; c++) 777 baddr = ((uint64_t)baddr << 32) | cell[regno++]; 778 rsize = 0; 779 for (c = 0; c < nsize; c++) 780 rsize = ((uint64_t)rsize << 32) | cell[regno++]; 781 if (addr < raddr || addr >= raddr + rsize) 782 continue; 783 addr = addr - raddr + baddr; 784 if (rspc != ~0) 785 spc = rspc; 786 } 787 788 next: 789 bridge = parent; 790 parent = OF_parent(bridge); 791 OF_get_addr_props(bridge, &naddr, &nsize, &pci); 792 } 793 794 return (bus_space_map(*tag, addr, size, 795 prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle)); 796} 797 798