Path: blob/master/arch/powerpc/platforms/pseries/pci_dlpar.c
10818 views
/*1* PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code2* for RPA-compliant PPC64 platform.3* Copyright (C) 2003 Linda Xie <[email protected]>4* Copyright (C) 2005 International Business Machines5*6* Updates, 2005, John Rose <[email protected]>7* Updates, 2005, Linas Vepstas <[email protected]>8*9* All rights reserved.10*11* This program is free software; you can redistribute it and/or modify12* it under the terms of the GNU General Public License as published by13* the Free Software Foundation; either version 2 of the License, or (at14* your option) any later version.15*16* This program is distributed in the hope that it will be useful, but17* WITHOUT ANY WARRANTY; without even the implied warranty of18* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or19* NON INFRINGEMENT. See the GNU General Public License for more20* details.21*22* You should have received a copy of the GNU General Public License23* along with this program; if not, write to the Free Software24* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.25*/2627#include <linux/pci.h>28#include <asm/pci-bridge.h>29#include <asm/ppc-pci.h>30#include <asm/firmware.h>31#include <asm/eeh.h>3233static struct pci_bus *34find_bus_among_children(struct pci_bus *bus,35struct device_node *dn)36{37struct pci_bus *child = NULL;38struct list_head *tmp;39struct device_node *busdn;4041busdn = pci_bus_to_OF_node(bus);42if (busdn == dn)43return bus;4445list_for_each(tmp, &bus->children) {46child = find_bus_among_children(pci_bus_b(tmp), dn);47if (child)48break;49};50return child;51}5253struct pci_bus *54pcibios_find_pci_bus(struct device_node *dn)55{56struct pci_dn *pdn = dn->data;5758if (!pdn || !pdn->phb || !pdn->phb->bus)59return NULL;6061return find_bus_among_children(pdn->phb->bus, dn);62}63EXPORT_SYMBOL_GPL(pcibios_find_pci_bus);6465/**66* pcibios_remove_pci_devices - remove all devices under this bus67*68* Remove all of the PCI devices under this bus both from the69* linux pci device tree, and from the powerpc EEH address cache.70*/71void pcibios_remove_pci_devices(struct pci_bus *bus)72{73struct pci_dev *dev, *tmp;74struct pci_bus *child_bus;7576/* First go down child busses */77list_for_each_entry(child_bus, &bus->children, node)78pcibios_remove_pci_devices(child_bus);7980pr_debug("PCI: Removing devices on bus %04x:%02x\n",81pci_domain_nr(bus), bus->number);82list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {83pr_debug(" * Removing %s...\n", pci_name(dev));84eeh_remove_bus_device(dev);85pci_remove_bus_device(dev);86}87}88EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);8990/**91* pcibios_add_pci_devices - adds new pci devices to bus92*93* This routine will find and fixup new pci devices under94* the indicated bus. This routine presumes that there95* might already be some devices under this bridge, so96* it carefully tries to add only new devices. (And that97* is how this routine differs from other, similar pcibios98* routines.)99*/100void pcibios_add_pci_devices(struct pci_bus * bus)101{102int slotno, num, mode, pass, max;103struct pci_dev *dev;104struct device_node *dn = pci_bus_to_OF_node(bus);105106eeh_add_device_tree_early(dn);107108mode = PCI_PROBE_NORMAL;109if (ppc_md.pci_probe_mode)110mode = ppc_md.pci_probe_mode(bus);111112if (mode == PCI_PROBE_DEVTREE) {113/* use ofdt-based probe */114of_rescan_bus(dn, bus);115} else if (mode == PCI_PROBE_NORMAL) {116/* use legacy probe */117slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);118num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));119if (!num)120return;121pcibios_setup_bus_devices(bus);122max = bus->secondary;123for (pass=0; pass < 2; pass++)124list_for_each_entry(dev, &bus->devices, bus_list) {125if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||126dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)127max = pci_scan_bridge(bus, dev, max, pass);128}129}130pcibios_finish_adding_to_bus(bus);131}132EXPORT_SYMBOL_GPL(pcibios_add_pci_devices);133134struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)135{136struct pci_controller *phb;137138pr_debug("PCI: Initializing new hotplug PHB %s\n", dn->full_name);139140phb = pcibios_alloc_controller(dn);141if (!phb)142return NULL;143rtas_setup_phb(phb);144pci_process_bridge_OF_ranges(phb, dn, 0);145146pci_devs_phb_init_dynamic(phb);147148if (dn->child)149eeh_add_device_tree_early(dn);150151pcibios_scan_phb(phb);152pcibios_finish_adding_to_bus(phb->bus);153154return phb;155}156EXPORT_SYMBOL_GPL(init_phb_dynamic);157158/* RPA-specific bits for removing PHBs */159int remove_phb_dynamic(struct pci_controller *phb)160{161struct pci_bus *b = phb->bus;162struct resource *res;163int rc, i;164165pr_debug("PCI: Removing PHB %04x:%02x...\n",166pci_domain_nr(b), b->number);167168/* We cannot to remove a root bus that has children */169if (!(list_empty(&b->children) && list_empty(&b->devices)))170return -EBUSY;171172/* We -know- there aren't any child devices anymore at this stage173* and thus, we can safely unmap the IO space as it's not in use174*/175res = &phb->io_resource;176if (res->flags & IORESOURCE_IO) {177rc = pcibios_unmap_io_space(b);178if (rc) {179printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",180__func__, b->name);181return 1;182}183}184185/* Unregister the bridge device from sysfs and remove the PCI bus */186device_unregister(b->bridge);187phb->bus = NULL;188pci_remove_bus(b);189190/* Now release the IO resource */191if (res->flags & IORESOURCE_IO)192release_resource(res);193194/* Release memory resources */195for (i = 0; i < 3; ++i) {196res = &phb->mem_resources[i];197if (!(res->flags & IORESOURCE_MEM))198continue;199release_resource(res);200}201202/* Free pci_controller data structure */203pcibios_free_controller(phb);204205return 0;206}207EXPORT_SYMBOL_GPL(remove_phb_dynamic);208209210