1 /* $NetBSD: ofwoea_machdep.c,v 1.38 2014/03/25 16:41:37 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tim Rightnour 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: ofwoea_machdep.c,v 1.38 2014/03/25 16:41:37 matt Exp $"); 34 35 #include "opt_ppcarch.h" 36 #include "opt_compat_netbsd.h" 37 #include "opt_ddb.h" 38 #include "opt_kgdb.h" 39 #include "opt_ipkdb.h" 40 #include "opt_modular.h" 41 42 #include "wsdisplay.h" 43 44 #include <sys/param.h> 45 #include <sys/buf.h> 46 #include <sys/boot_flag.h> 47 #include <sys/extent.h> 48 #include <sys/kernel.h> 49 #include <sys/ksyms.h> 50 #include <uvm/uvm_extern.h> 51 52 #include <dev/ofw/openfirm.h> 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wscons/wsdisplayvar.h> 55 #include <dev/rasops/rasops.h> 56 #include <dev/wscons/wsdisplay_vconsvar.h> 57 #include <machine/pmap.h> 58 #include <machine/powerpc.h> 59 #include <machine/trap.h> 60 #include <machine/vmparam.h> 61 #include <machine/autoconf.h> 62 #include <sys/bus.h> 63 #include <powerpc/oea/bat.h> 64 #include <powerpc/oea/ofw_rasconsvar.h> 65 #include <powerpc/oea/cpufeat.h> 66 #include <powerpc/include/oea/spr.h> 67 #include <powerpc/ofw_cons.h> 68 #include <powerpc/spr.h> 69 #include <powerpc/pic/picvar.h> 70 71 #include "opt_oea.h" 72 73 #include "ksyms.h" 74 75 #ifdef DDB 76 #include <machine/db_machdep.h> 77 #include <ddb/db_extern.h> 78 #endif 79 80 #ifdef KGDB 81 #include <sys/kgdb.h> 82 #endif 83 84 #ifdef IPKDB 85 #include <ipkdb/ipkdb.h> 86 #endif 87 88 #include "opt_ofwoea.h" 89 90 #ifdef ofppc 91 extern struct model_data modeldata; 92 #endif 93 94 #ifdef OFWOEA_DEBUG 95 #define DPRINTF printf 96 #else 97 #define DPRINTF while (0) printf 98 #endif 99 100 typedef struct _rangemap { 101 u_int32_t addr; 102 u_int32_t size; 103 int type; 104 } rangemap_t; 105 106 struct ofw_translations { 107 vaddr_t va; 108 int len; 109 #if defined (PMAC_G5) 110 register64_t pa; 111 #else 112 register_t pa; 113 #endif 114 int mode; 115 }__attribute__((packed)); 116 117 struct pmap ofw_pmap; 118 struct ofw_translations ofmap[32]; 119 char bootpath[256]; 120 char model_name[64]; 121 #if NKSYMS || defined(DDB) || defined(MODULAR) 122 void *startsym, *endsym; 123 #endif 124 125 #if PPC_OEA601 126 #define TIMEBASE_FREQ (1000000000) /* RTC register */ 127 #endif 128 129 #ifdef TIMEBASE_FREQ 130 u_int timebase_freq = TIMEBASE_FREQ; 131 #else 132 u_int timebase_freq = 0; 133 #endif 134 135 extern int ofwmsr; 136 extern int chosen; 137 extern uint32_t ticks_per_sec; 138 extern uint32_t ns_per_tick; 139 extern uint32_t ticks_per_intr; 140 141 static int save_ofmap(struct ofw_translations *, int); 142 static void restore_ofmap(struct ofw_translations *, int); 143 static void set_timebase(void); 144 145 extern void cpu_spinstart(u_int); 146 extern volatile u_int cpu_spinstart_ack; 147 148 void 149 ofwoea_initppc(u_int startkernel, u_int endkernel, char *args) 150 { 151 int ofmaplen, node, l; 152 register_t scratch; 153 154 #if defined(MULTIPROCESSOR) && defined(ofppc) 155 char cpupath[32]; 156 int i; 157 #endif 158 159 /* initialze bats */ 160 if ((oeacpufeat & OEACPU_NOBAT) == 0) 161 ofwoea_batinit(); 162 163 #if NKSYMS || defined(DDB) || defined(MODULAR) 164 /* get info of kernel symbol table from bootloader */ 165 memcpy(&startsym, args + strlen(args) + 1, sizeof(startsym)); 166 memcpy(&endsym, args + strlen(args) + 1 + sizeof(startsym), 167 sizeof(endsym)); 168 if (startsym == NULL || endsym == NULL) 169 startsym = endsym = NULL; 170 #endif 171 172 /* get model name and perform model-specific actions */ 173 memset(model_name, 0, sizeof(model_name)); 174 node = OF_finddevice("/"); 175 if (node != -1) { 176 l = OF_getprop(node, "model", model_name, sizeof(model_name)); 177 if (l == -1) 178 OF_getprop(node, "name", model_name, 179 sizeof(model_name)); 180 model_init(); 181 } 182 183 if (strcmp(model_name, "PowerMac11,2") == 0 || 184 strcmp(model_name, "PowerMac11,1") == 0) 185 OF_quiesce(); 186 187 /* Initialize bus_space */ 188 ofwoea_bus_space_init(); 189 190 ofwoea_consinit(); 191 192 #if defined(MULTIPROCESSOR) && defined(ofppc) 193 for (i=1; i < CPU_MAXNUM; i++) { 194 snprintf(cpupath, sizeof(cpupath), "/cpus/@%x", i); 195 node = OF_finddevice(cpupath); 196 if (node <= 0) 197 continue; 198 aprint_verbose("Starting up CPU %d %s\n", i, cpupath); 199 OF_start_cpu(node, (u_int)cpu_spinstart, i); 200 for (l=0; l < 100000000; l++) { 201 if (cpu_spinstart_ack == i) { 202 aprint_verbose("CPU %d spun up.\n", i); 203 break; 204 } 205 __asm volatile ("sync"); 206 } 207 } 208 #endif 209 210 oea_init(pic_ext_intr); 211 212 ofmaplen = save_ofmap(NULL, 0); 213 if (ofmaplen > 0) 214 save_ofmap(ofmap, ofmaplen); 215 216 /* 217 * XXX 218 * we need to do this here instead of earlier on in ofwinit() for some reason 219 * At least some versions of Apple OF 2.0.1 hang if we do this earlier 220 */ 221 ofwmsr &= ~PSL_IP; 222 223 /* Parse the args string */ 224 if (args) { 225 strcpy(bootpath, args); 226 args = bootpath; 227 while (*++args && *args != ' '); 228 if (*args) { 229 *args++ = 0; 230 while (*args) 231 BOOT_FLAG(*args++, boothowto); 232 } 233 } 234 235 uvm_setpagesize(); 236 237 pmap_bootstrap(startkernel, endkernel); 238 239 /* as far as I can tell, the pmap_setup_seg0 stuff is horribly broken */ 240 #if defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE) 241 #if defined (PMAC_G5) 242 /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/ 243 if (oeacpufeat & OEACPU_64_BRIDGE) { 244 vaddr_t va; 245 paddr_t pa; 246 int i; 247 248 pmap_setup_segment0_map(0, msgbuf_paddr, msgbuf_paddr, 249 round_page(MSGBUFSIZE), 0x0); 250 251 /* Map OFW code+data */ 252 253 for (i = 0; i < ofmaplen / sizeof(struct ofw_translations); i++) { 254 if (ofmap[i].va < 0xff800000) 255 continue; 256 257 for (va = ofmap[i].va, pa = ofmap[i].pa; 258 va < ofmap[i].va + ofmap[i].len; 259 va += PAGE_SIZE, pa += PAGE_SIZE) { 260 pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 261 VM_PROT_ALL | PMAP_WIRED); 262 } 263 } 264 265 #if NWSDISPLAY > 0 266 /* Map video frame buffer */ 267 268 struct rasops_info *ri = &rascons_console_screen.scr_ri; 269 270 if (ri->ri_bits != NULL) { 271 for (va = (vaddr_t) ri->ri_bits; 272 va < round_page((vaddr_t) ri->ri_bits + 273 ri->ri_height * ri->ri_stride); 274 va += PAGE_SIZE) { 275 pmap_enter(pmap_kernel(), va, va, 276 VM_PROT_READ | VM_PROT_WRITE, 277 PMAP_NOCACHE | PMAP_WIRED); 278 } 279 } 280 #endif 281 } 282 #elif defined (MAMBO) 283 /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/ 284 if (oeacpufeat & OEACPU_64_BRIDGE) 285 pmap_setup_segment0_map(0, 0xf4000000, 0xf4000000, 0x1000, 0x0); 286 #endif /* PMAC_G5 */ 287 #endif /* PPC_OEA64 || PPC_OEA64_BRIDGE */ 288 289 /* Now enable translation (and machine checks/recoverable interrupts) */ 290 __asm __volatile ("sync; mfmsr %0; ori %0,%0,%1; mtmsr %0; isync" 291 : "=r"(scratch) 292 : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI)); 293 294 restore_ofmap(ofmap, ofmaplen); 295 296 #if NKSYMS || defined(DDB) || defined(MODULAR) 297 ksyms_addsyms_elf((int)((uintptr_t)endsym - (uintptr_t)startsym), startsym, endsym); 298 #endif 299 300 /* CPU clock stuff */ 301 set_timebase(); 302 303 #ifdef DDB 304 if (boothowto & RB_KDB) 305 Debugger(); 306 #endif 307 } 308 309 void 310 set_timebase(void) 311 { 312 int qhandle, phandle, msr, scratch; 313 char type[32]; 314 315 if (timebase_freq != 0) { 316 ticks_per_sec = timebase_freq; 317 goto found; 318 } 319 320 for (qhandle = OF_peer(0); qhandle; qhandle = phandle) { 321 if (OF_getprop(qhandle, "device_type", type, sizeof type) > 0 322 && strcmp(type, "cpu") == 0 323 && OF_getprop(qhandle, "timebase-frequency", 324 &ticks_per_sec, sizeof ticks_per_sec) > 0) { 325 goto found; 326 } 327 if ((phandle = OF_child(qhandle))) 328 continue; 329 while (qhandle) { 330 if ((phandle = OF_peer(qhandle))) 331 break; 332 qhandle = OF_parent(qhandle); 333 } 334 } 335 panic("no cpu node"); 336 337 found: 338 __asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1" 339 : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE)); 340 ns_per_tick = 1000000000 / ticks_per_sec; 341 ticks_per_intr = ticks_per_sec / hz; 342 cpu_timebase = ticks_per_sec; 343 344 #ifdef PPC_OEA601 345 if ((mfpvr() >> 16) == MPC601) 346 curcpu()->ci_lasttb = rtc_nanosecs(); 347 else 348 #endif 349 curcpu()->ci_lasttb = mftbl(); 350 351 mtspr(SPR_DEC, ticks_per_intr); 352 mtmsr(msr); 353 } 354 355 static int 356 save_ofmap(struct ofw_translations *map, int maxlen) 357 { 358 int mmui, mmu, len; 359 360 OF_getprop(chosen, "mmu", &mmui, sizeof mmui); 361 mmu = OF_instance_to_package(mmui); 362 363 if (map) { 364 memset(map, 0, maxlen); /* to be safe */ 365 len = OF_getprop(mmu, "translations", map, maxlen); 366 } else 367 len = OF_getproplen(mmu, "translations"); 368 369 if (len < 0) 370 len = 0; 371 return len; 372 } 373 374 375 /* The PMAC_G5 code here needs to be replaced by code that looks for the 376 size_cells and does the right thing automatically. 377 */ 378 void 379 restore_ofmap(struct ofw_translations *map, int len) 380 { 381 int n = len / sizeof(struct ofw_translations); 382 int i; 383 384 pmap_pinit(&ofw_pmap); 385 386 #ifndef _LP64 387 ofw_pmap.pm_sr[0] = KERNELN_SEGMENT(0)|SR_PRKEY; 388 ofw_pmap.pm_sr[KERNEL_SR] = KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY; 389 390 #ifdef KERNEL2_SR 391 ofw_pmap.pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT|SR_SUKEY|SR_PRKEY; 392 #endif 393 #endif 394 395 for (i = 0; i < n; i++) { 396 #if defined (PMAC_G5) 397 register64_t pa = map[i].pa; 398 #else 399 register_t pa = map[i].pa; 400 #endif 401 vaddr_t va = map[i].va; 402 size_t length = map[i].len; 403 404 if (va < 0xf0000000) /* XXX */ 405 continue; 406 407 while (length > 0) { 408 pmap_enter(&ofw_pmap, va, (paddr_t)pa, VM_PROT_ALL, 409 VM_PROT_ALL|PMAP_WIRED); 410 pa += PAGE_SIZE; 411 va += PAGE_SIZE; 412 length -= PAGE_SIZE; 413 } 414 } 415 pmap_update(&ofw_pmap); 416 } 417 418 419 420 /* 421 * Scan the device tree for ranges, and return them as bitmap 0..15 422 */ 423 #if !defined(macppc) && defined(PPC_OEA) 424 static u_int16_t 425 ranges_bitmap(int node, u_int16_t bitmap) 426 { 427 int child, mlen, acells, scells, reclen, i, j; 428 u_int32_t addr, len, map[160]; 429 430 for (child = OF_child(node); child; child = OF_peer(child)) { 431 mlen = OF_getprop(child, "ranges", map, sizeof(map)); 432 if (mlen == -1) 433 goto noranges; 434 435 j = OF_getprop(child, "#address-cells", &acells, 436 sizeof(acells)); 437 if (j == -1) 438 goto noranges; 439 440 j = OF_getprop(child, "#size-cells", &scells, 441 sizeof(scells)); 442 if (j == -1) 443 goto noranges; 444 445 #ifdef ofppc 446 reclen = acells + modeldata.ranges_offset + scells; 447 #else 448 reclen = acells + 1 + scells; 449 #endif 450 451 for (i=0; i < (mlen/4)/reclen; i++) { 452 addr = map[reclen * i + acells]; 453 len = map[reclen * i + reclen - 1]; 454 for (j = 0; j < len / 0x10000000; j++) 455 bitmap |= 1 << ((addr+j*0x10000000) >>28); 456 bitmap |= 1 << (addr >> 28); 457 } 458 noranges: 459 bitmap |= ranges_bitmap(child, bitmap); 460 continue; 461 } 462 return bitmap; 463 } 464 #endif /* !macppc && PPC_OEA */ 465 466 void 467 ofwoea_batinit(void) 468 { 469 #if defined (PPC_OEA) 470 471 #ifdef macppc 472 /* 473 * cover PCI and register space but not the firmware ROM 474 */ 475 #ifdef PPC_OEA601 476 477 /* 478 * use segment registers for the 601 479 */ 480 if ((mfpvr() >> 16 ) == MPC601) 481 oea_batinit( 482 0x80000000, BAT_BL_256M, 483 0x90000000, BAT_BL_256M, 484 0xa0000000, BAT_BL_256M, 485 0xb0000000, BAT_BL_256M, 486 0xf0000000, BAT_BL_256M, 487 0); 488 else 489 #endif 490 /* 491 * map to bats 492 */ 493 oea_batinit(0x80000000, BAT_BL_1G, 494 0xf0000000, BAT_BL_128M, 495 0xf8000000, BAT_BL_64M, 496 0xfe000000, BAT_BL_8M, /* Grackle IO */ 497 0); 498 #else 499 uint16_t bitmap; 500 int node, i; 501 502 node = OF_finddevice("/"); 503 504 bitmap = ranges_bitmap(node, 0); 505 oea_batinit(0); 506 507 for (i=1; i < 0x10; i++) { 508 /* skip the three vital SR regions */ 509 if (i == USER_SR || i == KERNEL_SR || i == KERNEL2_SR) 510 continue; 511 if (bitmap & (1 << i)) { 512 oea_iobat_add(0x10000000 * i, BAT_BL_256M); 513 DPRINTF("Batmapped 256M at 0x%x\n", 0x10000000 * i); 514 } 515 } 516 #endif 517 #endif /* OEA */ 518 } 519 520 521 /* we define these partially, as we will fill the rest in later */ 522 struct powerpc_bus_space genppc_isa_io_space_tag = { 523 .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE, 524 .pbs_base = 0x00000000, 525 }; 526 527 struct powerpc_bus_space genppc_isa_mem_space_tag = { 528 .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE, 529 .pbs_base = 0x00000000, 530 }; 531 532 /* This gives us a maximum of 6 PCI busses, assuming both io/mem on each. 533 * Increase if necc. 534 */ 535 static char ex_storage[EXSTORAGE_MAX][EXTENT_FIXED_STORAGE_SIZE(EXTMAP_RANGES)] 536 __attribute__((aligned(8))); 537 538 539 static void 540 find_ranges(int base, rangemap_t *regions, int *cur, int type) 541 { 542 int node, i, len, reclen; 543 u_int32_t parent_acells, acells, scells, map[160]; 544 char tmp[32]; 545 546 node = base; 547 if (OF_getprop(node, "device_type", tmp, sizeof(tmp)) == -1) 548 goto rec; 549 if ((type == RANGE_TYPE_PCI || type == RANGE_TYPE_FIRSTPCI) && 550 strcmp("pci", tmp) != 0) 551 goto rec; 552 if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) != 0) 553 goto rec; 554 len = OF_getprop(node, "ranges", map, sizeof(map)); 555 if (len == -1) 556 goto rec; 557 if (OF_getprop(OF_parent(node), "#address-cells", &parent_acells, 558 sizeof(parent_acells)) != sizeof(parent_acells)) 559 parent_acells = 1; 560 if (OF_getprop(node, "#address-cells", &acells, 561 sizeof(acells)) != sizeof(acells)) 562 acells = 3; 563 if (OF_getprop(node, "#size-cells", &scells, 564 sizeof(scells)) != sizeof(scells)) 565 scells = 2; 566 #ifdef ofppc 567 if (modeldata.ranges_offset == 0) 568 scells -= 1; 569 #endif 570 if (type == RANGE_TYPE_ISA) 571 reclen = 6; 572 else 573 reclen = parent_acells + acells + scells; 574 /* 575 * There exist ISA buses with empty ranges properties. This is 576 * known to occur on the Pegasos II machine, and likely others. 577 * According to them, that means that the isa bus is a fake bus, and 578 * the real maps are the PCI maps of the preceeding bus. To deal 579 * with this, we will set cur to -1 and return. 580 */ 581 if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) == 0 && len == 0) { 582 *cur = -1; 583 DPRINTF("Found empty range in isa bus\n"); 584 return; 585 } 586 587 DPRINTF("found a map reclen=%d cur=%d len=%d\n", reclen, *cur, len); 588 switch (type) { 589 case RANGE_TYPE_PCI: 590 case RANGE_TYPE_FIRSTPCI: 591 for (i=0; i < len/(4*reclen); i++) { 592 DPRINTF("FOUND PCI RANGE\n"); 593 regions[*cur].size = 594 map[i*reclen + parent_acells + acells + scells - 1]; 595 /* skip ranges of size==0 */ 596 if (regions[*cur].size == 0) 597 continue; 598 regions[*cur].type = (map[i*reclen] >> 24) & 0x3; 599 regions[*cur].addr = map[i*reclen + parent_acells + acells - 1]; 600 (*cur)++; 601 } 602 break; 603 case RANGE_TYPE_ISA: 604 for (i=0; i < len/(4*reclen); i++) { 605 if (map[i*reclen] == 1) 606 regions[*cur].type = RANGE_IO; 607 else 608 regions[*cur].type = RANGE_MEM; 609 DPRINTF("FOUND ISA RANGE TYPE=%d\n", 610 regions[*cur].type); 611 regions[*cur].size = 612 map[i*reclen + acells + scells]; 613 (*cur)++; 614 } 615 break; 616 } 617 DPRINTF("returning with CUR=%d\n", *cur); 618 return; 619 rec: 620 for (node = OF_child(base); node; node = OF_peer(node)) { 621 DPRINTF("RECURSE 1 STEP\n"); 622 find_ranges(node, regions, cur, type); 623 if (*cur == -1) 624 return; 625 } 626 } 627 628 static int 629 find_lowest_range(rangemap_t *ranges, int nrof, int type) 630 { 631 int i, low = 0; 632 u_int32_t addr = 0xffffffff; 633 634 for (i=0; i < nrof; i++) { 635 if (ranges[i].type == type && ranges[i].addr != 0 && 636 ranges[i].addr < addr) { 637 low = i; 638 addr = ranges[i].addr; 639 } 640 } 641 if (addr == 0xffffffff) 642 return -1; 643 return low; 644 } 645 646 /* 647 * Find a region of memory, and create a bus_space_tag for it. 648 * Notes: 649 * For ISA node is ignored. 650 * node is the starting node. if -1, we start at / and map everything. 651 */ 652 653 int 654 ofwoea_map_space(int rangetype, int iomem, int node, 655 struct powerpc_bus_space *tag, const char *name) 656 { 657 int i, cur, range, nrofholes, error; 658 static int exmap=0; 659 rangemap_t region, holes[32], list[32]; 660 661 memset(list, 0, sizeof(list)); 662 memset(®ion, 0, sizeof(region)); 663 cur = 0; 664 if (rangetype == RANGE_TYPE_ISA || node == -1) 665 node = OF_finddevice("/"); 666 if (rangetype == RANGE_TYPE_ISA) { 667 u_int32_t size = 0; 668 rangemap_t regions[32]; 669 670 DPRINTF("LOOKING FOR FIRSTPCI\n"); 671 find_ranges(node, list, &cur, RANGE_TYPE_FIRSTPCI); 672 range = 0; 673 DPRINTF("LOOKING FOR ISA\n"); 674 find_ranges(node, regions, &range, RANGE_TYPE_ISA); 675 if (range == 0 || cur == 0) 676 return -1; /* no isa stuff found */ 677 /* 678 * This may be confusing to some. The ISA ranges property 679 * is supposed to be a set of IO ranges for the ISA bus, but 680 * generally, it's just a set of pci devfunc lists that tell 681 * you to go look at the parent PCI device for the actual 682 * ranges. 683 */ 684 if (range == -1) { 685 /* we found a rangeless isa bus */ 686 if (iomem == RANGE_IO) 687 size = 0x10000; 688 else 689 size = 0x1000000; 690 } 691 DPRINTF("found isa stuff\n"); 692 for (i=0; i < range; i++) 693 if (regions[i].type == iomem) 694 size = regions[i].size; 695 if (iomem == RANGE_IO) { 696 /* the first io range is the one */ 697 for (i=0; i < cur; i++) 698 if (list[i].type == RANGE_IO && size) { 699 DPRINTF("found IO\n"); 700 tag->pbs_offset = list[i].addr; 701 tag->pbs_limit = size; 702 error = bus_space_init(tag, name, 703 ex_storage[exmap], 704 sizeof(ex_storage[exmap])); 705 exmap++; 706 return error; 707 } 708 } else { 709 for (i=0; i < cur; i++) 710 if (list[i].type == RANGE_MEM && 711 list[i].size == size) { 712 DPRINTF("found mem\n"); 713 tag->pbs_offset = list[i].addr; 714 tag->pbs_limit = size; 715 error = bus_space_init(tag, name, 716 ex_storage[exmap], 717 sizeof(ex_storage[exmap])); 718 exmap++; 719 return error; 720 } 721 } 722 return -1; /* NO ISA FOUND */ 723 } 724 find_ranges(node, list, &cur, rangetype); 725 726 DPRINTF("cur == %d\n", cur); 727 /* now list should contain a list of memory regions */ 728 for (i=0; i < cur; i++) 729 DPRINTF("addr=0x%x size=0x%x type=%d\n", list[i].addr, 730 list[i].size, list[i].type); 731 732 range = find_lowest_range(list, cur, iomem); 733 i = 0; 734 nrofholes = 0; 735 while (range != -1) { 736 DPRINTF("range==%d\n", range); 737 DPRINTF("i==%d\n", i); 738 if (i == 0) { 739 memcpy(®ion, &list[range], sizeof(rangemap_t)); 740 list[range].addr = 0; 741 i++; 742 range = find_lowest_range(list, cur, iomem); 743 continue; 744 } 745 if (region.addr + region.size < list[range].addr) { 746 /* allocate a hole */ 747 holes[nrofholes].type = iomem; 748 holes[nrofholes].addr = region.size + region.addr; 749 holes[nrofholes].size = list[range].addr - 750 holes[nrofholes].addr - 1; 751 nrofholes++; 752 } 753 region.size = list[range].size + list[range].addr - 754 region.addr; 755 list[range].addr = 0; 756 range = find_lowest_range(list, cur, iomem); 757 } 758 DPRINTF("RANGE iomem=%d FOUND\n", iomem); 759 DPRINTF("addr=0x%x size=0x%x type=%d\n", region.addr, 760 region.size, region.type); 761 DPRINTF("HOLES FOUND\n"); 762 for (i=0; i < nrofholes; i++) 763 DPRINTF("addr=0x%x size=0x%x type=%d\n", holes[i].addr, 764 holes[i].size, holes[i].type); 765 /* AT THIS POINT WE MAP IT */ 766 767 if (rangetype == RANGE_TYPE_PCI) { 768 if (exmap == EXSTORAGE_MAX) 769 panic("Not enough ex_storage space. " 770 "Increase EXSTORAGE_MAX"); 771 772 /* XXX doing this in here might be wrong */ 773 if (iomem == 1) { 774 /* we map an IO region */ 775 tag->pbs_offset = region.addr; 776 tag->pbs_base = 0; 777 tag->pbs_limit = region.size; 778 } else { 779 /* ... or a memory region */ 780 tag->pbs_offset = 0; 781 tag->pbs_base = region.addr; 782 tag->pbs_limit = region.size + region.addr; 783 } 784 785 error = bus_space_init(tag, name, ex_storage[exmap], 786 sizeof(ex_storage[exmap])); 787 exmap++; 788 if (error) 789 panic("ofwoea_bus_space_init: can't init tag %s", name); 790 for (i=0; i < nrofholes; i++) { 791 if (holes[i].type == RANGE_IO) { 792 error = extent_alloc_region(tag->pbs_extent, 793 holes[i].addr - tag->pbs_offset, 794 holes[i].size, EX_NOWAIT); 795 } else { 796 error = extent_alloc_region(tag->pbs_extent, 797 holes[i].addr, holes[i].size, EX_NOWAIT); 798 } 799 if (error) 800 panic("ofwoea_bus_space_init: can't block out" 801 " reserved space 0x%x-0x%x: error=%d", 802 holes[i].addr, holes[i].addr+holes[i].size, 803 error); 804 } 805 return error; 806 } 807 return -1; 808 } 809 810 void 811 ofwoea_bus_space_init(void) 812 { 813 int error; 814 815 error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_IO, -1, 816 &genppc_isa_io_space_tag, "isa-ioport"); 817 if (error > 0) 818 panic("Could not map ISA IO"); 819 820 error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_MEM, -1, 821 &genppc_isa_mem_space_tag, "isa-iomem"); 822 if (error > 0) 823 panic("Could not map ISA MEM"); 824 } 825