linux/arch/powerpc/platforms/pseries/pci_dlpar.c
<<
>>
Prefs
   1/*
   2 * PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code
   3 * for RPA-compliant PPC64 platform.
   4 * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
   5 * Copyright (C) 2005 International Business Machines
   6 *
   7 * Updates, 2005, John Rose <johnrose@austin.ibm.com>
   8 * Updates, 2005, Linas Vepstas <linas@austin.ibm.com>
   9 *
  10 * All rights reserved.
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License as published by
  14 * the Free Software Foundation; either version 2 of the License, or (at
  15 * your option) any later version.
  16 *
  17 * This program is distributed in the hope that it will be useful, but
  18 * WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  20 * NON INFRINGEMENT.  See the GNU General Public License for more
  21 * details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, write to the Free Software
  25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26 */
  27
  28#include <linux/pci.h>
  29#include <linux/export.h>
  30#include <asm/pci-bridge.h>
  31#include <asm/ppc-pci.h>
  32#include <asm/firmware.h>
  33#include <asm/eeh.h>
  34
  35static struct pci_bus *
  36find_bus_among_children(struct pci_bus *bus,
  37                        struct device_node *dn)
  38{
  39        struct pci_bus *child = NULL;
  40        struct list_head *tmp;
  41        struct device_node *busdn;
  42
  43        busdn = pci_bus_to_OF_node(bus);
  44        if (busdn == dn)
  45                return bus;
  46
  47        list_for_each(tmp, &bus->children) {
  48                child = find_bus_among_children(pci_bus_b(tmp), dn);
  49                if (child)
  50                        break;
  51        };
  52        return child;
  53}
  54
  55struct pci_bus *
  56pcibios_find_pci_bus(struct device_node *dn)
  57{
  58        struct pci_dn *pdn = dn->data;
  59
  60        if (!pdn  || !pdn->phb || !pdn->phb->bus)
  61                return NULL;
  62
  63        return find_bus_among_children(pdn->phb->bus, dn);
  64}
  65EXPORT_SYMBOL_GPL(pcibios_find_pci_bus);
  66
  67/**
  68 * pcibios_remove_pci_devices - remove all devices under this bus
  69 *
  70 * Remove all of the PCI devices under this bus both from the
  71 * linux pci device tree, and from the powerpc EEH address cache.
  72 */
  73void pcibios_remove_pci_devices(struct pci_bus *bus)
  74{
  75        struct pci_dev *dev, *tmp;
  76        struct pci_bus *child_bus;
  77
  78        /* First go down child busses */
  79        list_for_each_entry(child_bus, &bus->children, node)
  80                pcibios_remove_pci_devices(child_bus);
  81
  82        pr_debug("PCI: Removing devices on bus %04x:%02x\n",
  83                 pci_domain_nr(bus),  bus->number);
  84        list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
  85                pr_debug("     * Removing %s...\n", pci_name(dev));
  86                eeh_remove_bus_device(dev);
  87                pci_remove_bus_device(dev);
  88        }
  89}
  90EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
  91
  92/**
  93 * pcibios_add_pci_devices - adds new pci devices to bus
  94 *
  95 * This routine will find and fixup new pci devices under
  96 * the indicated bus. This routine presumes that there
  97 * might already be some devices under this bridge, so
  98 * it carefully tries to add only new devices.  (And that
  99 * is how this routine differs from other, similar pcibios
 100 * routines.)
 101 */
 102void pcibios_add_pci_devices(struct pci_bus * bus)
 103{
 104        int slotno, num, mode, pass, max;
 105        struct pci_dev *dev;
 106        struct device_node *dn = pci_bus_to_OF_node(bus);
 107
 108        eeh_add_device_tree_early(dn);
 109
 110        mode = PCI_PROBE_NORMAL;
 111        if (ppc_md.pci_probe_mode)
 112                mode = ppc_md.pci_probe_mode(bus);
 113
 114        if (mode == PCI_PROBE_DEVTREE) {
 115                /* use ofdt-based probe */
 116                of_rescan_bus(dn, bus);
 117        } else if (mode == PCI_PROBE_NORMAL) {
 118                /* use legacy probe */
 119                slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
 120                num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
 121                if (!num)
 122                        return;
 123                pcibios_setup_bus_devices(bus);
 124                max = bus->secondary;
 125                for (pass=0; pass < 2; pass++)
 126                        list_for_each_entry(dev, &bus->devices, bus_list) {
 127                        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
 128                            dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 129                                max = pci_scan_bridge(bus, dev, max, pass);
 130                }
 131        }
 132        pcibios_finish_adding_to_bus(bus);
 133}
 134EXPORT_SYMBOL_GPL(pcibios_add_pci_devices);
 135
 136struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
 137{
 138        struct pci_controller *phb;
 139
 140        pr_debug("PCI: Initializing new hotplug PHB %s\n", dn->full_name);
 141
 142        phb = pcibios_alloc_controller(dn);
 143        if (!phb)
 144                return NULL;
 145        rtas_setup_phb(phb);
 146        pci_process_bridge_OF_ranges(phb, dn, 0);
 147
 148        pci_devs_phb_init_dynamic(phb);
 149
 150        if (dn->child)
 151                eeh_add_device_tree_early(dn);
 152
 153        pcibios_scan_phb(phb);
 154        pcibios_finish_adding_to_bus(phb->bus);
 155
 156        return phb;
 157}
 158EXPORT_SYMBOL_GPL(init_phb_dynamic);
 159
 160/* RPA-specific bits for removing PHBs */
 161int remove_phb_dynamic(struct pci_controller *phb)
 162{
 163        struct pci_bus *b = phb->bus;
 164        struct resource *res;
 165        int rc, i;
 166
 167        pr_debug("PCI: Removing PHB %04x:%02x...\n",
 168                 pci_domain_nr(b), b->number);
 169
 170        /* We cannot to remove a root bus that has children */
 171        if (!(list_empty(&b->children) && list_empty(&b->devices)))
 172                return -EBUSY;
 173
 174        /* We -know- there aren't any child devices anymore at this stage
 175         * and thus, we can safely unmap the IO space as it's not in use
 176         */
 177        res = &phb->io_resource;
 178        if (res->flags & IORESOURCE_IO) {
 179                rc = pcibios_unmap_io_space(b);
 180                if (rc) {
 181                        printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
 182                               __func__, b->name);
 183                        return 1;
 184                }
 185        }
 186
 187        /* Unregister the bridge device from sysfs and remove the PCI bus */
 188        device_unregister(b->bridge);
 189        phb->bus = NULL;
 190        pci_remove_bus(b);
 191
 192        /* Now release the IO resource */
 193        if (res->flags & IORESOURCE_IO)
 194                release_resource(res);
 195
 196        /* Release memory resources */
 197        for (i = 0; i < 3; ++i) {
 198                res = &phb->mem_resources[i];
 199                if (!(res->flags & IORESOURCE_MEM))
 200                        continue;
 201                release_resource(res);
 202        }
 203
 204        /* Free pci_controller data structure */
 205        pcibios_free_controller(phb);
 206
 207        return 0;
 208}
 209EXPORT_SYMBOL_GPL(remove_phb_dynamic);
 210