1d3d2176aSDavid Gibson /* 2d3d2176aSDavid Gibson * Copyright (C) 2001 Dave Engebretsen, IBM Corporation 3d3d2176aSDavid Gibson * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM 4d3d2176aSDavid Gibson * 5d3d2176aSDavid Gibson * RTAS specific routines for PCI. 6d3d2176aSDavid Gibson * 7d3d2176aSDavid Gibson * Based on code from pci.c, chrp_pci.c and pSeries_pci.c 8d3d2176aSDavid Gibson * 9d3d2176aSDavid Gibson * This program is free software; you can redistribute it and/or modify 10d3d2176aSDavid Gibson * it under the terms of the GNU General Public License as published by 11d3d2176aSDavid Gibson * the Free Software Foundation; either version 2 of the License, or 12d3d2176aSDavid Gibson * (at your option) any later version. 13d3d2176aSDavid Gibson * 14d3d2176aSDavid Gibson * This program is distributed in the hope that it will be useful, 15d3d2176aSDavid Gibson * but WITHOUT ANY WARRANTY; without even the implied warranty of 16d3d2176aSDavid Gibson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17d3d2176aSDavid Gibson * GNU General Public License for more details. 18d3d2176aSDavid Gibson * 19d3d2176aSDavid Gibson * You should have received a copy of the GNU General Public License 20d3d2176aSDavid Gibson * along with this program; if not, write to the Free Software 21d3d2176aSDavid Gibson * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22d3d2176aSDavid Gibson */ 23d3d2176aSDavid Gibson 24d3d2176aSDavid Gibson #include <linux/kernel.h> 25d3d2176aSDavid Gibson #include <linux/threads.h> 26d3d2176aSDavid Gibson #include <linux/pci.h> 27d3d2176aSDavid Gibson #include <linux/string.h> 28d3d2176aSDavid Gibson #include <linux/init.h> 29d3d2176aSDavid Gibson #include <linux/bootmem.h> 30d3d2176aSDavid Gibson 31d3d2176aSDavid Gibson #include <asm/io.h> 32d3d2176aSDavid Gibson #include <asm/pgtable.h> 33d3d2176aSDavid Gibson #include <asm/irq.h> 34d3d2176aSDavid Gibson #include <asm/prom.h> 35d3d2176aSDavid Gibson #include <asm/machdep.h> 36d3d2176aSDavid Gibson #include <asm/pci-bridge.h> 37d3d2176aSDavid Gibson #include <asm/iommu.h> 38d3d2176aSDavid Gibson #include <asm/rtas.h> 39d3d2176aSDavid Gibson #include <asm/mpic.h> 40d3d2176aSDavid Gibson #include <asm/ppc-pci.h> 41d3d2176aSDavid Gibson 42d3d2176aSDavid Gibson /* RTAS tokens */ 43d3d2176aSDavid Gibson static int read_pci_config; 44d3d2176aSDavid Gibson static int write_pci_config; 45d3d2176aSDavid Gibson static int ibm_read_pci_config; 46d3d2176aSDavid Gibson static int ibm_write_pci_config; 47d3d2176aSDavid Gibson 48d3d2176aSDavid Gibson static inline int config_access_valid(struct pci_dn *dn, int where) 49d3d2176aSDavid Gibson { 50d3d2176aSDavid Gibson if (where < 256) 51d3d2176aSDavid Gibson return 1; 52d3d2176aSDavid Gibson if (where < 4096 && dn->pci_ext_config_space) 53d3d2176aSDavid Gibson return 1; 54d3d2176aSDavid Gibson 55d3d2176aSDavid Gibson return 0; 56d3d2176aSDavid Gibson } 57d3d2176aSDavid Gibson 58d3d2176aSDavid Gibson static int of_device_available(struct device_node * dn) 59d3d2176aSDavid Gibson { 60a7f67bdfSJeremy Kerr const char *status; 61d3d2176aSDavid Gibson 62d3d2176aSDavid Gibson status = get_property(dn, "status", NULL); 63d3d2176aSDavid Gibson 64d3d2176aSDavid Gibson if (!status) 65d3d2176aSDavid Gibson return 1; 66d3d2176aSDavid Gibson 67d3d2176aSDavid Gibson if (!strcmp(status, "okay")) 68d3d2176aSDavid Gibson return 1; 69d3d2176aSDavid Gibson 70d3d2176aSDavid Gibson return 0; 71d3d2176aSDavid Gibson } 72d3d2176aSDavid Gibson 737684b40cSLinas Vepstas int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) 74d3d2176aSDavid Gibson { 75d3d2176aSDavid Gibson int returnval = -1; 76d3d2176aSDavid Gibson unsigned long buid, addr; 77d3d2176aSDavid Gibson int ret; 78d3d2176aSDavid Gibson 79d3d2176aSDavid Gibson if (!pdn) 80d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 81d3d2176aSDavid Gibson if (!config_access_valid(pdn, where)) 82d3d2176aSDavid Gibson return PCIBIOS_BAD_REGISTER_NUMBER; 83d3d2176aSDavid Gibson 84*6f3d5d3cSMichael Ellerman addr = rtas_config_addr(pdn->busno, pdn->devfn, where); 85d3d2176aSDavid Gibson buid = pdn->phb->buid; 86d3d2176aSDavid Gibson if (buid) { 87d3d2176aSDavid Gibson ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, 88d3d2176aSDavid Gibson addr, BUID_HI(buid), BUID_LO(buid), size); 89d3d2176aSDavid Gibson } else { 90d3d2176aSDavid Gibson ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); 91d3d2176aSDavid Gibson } 92d3d2176aSDavid Gibson *val = returnval; 93d3d2176aSDavid Gibson 94d3d2176aSDavid Gibson if (ret) 95d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 96d3d2176aSDavid Gibson 97d3d2176aSDavid Gibson if (returnval == EEH_IO_ERROR_VALUE(size) && 98d3d2176aSDavid Gibson eeh_dn_check_failure (pdn->node, NULL)) 99d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 100d3d2176aSDavid Gibson 101d3d2176aSDavid Gibson return PCIBIOS_SUCCESSFUL; 102d3d2176aSDavid Gibson } 103d3d2176aSDavid Gibson 104d3d2176aSDavid Gibson static int rtas_pci_read_config(struct pci_bus *bus, 105d3d2176aSDavid Gibson unsigned int devfn, 106d3d2176aSDavid Gibson int where, int size, u32 *val) 107d3d2176aSDavid Gibson { 108d3d2176aSDavid Gibson struct device_node *busdn, *dn; 109d3d2176aSDavid Gibson 110d3d2176aSDavid Gibson if (bus->self) 111d3d2176aSDavid Gibson busdn = pci_device_to_OF_node(bus->self); 112d3d2176aSDavid Gibson else 113d3d2176aSDavid Gibson busdn = bus->sysdata; /* must be a phb */ 114d3d2176aSDavid Gibson 115d3d2176aSDavid Gibson /* Search only direct children of the bus */ 116d3d2176aSDavid Gibson for (dn = busdn->child; dn; dn = dn->sibling) { 117d3d2176aSDavid Gibson struct pci_dn *pdn = PCI_DN(dn); 118d3d2176aSDavid Gibson if (pdn && pdn->devfn == devfn 119d3d2176aSDavid Gibson && of_device_available(dn)) 120d3d2176aSDavid Gibson return rtas_read_config(pdn, where, size, val); 121d3d2176aSDavid Gibson } 122d3d2176aSDavid Gibson 123d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 124d3d2176aSDavid Gibson } 125d3d2176aSDavid Gibson 126d3d2176aSDavid Gibson int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val) 127d3d2176aSDavid Gibson { 128d3d2176aSDavid Gibson unsigned long buid, addr; 129d3d2176aSDavid Gibson int ret; 130d3d2176aSDavid Gibson 131d3d2176aSDavid Gibson if (!pdn) 132d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 133d3d2176aSDavid Gibson if (!config_access_valid(pdn, where)) 134d3d2176aSDavid Gibson return PCIBIOS_BAD_REGISTER_NUMBER; 135d3d2176aSDavid Gibson 136*6f3d5d3cSMichael Ellerman addr = rtas_config_addr(pdn->busno, pdn->devfn, where); 137d3d2176aSDavid Gibson buid = pdn->phb->buid; 138d3d2176aSDavid Gibson if (buid) { 139d3d2176aSDavid Gibson ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, 140d3d2176aSDavid Gibson BUID_HI(buid), BUID_LO(buid), size, (ulong) val); 141d3d2176aSDavid Gibson } else { 142d3d2176aSDavid Gibson ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); 143d3d2176aSDavid Gibson } 144d3d2176aSDavid Gibson 145d3d2176aSDavid Gibson if (ret) 146d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 147d3d2176aSDavid Gibson 148d3d2176aSDavid Gibson return PCIBIOS_SUCCESSFUL; 149d3d2176aSDavid Gibson } 150d3d2176aSDavid Gibson 151d3d2176aSDavid Gibson static int rtas_pci_write_config(struct pci_bus *bus, 152d3d2176aSDavid Gibson unsigned int devfn, 153d3d2176aSDavid Gibson int where, int size, u32 val) 154d3d2176aSDavid Gibson { 155d3d2176aSDavid Gibson struct device_node *busdn, *dn; 156d3d2176aSDavid Gibson 157d3d2176aSDavid Gibson if (bus->self) 158d3d2176aSDavid Gibson busdn = pci_device_to_OF_node(bus->self); 159d3d2176aSDavid Gibson else 160d3d2176aSDavid Gibson busdn = bus->sysdata; /* must be a phb */ 161d3d2176aSDavid Gibson 162d3d2176aSDavid Gibson /* Search only direct children of the bus */ 163d3d2176aSDavid Gibson for (dn = busdn->child; dn; dn = dn->sibling) { 164d3d2176aSDavid Gibson struct pci_dn *pdn = PCI_DN(dn); 165d3d2176aSDavid Gibson if (pdn && pdn->devfn == devfn 166d3d2176aSDavid Gibson && of_device_available(dn)) 167d3d2176aSDavid Gibson return rtas_write_config(pdn, where, size, val); 168d3d2176aSDavid Gibson } 169d3d2176aSDavid Gibson return PCIBIOS_DEVICE_NOT_FOUND; 170d3d2176aSDavid Gibson } 171d3d2176aSDavid Gibson 172d3d2176aSDavid Gibson struct pci_ops rtas_pci_ops = { 173d3d2176aSDavid Gibson rtas_pci_read_config, 174d3d2176aSDavid Gibson rtas_pci_write_config 175d3d2176aSDavid Gibson }; 176d3d2176aSDavid Gibson 177d3d2176aSDavid Gibson int is_python(struct device_node *dev) 178d3d2176aSDavid Gibson { 179a7f67bdfSJeremy Kerr const char *model = get_property(dev, "model", NULL); 180d3d2176aSDavid Gibson 181d3d2176aSDavid Gibson if (model && strstr(model, "Python")) 182d3d2176aSDavid Gibson return 1; 183d3d2176aSDavid Gibson 184d3d2176aSDavid Gibson return 0; 185d3d2176aSDavid Gibson } 186d3d2176aSDavid Gibson 187cc5d0189SBenjamin Herrenschmidt static void python_countermeasures(struct device_node *dev) 188d3d2176aSDavid Gibson { 189cc5d0189SBenjamin Herrenschmidt struct resource registers; 190d3d2176aSDavid Gibson void __iomem *chip_regs; 191d3d2176aSDavid Gibson volatile u32 val; 192d3d2176aSDavid Gibson 193cc5d0189SBenjamin Herrenschmidt if (of_address_to_resource(dev, 0, ®isters)) { 194cc5d0189SBenjamin Herrenschmidt printk(KERN_ERR "Can't get address for Python workarounds !\n"); 195d3d2176aSDavid Gibson return; 196cc5d0189SBenjamin Herrenschmidt } 197d3d2176aSDavid Gibson 198d3d2176aSDavid Gibson /* Python's register file is 1 MB in size. */ 199cc5d0189SBenjamin Herrenschmidt chip_regs = ioremap(registers.start & ~(0xfffffUL), 0x100000); 200d3d2176aSDavid Gibson 201d3d2176aSDavid Gibson /* 202d3d2176aSDavid Gibson * Firmware doesn't always clear this bit which is critical 203d3d2176aSDavid Gibson * for good performance - Anton 204d3d2176aSDavid Gibson */ 205d3d2176aSDavid Gibson 206d3d2176aSDavid Gibson #define PRG_CL_RESET_VALID 0x00010000 207d3d2176aSDavid Gibson 208d3d2176aSDavid Gibson val = in_be32(chip_regs + 0xf6030); 209d3d2176aSDavid Gibson if (val & PRG_CL_RESET_VALID) { 210d3d2176aSDavid Gibson printk(KERN_INFO "Python workaround: "); 211d3d2176aSDavid Gibson val &= ~PRG_CL_RESET_VALID; 212d3d2176aSDavid Gibson out_be32(chip_regs + 0xf6030, val); 213d3d2176aSDavid Gibson /* 214d3d2176aSDavid Gibson * We must read it back for changes to 215d3d2176aSDavid Gibson * take effect 216d3d2176aSDavid Gibson */ 217d3d2176aSDavid Gibson val = in_be32(chip_regs + 0xf6030); 218d3d2176aSDavid Gibson printk("reg0: %x\n", val); 219d3d2176aSDavid Gibson } 220d3d2176aSDavid Gibson 221d3d2176aSDavid Gibson iounmap(chip_regs); 222d3d2176aSDavid Gibson } 223d3d2176aSDavid Gibson 224d3d2176aSDavid Gibson void __init init_pci_config_tokens (void) 225d3d2176aSDavid Gibson { 226d3d2176aSDavid Gibson read_pci_config = rtas_token("read-pci-config"); 227d3d2176aSDavid Gibson write_pci_config = rtas_token("write-pci-config"); 228d3d2176aSDavid Gibson ibm_read_pci_config = rtas_token("ibm,read-pci-config"); 229d3d2176aSDavid Gibson ibm_write_pci_config = rtas_token("ibm,write-pci-config"); 230d3d2176aSDavid Gibson } 231d3d2176aSDavid Gibson 232d3d2176aSDavid Gibson unsigned long __devinit get_phb_buid (struct device_node *phb) 233d3d2176aSDavid Gibson { 234d3d2176aSDavid Gibson int addr_cells; 235a7f67bdfSJeremy Kerr const unsigned int *buid_vals; 236d3d2176aSDavid Gibson unsigned int len; 237d3d2176aSDavid Gibson unsigned long buid; 238d3d2176aSDavid Gibson 239d3d2176aSDavid Gibson if (ibm_read_pci_config == -1) return 0; 240d3d2176aSDavid Gibson 241d3d2176aSDavid Gibson /* PHB's will always be children of the root node, 242d3d2176aSDavid Gibson * or so it is promised by the current firmware. */ 243d3d2176aSDavid Gibson if (phb->parent == NULL) 244d3d2176aSDavid Gibson return 0; 245d3d2176aSDavid Gibson if (phb->parent->parent) 246d3d2176aSDavid Gibson return 0; 247d3d2176aSDavid Gibson 248a7f67bdfSJeremy Kerr buid_vals = get_property(phb, "reg", &len); 249d3d2176aSDavid Gibson if (buid_vals == NULL) 250d3d2176aSDavid Gibson return 0; 251d3d2176aSDavid Gibson 252d3d2176aSDavid Gibson addr_cells = prom_n_addr_cells(phb); 253d3d2176aSDavid Gibson if (addr_cells == 1) { 254d3d2176aSDavid Gibson buid = (unsigned long) buid_vals[0]; 255d3d2176aSDavid Gibson } else { 256d3d2176aSDavid Gibson buid = (((unsigned long)buid_vals[0]) << 32UL) | 257d3d2176aSDavid Gibson (((unsigned long)buid_vals[1]) & 0xffffffff); 258d3d2176aSDavid Gibson } 259d3d2176aSDavid Gibson return buid; 260d3d2176aSDavid Gibson } 261d3d2176aSDavid Gibson 262d3d2176aSDavid Gibson static int phb_set_bus_ranges(struct device_node *dev, 263d3d2176aSDavid Gibson struct pci_controller *phb) 264d3d2176aSDavid Gibson { 265a7f67bdfSJeremy Kerr const int *bus_range; 266d3d2176aSDavid Gibson unsigned int len; 267d3d2176aSDavid Gibson 268a7f67bdfSJeremy Kerr bus_range = get_property(dev, "bus-range", &len); 269d3d2176aSDavid Gibson if (bus_range == NULL || len < 2 * sizeof(int)) { 270d3d2176aSDavid Gibson return 1; 271d3d2176aSDavid Gibson } 272d3d2176aSDavid Gibson 273d3d2176aSDavid Gibson phb->first_busno = bus_range[0]; 274d3d2176aSDavid Gibson phb->last_busno = bus_range[1]; 275d3d2176aSDavid Gibson 276d3d2176aSDavid Gibson return 0; 277d3d2176aSDavid Gibson } 278d3d2176aSDavid Gibson 27992eb4602SJohn Rose int __devinit setup_phb(struct device_node *dev, struct pci_controller *phb) 280d3d2176aSDavid Gibson { 281d3d2176aSDavid Gibson if (is_python(dev)) 282cc5d0189SBenjamin Herrenschmidt python_countermeasures(dev); 283d3d2176aSDavid Gibson 284d3d2176aSDavid Gibson if (phb_set_bus_ranges(dev, phb)) 285d3d2176aSDavid Gibson return 1; 286d3d2176aSDavid Gibson 287d3d2176aSDavid Gibson phb->ops = &rtas_pci_ops; 288d3d2176aSDavid Gibson phb->buid = get_phb_buid(dev); 289d3d2176aSDavid Gibson 290d3d2176aSDavid Gibson return 0; 291d3d2176aSDavid Gibson } 292d3d2176aSDavid Gibson 293d3d2176aSDavid Gibson unsigned long __init find_and_init_phbs(void) 294d3d2176aSDavid Gibson { 295d3d2176aSDavid Gibson struct device_node *node; 296d3d2176aSDavid Gibson struct pci_controller *phb; 297d3d2176aSDavid Gibson unsigned int index; 298d3d2176aSDavid Gibson struct device_node *root = of_find_node_by_path("/"); 299d3d2176aSDavid Gibson 300d3d2176aSDavid Gibson index = 0; 301d3d2176aSDavid Gibson for (node = of_get_next_child(root, NULL); 302d3d2176aSDavid Gibson node != NULL; 303d3d2176aSDavid Gibson node = of_get_next_child(root, node)) { 304bb53bb3dSJake Moilanen 305bb53bb3dSJake Moilanen if (node->type == NULL || (strcmp(node->type, "pci") != 0 && 306bb53bb3dSJake Moilanen strcmp(node->type, "pciex") != 0)) 307d3d2176aSDavid Gibson continue; 308d3d2176aSDavid Gibson 309b5166cc2SBenjamin Herrenschmidt phb = pcibios_alloc_controller(node); 310d3d2176aSDavid Gibson if (!phb) 311d3d2176aSDavid Gibson continue; 312cc5d0189SBenjamin Herrenschmidt setup_phb(node, phb); 313d3d2176aSDavid Gibson pci_process_bridge_OF_ranges(phb, node, 0); 314d3d2176aSDavid Gibson pci_setup_phb_io(phb, index == 0); 315d3d2176aSDavid Gibson index++; 316d3d2176aSDavid Gibson } 317d3d2176aSDavid Gibson 318d3d2176aSDavid Gibson of_node_put(root); 319d3d2176aSDavid Gibson pci_devs_phb_init(); 320d3d2176aSDavid Gibson 321d3d2176aSDavid Gibson /* 322d3d2176aSDavid Gibson * pci_probe_only and pci_assign_all_buses can be set via properties 323d3d2176aSDavid Gibson * in chosen. 324d3d2176aSDavid Gibson */ 325d3d2176aSDavid Gibson if (of_chosen) { 326a7f67bdfSJeremy Kerr const int *prop; 327d3d2176aSDavid Gibson 328a7f67bdfSJeremy Kerr prop = get_property(of_chosen, 329a7f67bdfSJeremy Kerr "linux,pci-probe-only", NULL); 330d3d2176aSDavid Gibson if (prop) 331d3d2176aSDavid Gibson pci_probe_only = *prop; 332d3d2176aSDavid Gibson 333a7f67bdfSJeremy Kerr prop = get_property(of_chosen, 334d3d2176aSDavid Gibson "linux,pci-assign-all-buses", NULL); 335d3d2176aSDavid Gibson if (prop) 336d3d2176aSDavid Gibson pci_assign_all_buses = *prop; 337d3d2176aSDavid Gibson } 338d3d2176aSDavid Gibson 339d3d2176aSDavid Gibson return 0; 340d3d2176aSDavid Gibson } 341d3d2176aSDavid Gibson 342d3d2176aSDavid Gibson /* RPA-specific bits for removing PHBs */ 343d3d2176aSDavid Gibson int pcibios_remove_root_bus(struct pci_controller *phb) 344d3d2176aSDavid Gibson { 345d3d2176aSDavid Gibson struct pci_bus *b = phb->bus; 346d3d2176aSDavid Gibson struct resource *res; 347d3d2176aSDavid Gibson int rc, i; 348d3d2176aSDavid Gibson 349d3d2176aSDavid Gibson res = b->resource[0]; 350d3d2176aSDavid Gibson if (!res->flags) { 351d3d2176aSDavid Gibson printk(KERN_ERR "%s: no IO resource for PHB %s\n", __FUNCTION__, 352d3d2176aSDavid Gibson b->name); 353d3d2176aSDavid Gibson return 1; 354d3d2176aSDavid Gibson } 355d3d2176aSDavid Gibson 356d3d2176aSDavid Gibson rc = unmap_bus_range(b); 357d3d2176aSDavid Gibson if (rc) { 358d3d2176aSDavid Gibson printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", 359d3d2176aSDavid Gibson __FUNCTION__, b->name); 360d3d2176aSDavid Gibson return 1; 361d3d2176aSDavid Gibson } 362d3d2176aSDavid Gibson 363d3d2176aSDavid Gibson if (release_resource(res)) { 364d3d2176aSDavid Gibson printk(KERN_ERR "%s: failed to release IO on bus %s\n", 365d3d2176aSDavid Gibson __FUNCTION__, b->name); 366d3d2176aSDavid Gibson return 1; 367d3d2176aSDavid Gibson } 368d3d2176aSDavid Gibson 369d3d2176aSDavid Gibson for (i = 1; i < 3; ++i) { 370d3d2176aSDavid Gibson res = b->resource[i]; 371d3d2176aSDavid Gibson if (!res->flags && i == 0) { 372d3d2176aSDavid Gibson printk(KERN_ERR "%s: no MEM resource for PHB %s\n", 373d3d2176aSDavid Gibson __FUNCTION__, b->name); 374d3d2176aSDavid Gibson return 1; 375d3d2176aSDavid Gibson } 376d3d2176aSDavid Gibson if (res->flags && release_resource(res)) { 377d3d2176aSDavid Gibson printk(KERN_ERR 378d3d2176aSDavid Gibson "%s: failed to release IO %d on bus %s\n", 379d3d2176aSDavid Gibson __FUNCTION__, i, b->name); 380d3d2176aSDavid Gibson return 1; 381d3d2176aSDavid Gibson } 382d3d2176aSDavid Gibson } 383d3d2176aSDavid Gibson 384d3d2176aSDavid Gibson list_del(&phb->list_node); 385b5166cc2SBenjamin Herrenschmidt pcibios_free_controller(phb); 386d3d2176aSDavid Gibson 387d3d2176aSDavid Gibson return 0; 388d3d2176aSDavid Gibson } 389d3d2176aSDavid Gibson EXPORT_SYMBOL(pcibios_remove_root_bus); 390