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