xref: /linux/arch/powerpc/platforms/pseries/pci_dlpar.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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