ofw_machdep.c revision 259231
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 259231 2013-12-11 21:41:21Z 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 63static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ]; 64static struct mem_region OFfree[PHYS_AVAIL_SZ]; 65 66extern register_t ofmsr[5]; 67extern void *openfirmware_entry; 68static void *fdt; 69int ofw_real_mode; 70 71int ofwcall(void *); 72static int openfirmware(void *args); 73 74/* 75 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 76 */ 77register_t ofw_sprg0_save; 78 79static __inline void 80ofw_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 98static __inline void 99ofw_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 */ 115static int 116memr_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 125static void 126memr_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 */ 137static int mr_cmp(const void *a, const void *b); 138 139static int 140mr_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 155static int 156parse_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 264static int 265parse_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 printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20); 286 287 /* Parse the /ibm,dynamic-memory. 288 The first position gives the # of entries. The next two words 289 reflect the address of the memory block. The next four words are 290 the DRC index, reserved, list index and flags. 291 (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) 292 293 #el Addr DRC-idx res list-idx flags 294 ------------------------------------------------- 295 | 4 | 8 | 4 | 4 | 4 | 4 |.... 296 ------------------------------------------------- 297 */ 298 299 len = OF_getproplen(phandle, "ibm,dynamic-memory"); 300 if (len > 0) { 301 302 /* We have to use a variable length array on the stack 303 since we have very limited stack space. 304 */ 305 cell_t arr[len/sizeof(cell_t)]; 306 307 res = OF_getprop(phandle, "ibm,dynamic-memory", &arr, 308 sizeof(arr)); 309 if (res == -1) 310 return (0); 311 312 /* Number of elements */ 313 idx = arr[0]; 314 315 /* First address. */ 316 dmem = (void*)&arr[1]; 317 318 for (i = 0; i < idx; i++) { 319 base = *dmem; 320 dmem += 2; 321 flags = *dmem; 322 /* Use region only if available and not reserved. */ 323 if ((flags & 0x8) && !(flags & 0x80)) { 324 ofmem[lmsz].mr_start = base; 325 ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; 326 ofavail[lasz].mr_start = base; 327 ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; 328 lmsz++; 329 lasz++; 330 } 331 dmem++; 332 } 333 } 334 335 *msz = lmsz; 336 *asz = lasz; 337 338 return (1); 339} 340/* 341 * This is called during powerpc_init, before the system is really initialized. 342 * It shall provide the total and the available regions of RAM. 343 * Both lists must have a zero-size entry as terminator. 344 * The available regions need not take the kernel into account, but needs 345 * to provide space for two additional entry beyond the terminating one. 346 */ 347void 348ofw_mem_regions(struct mem_region **memp, int *memsz, 349 struct mem_region **availp, int *availsz) 350{ 351 phandle_t phandle; 352 vm_offset_t maxphysaddr; 353 int asz, msz, fsz; 354 int i, j, res; 355 int still_merging; 356 char name[31]; 357 358 asz = msz = 0; 359 360 /* 361 * Get memory from all the /memory nodes. 362 */ 363 for (phandle = OF_child(OF_peer(0)); phandle != 0; 364 phandle = OF_peer(phandle)) { 365 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 366 continue; 367 if (strncmp(name, "memory", sizeof(name)) != 0) 368 continue; 369 370 res = parse_ofw_memory(phandle, "reg", &OFmem[msz]); 371 msz += res/sizeof(struct mem_region); 372 if (OF_getproplen(phandle, "available") >= 0) 373 res = parse_ofw_memory(phandle, "available", 374 &OFavail[asz]); 375 else 376 res = parse_ofw_memory(phandle, "reg", &OFavail[asz]); 377 asz += res/sizeof(struct mem_region); 378 } 379 380 /* Check for memory in ibm,dynamic-reconfiguration-memory */ 381 parse_drconf_memory(&msz, &asz, OFmem, OFavail); 382 383 qsort(OFmem, msz, sizeof(*OFmem), mr_cmp); 384 qsort(OFavail, asz, sizeof(*OFavail), mr_cmp); 385 386 *memp = OFmem; 387 *memsz = msz; 388 389 /* 390 * On some firmwares (SLOF), some memory may be marked available that 391 * doesn't actually exist. This manifests as an extension of the last 392 * available segment past the end of physical memory, so truncate that 393 * one. 394 */ 395 maxphysaddr = 0; 396 for (i = 0; i < msz; i++) 397 if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr) 398 maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size; 399 400 if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr) 401 OFavail[asz - 1].mr_size = maxphysaddr - 402 OFavail[asz - 1].mr_start; 403 404 /* 405 * OFavail may have overlapping regions - collapse these 406 * and copy out remaining regions to OFfree 407 */ 408 do { 409 still_merging = FALSE; 410 for (i = 0; i < asz; i++) { 411 if (OFavail[i].mr_size == 0) 412 continue; 413 for (j = i+1; j < asz; j++) { 414 if (OFavail[j].mr_size == 0) 415 continue; 416 if (memr_overlap(&OFavail[j], &OFavail[i])) { 417 memr_merge(&OFavail[j], &OFavail[i]); 418 /* mark inactive */ 419 OFavail[j].mr_size = 0; 420 still_merging = TRUE; 421 } 422 } 423 } 424 } while (still_merging == TRUE); 425 426 /* evict inactive ranges */ 427 for (i = 0, fsz = 0; i < asz; i++) { 428 if (OFavail[i].mr_size != 0) { 429 OFfree[fsz] = OFavail[i]; 430 fsz++; 431 } 432 } 433 434 *availp = OFfree; 435 *availsz = fsz; 436} 437 438void 439OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 440{ 441 if (ofmsr[0] & PSL_DR) 442 ofw_real_mode = 0; 443 else 444 ofw_real_mode = 1; 445 446 fdt = fdt_ptr; 447 448 #ifdef FDT_DTB_STATIC 449 /* Check for a statically included blob */ 450 if (fdt == NULL) 451 fdt = &fdt_static_dtb; 452 #endif 453} 454 455boolean_t 456OF_bootstrap() 457{ 458 boolean_t status = FALSE; 459 460 if (openfirmware_entry != NULL) { 461 if (ofw_real_mode) { 462 status = OF_install(OFW_STD_REAL, 0); 463 } else { 464 #ifdef __powerpc64__ 465 status = OF_install(OFW_STD_32BIT, 0); 466 #else 467 status = OF_install(OFW_STD_DIRECT, 0); 468 #endif 469 } 470 471 if (status != TRUE) 472 return status; 473 474 OF_init(openfirmware); 475 } else if (fdt != NULL) { 476 status = OF_install(OFW_FDT, 0); 477 478 if (status != TRUE) 479 return status; 480 481 OF_init(fdt); 482 } 483 484 return (status); 485} 486 487void 488ofw_quiesce(void) 489{ 490 struct { 491 cell_t name; 492 cell_t nargs; 493 cell_t nreturns; 494 } args; 495 496 KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 497 498 args.name = (cell_t)(uintptr_t)"quiesce"; 499 args.nargs = 0; 500 args.nreturns = 0; 501 openfirmware(&args); 502} 503 504static int 505openfirmware_core(void *args) 506{ 507 int result; 508 register_t oldmsr; 509 510 /* 511 * Turn off exceptions - we really don't want to end up 512 * anywhere unexpected with PCPU set to something strange 513 * or the stack pointer wrong. 514 */ 515 oldmsr = intr_disable(); 516 517 ofw_sprg_prepare(); 518 519#if defined(AIM) && !defined(__powerpc64__) 520 /* 521 * Clear battable[] translations 522 */ 523 if (!(cpu_features & PPC_FEATURE_64)) 524 __asm __volatile("mtdbatu 2, %0\n" 525 "mtdbatu 3, %0" : : "r" (0)); 526 isync(); 527#endif 528 529 result = ofwcall(args); 530 ofw_sprg_restore(); 531 532 intr_restore(oldmsr); 533 534 return (result); 535} 536 537#ifdef SMP 538struct ofw_rv_args { 539 void *args; 540 int retval; 541 volatile int in_progress; 542}; 543 544static void 545ofw_rendezvous_dispatch(void *xargs) 546{ 547 struct ofw_rv_args *rv_args = xargs; 548 549 /* NOTE: Interrupts are disabled here */ 550 551 if (PCPU_GET(cpuid) == 0) { 552 /* 553 * Execute all OF calls on CPU 0 554 */ 555 rv_args->retval = openfirmware_core(rv_args->args); 556 rv_args->in_progress = 0; 557 } else { 558 /* 559 * Spin with interrupts off on other CPUs while OF has 560 * control of the machine. 561 */ 562 while (rv_args->in_progress) 563 cpu_spinwait(); 564 } 565} 566#endif 567 568static int 569openfirmware(void *args) 570{ 571 int result; 572 #ifdef SMP 573 struct ofw_rv_args rv_args; 574 575 rv_args.args = args; 576 rv_args.in_progress = 1; 577 smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, 578 smp_no_rendevous_barrier, &rv_args); 579 result = rv_args.retval; 580 #else 581 result = openfirmware_core(args); 582 #endif 583 584 return (result); 585} 586 587void 588OF_reboot() 589{ 590 struct { 591 cell_t name; 592 cell_t nargs; 593 cell_t nreturns; 594 cell_t arg; 595 } args; 596 597 args.name = (cell_t)(uintptr_t)"interpret"; 598 args.nargs = 1; 599 args.nreturns = 0; 600 args.arg = (cell_t)(uintptr_t)"reset-all"; 601 openfirmware_core(&args); /* Don't do rendezvous! */ 602 603 for (;;); /* just in case */ 604} 605 606void 607OF_getetheraddr(device_t dev, u_char *addr) 608{ 609 phandle_t node; 610 611 node = ofw_bus_get_node(dev); 612 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 613} 614 615/* 616 * Return a bus handle and bus tag that corresponds to the register 617 * numbered regno for the device referenced by the package handle 618 * dev. This function is intended to be used by console drivers in 619 * early boot only. It works by mapping the address of the device's 620 * register in the address space of its parent and recursively walk 621 * the device tree upward this way. 622 */ 623static void 624OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip) 625{ 626 char name[16]; 627 uint32_t addr, size; 628 int pci, res; 629 630 res = OF_getprop(node, "#address-cells", &addr, sizeof(addr)); 631 if (res == -1) 632 addr = 2; 633 res = OF_getprop(node, "#size-cells", &size, sizeof(size)); 634 if (res == -1) 635 size = 1; 636 pci = 0; 637 if (addr == 3 && size == 2) { 638 res = OF_getprop(node, "name", name, sizeof(name)); 639 if (res != -1) { 640 name[sizeof(name) - 1] = '\0'; 641 pci = (strcmp(name, "pci") == 0) ? 1 : 0; 642 } 643 } 644 if (addrp != NULL) 645 *addrp = addr; 646 if (sizep != NULL) 647 *sizep = size; 648 if (pcip != NULL) 649 *pcip = pci; 650} 651 652int 653OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 654 bus_space_handle_t *handle) 655{ 656 uint32_t cell[32]; 657 bus_addr_t addr, raddr, baddr; 658 bus_size_t size, rsize; 659 uint32_t c, nbridge, naddr, nsize; 660 phandle_t bridge, parent; 661 u_int spc, rspc, prefetch; 662 int pci, pcib, res; 663 664 /* Sanity checking. */ 665 if (dev == 0) 666 return (EINVAL); 667 bridge = OF_parent(dev); 668 if (bridge == 0) 669 return (EINVAL); 670 if (regno < 0) 671 return (EINVAL); 672 if (tag == NULL || handle == NULL) 673 return (EINVAL); 674 675 /* Get the requested register. */ 676 OF_get_addr_props(bridge, &naddr, &nsize, &pci); 677 res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg", 678 cell, sizeof(cell)); 679 if (res == -1) 680 return (ENXIO); 681 if (res % sizeof(cell[0])) 682 return (ENXIO); 683 res /= sizeof(cell[0]); 684 regno *= naddr + nsize; 685 if (regno + naddr + nsize > res) 686 return (EINVAL); 687 spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0; 688 prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0; 689 addr = 0; 690 for (c = 0; c < naddr; c++) 691 addr = ((uint64_t)addr << 32) | cell[regno++]; 692 size = 0; 693 for (c = 0; c < nsize; c++) 694 size = ((uint64_t)size << 32) | cell[regno++]; 695 696 /* 697 * Map the address range in the bridge's decoding window as given 698 * by the "ranges" property. If a node doesn't have such property 699 * then no mapping is done. 700 */ 701 parent = OF_parent(bridge); 702 while (parent != 0) { 703 OF_get_addr_props(parent, &nbridge, NULL, &pcib); 704 res = OF_getprop(bridge, "ranges", cell, sizeof(cell)); 705 if (res == -1) 706 goto next; 707 if (res % sizeof(cell[0])) 708 return (ENXIO); 709 res /= sizeof(cell[0]); 710 regno = 0; 711 while (regno < res) { 712 rspc = (pci) 713 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 714 : ~0; 715 if (rspc != spc) { 716 regno += naddr + nbridge + nsize; 717 continue; 718 } 719 raddr = 0; 720 for (c = 0; c < naddr; c++) 721 raddr = ((uint64_t)raddr << 32) | cell[regno++]; 722 rspc = (pcib) 723 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 724 : ~0; 725 baddr = 0; 726 for (c = 0; c < nbridge; c++) 727 baddr = ((uint64_t)baddr << 32) | cell[regno++]; 728 rsize = 0; 729 for (c = 0; c < nsize; c++) 730 rsize = ((uint64_t)rsize << 32) | cell[regno++]; 731 if (addr < raddr || addr >= raddr + rsize) 732 continue; 733 addr = addr - raddr + baddr; 734 if (rspc != ~0) 735 spc = rspc; 736 } 737 738 next: 739 bridge = parent; 740 parent = OF_parent(bridge); 741 OF_get_addr_props(bridge, &naddr, &nsize, &pci); 742 } 743 744 *tag = &bs_le_tag; 745 return (bus_space_map(*tag, addr, size, 746 prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle)); 747} 748 749