1bbbd7f11SThomas Huth // SPDX-License-Identifier: GPL-2.0-or-later
22bf6a8faSLinas Vepstas /*
32bf6a8faSLinas Vepstas * PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code
42bf6a8faSLinas Vepstas * for RPA-compliant PPC64 platform.
52bf6a8faSLinas Vepstas * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
62bf6a8faSLinas Vepstas * Copyright (C) 2005 International Business Machines
72bf6a8faSLinas Vepstas *
82bf6a8faSLinas Vepstas * Updates, 2005, John Rose <johnrose@austin.ibm.com>
92bf6a8faSLinas Vepstas * Updates, 2005, Linas Vepstas <linas@austin.ibm.com>
102bf6a8faSLinas Vepstas */
112bf6a8faSLinas Vepstas
122bf6a8faSLinas Vepstas #include <linux/pci.h>
1393087948SPaul Gortmaker #include <linux/export.h>
14*11981816SNilay Shroff #include <linux/node.h>
152bf6a8faSLinas Vepstas #include <asm/pci-bridge.h>
1692eb4602SJohn Rose #include <asm/ppc-pci.h>
17e8222502SBenjamin Herrenschmidt #include <asm/firmware.h>
18c3b9d9abSOlaf Hering #include <asm/eeh.h>
192bf6a8faSLinas Vepstas
2038ae9ec4SDaniel Axtens #include "pseries.h"
2138ae9ec4SDaniel Axtens
init_phb_dynamic(struct device_node * dn)22cad5cef6SGreg Kroah-Hartman struct pci_controller *init_phb_dynamic(struct device_node *dn)
2392eb4602SJohn Rose {
2492eb4602SJohn Rose struct pci_controller *phb;
25*11981816SNilay Shroff int nid;
2692eb4602SJohn Rose
27b7c670d6SRob Herring pr_debug("PCI: Initializing new hotplug PHB %pOF\n", dn);
28fd6852c8SBenjamin Herrenschmidt
29*11981816SNilay Shroff nid = of_node_to_nid(dn);
30*11981816SNilay Shroff if (likely((nid) >= 0)) {
31*11981816SNilay Shroff if (!node_online(nid)) {
32*11981816SNilay Shroff if (__register_one_node(nid)) {
33*11981816SNilay Shroff pr_err("PCI: Failed to register node %d\n", nid);
34*11981816SNilay Shroff } else {
35*11981816SNilay Shroff update_numa_distance(dn);
36*11981816SNilay Shroff node_set_online(nid);
37*11981816SNilay Shroff }
38*11981816SNilay Shroff }
39*11981816SNilay Shroff }
40*11981816SNilay Shroff
4192eb4602SJohn Rose phb = pcibios_alloc_controller(dn);
4292eb4602SJohn Rose if (!phb)
4392eb4602SJohn Rose return NULL;
444c9d2800SBenjamin Herrenschmidt rtas_setup_phb(phb);
4592eb4602SJohn Rose pci_process_bridge_OF_ranges(phb, dn, 0);
4638ae9ec4SDaniel Axtens phb->controller_ops = pseries_pci_controller_ops;
4792eb4602SJohn Rose
4892eb4602SJohn Rose pci_devs_phb_init_dynamic(phb);
4992eb4602SJohn Rose
50174db9e7SCédric Le Goater pseries_msi_allocate_domains(phb);
51174db9e7SCédric Le Goater
52a5c57fd2SGaurav Batra ppc_iommu_register_device(phb);
53a5c57fd2SGaurav Batra
54eb740b5fSGavin Shan /* Create EEH devices for the PHB */
55475028efSOliver O'Halloran eeh_phb_pe_create(phb);
56eb740b5fSGavin Shan
5792eb4602SJohn Rose if (dn->child)
58b6eebb09SOliver O'Halloran pseries_eeh_init_edev_recursive(PCI_DN(dn));
5992eb4602SJohn Rose
60b5d937deSGrant Likely pcibios_scan_phb(phb);
61fd6852c8SBenjamin Herrenschmidt pcibios_finish_adding_to_bus(phb->bus);
6292eb4602SJohn Rose
6392eb4602SJohn Rose return phb;
6492eb4602SJohn Rose }
6592eb4602SJohn Rose EXPORT_SYMBOL_GPL(init_phb_dynamic);
66fd6852c8SBenjamin Herrenschmidt
67fd6852c8SBenjamin Herrenschmidt /* RPA-specific bits for removing PHBs */
remove_phb_dynamic(struct pci_controller * phb)68fd6852c8SBenjamin Herrenschmidt int remove_phb_dynamic(struct pci_controller *phb)
69fd6852c8SBenjamin Herrenschmidt {
70fd6852c8SBenjamin Herrenschmidt struct pci_bus *b = phb->bus;
7138d0b1c9STyrel Datwyler struct pci_host_bridge *host_bridge = to_pci_host_bridge(b->bridge);
72fd6852c8SBenjamin Herrenschmidt struct resource *res;
73fd6852c8SBenjamin Herrenschmidt int rc, i;
74fd6852c8SBenjamin Herrenschmidt
75fd6852c8SBenjamin Herrenschmidt pr_debug("PCI: Removing PHB %04x:%02x...\n",
76fd6852c8SBenjamin Herrenschmidt pci_domain_nr(b), b->number);
77fd6852c8SBenjamin Herrenschmidt
78fd6852c8SBenjamin Herrenschmidt /* We cannot to remove a root bus that has children */
79fd6852c8SBenjamin Herrenschmidt if (!(list_empty(&b->children) && list_empty(&b->devices)))
80fd6852c8SBenjamin Herrenschmidt return -EBUSY;
81fd6852c8SBenjamin Herrenschmidt
82fd6852c8SBenjamin Herrenschmidt /* We -know- there aren't any child devices anymore at this stage
83fd6852c8SBenjamin Herrenschmidt * and thus, we can safely unmap the IO space as it's not in use
84fd6852c8SBenjamin Herrenschmidt */
85fd6852c8SBenjamin Herrenschmidt res = &phb->io_resource;
86fd6852c8SBenjamin Herrenschmidt if (res->flags & IORESOURCE_IO) {
87fd6852c8SBenjamin Herrenschmidt rc = pcibios_unmap_io_space(b);
88fd6852c8SBenjamin Herrenschmidt if (rc) {
89fd6852c8SBenjamin Herrenschmidt printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
90fd6852c8SBenjamin Herrenschmidt __func__, b->name);
91fd6852c8SBenjamin Herrenschmidt return 1;
92fd6852c8SBenjamin Herrenschmidt }
93fd6852c8SBenjamin Herrenschmidt }
94fd6852c8SBenjamin Herrenschmidt
95a5c57fd2SGaurav Batra ppc_iommu_unregister_device(phb);
96a5c57fd2SGaurav Batra
97174db9e7SCédric Le Goater pseries_msi_free_domains(phb);
98174db9e7SCédric Le Goater
99fe2640bdSMichael Ellerman /* Keep a reference so phb isn't freed yet */
100fe2640bdSMichael Ellerman get_device(&host_bridge->dev);
101fe2640bdSMichael Ellerman
10273400565STyrel Datwyler /* Remove the PCI bus and unregister the bridge device from sysfs */
103fd6852c8SBenjamin Herrenschmidt phb->bus = NULL;
104fd6852c8SBenjamin Herrenschmidt pci_remove_bus(b);
10538d0b1c9STyrel Datwyler host_bridge->bus = NULL;
10638d0b1c9STyrel Datwyler device_unregister(&host_bridge->dev);
107fd6852c8SBenjamin Herrenschmidt
108fd6852c8SBenjamin Herrenschmidt /* Now release the IO resource */
109fd6852c8SBenjamin Herrenschmidt if (res->flags & IORESOURCE_IO)
110fd6852c8SBenjamin Herrenschmidt release_resource(res);
111fd6852c8SBenjamin Herrenschmidt
112fd6852c8SBenjamin Herrenschmidt /* Release memory resources */
113fd6852c8SBenjamin Herrenschmidt for (i = 0; i < 3; ++i) {
114fd6852c8SBenjamin Herrenschmidt res = &phb->mem_resources[i];
115fd6852c8SBenjamin Herrenschmidt if (!(res->flags & IORESOURCE_MEM))
116fd6852c8SBenjamin Herrenschmidt continue;
117fd6852c8SBenjamin Herrenschmidt release_resource(res);
118fd6852c8SBenjamin Herrenschmidt }
119fd6852c8SBenjamin Herrenschmidt
1202dd9c11bSMauricio Faria de Oliveira /*
1212dd9c11bSMauricio Faria de Oliveira * The pci_controller data structure is freed by
1222dd9c11bSMauricio Faria de Oliveira * the pcibios_free_controller_deferred() callback;
1232dd9c11bSMauricio Faria de Oliveira * see pseries_root_bridge_prepare().
1242dd9c11bSMauricio Faria de Oliveira */
125fe2640bdSMichael Ellerman put_device(&host_bridge->dev);
126fd6852c8SBenjamin Herrenschmidt
127fd6852c8SBenjamin Herrenschmidt return 0;
128fd6852c8SBenjamin Herrenschmidt }
129fd6852c8SBenjamin Herrenschmidt EXPORT_SYMBOL_GPL(remove_phb_dynamic);
130