1*d3d2176aSDavid Gibson /* 2*d3d2176aSDavid Gibson * arch/ppc64/kernel/rtas_pci.c 3*d3d2176aSDavid Gibson * 4*d3d2176aSDavid Gibson * Copyright (C) 2001 Dave Engebretsen, IBM Corporation 5*d3d2176aSDavid Gibson * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM 6*d3d2176aSDavid Gibson * 7*d3d2176aSDavid Gibson * RTAS specific routines for PCI. 8*d3d2176aSDavid Gibson * 9*d3d2176aSDavid Gibson * Based on code from pci.c, chrp_pci.c and pSeries_pci.c 10*d3d2176aSDavid Gibson * 11*d3d2176aSDavid Gibson * This program is free software; you can redistribute it and/or modify 12*d3d2176aSDavid Gibson * it under the terms of the GNU General Public License as published by 13*d3d2176aSDavid Gibson * the Free Software Foundation; either version 2 of the License, or 14*d3d2176aSDavid Gibson * (at your option) any later version. 15*d3d2176aSDavid Gibson * 16*d3d2176aSDavid Gibson * This program is distributed in the hope that it will be useful, 17*d3d2176aSDavid Gibson * but WITHOUT ANY WARRANTY; without even the implied warranty of 18*d3d2176aSDavid Gibson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19*d3d2176aSDavid Gibson * GNU General Public License for more details. 20*d3d2176aSDavid Gibson * 21*d3d2176aSDavid Gibson * You should have received a copy of the GNU General Public License 22*d3d2176aSDavid Gibson * along with this program; if not, write to the Free Software 23*d3d2176aSDavid Gibson * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24*d3d2176aSDavid Gibson */ 25*d3d2176aSDavid Gibson 26*d3d2176aSDavid Gibson #include <linux/kernel.h> 27*d3d2176aSDavid Gibson #include <linux/threads.h> 28*d3d2176aSDavid Gibson #include <linux/pci.h> 29*d3d2176aSDavid Gibson #include <linux/string.h> 30*d3d2176aSDavid Gibson #include <linux/init.h> 31*d3d2176aSDavid Gibson #include <linux/bootmem.h> 32*d3d2176aSDavid Gibson 33*d3d2176aSDavid Gibson #include <asm/io.h> 34*d3d2176aSDavid Gibson #include <asm/pgtable.h> 35*d3d2176aSDavid Gibson #include <asm/irq.h> 36*d3d2176aSDavid Gibson #include <asm/prom.h> 37*d3d2176aSDavid Gibson #include <asm/machdep.h> 38*d3d2176aSDavid Gibson #include <asm/pci-bridge.h> 39*d3d2176aSDavid Gibson #include <asm/iommu.h> 40*d3d2176aSDavid Gibson #include <asm/rtas.h> 41*d3d2176aSDavid Gibson #include <asm/mpic.h> 42*d3d2176aSDavid Gibson #include <asm/ppc-pci.h> 43*d3d2176aSDavid Gibson 44*d3d2176aSDavid Gibson /* RTAS tokens */ 45*d3d2176aSDavid Gibson static int read_pci_config; 46*d3d2176aSDavid Gibson static int write_pci_config; 47*d3d2176aSDavid Gibson static int ibm_read_pci_config; 48*d3d2176aSDavid Gibson static int ibm_write_pci_config; 49*d3d2176aSDavid Gibson 50*d3d2176aSDavid Gibson static inline int config_access_valid(struct pci_dn *dn, int where) 51*d3d2176aSDavid Gibson { 52*d3d2176aSDavid Gibson if (where < 256) 53*d3d2176aSDavid Gibson return 1; 54*d3d2176aSDavid Gibson if (where < 4096 && dn->pci_ext_config_space) 55*d3d2176aSDavid Gibson return 1; 56*d3d2176aSDavid Gibson 57*d3d2176aSDavid Gibson return 0; 58*d3d2176aSDavid Gibson } 59*d3d2176aSDavid Gibson 60*d3d2176aSDavid Gibson static int of_device_available(struct device_node * dn) 61*d3d2176aSDavid Gibson { 62*d3d2176aSDavid Gibson char * status; 63*d3d2176aSDavid Gibson 64*d3d2176aSDavid Gibson status = get_property(dn, "status", NULL); 65*d3d2176aSDavid Gibson 66*d3d2176aSDavid Gibson if (!status) 67*d3d2176aSDavid Gibson return 1; 68*d3d2176aSDavid Gibson 69*d3d2176aSDavid Gibson if (!strcmp(status, "okay")) 70*d3d2176aSDavid Gibson return 1; 71*d3d2176aSDavid Gibson 72*d3d2176aSDavid Gibson return 0; 73*d3d2176aSDavid Gibson } 74*d3d2176aSDavid Gibson 75*d3d2176aSDavid Gibson static int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) 76*d3d2176aSDavid Gibson { 77*d3d2176aSDavid Gibson int returnval = -1; 78*d3d2176aSDavid Gibson unsigned long buid, addr; 79*d3d2176aSDavid Gibson int ret; 80*d3d2176aSDavid Gibson 81*d3d2176aSDavid Gibson if (!pdn) 82*d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 83*d3d2176aSDavid Gibson if (!config_access_valid(pdn, where)) 84*d3d2176aSDavid Gibson return PCIBIOS_BAD_REGISTER_NUMBER; 85*d3d2176aSDavid Gibson 86*d3d2176aSDavid Gibson addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | 87*d3d2176aSDavid Gibson (pdn->devfn << 8) | (where & 0xff); 88*d3d2176aSDavid Gibson buid = pdn->phb->buid; 89*d3d2176aSDavid Gibson if (buid) { 90*d3d2176aSDavid Gibson ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, 91*d3d2176aSDavid Gibson addr, BUID_HI(buid), BUID_LO(buid), size); 92*d3d2176aSDavid Gibson } else { 93*d3d2176aSDavid Gibson ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); 94*d3d2176aSDavid Gibson } 95*d3d2176aSDavid Gibson *val = returnval; 96*d3d2176aSDavid Gibson 97*d3d2176aSDavid Gibson if (ret) 98*d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 99*d3d2176aSDavid Gibson 100*d3d2176aSDavid Gibson if (returnval == EEH_IO_ERROR_VALUE(size) && 101*d3d2176aSDavid Gibson eeh_dn_check_failure (pdn->node, NULL)) 102*d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 103*d3d2176aSDavid Gibson 104*d3d2176aSDavid Gibson return PCIBIOS_SUCCESSFUL; 105*d3d2176aSDavid Gibson } 106*d3d2176aSDavid Gibson 107*d3d2176aSDavid Gibson static int rtas_pci_read_config(struct pci_bus *bus, 108*d3d2176aSDavid Gibson unsigned int devfn, 109*d3d2176aSDavid Gibson int where, int size, u32 *val) 110*d3d2176aSDavid Gibson { 111*d3d2176aSDavid Gibson struct device_node *busdn, *dn; 112*d3d2176aSDavid Gibson 113*d3d2176aSDavid Gibson if (bus->self) 114*d3d2176aSDavid Gibson busdn = pci_device_to_OF_node(bus->self); 115*d3d2176aSDavid Gibson else 116*d3d2176aSDavid Gibson busdn = bus->sysdata; /* must be a phb */ 117*d3d2176aSDavid Gibson 118*d3d2176aSDavid Gibson /* Search only direct children of the bus */ 119*d3d2176aSDavid Gibson for (dn = busdn->child; dn; dn = dn->sibling) { 120*d3d2176aSDavid Gibson struct pci_dn *pdn = PCI_DN(dn); 121*d3d2176aSDavid Gibson if (pdn && pdn->devfn == devfn 122*d3d2176aSDavid Gibson && of_device_available(dn)) 123*d3d2176aSDavid Gibson return rtas_read_config(pdn, where, size, val); 124*d3d2176aSDavid Gibson } 125*d3d2176aSDavid Gibson 126*d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 127*d3d2176aSDavid Gibson } 128*d3d2176aSDavid Gibson 129*d3d2176aSDavid Gibson int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val) 130*d3d2176aSDavid Gibson { 131*d3d2176aSDavid Gibson unsigned long buid, addr; 132*d3d2176aSDavid Gibson int ret; 133*d3d2176aSDavid Gibson 134*d3d2176aSDavid Gibson if (!pdn) 135*d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 136*d3d2176aSDavid Gibson if (!config_access_valid(pdn, where)) 137*d3d2176aSDavid Gibson return PCIBIOS_BAD_REGISTER_NUMBER; 138*d3d2176aSDavid Gibson 139*d3d2176aSDavid Gibson addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | 140*d3d2176aSDavid Gibson (pdn->devfn << 8) | (where & 0xff); 141*d3d2176aSDavid Gibson buid = pdn->phb->buid; 142*d3d2176aSDavid Gibson if (buid) { 143*d3d2176aSDavid Gibson ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, 144*d3d2176aSDavid Gibson BUID_HI(buid), BUID_LO(buid), size, (ulong) val); 145*d3d2176aSDavid Gibson } else { 146*d3d2176aSDavid Gibson ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); 147*d3d2176aSDavid Gibson } 148*d3d2176aSDavid Gibson 149*d3d2176aSDavid Gibson if (ret) 150*d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 151*d3d2176aSDavid Gibson 152*d3d2176aSDavid Gibson return PCIBIOS_SUCCESSFUL; 153*d3d2176aSDavid Gibson } 154*d3d2176aSDavid Gibson 155*d3d2176aSDavid Gibson static int rtas_pci_write_config(struct pci_bus *bus, 156*d3d2176aSDavid Gibson unsigned int devfn, 157*d3d2176aSDavid Gibson int where, int size, u32 val) 158*d3d2176aSDavid Gibson { 159*d3d2176aSDavid Gibson struct device_node *busdn, *dn; 160*d3d2176aSDavid Gibson 161*d3d2176aSDavid Gibson if (bus->self) 162*d3d2176aSDavid Gibson busdn = pci_device_to_OF_node(bus->self); 163*d3d2176aSDavid Gibson else 164*d3d2176aSDavid Gibson busdn = bus->sysdata; /* must be a phb */ 165*d3d2176aSDavid Gibson 166*d3d2176aSDavid Gibson /* Search only direct children of the bus */ 167*d3d2176aSDavid Gibson for (dn = busdn->child; dn; dn = dn->sibling) { 168*d3d2176aSDavid Gibson struct pci_dn *pdn = PCI_DN(dn); 169*d3d2176aSDavid Gibson if (pdn && pdn->devfn == devfn 170*d3d2176aSDavid Gibson && of_device_available(dn)) 171*d3d2176aSDavid Gibson return rtas_write_config(pdn, where, size, val); 172*d3d2176aSDavid Gibson } 173*d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 174*d3d2176aSDavid Gibson } 175*d3d2176aSDavid Gibson 176*d3d2176aSDavid Gibson struct pci_ops rtas_pci_ops = { 177*d3d2176aSDavid Gibson rtas_pci_read_config, 178*d3d2176aSDavid Gibson rtas_pci_write_config 179*d3d2176aSDavid Gibson }; 180*d3d2176aSDavid Gibson 181*d3d2176aSDavid Gibson int is_python(struct device_node *dev) 182*d3d2176aSDavid Gibson { 183*d3d2176aSDavid Gibson char *model = (char *)get_property(dev, "model", NULL); 184*d3d2176aSDavid Gibson 185*d3d2176aSDavid Gibson if (model && strstr(model, "Python")) 186*d3d2176aSDavid Gibson return 1; 187*d3d2176aSDavid Gibson 188*d3d2176aSDavid Gibson return 0; 189*d3d2176aSDavid Gibson } 190*d3d2176aSDavid Gibson 191*d3d2176aSDavid Gibson static int get_phb_reg_prop(struct device_node *dev, 192*d3d2176aSDavid Gibson unsigned int addr_size_words, 193*d3d2176aSDavid Gibson struct reg_property64 *reg) 194*d3d2176aSDavid Gibson { 195*d3d2176aSDavid Gibson unsigned int *ui_ptr = NULL, len; 196*d3d2176aSDavid Gibson 197*d3d2176aSDavid Gibson /* Found a PHB, now figure out where his registers are mapped. */ 198*d3d2176aSDavid Gibson ui_ptr = (unsigned int *)get_property(dev, "reg", &len); 199*d3d2176aSDavid Gibson if (ui_ptr == NULL) 200*d3d2176aSDavid Gibson return 1; 201*d3d2176aSDavid Gibson 202*d3d2176aSDavid Gibson if (addr_size_words == 1) { 203*d3d2176aSDavid Gibson reg->address = ((struct reg_property32 *)ui_ptr)->address; 204*d3d2176aSDavid Gibson reg->size = ((struct reg_property32 *)ui_ptr)->size; 205*d3d2176aSDavid Gibson } else { 206*d3d2176aSDavid Gibson *reg = *((struct reg_property64 *)ui_ptr); 207*d3d2176aSDavid Gibson } 208*d3d2176aSDavid Gibson 209*d3d2176aSDavid Gibson return 0; 210*d3d2176aSDavid Gibson } 211*d3d2176aSDavid Gibson 212*d3d2176aSDavid Gibson static void python_countermeasures(struct device_node *dev, 213*d3d2176aSDavid Gibson unsigned int addr_size_words) 214*d3d2176aSDavid Gibson { 215*d3d2176aSDavid Gibson struct reg_property64 reg_struct; 216*d3d2176aSDavid Gibson void __iomem *chip_regs; 217*d3d2176aSDavid Gibson volatile u32 val; 218*d3d2176aSDavid Gibson 219*d3d2176aSDavid Gibson if (get_phb_reg_prop(dev, addr_size_words, ®_struct)) 220*d3d2176aSDavid Gibson return; 221*d3d2176aSDavid Gibson 222*d3d2176aSDavid Gibson /* Python's register file is 1 MB in size. */ 223*d3d2176aSDavid Gibson chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); 224*d3d2176aSDavid Gibson 225*d3d2176aSDavid Gibson /* 226*d3d2176aSDavid Gibson * Firmware doesn't always clear this bit which is critical 227*d3d2176aSDavid Gibson * for good performance - Anton 228*d3d2176aSDavid Gibson */ 229*d3d2176aSDavid Gibson 230*d3d2176aSDavid Gibson #define PRG_CL_RESET_VALID 0x00010000 231*d3d2176aSDavid Gibson 232*d3d2176aSDavid Gibson val = in_be32(chip_regs + 0xf6030); 233*d3d2176aSDavid Gibson if (val & PRG_CL_RESET_VALID) { 234*d3d2176aSDavid Gibson printk(KERN_INFO "Python workaround: "); 235*d3d2176aSDavid Gibson val &= ~PRG_CL_RESET_VALID; 236*d3d2176aSDavid Gibson out_be32(chip_regs + 0xf6030, val); 237*d3d2176aSDavid Gibson /* 238*d3d2176aSDavid Gibson * We must read it back for changes to 239*d3d2176aSDavid Gibson * take effect 240*d3d2176aSDavid Gibson */ 241*d3d2176aSDavid Gibson val = in_be32(chip_regs + 0xf6030); 242*d3d2176aSDavid Gibson printk("reg0: %x\n", val); 243*d3d2176aSDavid Gibson } 244*d3d2176aSDavid Gibson 245*d3d2176aSDavid Gibson iounmap(chip_regs); 246*d3d2176aSDavid Gibson } 247*d3d2176aSDavid Gibson 248*d3d2176aSDavid Gibson void __init init_pci_config_tokens (void) 249*d3d2176aSDavid Gibson { 250*d3d2176aSDavid Gibson read_pci_config = rtas_token("read-pci-config"); 251*d3d2176aSDavid Gibson write_pci_config = rtas_token("write-pci-config"); 252*d3d2176aSDavid Gibson ibm_read_pci_config = rtas_token("ibm,read-pci-config"); 253*d3d2176aSDavid Gibson ibm_write_pci_config = rtas_token("ibm,write-pci-config"); 254*d3d2176aSDavid Gibson } 255*d3d2176aSDavid Gibson 256*d3d2176aSDavid Gibson unsigned long __devinit get_phb_buid (struct device_node *phb) 257*d3d2176aSDavid Gibson { 258*d3d2176aSDavid Gibson int addr_cells; 259*d3d2176aSDavid Gibson unsigned int *buid_vals; 260*d3d2176aSDavid Gibson unsigned int len; 261*d3d2176aSDavid Gibson unsigned long buid; 262*d3d2176aSDavid Gibson 263*d3d2176aSDavid Gibson if (ibm_read_pci_config == -1) return 0; 264*d3d2176aSDavid Gibson 265*d3d2176aSDavid Gibson /* PHB's will always be children of the root node, 266*d3d2176aSDavid Gibson * or so it is promised by the current firmware. */ 267*d3d2176aSDavid Gibson if (phb->parent == NULL) 268*d3d2176aSDavid Gibson return 0; 269*d3d2176aSDavid Gibson if (phb->parent->parent) 270*d3d2176aSDavid Gibson return 0; 271*d3d2176aSDavid Gibson 272*d3d2176aSDavid Gibson buid_vals = (unsigned int *) get_property(phb, "reg", &len); 273*d3d2176aSDavid Gibson if (buid_vals == NULL) 274*d3d2176aSDavid Gibson return 0; 275*d3d2176aSDavid Gibson 276*d3d2176aSDavid Gibson addr_cells = prom_n_addr_cells(phb); 277*d3d2176aSDavid Gibson if (addr_cells == 1) { 278*d3d2176aSDavid Gibson buid = (unsigned long) buid_vals[0]; 279*d3d2176aSDavid Gibson } else { 280*d3d2176aSDavid Gibson buid = (((unsigned long)buid_vals[0]) << 32UL) | 281*d3d2176aSDavid Gibson (((unsigned long)buid_vals[1]) & 0xffffffff); 282*d3d2176aSDavid Gibson } 283*d3d2176aSDavid Gibson return buid; 284*d3d2176aSDavid Gibson } 285*d3d2176aSDavid Gibson 286*d3d2176aSDavid Gibson static int phb_set_bus_ranges(struct device_node *dev, 287*d3d2176aSDavid Gibson struct pci_controller *phb) 288*d3d2176aSDavid Gibson { 289*d3d2176aSDavid Gibson int *bus_range; 290*d3d2176aSDavid Gibson unsigned int len; 291*d3d2176aSDavid Gibson 292*d3d2176aSDavid Gibson bus_range = (int *) get_property(dev, "bus-range", &len); 293*d3d2176aSDavid Gibson if (bus_range == NULL || len < 2 * sizeof(int)) { 294*d3d2176aSDavid Gibson return 1; 295*d3d2176aSDavid Gibson } 296*d3d2176aSDavid Gibson 297*d3d2176aSDavid Gibson phb->first_busno = bus_range[0]; 298*d3d2176aSDavid Gibson phb->last_busno = bus_range[1]; 299*d3d2176aSDavid Gibson 300*d3d2176aSDavid Gibson return 0; 301*d3d2176aSDavid Gibson } 302*d3d2176aSDavid Gibson 303*d3d2176aSDavid Gibson static int __devinit setup_phb(struct device_node *dev, 304*d3d2176aSDavid Gibson struct pci_controller *phb, 305*d3d2176aSDavid Gibson unsigned int addr_size_words) 306*d3d2176aSDavid Gibson { 307*d3d2176aSDavid Gibson pci_setup_pci_controller(phb); 308*d3d2176aSDavid Gibson 309*d3d2176aSDavid Gibson if (is_python(dev)) 310*d3d2176aSDavid Gibson python_countermeasures(dev, addr_size_words); 311*d3d2176aSDavid Gibson 312*d3d2176aSDavid Gibson if (phb_set_bus_ranges(dev, phb)) 313*d3d2176aSDavid Gibson return 1; 314*d3d2176aSDavid Gibson 315*d3d2176aSDavid Gibson phb->arch_data = dev; 316*d3d2176aSDavid Gibson phb->ops = &rtas_pci_ops; 317*d3d2176aSDavid Gibson phb->buid = get_phb_buid(dev); 318*d3d2176aSDavid Gibson 319*d3d2176aSDavid Gibson return 0; 320*d3d2176aSDavid Gibson } 321*d3d2176aSDavid Gibson 322*d3d2176aSDavid Gibson static void __devinit add_linux_pci_domain(struct device_node *dev, 323*d3d2176aSDavid Gibson struct pci_controller *phb, 324*d3d2176aSDavid Gibson struct property *of_prop) 325*d3d2176aSDavid Gibson { 326*d3d2176aSDavid Gibson memset(of_prop, 0, sizeof(struct property)); 327*d3d2176aSDavid Gibson of_prop->name = "linux,pci-domain"; 328*d3d2176aSDavid Gibson of_prop->length = sizeof(phb->global_number); 329*d3d2176aSDavid Gibson of_prop->value = (unsigned char *)&of_prop[1]; 330*d3d2176aSDavid Gibson memcpy(of_prop->value, &phb->global_number, sizeof(phb->global_number)); 331*d3d2176aSDavid Gibson prom_add_property(dev, of_prop); 332*d3d2176aSDavid Gibson } 333*d3d2176aSDavid Gibson 334*d3d2176aSDavid Gibson static struct pci_controller * __init alloc_phb(struct device_node *dev, 335*d3d2176aSDavid Gibson unsigned int addr_size_words) 336*d3d2176aSDavid Gibson { 337*d3d2176aSDavid Gibson struct pci_controller *phb; 338*d3d2176aSDavid Gibson struct property *of_prop; 339*d3d2176aSDavid Gibson 340*d3d2176aSDavid Gibson phb = alloc_bootmem(sizeof(struct pci_controller)); 341*d3d2176aSDavid Gibson if (phb == NULL) 342*d3d2176aSDavid Gibson return NULL; 343*d3d2176aSDavid Gibson 344*d3d2176aSDavid Gibson of_prop = alloc_bootmem(sizeof(struct property) + 345*d3d2176aSDavid Gibson sizeof(phb->global_number)); 346*d3d2176aSDavid Gibson if (!of_prop) 347*d3d2176aSDavid Gibson return NULL; 348*d3d2176aSDavid Gibson 349*d3d2176aSDavid Gibson if (setup_phb(dev, phb, addr_size_words)) 350*d3d2176aSDavid Gibson return NULL; 351*d3d2176aSDavid Gibson 352*d3d2176aSDavid Gibson add_linux_pci_domain(dev, phb, of_prop); 353*d3d2176aSDavid Gibson 354*d3d2176aSDavid Gibson return phb; 355*d3d2176aSDavid Gibson } 356*d3d2176aSDavid Gibson 357*d3d2176aSDavid Gibson static struct pci_controller * __devinit alloc_phb_dynamic(struct device_node *dev, unsigned int addr_size_words) 358*d3d2176aSDavid Gibson { 359*d3d2176aSDavid Gibson struct pci_controller *phb; 360*d3d2176aSDavid Gibson 361*d3d2176aSDavid Gibson phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), 362*d3d2176aSDavid Gibson GFP_KERNEL); 363*d3d2176aSDavid Gibson if (phb == NULL) 364*d3d2176aSDavid Gibson return NULL; 365*d3d2176aSDavid Gibson 366*d3d2176aSDavid Gibson if (setup_phb(dev, phb, addr_size_words)) 367*d3d2176aSDavid Gibson return NULL; 368*d3d2176aSDavid Gibson 369*d3d2176aSDavid Gibson phb->is_dynamic = 1; 370*d3d2176aSDavid Gibson 371*d3d2176aSDavid Gibson /* TODO: linux,pci-domain? */ 372*d3d2176aSDavid Gibson 373*d3d2176aSDavid Gibson return phb; 374*d3d2176aSDavid Gibson } 375*d3d2176aSDavid Gibson 376*d3d2176aSDavid Gibson unsigned long __init find_and_init_phbs(void) 377*d3d2176aSDavid Gibson { 378*d3d2176aSDavid Gibson struct device_node *node; 379*d3d2176aSDavid Gibson struct pci_controller *phb; 380*d3d2176aSDavid Gibson unsigned int root_size_cells = 0; 381*d3d2176aSDavid Gibson unsigned int index; 382*d3d2176aSDavid Gibson unsigned int *opprop = NULL; 383*d3d2176aSDavid Gibson struct device_node *root = of_find_node_by_path("/"); 384*d3d2176aSDavid Gibson 385*d3d2176aSDavid Gibson if (ppc64_interrupt_controller == IC_OPEN_PIC) { 386*d3d2176aSDavid Gibson opprop = (unsigned int *)get_property(root, 387*d3d2176aSDavid Gibson "platform-open-pic", NULL); 388*d3d2176aSDavid Gibson } 389*d3d2176aSDavid Gibson 390*d3d2176aSDavid Gibson root_size_cells = prom_n_size_cells(root); 391*d3d2176aSDavid Gibson 392*d3d2176aSDavid Gibson index = 0; 393*d3d2176aSDavid Gibson 394*d3d2176aSDavid Gibson for (node = of_get_next_child(root, NULL); 395*d3d2176aSDavid Gibson node != NULL; 396*d3d2176aSDavid Gibson node = of_get_next_child(root, node)) { 397*d3d2176aSDavid Gibson if (node->type == NULL || strcmp(node->type, "pci") != 0) 398*d3d2176aSDavid Gibson continue; 399*d3d2176aSDavid Gibson 400*d3d2176aSDavid Gibson phb = alloc_phb(node, root_size_cells); 401*d3d2176aSDavid Gibson if (!phb) 402*d3d2176aSDavid Gibson continue; 403*d3d2176aSDavid Gibson 404*d3d2176aSDavid Gibson pci_process_bridge_OF_ranges(phb, node, 0); 405*d3d2176aSDavid Gibson pci_setup_phb_io(phb, index == 0); 406*d3d2176aSDavid Gibson #ifdef CONFIG_PPC_PSERIES 407*d3d2176aSDavid Gibson if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) { 408*d3d2176aSDavid Gibson int addr = root_size_cells * (index + 2) - 1; 409*d3d2176aSDavid Gibson mpic_assign_isu(pSeries_mpic, index, opprop[addr]); 410*d3d2176aSDavid Gibson } 411*d3d2176aSDavid Gibson #endif 412*d3d2176aSDavid Gibson index++; 413*d3d2176aSDavid Gibson } 414*d3d2176aSDavid Gibson 415*d3d2176aSDavid Gibson of_node_put(root); 416*d3d2176aSDavid Gibson pci_devs_phb_init(); 417*d3d2176aSDavid Gibson 418*d3d2176aSDavid Gibson /* 419*d3d2176aSDavid Gibson * pci_probe_only and pci_assign_all_buses can be set via properties 420*d3d2176aSDavid Gibson * in chosen. 421*d3d2176aSDavid Gibson */ 422*d3d2176aSDavid Gibson if (of_chosen) { 423*d3d2176aSDavid Gibson int *prop; 424*d3d2176aSDavid Gibson 425*d3d2176aSDavid Gibson prop = (int *)get_property(of_chosen, "linux,pci-probe-only", 426*d3d2176aSDavid Gibson NULL); 427*d3d2176aSDavid Gibson if (prop) 428*d3d2176aSDavid Gibson pci_probe_only = *prop; 429*d3d2176aSDavid Gibson 430*d3d2176aSDavid Gibson prop = (int *)get_property(of_chosen, 431*d3d2176aSDavid Gibson "linux,pci-assign-all-buses", NULL); 432*d3d2176aSDavid Gibson if (prop) 433*d3d2176aSDavid Gibson pci_assign_all_buses = *prop; 434*d3d2176aSDavid Gibson } 435*d3d2176aSDavid Gibson 436*d3d2176aSDavid Gibson return 0; 437*d3d2176aSDavid Gibson } 438*d3d2176aSDavid Gibson 439*d3d2176aSDavid Gibson struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) 440*d3d2176aSDavid Gibson { 441*d3d2176aSDavid Gibson struct device_node *root = of_find_node_by_path("/"); 442*d3d2176aSDavid Gibson unsigned int root_size_cells = 0; 443*d3d2176aSDavid Gibson struct pci_controller *phb; 444*d3d2176aSDavid Gibson int primary; 445*d3d2176aSDavid Gibson 446*d3d2176aSDavid Gibson root_size_cells = prom_n_size_cells(root); 447*d3d2176aSDavid Gibson 448*d3d2176aSDavid Gibson primary = list_empty(&hose_list); 449*d3d2176aSDavid Gibson phb = alloc_phb_dynamic(dn, root_size_cells); 450*d3d2176aSDavid Gibson if (!phb) 451*d3d2176aSDavid Gibson return NULL; 452*d3d2176aSDavid Gibson 453*d3d2176aSDavid Gibson pci_process_bridge_OF_ranges(phb, dn, primary); 454*d3d2176aSDavid Gibson 455*d3d2176aSDavid Gibson pci_setup_phb_io_dynamic(phb, primary); 456*d3d2176aSDavid Gibson of_node_put(root); 457*d3d2176aSDavid Gibson 458*d3d2176aSDavid Gibson pci_devs_phb_init_dynamic(phb); 459*d3d2176aSDavid Gibson scan_phb(phb); 460*d3d2176aSDavid Gibson 461*d3d2176aSDavid Gibson return phb; 462*d3d2176aSDavid Gibson } 463*d3d2176aSDavid Gibson EXPORT_SYMBOL(init_phb_dynamic); 464*d3d2176aSDavid Gibson 465*d3d2176aSDavid Gibson /* RPA-specific bits for removing PHBs */ 466*d3d2176aSDavid Gibson int pcibios_remove_root_bus(struct pci_controller *phb) 467*d3d2176aSDavid Gibson { 468*d3d2176aSDavid Gibson struct pci_bus *b = phb->bus; 469*d3d2176aSDavid Gibson struct resource *res; 470*d3d2176aSDavid Gibson int rc, i; 471*d3d2176aSDavid Gibson 472*d3d2176aSDavid Gibson res = b->resource[0]; 473*d3d2176aSDavid Gibson if (!res->flags) { 474*d3d2176aSDavid Gibson printk(KERN_ERR "%s: no IO resource for PHB %s\n", __FUNCTION__, 475*d3d2176aSDavid Gibson b->name); 476*d3d2176aSDavid Gibson return 1; 477*d3d2176aSDavid Gibson } 478*d3d2176aSDavid Gibson 479*d3d2176aSDavid Gibson rc = unmap_bus_range(b); 480*d3d2176aSDavid Gibson if (rc) { 481*d3d2176aSDavid Gibson printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", 482*d3d2176aSDavid Gibson __FUNCTION__, b->name); 483*d3d2176aSDavid Gibson return 1; 484*d3d2176aSDavid Gibson } 485*d3d2176aSDavid Gibson 486*d3d2176aSDavid Gibson if (release_resource(res)) { 487*d3d2176aSDavid Gibson printk(KERN_ERR "%s: failed to release IO on bus %s\n", 488*d3d2176aSDavid Gibson __FUNCTION__, b->name); 489*d3d2176aSDavid Gibson return 1; 490*d3d2176aSDavid Gibson } 491*d3d2176aSDavid Gibson 492*d3d2176aSDavid Gibson for (i = 1; i < 3; ++i) { 493*d3d2176aSDavid Gibson res = b->resource[i]; 494*d3d2176aSDavid Gibson if (!res->flags && i == 0) { 495*d3d2176aSDavid Gibson printk(KERN_ERR "%s: no MEM resource for PHB %s\n", 496*d3d2176aSDavid Gibson __FUNCTION__, b->name); 497*d3d2176aSDavid Gibson return 1; 498*d3d2176aSDavid Gibson } 499*d3d2176aSDavid Gibson if (res->flags && release_resource(res)) { 500*d3d2176aSDavid Gibson printk(KERN_ERR 501*d3d2176aSDavid Gibson "%s: failed to release IO %d on bus %s\n", 502*d3d2176aSDavid Gibson __FUNCTION__, i, b->name); 503*d3d2176aSDavid Gibson return 1; 504*d3d2176aSDavid Gibson } 505*d3d2176aSDavid Gibson } 506*d3d2176aSDavid Gibson 507*d3d2176aSDavid Gibson list_del(&phb->list_node); 508*d3d2176aSDavid Gibson if (phb->is_dynamic) 509*d3d2176aSDavid Gibson kfree(phb); 510*d3d2176aSDavid Gibson 511*d3d2176aSDavid Gibson return 0; 512*d3d2176aSDavid Gibson } 513*d3d2176aSDavid Gibson EXPORT_SYMBOL(pcibios_remove_root_bus); 514