|
|
1.1 ! root 1: /* ! 2: * OpenBIOS pci driver ! 3: * ! 4: * This driver is compliant to the ! 5: * PCI bus binding to IEEE 1275-1994 Rev 2.1 ! 6: * ! 7: * (C) 2004 Stefan Reinauer <[email protected]> ! 8: * (C) 2005 Ed Schouten <[email protected]> ! 9: * ! 10: * Some parts from OpenHackWare-0.4, Copyright (c) 2004-2005 Jocelyn Mayer ! 11: * ! 12: * This program is free software; you can redistribute it and/or ! 13: * modify it under the terms of the GNU General Public License ! 14: * version 2 ! 15: * ! 16: */ ! 17: ! 18: #include "config.h" ! 19: #include "libopenbios/bindings.h" ! 20: #include "kernel/kernel.h" ! 21: #include "drivers/pci.h" ! 22: #include "libc/byteorder.h" ! 23: #include "libc/vsprintf.h" ! 24: ! 25: #include "drivers/drivers.h" ! 26: #include "drivers/vga.h" ! 27: #include "timer.h" ! 28: #include "pci.h" ! 29: #include "pci_database.h" ! 30: #ifdef CONFIG_DRIVER_MACIO ! 31: #include "cuda.h" ! 32: #include "macio.h" ! 33: #endif ! 34: ! 35: #if defined (CONFIG_DEBUG_PCI) ! 36: # define PCI_DPRINTF(format, ...) printk(format, ## __VA_ARGS__) ! 37: #else ! 38: # define PCI_DPRINTF(format, ...) do { } while (0) ! 39: #endif ! 40: ! 41: #define set_bool_property(ph, name) set_property(ph, name, NULL, 0); ! 42: ! 43: /* DECLARE data structures for the nodes. */ ! 44: ! 45: DECLARE_UNNAMED_NODE( ob_pci_bus_node, INSTALL_OPEN, 2*sizeof(int) ); ! 46: DECLARE_UNNAMED_NODE( ob_pci_simple_node, INSTALL_OPEN, 2*sizeof(int) ); ! 47: ! 48: const pci_arch_t *arch; ! 49: ! 50: #define IS_NOT_RELOCATABLE 0x80000000 ! 51: #define IS_PREFETCHABLE 0x40000000 ! 52: #define IS_ALIASED 0x20000000 ! 53: ! 54: enum { ! 55: CONFIGURATION_SPACE = 0, ! 56: IO_SPACE = 1, ! 57: MEMORY_SPACE_32 = 2, ! 58: MEMORY_SPACE_64 = 3, ! 59: }; ! 60: ! 61: static int encode_int32_cells(int num_cells, u32 *prop, ucell val) ! 62: { ! 63: int i = 0; ! 64: ! 65: /* hi ... lo */ ! 66: for (i=0; i < num_cells; ++i) { ! 67: prop[num_cells - i - 1] = val; ! 68: val >>= 16; ! 69: val >>= 16; ! 70: } ! 71: ! 72: return num_cells; ! 73: } ! 74: ! 75: static inline int pci_encode_phys_addr(u32 *phys, int flags, int space_code, ! 76: pci_addr dev, uint8_t reg, uint64_t addr) ! 77: { ! 78: ! 79: /* phys.hi */ ! 80: ! 81: phys[0] = flags | (space_code << 24) | dev | reg; ! 82: ! 83: /* phys.mid */ ! 84: ! 85: phys[1] = addr >> 32; ! 86: ! 87: /* phys.lo */ ! 88: ! 89: phys[2] = addr; ! 90: ! 91: return 3; ! 92: } ! 93: ! 94: static inline int pci_encode_size(u32 *prop, uint64_t size) ! 95: { ! 96: return encode_int32_cells(2, prop, size); ! 97: } ! 98: ! 99: static int host_address_cells(void) ! 100: { ! 101: return get_int_property(find_dev("/"), "#address-cells", NULL); ! 102: } ! 103: ! 104: static int host_encode_phys_addr(u32 *prop, ucell addr) ! 105: { ! 106: return encode_int32_cells(host_address_cells(), prop, addr); ! 107: } ! 108: ! 109: static int host_size_cells(void) ! 110: { ! 111: return get_int_property(find_dev("/"), "#size-cells", NULL); ! 112: } ! 113: ! 114: /* ! 115: static int parent_address_cells(void) ! 116: { ! 117: phandle_t parent_ph = ih_to_phandle(my_parent()); ! 118: return get_int_property(parent_ph, "#address-cells", NULL); ! 119: } ! 120: ! 121: static int parent_size_cells(void) ! 122: { ! 123: phandle_t parent_ph = ih_to_phandle(my_parent()); ! 124: return get_int_property(parent_ph, "#size-cells", NULL); ! 125: } ! 126: */ ! 127: ! 128: #if defined(CONFIG_DEBUG_PCI) ! 129: static void dump_reg_property(const char* description, int nreg, u32 *reg) ! 130: { ! 131: int i; ! 132: printk("%s reg", description); ! 133: for (i=0; i < nreg; ++i) { ! 134: printk(" %08X", reg[i]); ! 135: } ! 136: printk("\n"); ! 137: } ! 138: #endif ! 139: ! 140: static void ! 141: ob_pci_open(int *idx) ! 142: { ! 143: int ret=1; ! 144: RET ( -ret ); ! 145: } ! 146: ! 147: static void ! 148: ob_pci_close(int *idx) ! 149: { ! 150: } ! 151: ! 152: static void ! 153: ob_pci_initialize(int *idx) ! 154: { ! 155: } ! 156: ! 157: /* ( str len -- phys.lo phys.mid phys.hi ) */ ! 158: ! 159: static void ! 160: ob_pci_decode_unit(int *idx) ! 161: { ! 162: ucell hi, mid, lo; ! 163: const char *arg = pop_fstr_copy(); ! 164: int dev, fn, reg, ss, n, p, t; ! 165: int bus = 0; /* no information */ ! 166: char *ptr; ! 167: ! 168: PCI_DPRINTF("ob_pci_decode_unit idx=%p\n", idx); ! 169: ! 170: fn = 0; ! 171: reg = 0; ! 172: n = 0; ! 173: p = 0; ! 174: t = 0; ! 175: ! 176: ptr = (char*)arg; ! 177: if (*ptr == 'n') { ! 178: n = IS_NOT_RELOCATABLE; ! 179: ptr++; ! 180: } ! 181: if (*ptr == 'i') { ! 182: ss = IO_SPACE; ! 183: ptr++; ! 184: if (*ptr == 't') { ! 185: t = IS_ALIASED; ! 186: ptr++; ! 187: } ! 188: ! 189: /* DD,F,RR,NNNNNNNN */ ! 190: ! 191: dev = strtol(ptr, &ptr, 16); ! 192: ptr++; ! 193: fn = strtol(ptr, &ptr, 16); ! 194: ptr++; ! 195: reg = strtol(ptr, &ptr, 16); ! 196: ptr++; ! 197: lo = strtol(ptr, &ptr, 16); ! 198: mid = 0; ! 199: ! 200: } else if (*ptr == 'm') { ! 201: ss = MEMORY_SPACE_32; ! 202: ptr++; ! 203: if (*ptr == 't') { ! 204: t = IS_ALIASED; ! 205: ptr++; ! 206: } ! 207: if (*ptr == 'p') { ! 208: p = IS_PREFETCHABLE; ! 209: ptr++; ! 210: } ! 211: ! 212: /* DD,F,RR,NNNNNNNN */ ! 213: ! 214: dev = strtol(ptr, &ptr, 16); ! 215: ptr++; ! 216: fn = strtol(ptr, &ptr, 16); ! 217: ptr++; ! 218: reg = strtol(ptr, &ptr, 16); ! 219: ptr++; ! 220: lo = strtol(ptr, &ptr, 16); ! 221: mid = 0; ! 222: ! 223: } else if (*ptr == 'x') { ! 224: unsigned long long addr64; ! 225: ss = MEMORY_SPACE_64; ! 226: ptr++; ! 227: if (*ptr == 'p') { ! 228: p = IS_PREFETCHABLE; ! 229: ptr++; ! 230: } ! 231: ! 232: /* DD,F,RR,NNNNNNNNNNNNNNNN */ ! 233: ! 234: dev = strtol(ptr, &ptr, 16); ! 235: ptr++; ! 236: fn = strtol(ptr, &ptr, 16); ! 237: ptr++; ! 238: reg = strtol(ptr, &ptr, 16); ! 239: ptr++; ! 240: addr64 = strtoll(ptr, &ptr, 16); ! 241: lo = (ucell)addr64; ! 242: mid = addr64 >> 32; ! 243: ! 244: } else { ! 245: ss = CONFIGURATION_SPACE; ! 246: /* "DD" or "DD,FF" */ ! 247: dev = strtol(ptr, &ptr, 16); ! 248: if (*ptr == ',') { ! 249: ptr++; ! 250: fn = strtol(ptr, NULL, 16); ! 251: } ! 252: lo = 0; ! 253: mid = 0; ! 254: } ! 255: free((char*)arg); ! 256: ! 257: hi = n | p | t | (ss << 24) | (bus << 16) | (dev << 11) | (fn << 8) | reg; ! 258: ! 259: PUSH(lo); ! 260: PUSH(mid); ! 261: PUSH(hi); ! 262: ! 263: PCI_DPRINTF("ob_pci_decode_unit idx=%p addr=" ! 264: FMT_ucellx " " FMT_ucellx " " FMT_ucellx "\n", ! 265: idx, lo, mid, hi); ! 266: } ! 267: ! 268: /* ( phys.lo phy.mid phys.hi -- str len ) */ ! 269: ! 270: static void ! 271: ob_pci_encode_unit(int *idx) ! 272: { ! 273: char buf[28]; ! 274: cell hi = POP(); ! 275: cell mid = POP(); ! 276: cell lo = POP(); ! 277: int n, p, t, ss, dev, fn, reg; ! 278: ! 279: n = hi & IS_NOT_RELOCATABLE; ! 280: p = hi & IS_PREFETCHABLE; ! 281: t = hi & IS_ALIASED; ! 282: ss = (hi >> 24) & 0x03; ! 283: ! 284: dev = (hi >> 11) & 0x1F; ! 285: fn = (hi >> 8) & 0x07; ! 286: reg = hi & 0xFF; ! 287: ! 288: switch(ss) { ! 289: case CONFIGURATION_SPACE: ! 290: ! 291: if (fn == 0) /* DD */ ! 292: snprintf(buf, sizeof(buf), "%x", dev); ! 293: else /* DD,F */ ! 294: snprintf(buf, sizeof(buf), "%x,%x", dev, fn); ! 295: break; ! 296: ! 297: case IO_SPACE: ! 298: ! 299: /* [n]i[t]DD,F,RR,NNNNNNNN */ ! 300: snprintf(buf, sizeof(buf), "%si%s%x,%x,%x," FMT_ucellx, ! 301: n ? "n" : "", /* relocatable */ ! 302: t ? "t" : "", /* aliased */ ! 303: dev, fn, reg, t ? lo & 0x03FF : lo); ! 304: break; ! 305: ! 306: case MEMORY_SPACE_32: ! 307: ! 308: /* [n]m[t][p]DD,F,RR,NNNNNNNN */ ! 309: snprintf(buf, sizeof(buf), "%sm%s%s%x,%x,%x," FMT_ucellx, ! 310: n ? "n" : "", /* relocatable */ ! 311: t ? "t" : "", /* aliased */ ! 312: p ? "p" : "", /* prefetchable */ ! 313: dev, fn, reg, lo ); ! 314: break; ! 315: ! 316: case MEMORY_SPACE_64: ! 317: ! 318: /* [n]x[p]DD,F,RR,NNNNNNNNNNNNNNNN */ ! 319: snprintf(buf, sizeof(buf), "%sx%s%x,%x,%x,%llx", ! 320: n ? "n" : "", /* relocatable */ ! 321: p ? "p" : "", /* prefetchable */ ! 322: dev, fn, reg, ((long long)mid << 32) | (long long)lo); ! 323: break; ! 324: } ! 325: push_str(buf); ! 326: ! 327: PCI_DPRINTF("ob_pci_encode_unit space=%d dev=%d fn=%d buf=%s\n", ! 328: ss, dev, fn, buf); ! 329: } ! 330: ! 331: NODE_METHODS(ob_pci_bus_node) = { ! 332: { NULL, ob_pci_initialize }, ! 333: { "open", ob_pci_open }, ! 334: { "close", ob_pci_close }, ! 335: { "decode-unit", ob_pci_decode_unit }, ! 336: { "encode-unit", ob_pci_encode_unit }, ! 337: }; ! 338: ! 339: NODE_METHODS(ob_pci_simple_node) = { ! 340: { NULL, ob_pci_initialize }, ! 341: { "open", ob_pci_open }, ! 342: { "close", ob_pci_close }, ! 343: }; ! 344: ! 345: static void pci_set_bus_range(const pci_config_t *config) ! 346: { ! 347: phandle_t dev = find_dev(config->path); ! 348: u32 props[2]; ! 349: ! 350: props[0] = config->secondary_bus; ! 351: props[1] = config->subordinate_bus; ! 352: ! 353: PCI_DPRINTF("setting bus range for %s PCI device, " ! 354: "package handle " FMT_ucellx " " ! 355: "bus primary=%d secondary=%d subordinate=%d\n", ! 356: config->path, ! 357: dev, ! 358: config->primary_bus, ! 359: config->secondary_bus, ! 360: config->subordinate_bus); ! 361: ! 362: ! 363: set_property(dev, "bus-range", (char *)props, 2 * sizeof(props[0])); ! 364: } ! 365: ! 366: static void pci_host_set_interrupt_map(const pci_config_t *config) ! 367: { ! 368: /* XXX We currently have a hook in the MPIC init code to fill in its handle. ! 369: * If you want to have interrupt maps for your PCI host bus, add your ! 370: * architecture to the #if and make your bridge detect code fill in its ! 371: * handle too. ! 372: * ! 373: * It would be great if someone clever could come up with a more universal ! 374: * mechanism here. ! 375: */ ! 376: #if defined(CONFIG_PPC) ! 377: phandle_t dev = get_cur_dev(); ! 378: u32 props[7 * 4]; ! 379: int i; ! 380: ! 381: #if defined(CONFIG_PPC) ! 382: /* Oldworld macs do interrupt maps differently */ ! 383: if(!is_newworld()) ! 384: return; ! 385: #endif ! 386: ! 387: for (i = 0; i < (7*4); i+=7) { ! 388: props[i+PCI_INT_MAP_PCI0] = 0; ! 389: props[i+PCI_INT_MAP_PCI1] = 0; ! 390: props[i+PCI_INT_MAP_PCI2] = 0; ! 391: props[i+PCI_INT_MAP_PCI_INT] = (i / 7) + 1; // starts at PINA=1 ! 392: props[i+PCI_INT_MAP_PIC_HANDLE] = 0; // gets patched in later ! 393: props[i+PCI_INT_MAP_PIC_INT] = arch->irqs[i / 7]; ! 394: props[i+PCI_INT_MAP_PIC_POL] = 3; ! 395: } ! 396: set_property(dev, "interrupt-map", (char *)props, 7 * 4 * sizeof(props[0])); ! 397: ! 398: props[PCI_INT_MAP_PCI0] = 0; ! 399: props[PCI_INT_MAP_PCI1] = 0; ! 400: props[PCI_INT_MAP_PCI2] = 0; ! 401: props[PCI_INT_MAP_PCI_INT] = 0x7; ! 402: ! 403: set_property(dev, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); ! 404: #endif ! 405: } ! 406: ! 407: static void pci_host_set_reg(phandle_t phandle) ! 408: { ! 409: phandle_t dev = phandle; ! 410: ! 411: /* at most 2 integers for address and size */ ! 412: u32 props[4]; ! 413: int ncells = 0; ! 414: ! 415: ncells += encode_int32_cells(host_address_cells(), props + ncells, ! 416: arch->cfg_base); ! 417: ! 418: ncells += encode_int32_cells(host_size_cells(), props + ncells, ! 419: arch->cfg_len); ! 420: ! 421: set_property(dev, "reg", (char *)props, ncells * sizeof(props[0])); ! 422: ! 423: #if defined(CONFIG_DEBUG_PCI) ! 424: dump_reg_property("pci_host_set_reg", 4, props); ! 425: #endif ! 426: } ! 427: ! 428: /* child-phys : parent-phys : size */ ! 429: /* 3 cells for PCI : 2 cells for 64bit parent : 2 cells for PCI */ ! 430: ! 431: static void pci_host_set_ranges(const pci_config_t *config) ! 432: { ! 433: phandle_t dev = get_cur_dev(); ! 434: u32 props[32]; ! 435: int ncells; ! 436: ! 437: ncells = 0; ! 438: /* first encode PCI configuration space */ ! 439: { ! 440: ncells += pci_encode_phys_addr(props + ncells, 0, CONFIGURATION_SPACE, ! 441: config->dev, 0, 0); ! 442: ncells += host_encode_phys_addr(props + ncells, arch->cfg_addr); ! 443: ncells += pci_encode_size(props + ncells, arch->cfg_len); ! 444: } ! 445: ! 446: if (arch->io_base) { ! 447: ncells += pci_encode_phys_addr(props + ncells, 0, IO_SPACE, ! 448: config->dev, 0, 0); ! 449: ncells += host_encode_phys_addr(props + ncells, arch->io_base); ! 450: ncells += pci_encode_size(props + ncells, arch->io_len); ! 451: } ! 452: if (arch->rbase) { ! 453: ncells += pci_encode_phys_addr(props + ncells, 0, MEMORY_SPACE_32, ! 454: config->dev, 0, 0); ! 455: ncells += host_encode_phys_addr(props + ncells, arch->rbase); ! 456: ncells += pci_encode_size(props + ncells, arch->rlen); ! 457: } ! 458: if (arch->host_mem_base) { ! 459: ncells += pci_encode_phys_addr(props + ncells, 0, MEMORY_SPACE_32, ! 460: config->dev, 0, arch->pci_mem_base); ! 461: ncells += host_encode_phys_addr(props + ncells, arch->host_mem_base); ! 462: ncells += pci_encode_size(props + ncells, arch->mem_len); ! 463: } ! 464: set_property(dev, "ranges", (char *)props, ncells * sizeof(props[0])); ! 465: } ! 466: ! 467: static unsigned long pci_bus_addr_to_host_addr(uint32_t ba) ! 468: { ! 469: #ifdef CONFIG_SPARC64 ! 470: return arch->cfg_data + (unsigned long)ba; ! 471: #else ! 472: return (unsigned long)ba; ! 473: #endif ! 474: } ! 475: ! 476: int host_config_cb(const pci_config_t *config) ! 477: { ! 478: //XXX this overrides "reg" property ! 479: pci_host_set_reg(get_cur_dev()); ! 480: pci_host_set_ranges(config); ! 481: pci_host_set_interrupt_map(config); ! 482: ! 483: return 0; ! 484: } ! 485: ! 486: static int sabre_configure(phandle_t dev) ! 487: { ! 488: uint32_t props[28]; ! 489: ! 490: props[0] = 0xc0000000; ! 491: props[1] = 0x20000000; ! 492: set_property(dev, "virtual-dma", (char *)props, 2 * sizeof(props[0])); ! 493: props[0] = 1; ! 494: set_property(dev, "#virtual-dma-size-cells", (char *)props, ! 495: sizeof(props[0])); ! 496: set_property(dev, "#virtual-dma-addr-cells", (char *)props, ! 497: sizeof(props[0])); ! 498: props[0] = 0x000007f0; ! 499: props[1] = 0x000007ee; ! 500: props[2] = 0x000007ef; ! 501: props[3] = 0x000007e5; ! 502: set_property(dev, "interrupts", (char *)props, 4 * sizeof(props[0])); ! 503: props[0] = 0x0000001f; ! 504: set_property(dev, "upa-portid", (char *)props, 1 * sizeof(props[0])); ! 505: return 0; ! 506: } ! 507: ! 508: int sabre_config_cb(const pci_config_t *config) ! 509: { ! 510: host_config_cb(config); ! 511: ! 512: return sabre_configure(get_cur_dev()); ! 513: } ! 514: ! 515: int bridge_config_cb(const pci_config_t *config) ! 516: { ! 517: phandle_t aliases; ! 518: ! 519: aliases = find_dev("/aliases"); ! 520: set_property(aliases, "bridge", config->path, strlen(config->path) + 1); ! 521: ! 522: return 0; ! 523: } ! 524: ! 525: int ide_config_cb2 (const pci_config_t *config) ! 526: { ! 527: ob_ide_init(config->path, ! 528: config->assigned[0] & ~0x0000000F, ! 529: config->assigned[1] & ~0x0000000F, ! 530: config->assigned[2] & ~0x0000000F, ! 531: config->assigned[3] & ~0x0000000F); ! 532: return 0; ! 533: } ! 534: ! 535: int eth_config_cb (const pci_config_t *config) ! 536: { ! 537: phandle_t ph = get_cur_dev(); ! 538: ! 539: set_property(ph, "network-type", "ethernet", 9); ! 540: set_property(ph, "removable", "network", 8); ! 541: set_property(ph, "category", "net", 4); ! 542: ! 543: return 0; ! 544: } ! 545: ! 546: static inline void pci_decode_pci_addr(pci_addr addr, int *flags, ! 547: int *space_code, uint32_t *mask) ! 548: { ! 549: *flags = 0; ! 550: ! 551: if (addr & 0x01) { ! 552: *space_code = IO_SPACE; ! 553: *mask = 0x00000001; ! 554: } else { ! 555: if (addr & 0x04) { ! 556: *space_code = MEMORY_SPACE_64; ! 557: *flags |= IS_NOT_RELOCATABLE; /* XXX: why not relocatable? */ ! 558: } else { ! 559: *space_code = MEMORY_SPACE_32; ! 560: } ! 561: ! 562: if (addr & 0x08) { ! 563: *flags |= IS_PREFETCHABLE; ! 564: } ! 565: ! 566: *mask = 0x0000000F; ! 567: } ! 568: } ! 569: ! 570: /* ! 571: * "Designing PCI Cards and Drivers for Power Macintosh Computers", p. 454 ! 572: * ! 573: * "AAPL,address" provides an array of 32-bit logical addresses ! 574: * Nth entry corresponding to Nth "assigned-address" base address entry. ! 575: */ ! 576: ! 577: static void pci_set_AAPL_address(const pci_config_t *config) ! 578: { ! 579: phandle_t dev = get_cur_dev(); ! 580: cell props[7]; ! 581: int ncells, i; ! 582: ! 583: ncells = 0; ! 584: for (i = 0; i < 6; i++) { ! 585: if (!config->assigned[i] || !config->sizes[i]) ! 586: continue; ! 587: props[ncells++] = config->assigned[i] & ~0x0000000F; ! 588: } ! 589: if (ncells) ! 590: set_property(dev, "AAPL,address", (char *)props, ! 591: ncells * sizeof(cell)); ! 592: } ! 593: ! 594: static void pci_set_assigned_addresses(phandle_t phandle, ! 595: const pci_config_t *config, int num_bars) ! 596: { ! 597: phandle_t dev = phandle; ! 598: u32 props[32]; ! 599: int ncells; ! 600: int i; ! 601: uint32_t mask; ! 602: int flags, space_code; ! 603: ! 604: ncells = 0; ! 605: for (i = 0; i < num_bars; i++) { ! 606: /* consider only bars with non-zero region size */ ! 607: if (!config->sizes[i]) ! 608: continue; ! 609: pci_decode_pci_addr(config->assigned[i], ! 610: &flags, &space_code, &mask); ! 611: ! 612: ncells += pci_encode_phys_addr(props + ncells, ! 613: flags, space_code, config->dev, ! 614: PCI_BASE_ADDR_0 + (i * sizeof(uint32_t)), ! 615: config->assigned[i] & ~mask); ! 616: ! 617: props[ncells++] = 0x00000000; ! 618: props[ncells++] = config->sizes[i]; ! 619: } ! 620: if (ncells) ! 621: set_property(dev, "assigned-addresses", (char *)props, ! 622: ncells * sizeof(props[0])); ! 623: } ! 624: ! 625: /* call after writing "reg" property to update config->path */ ! 626: static void ob_pci_reload_device_path(phandle_t phandle, pci_config_t *config) ! 627: { ! 628: /* since "name" and "reg" are now assigned ! 629: we need to reload current node name */ ! 630: ! 631: PUSH(phandle); ! 632: fword("get-package-path"); ! 633: char *new_path = pop_fstr_copy(); ! 634: if (new_path) { ! 635: if (0 != strcmp(config->path, new_path)) { ! 636: PCI_DPRINTF("\n=== CHANGED === package path old=%s new=%s\n", ! 637: config->path, new_path); ! 638: strncpy(config->path, new_path, sizeof(config->path)); ! 639: config->path[sizeof(config->path)-1] = '\0'; ! 640: } ! 641: free(new_path); ! 642: } else { ! 643: PCI_DPRINTF("\n=== package path old=%s new=NULL\n", config->path); ! 644: } ! 645: } ! 646: ! 647: static void pci_set_reg(phandle_t phandle, ! 648: pci_config_t *config, int num_bars) ! 649: { ! 650: phandle_t dev = phandle; ! 651: u32 props[38]; ! 652: int ncells; ! 653: int i; ! 654: uint32_t mask; ! 655: int space_code, flags; ! 656: ! 657: ncells = 0; ! 658: ! 659: /* first (addr, size) pair is the beginning of configuration address space */ ! 660: ncells += pci_encode_phys_addr(props + ncells, 0, CONFIGURATION_SPACE, ! 661: config->dev, 0, 0); ! 662: ! 663: ncells += pci_encode_size(props + ncells, 0); ! 664: ! 665: for (i = 0; i < num_bars; i++) { ! 666: /* consider only bars with non-zero region size */ ! 667: if (!config->sizes[i]) ! 668: continue; ! 669: ! 670: pci_decode_pci_addr(config->regions[i], ! 671: &flags, &space_code, &mask); ! 672: ! 673: ncells += pci_encode_phys_addr(props + ncells, ! 674: flags, space_code, config->dev, ! 675: PCI_BASE_ADDR_0 + (i * sizeof(uint32_t)), ! 676: config->regions[i] & ~mask); ! 677: ! 678: /* set size */ ! 679: ncells += pci_encode_size(props + ncells, config->sizes[i]); ! 680: } ! 681: ! 682: set_property(dev, "reg", (char *)props, ncells * sizeof(props[0])); ! 683: ob_pci_reload_device_path(dev, config); ! 684: ! 685: #if defined(CONFIG_DEBUG_PCI) ! 686: dump_reg_property("pci_set_reg", ncells, props); ! 687: #endif ! 688: } ! 689: ! 690: ! 691: static void pci_set_ranges(const pci_config_t *config) ! 692: { ! 693: phandle_t dev = get_cur_dev(); ! 694: u32 props[32]; ! 695: int ncells; ! 696: int i; ! 697: uint32_t mask; ! 698: int flags; ! 699: int space_code; ! 700: ! 701: ncells = 0; ! 702: for (i = 0; i < 6; i++) { ! 703: if (!config->assigned[i] || !config->sizes[i]) ! 704: continue; ! 705: ! 706: /* child address */ ! 707: ! 708: props[ncells++] = 0x00000000; ! 709: ! 710: /* parent address */ ! 711: ! 712: pci_decode_pci_addr(config->assigned[i], ! 713: &flags, &space_code, &mask); ! 714: ncells += pci_encode_phys_addr(props + ncells, flags, space_code, ! 715: config->dev, 0x10 + i * 4, ! 716: config->assigned[i] & ~mask); ! 717: ! 718: /* size */ ! 719: ! 720: props[ncells++] = config->sizes[i]; ! 721: } ! 722: set_property(dev, "ranges", (char *)props, ncells * sizeof(props[0])); ! 723: } ! 724: ! 725: int macio_heathrow_config_cb (const pci_config_t *config) ! 726: { ! 727: pci_set_ranges(config); ! 728: ! 729: #ifdef CONFIG_DRIVER_MACIO ! 730: ob_macio_heathrow_init(config->path, config->assigned[0] & ~0x0000000F); ! 731: #endif ! 732: return 0; ! 733: } ! 734: ! 735: int macio_keylargo_config_cb (const pci_config_t *config) ! 736: { ! 737: pci_set_ranges(config); ! 738: ! 739: #ifdef CONFIG_DRIVER_MACIO ! 740: ob_macio_keylargo_init(config->path, config->assigned[0] & ~0x0000000F); ! 741: #endif ! 742: return 0; ! 743: } ! 744: ! 745: int vga_config_cb (const pci_config_t *config) ! 746: { ! 747: if (config->assigned[0] != 0x00000000) ! 748: vga_vbe_init(config->path, ! 749: pci_bus_addr_to_host_addr(config->assigned[0] & ~0x0000000F), ! 750: config->sizes[0], ! 751: pci_bus_addr_to_host_addr(config->assigned[1] & ~0x0000000F), ! 752: config->sizes[1]); ! 753: return 0; ! 754: } ! 755: ! 756: int ebus_config_cb(const pci_config_t *config) ! 757: { ! 758: #ifdef CONFIG_DRIVER_EBUS ! 759: #ifdef CONFIG_DRIVER_FLOPPY ! 760: ob_floppy_init(config->path, "fdthree", 0x3f0ULL, 0); ! 761: #endif ! 762: #ifdef CONFIG_DRIVER_PC_SERIAL ! 763: ob_pc_serial_init(config->path, "su", arch->io_base, 0x3f8ULL, 0); ! 764: #endif ! 765: #ifdef CONFIG_DRIVER_PC_KBD ! 766: ob_pc_kbd_init(config->path, "kb_ps2", arch->io_base, 0x60ULL, 0); ! 767: #endif ! 768: #endif ! 769: return 0; ! 770: } ! 771: ! 772: static void ob_pci_add_properties(phandle_t phandle, ! 773: pci_addr addr, const pci_dev_t *pci_dev, ! 774: const pci_config_t *config, int num_bars) ! 775: { ! 776: /* cannot use get_cur_dev() path resolution since "name" and "reg" ! 777: properties are being changed */ ! 778: phandle_t dev=phandle; ! 779: int status,id; ! 780: uint16_t vendor_id, device_id; ! 781: uint8_t rev; ! 782: uint32_t class_code; ! 783: ! 784: vendor_id = pci_config_read16(addr, PCI_VENDOR_ID); ! 785: device_id = pci_config_read16(addr, PCI_DEVICE_ID); ! 786: rev = pci_config_read8(addr, PCI_REVISION_ID); ! 787: class_code = pci_config_read16(addr, PCI_CLASS_DEVICE); ! 788: ! 789: if (pci_dev) { ! 790: /**/ ! 791: if (pci_dev->name) { ! 792: push_str(pci_dev->name); ! 793: fword("encode-string"); ! 794: push_str("name"); ! 795: fword("property"); ! 796: } else { ! 797: char path[256]; ! 798: snprintf(path, sizeof(path), ! 799: "pci%x,%x", vendor_id, device_id); ! 800: push_str(path); ! 801: fword("encode-string"); ! 802: push_str("name"); ! 803: fword("property"); ! 804: } ! 805: } else { ! 806: PCI_DPRINTF("*** missing pci_dev\n"); ! 807: } ! 808: ! 809: /* create properties as described in 2.5 */ ! 810: ! 811: set_int_property(dev, "vendor-id", vendor_id); ! 812: set_int_property(dev, "device-id", device_id); ! 813: set_int_property(dev, "revision-id", rev); ! 814: set_int_property(dev, "class-code", class_code << 8); ! 815: ! 816: if (config->irq_pin) { ! 817: OLDWORLD(set_int_property(dev, "AAPL,interrupts", ! 818: config->irq_line)); ! 819: set_int_property(dev, "interrupts", config->irq_pin); ! 820: } ! 821: ! 822: set_int_property(dev, "min-grant", pci_config_read8(addr, PCI_MIN_GNT)); ! 823: set_int_property(dev, "max-latency", pci_config_read8(addr, PCI_MAX_LAT)); ! 824: ! 825: status=pci_config_read16(addr, PCI_STATUS); ! 826: ! 827: set_int_property(dev, "devsel-speed", ! 828: (status&PCI_STATUS_DEVSEL_MASK)>>10); ! 829: ! 830: if(status&PCI_STATUS_FAST_BACK) ! 831: set_bool_property(dev, "fast-back-to-back"); ! 832: if(status&PCI_STATUS_66MHZ) ! 833: set_bool_property(dev, "66mhz-capable"); ! 834: if(status&PCI_STATUS_UDF) ! 835: set_bool_property(dev, "udf-supported"); ! 836: ! 837: id=pci_config_read16(addr, PCI_SUBSYSTEM_VENDOR_ID); ! 838: if(id) ! 839: set_int_property(dev, "subsystem-vendor-id", id); ! 840: id=pci_config_read16(addr, PCI_SUBSYSTEM_ID); ! 841: if(id) ! 842: set_int_property(dev, "subsystem-id", id); ! 843: ! 844: set_int_property(dev, "cache-line-size", ! 845: pci_config_read16(addr, PCI_CACHE_LINE_SIZE)); ! 846: ! 847: if (pci_dev) { ! 848: if (pci_dev->type) { ! 849: push_str(pci_dev->type); ! 850: fword("encode-string"); ! 851: push_str("device_type"); ! 852: fword("property"); ! 853: } ! 854: if (pci_dev->model) { ! 855: push_str(pci_dev->model); ! 856: fword("encode-string"); ! 857: push_str("model"); ! 858: fword("property"); ! 859: } ! 860: if (pci_dev->compat) ! 861: set_property(dev, "compatible", ! 862: pci_dev->compat, pci_compat_len(pci_dev)); ! 863: ! 864: if (pci_dev->acells) ! 865: set_int_property(dev, "#address-cells", ! 866: pci_dev->acells); ! 867: if (pci_dev->scells) ! 868: set_int_property(dev, "#size-cells", ! 869: pci_dev->scells); ! 870: if (pci_dev->icells) ! 871: set_int_property(dev, "#interrupt-cells", ! 872: pci_dev->icells); ! 873: } ! 874: ! 875: pci_set_assigned_addresses(phandle, config, num_bars); ! 876: OLDWORLD(pci_set_AAPL_address(config)); ! 877: ! 878: PCI_DPRINTF("\n"); ! 879: } ! 880: ! 881: #ifdef CONFIG_XBOX ! 882: static char pci_xbox_blacklisted (int bus, int devnum, int fn) ! 883: { ! 884: /* ! 885: * The Xbox MCPX chipset is a derivative of the nForce 1 ! 886: * chipset. It almost has the same bus layout; some devices ! 887: * cannot be used, because they have been removed. ! 888: */ ! 889: ! 890: /* ! 891: * Devices 00:00.1 and 00:00.2 used to be memory controllers on ! 892: * the nForce chipset, but on the Xbox, using them will lockup ! 893: * the chipset. ! 894: */ ! 895: if ((bus == 0) && (devnum == 0) && ((fn == 1) || (fn == 2))) ! 896: return 1; ! 897: ! 898: /* ! 899: * Bus 1 only contains a VGA controller at 01:00.0. When you try ! 900: * to probe beyond that device, you only get garbage, which ! 901: * could cause lockups. ! 902: */ ! 903: if ((bus == 1) && ((devnum != 0) || (fn != 0))) ! 904: return 1; ! 905: ! 906: /* ! 907: * Bus 2 used to contain the AGP controller, but the Xbox MCPX ! 908: * doesn't have one. Probing it can cause lockups. ! 909: */ ! 910: if (bus >= 2) ! 911: return 1; ! 912: ! 913: /* ! 914: * The device is not blacklisted. ! 915: */ ! 916: return 0; ! 917: } ! 918: #endif ! 919: ! 920: static void ob_pci_configure_bar(pci_addr addr, pci_config_t *config, ! 921: int reg, int config_addr, ! 922: uint32_t *p_omask, ! 923: unsigned long *mem_base, ! 924: unsigned long *io_base) ! 925: { ! 926: uint32_t smask, amask, size, reloc, min_align; ! 927: unsigned long base; ! 928: ! 929: config->assigned[reg] = 0x00000000; ! 930: config->sizes[reg] = 0x00000000; ! 931: ! 932: if ((*p_omask & 0x0000000f) == 0x4) { ! 933: /* 64 bits memory mapping */ ! 934: return; ! 935: } ! 936: ! 937: config->regions[reg] = pci_config_read32(addr, config_addr); ! 938: ! 939: /* get region size */ ! 940: ! 941: pci_config_write32(addr, config_addr, 0xffffffff); ! 942: smask = pci_config_read32(addr, config_addr); ! 943: if (smask == 0x00000000 || smask == 0xffffffff) ! 944: return; ! 945: ! 946: if (smask & 0x00000001 && reg != 6) { ! 947: /* I/O space */ ! 948: base = *io_base; ! 949: min_align = 1 << 7; ! 950: amask = 0x00000001; ! 951: } else { ! 952: /* Memory Space */ ! 953: base = *mem_base; ! 954: min_align = 1 << 16; ! 955: amask = 0x0000000F; ! 956: if (reg == 6) { ! 957: smask |= 1; /* ROM */ ! 958: } ! 959: } ! 960: *p_omask = smask & amask; ! 961: smask &= ~amask; ! 962: size = (~smask) + 1; ! 963: config->sizes[reg] = size; ! 964: reloc = base; ! 965: if (size < min_align) ! 966: size = min_align; ! 967: reloc = (reloc + size -1) & ~(size - 1); ! 968: if (*io_base == base) { ! 969: *io_base = reloc + size; ! 970: reloc -= arch->io_base; ! 971: } else { ! 972: *mem_base = reloc + size; ! 973: } ! 974: pci_config_write32(addr, config_addr, reloc | *p_omask); ! 975: config->assigned[reg] = reloc | *p_omask; ! 976: } ! 977: ! 978: static void ob_pci_configure_irq(pci_addr addr, pci_config_t *config) ! 979: { ! 980: uint8_t irq_pin, irq_line; ! 981: ! 982: irq_pin = pci_config_read8(addr, PCI_INTERRUPT_PIN); ! 983: if (irq_pin) { ! 984: config->irq_pin = irq_pin; ! 985: irq_pin = (((config->dev >> 11) & 0x1F) + irq_pin - 1) & 3; ! 986: irq_line = arch->irqs[irq_pin]; ! 987: pci_config_write8(addr, PCI_INTERRUPT_LINE, irq_line); ! 988: config->irq_line = irq_line; ! 989: } else ! 990: config->irq_line = -1; ! 991: } ! 992: ! 993: static void ! 994: ob_pci_configure(pci_addr addr, pci_config_t *config, int num_regs, int rom_bar, ! 995: unsigned long *mem_base, unsigned long *io_base) ! 996: ! 997: { ! 998: uint32_t omask; ! 999: uint16_t cmd; ! 1000: int reg; ! 1001: pci_addr config_addr; ! 1002: ! 1003: ob_pci_configure_irq(addr, config); ! 1004: ! 1005: omask = 0x00000000; ! 1006: for (reg = 0; reg < num_regs; ++reg) { ! 1007: config_addr = PCI_BASE_ADDR_0 + reg * 4; ! 1008: ! 1009: ob_pci_configure_bar(addr, config, reg, config_addr, ! 1010: &omask, mem_base, ! 1011: io_base); ! 1012: } ! 1013: ! 1014: if (rom_bar) { ! 1015: config_addr = rom_bar; ! 1016: ob_pci_configure_bar(addr, config, reg, config_addr, ! 1017: &omask, mem_base, io_base); ! 1018: } ! 1019: cmd = pci_config_read16(addr, PCI_COMMAND); ! 1020: cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; ! 1021: pci_config_write16(addr, PCI_COMMAND, cmd); ! 1022: } ! 1023: ! 1024: static void ob_configure_pci_device(const char* parent_path, ! 1025: int *bus_num, unsigned long *mem_base, unsigned long *io_base, ! 1026: int bus, int devnum, int fn, int *p_is_multi); ! 1027: ! 1028: static void ob_scan_pci_bus(int *bus_num, unsigned long *mem_base, ! 1029: unsigned long *io_base, const char *path, ! 1030: int bus) ! 1031: { ! 1032: int devnum, fn, is_multi; ! 1033: ! 1034: PCI_DPRINTF("\nScanning bus %d at %s...\n", bus, path); ! 1035: ! 1036: for (devnum = 0; devnum < 32; devnum++) { ! 1037: is_multi = 0; ! 1038: for (fn = 0; fn==0 || (is_multi && fn<8); fn++) { ! 1039: ob_configure_pci_device(path, bus_num, mem_base, io_base, ! 1040: bus, devnum, fn, &is_multi); ! 1041: ! 1042: } ! 1043: } ! 1044: } ! 1045: ! 1046: static void ob_configure_pci_bridge(pci_addr addr, ! 1047: int *bus_num, unsigned long *mem_base, ! 1048: unsigned long *io_base, ! 1049: int primary_bus, pci_config_t *config) ! 1050: { ! 1051: config->primary_bus = primary_bus; ! 1052: pci_config_write8(addr, PCI_PRIMARY_BUS, config->primary_bus); ! 1053: ! 1054: config->secondary_bus = *bus_num; ! 1055: pci_config_write8(addr, PCI_SECONDARY_BUS, config->secondary_bus); ! 1056: ! 1057: config->subordinate_bus = 0xff; ! 1058: pci_config_write8(addr, PCI_SUBORDINATE_BUS, config->subordinate_bus); ! 1059: ! 1060: PCI_DPRINTF("scanning new pci bus %u under bridge %s\n", ! 1061: config->secondary_bus, config->path); ! 1062: ! 1063: /* make pci bridge parent device, prepare for recursion */ ! 1064: ! 1065: ob_scan_pci_bus(bus_num, mem_base, io_base, ! 1066: config->path, config->secondary_bus); ! 1067: ! 1068: /* bus scan updates *bus_num to last revealed pci bus number */ ! 1069: config->subordinate_bus = *bus_num; ! 1070: pci_config_write8(addr, PCI_SUBORDINATE_BUS, config->subordinate_bus); ! 1071: ! 1072: PCI_DPRINTF("bridge %s PCI bus primary=%d secondary=%d subordinate=%d\n", ! 1073: config->path, config->primary_bus, config->secondary_bus, ! 1074: config->subordinate_bus); ! 1075: ! 1076: pci_set_bus_range(config); ! 1077: } ! 1078: ! 1079: static int ob_pci_read_identification(int bus, int devnum, int fn, ! 1080: int *p_vid, int *p_did, ! 1081: uint8_t *p_class, uint8_t *p_subclass) ! 1082: { ! 1083: int vid, did; ! 1084: uint32_t ccode; ! 1085: pci_addr addr; ! 1086: ! 1087: #ifdef CONFIG_XBOX ! 1088: if (pci_xbox_blacklisted (bus, devnum, fn)) ! 1089: return; ! 1090: #endif ! 1091: addr = PCI_ADDR(bus, devnum, fn); ! 1092: vid = pci_config_read16(addr, PCI_VENDOR_ID); ! 1093: did = pci_config_read16(addr, PCI_DEVICE_ID); ! 1094: ! 1095: if (vid==0xffff || vid==0) { ! 1096: return 0; ! 1097: } ! 1098: ! 1099: if (p_vid) { ! 1100: *p_vid = vid; ! 1101: } ! 1102: ! 1103: if (p_did) { ! 1104: *p_did = did; ! 1105: } ! 1106: ! 1107: ccode = pci_config_read16(addr, PCI_CLASS_DEVICE); ! 1108: ! 1109: if (p_class) { ! 1110: *p_class = ccode >> 8; ! 1111: } ! 1112: ! 1113: if (p_subclass) { ! 1114: *p_subclass = ccode; ! 1115: } ! 1116: ! 1117: return 1; ! 1118: } ! 1119: ! 1120: static void ob_configure_pci_device(const char* parent_path, ! 1121: int *bus_num, unsigned long *mem_base, unsigned long *io_base, ! 1122: int bus, int devnum, int fn, int *p_is_multi) ! 1123: { ! 1124: int vid, did; ! 1125: unsigned int htype; ! 1126: pci_addr addr; ! 1127: pci_config_t config = {}; ! 1128: const pci_dev_t *pci_dev; ! 1129: uint8_t class, subclass, iface; ! 1130: int num_bars, rom_bar; ! 1131: ! 1132: phandle_t phandle = 0; ! 1133: int is_host_bridge = 0; ! 1134: ! 1135: if (!ob_pci_read_identification(bus, devnum, fn, &vid, &did, &class, &subclass)) { ! 1136: return; ! 1137: } ! 1138: ! 1139: addr = PCI_ADDR(bus, devnum, fn); ! 1140: iface = pci_config_read8(addr, PCI_CLASS_PROG); ! 1141: ! 1142: pci_dev = pci_find_device(class, subclass, iface, ! 1143: vid, did); ! 1144: ! 1145: PCI_DPRINTF("%x:%x.%x - %x:%x - ", bus, devnum, fn, ! 1146: vid, did); ! 1147: ! 1148: htype = pci_config_read8(addr, PCI_HEADER_TYPE); ! 1149: ! 1150: if (fn == 0) { ! 1151: if (p_is_multi) { ! 1152: *p_is_multi = htype & 0x80; ! 1153: } ! 1154: } ! 1155: ! 1156: /* stop adding host bridge accessible from it's primary bus ! 1157: PCI host bridge is to be added by host code ! 1158: */ ! 1159: if (class == PCI_BASE_CLASS_BRIDGE && ! 1160: subclass == PCI_SUBCLASS_BRIDGE_HOST) { ! 1161: is_host_bridge = 1; ! 1162: } ! 1163: ! 1164: if (is_host_bridge) { ! 1165: /* reuse device tree node */ ! 1166: PCI_DPRINTF("host bridge found - "); ! 1167: snprintf(config.path, sizeof(config.path), ! 1168: "%s", parent_path); ! 1169: } else if (pci_dev == NULL || pci_dev->name == NULL) { ! 1170: snprintf(config.path, sizeof(config.path), ! 1171: "%s/pci%x,%x", parent_path, vid, did); ! 1172: } ! 1173: else { ! 1174: snprintf(config.path, sizeof(config.path), ! 1175: "%s/%s", parent_path, pci_dev->name); ! 1176: } ! 1177: ! 1178: PCI_DPRINTF("%s - ", config.path); ! 1179: ! 1180: config.dev = addr & 0x00FFFFFF; ! 1181: ! 1182: switch (class) { ! 1183: case PCI_BASE_CLASS_BRIDGE: ! 1184: if (subclass != PCI_SUBCLASS_BRIDGE_HOST) { ! 1185: REGISTER_NAMED_NODE_PHANDLE(ob_pci_bus_node, config.path, phandle); ! 1186: } ! 1187: break; ! 1188: default: ! 1189: REGISTER_NAMED_NODE_PHANDLE(ob_pci_simple_node, config.path, phandle); ! 1190: break; ! 1191: } ! 1192: ! 1193: if (is_host_bridge) { ! 1194: phandle = find_dev(config.path); ! 1195: ! 1196: if (get_property(phandle, "vendor-id", NULL)) { ! 1197: PCI_DPRINTF("host bridge already configured\n"); ! 1198: return; ! 1199: } ! 1200: } ! 1201: ! 1202: activate_dev(phandle); ! 1203: ! 1204: if (htype & PCI_HEADER_TYPE_BRIDGE) { ! 1205: num_bars = 2; ! 1206: rom_bar = PCI_ROM_ADDRESS1; ! 1207: } else { ! 1208: num_bars = 6; ! 1209: rom_bar = PCI_ROM_ADDRESS; ! 1210: } ! 1211: ! 1212: ob_pci_configure(addr, &config, num_bars, rom_bar, ! 1213: mem_base, io_base); ! 1214: ! 1215: ob_pci_add_properties(phandle, addr, pci_dev, &config, num_bars); ! 1216: ! 1217: if (!is_host_bridge) { ! 1218: pci_set_reg(phandle, &config, num_bars); ! 1219: } ! 1220: ! 1221: /* call device-specific configuration callback */ ! 1222: if (pci_dev && pci_dev->config_cb) { ! 1223: //activate_device(config.path); ! 1224: pci_dev->config_cb(&config); ! 1225: } ! 1226: ! 1227: /* device is configured so we may move it out of scope */ ! 1228: device_end(); ! 1229: ! 1230: /* scan bus behind bridge device */ ! 1231: //if (htype & PCI_HEADER_TYPE_BRIDGE && class == PCI_BASE_CLASS_BRIDGE) { ! 1232: if ( class == PCI_BASE_CLASS_BRIDGE && ! 1233: ( subclass == PCI_SUBCLASS_BRIDGE_PCI || ! 1234: subclass == PCI_SUBCLASS_BRIDGE_HOST ) ) { ! 1235: ! 1236: if (subclass == PCI_SUBCLASS_BRIDGE_PCI) { ! 1237: /* reserve next pci bus number for this PCI bridge */ ! 1238: ++(*bus_num); ! 1239: } ! 1240: ! 1241: ob_configure_pci_bridge(addr, bus_num, mem_base, io_base, bus, &config); ! 1242: } ! 1243: } ! 1244: ! 1245: int ob_pci_init(void) ! 1246: { ! 1247: int bus, devnum, fn; ! 1248: uint8_t class, subclass; ! 1249: unsigned long mem_base, io_base; ! 1250: ! 1251: pci_config_t config = {}; /* host bridge */ ! 1252: phandle_t phandle_host; ! 1253: ! 1254: PCI_DPRINTF("Initializing PCI host bridge...\n"); ! 1255: ! 1256: activate_device("/"); ! 1257: ! 1258: /* Find all PCI bridges */ ! 1259: ! 1260: mem_base = arch->pci_mem_base; ! 1261: /* I/O ports under 0x400 are used by devices mapped at fixed ! 1262: location. */ ! 1263: io_base = arch->io_base + 0x400; ! 1264: ! 1265: bus = 0; ! 1266: ! 1267: for (devnum = 0; devnum < 32; devnum++) { ! 1268: /* scan only fn 0 */ ! 1269: fn = 0; ! 1270: ! 1271: if (!ob_pci_read_identification(bus, devnum, fn, ! 1272: 0, 0, &class, &subclass)) { ! 1273: continue; ! 1274: } ! 1275: ! 1276: if (class != PCI_BASE_CLASS_BRIDGE || subclass != PCI_SUBCLASS_BRIDGE_HOST) { ! 1277: continue; ! 1278: } ! 1279: ! 1280: /* create root node for host PCI bridge */ ! 1281: ! 1282: /* configure */ ! 1283: snprintf(config.path, sizeof(config.path), "/pci"); ! 1284: ! 1285: REGISTER_NAMED_NODE_PHANDLE(ob_pci_bus_node, config.path, phandle_host); ! 1286: ! 1287: pci_host_set_reg(phandle_host); ! 1288: ! 1289: /* update device path after changing "reg" property */ ! 1290: ob_pci_reload_device_path(phandle_host, &config); ! 1291: ! 1292: ob_configure_pci_device(config.path, &bus, &mem_base, &io_base, ! 1293: bus, devnum, fn, 0); ! 1294: ! 1295: /* we expect single host PCI bridge ! 1296: but this may be machine-specific */ ! 1297: break; ! 1298: } ! 1299: ! 1300: ! 1301: device_end(); ! 1302: ! 1303: return 0; ! 1304: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.