/****************************************************************** * Find all PHBs in the system and initialize a set of data * structures to represent them. ******************************************************************/ unsigned long __init find_and_init_phbs(void) { struct device_node *Pci_Node; struct pci_controller *phb; unsigned int root_addr_size_words = 0, this_addr_size_words = 0; unsigned int this_addr_count = 0, range_stride; unsigned int *ui_ptr = NULL, *ranges; char *model; struct pci_range64 range; struct resource *res; unsigned int memno, rlen, i, index; unsigned int *opprop; int has_isa = 0; PPCDBG(PPCDBG_PHBINIT, "find_and_init_phbs\n"); read_pci_config = rtas_token("read-pci-config"); write_pci_config = rtas_token("write-pci-config"); ibm_read_pci_config = rtas_token("ibm,read-pci-config"); ibm_write_pci_config = rtas_token("ibm,write-pci-config"); if (naca->interrupt_controller == IC_OPEN_PIC) { opprop = (unsigned int *)get_property(find_path_device("/"), "platform-open-pic", NULL); } /* Get the root address word size. */ ui_ptr = (unsigned int *) get_property(find_path_device("/"), "#size-cells", NULL); if (ui_ptr) { root_addr_size_words = *ui_ptr; } else { PPCDBG(PPCDBG_PHBINIT, "\tget #size-cells failed.\n"); return(-1); } if (find_type_devices("isa")) { has_isa = 1; PPCDBG(PPCDBG_PHBINIT, "\tFound an ISA bus.\n"); } index = 0; /****************************************************************** * Find all PHB devices and create an object for them. ******************************************************************/ for (Pci_Node = find_devices("pci"); Pci_Node != NULL; Pci_Node = Pci_Node->next) { model = (char *) get_property(Pci_Node, "model", NULL); if (model != NULL) { phb = alloc_phb(Pci_Node, model, root_addr_size_words); if (phb == NULL) return(-1); } else { continue; } /* Get this node's address word size. */ ui_ptr = (unsigned int *) get_property(Pci_Node, "#size-cells", NULL); if (ui_ptr) this_addr_size_words = *ui_ptr; else this_addr_size_words = 1; /* Get this node's address word count. */ ui_ptr = (unsigned int *) get_property(Pci_Node, "#address-cells", NULL); if (ui_ptr) this_addr_count = *ui_ptr; else this_addr_count = 3; range_stride = this_addr_count + root_addr_size_words + this_addr_size_words; memno = 0; phb->io_base_phys = 0; ranges = (unsigned int *) get_property(Pci_Node, "ranges", &rlen); PPCDBG(PPCDBG_PHBINIT, "\trange_stride = 0x%lx, rlen = 0x%x\n", range_stride, rlen); for (i = 0; i < (rlen/sizeof(*ranges)); i+=range_stride) { /* Put the PCI addr part of the current element into a * '64' struct. */ range = *((struct pci_range64 *)(ranges + i)); /* If this is a '32' element, map into a 64 struct. */ if ((range_stride * sizeof(int)) == sizeof(struct pci_range32)) { range.parent_addr = (unsigned long)(*(ranges + i + 3)); range.size = (((unsigned long)(*(ranges + i + 4)))<<32) | (*(ranges + i + 5)); } else { range.parent_addr = (((unsigned long)(*(ranges + i + 3)))<<32) | (*(ranges + i + 4)); range.size = (((unsigned long)(*(ranges + i + 5)))<<32) | (*(ranges + i + 6)); } PPCDBG(PPCDBG_PHBINIT, "\trange.parent_addr = 0x%lx\n", range.parent_addr); PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.hi = 0x%lx\n", range.child_addr.a_hi); PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.mid = 0x%lx\n", range.child_addr.a_mid); PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.lo = 0x%lx\n", range.child_addr.a_lo); PPCDBG(PPCDBG_PHBINIT, "\trange.size = 0x%lx\n", range.size); res = NULL; switch ((range.child_addr.a_hi >> 24) & 0x3) { case 1: /* I/O space */ PPCDBG(PPCDBG_PHBINIT, "\tIO Space\n"); phb->io_base_phys = range.parent_addr; res = &phb->io_resource; res->name = Pci_Node->full_name; res->flags = IORESOURCE_IO; phb->io_base_virt = __ioremap(phb->io_base_phys, range.size, _PAGE_NO_CACHE); if (!pci_io_base) { pci_io_base = (unsigned long)phb->io_base_virt; if (has_isa) isa_io_base = pci_io_base; } res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo)); res->start += (unsigned long)phb->io_base_virt - pci_io_base; res->end = res->start + range.size - 1; res->parent = NULL; res->sibling = NULL; res->child = NULL; phb->pci_io_offset = range.parent_addr - ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo)); PPCDBG(PPCDBG_PHBINIT, "\tpci_io_offset = 0x%lx\n", phb->pci_io_offset); break; case 2: /* mem space */ PPCDBG(PPCDBG_PHBINIT, "\tMem Space\n"); phb->pci_mem_offset = range.parent_addr - ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo)); PPCDBG(PPCDBG_PHBINIT, "\tpci_mem_offset = 0x%lx\n", phb->pci_mem_offset); if (memno < sizeof(phb->mem_resources)/sizeof(phb->mem_resources[0])) { res = &(phb->mem_resources[memno]); ++memno; res->name = Pci_Node->full_name; res->flags = IORESOURCE_MEM; res->start = range.parent_addr; res->end = range.parent_addr + range.size - 1; res->parent = NULL; res->sibling = NULL; res->child = NULL; } break; } } PPCDBG(PPCDBG_PHBINIT, "\tphb->io_base_phys = 0x%lx\n", phb->io_base_phys); PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%lx\n", phb->pci_mem_offset); if (naca->interrupt_controller == IC_OPEN_PIC) { int addr = root_addr_size_words * (index + 2) - 1; openpic_setup_ISU(index, opprop[addr]); } index++; } pci_devs_phb_init(); return 0; /*Success */ }
void __init chrp_find_bridges(void) { struct device_node *dev; int *bus_range; int len, index = -1; struct pci_controller *hose; volatile unsigned char *cfg; unsigned int *dma; char *model, *machine; int is_longtrail = 0, is_mot = 0; struct device_node *root = find_path_device("/"); #ifdef CONFIG_POWER3 unsigned int *opprop = (unsigned int *) get_property(root, "platform-open-pic", NULL); int i; #endif /* * The PCI host bridge nodes on some machines don't have * properties to adequately identify them, so we have to * look at what sort of machine this is as well. */ machine = get_property(root, "model", NULL); if (machine != NULL) { is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0; is_mot = strncmp(machine, "MOT", 3) == 0; } for (dev = root->child; dev != NULL; dev = dev->sibling) { if (dev->type == NULL || strcmp(dev->type, "pci") != 0) continue; ++index; /* The GG2 bridge on the LongTrail doesn't have an address */ if (dev->n_addrs < 1 && !is_longtrail) { printk(KERN_WARNING "Can't use %s: no address\n", dev->full_name); continue; } bus_range = (int *) get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s\n", dev->full_name); continue; } if (bus_range[1] == bus_range[0]) printk(KERN_INFO "PCI bus %d", bus_range[0]); else printk(KERN_INFO "PCI buses %d..%d", bus_range[0], bus_range[1]); printk(" controlled by %s", dev->type); if (dev->n_addrs > 0) printk(" at %x", dev->addrs[0].address); printk("\n"); hose = pcibios_alloc_controller(); if (!hose) { printk("Can't allocate PCI controller structure for %s\n", dev->full_name); continue; } hose->arch_data = dev; hose->first_busno = bus_range[0]; hose->last_busno = bus_range[1]; model = get_property(dev, "model", NULL); if (model == NULL) model = "<none>"; if (device_is_compatible(dev, "IBM,python")) { hose->ops = &python_pci_ops; cfg = ioremap(dev->addrs[0].address + 0xf8000, 0x20); hose->cfg_addr = (volatile unsigned int *) cfg; hose->cfg_data = cfg + 0x10; } else if (is_mot || strncmp(model, "Motorola, Grackle", 17) == 0) { setup_grackle(hose); } else if (is_longtrail) { hose->ops = &gg2_pci_ops; gg2_pci_config_base = (unsigned long) ioremap(GG2_PCI_CONFIG_BASE, 0x80000); } else { printk("No methods for %s (model %s), using RTAS\n", dev->full_name, model); hose->ops = &rtas_pci_ops; } pci_process_bridge_OF_ranges(hose, dev, index == 0); #ifdef CONFIG_POWER3 if (opprop != NULL) { i = prom_n_addr_cells(root) * (index + 2) - 1; openpic_setup_ISU(index, opprop[i]); } #endif /* CONFIG_POWER3 */ /* check the first bridge for a property that we can use to set pci_dram_offset */ dma = (unsigned int *) get_property(dev, "ibm,dma-ranges", &len); if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) { pci_dram_offset = dma[2] - dma[3]; printk("pci_dram_offset = %lx\n", pci_dram_offset); } } ppc_md.pcibios_fixup = chrp_pcibios_fixup; }