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