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