Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code
0004  * for RPA-compliant PPC64 platform.
0005  * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
0006  * Copyright (C) 2005 International Business Machines
0007  *
0008  * Updates, 2005, John Rose <johnrose@austin.ibm.com>
0009  * Updates, 2005, Linas Vepstas <linas@austin.ibm.com>
0010  */
0011 
0012 #include <linux/pci.h>
0013 #include <linux/export.h>
0014 #include <asm/pci-bridge.h>
0015 #include <asm/ppc-pci.h>
0016 #include <asm/firmware.h>
0017 #include <asm/eeh.h>
0018 
0019 #include "pseries.h"
0020 
0021 struct pci_controller *init_phb_dynamic(struct device_node *dn)
0022 {
0023     struct pci_controller *phb;
0024 
0025     pr_debug("PCI: Initializing new hotplug PHB %pOF\n", dn);
0026 
0027     phb = pcibios_alloc_controller(dn);
0028     if (!phb)
0029         return NULL;
0030     rtas_setup_phb(phb);
0031     pci_process_bridge_OF_ranges(phb, dn, 0);
0032     phb->controller_ops = pseries_pci_controller_ops;
0033 
0034     pci_devs_phb_init_dynamic(phb);
0035 
0036     pseries_msi_allocate_domains(phb);
0037 
0038     /* Create EEH devices for the PHB */
0039     eeh_phb_pe_create(phb);
0040 
0041     if (dn->child)
0042         pseries_eeh_init_edev_recursive(PCI_DN(dn));
0043 
0044     pcibios_scan_phb(phb);
0045     pcibios_finish_adding_to_bus(phb->bus);
0046 
0047     return phb;
0048 }
0049 EXPORT_SYMBOL_GPL(init_phb_dynamic);
0050 
0051 /* RPA-specific bits for removing PHBs */
0052 int remove_phb_dynamic(struct pci_controller *phb)
0053 {
0054     struct pci_bus *b = phb->bus;
0055     struct pci_host_bridge *host_bridge = to_pci_host_bridge(b->bridge);
0056     struct resource *res;
0057     int rc, i;
0058 
0059     pr_debug("PCI: Removing PHB %04x:%02x...\n",
0060          pci_domain_nr(b), b->number);
0061 
0062     /* We cannot to remove a root bus that has children */
0063     if (!(list_empty(&b->children) && list_empty(&b->devices)))
0064         return -EBUSY;
0065 
0066     /* We -know- there aren't any child devices anymore at this stage
0067      * and thus, we can safely unmap the IO space as it's not in use
0068      */
0069     res = &phb->io_resource;
0070     if (res->flags & IORESOURCE_IO) {
0071         rc = pcibios_unmap_io_space(b);
0072         if (rc) {
0073             printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
0074                    __func__, b->name);
0075             return 1;
0076         }
0077     }
0078 
0079     pseries_msi_free_domains(phb);
0080 
0081     /* Keep a reference so phb isn't freed yet */
0082     get_device(&host_bridge->dev);
0083 
0084     /* Remove the PCI bus and unregister the bridge device from sysfs */
0085     phb->bus = NULL;
0086     pci_remove_bus(b);
0087     host_bridge->bus = NULL;
0088     device_unregister(&host_bridge->dev);
0089 
0090     /* Now release the IO resource */
0091     if (res->flags & IORESOURCE_IO)
0092         release_resource(res);
0093 
0094     /* Release memory resources */
0095     for (i = 0; i < 3; ++i) {
0096         res = &phb->mem_resources[i];
0097         if (!(res->flags & IORESOURCE_MEM))
0098             continue;
0099         release_resource(res);
0100     }
0101 
0102     /*
0103      * The pci_controller data structure is freed by
0104      * the pcibios_free_controller_deferred() callback;
0105      * see pseries_root_bridge_prepare().
0106      */
0107     put_device(&host_bridge->dev);
0108 
0109     return 0;
0110 }
0111 EXPORT_SYMBOL_GPL(remove_phb_dynamic);