xref: /openbmc/linux/arch/powerpc/platforms/pseries/pci_dlpar.c (revision 96d3c5a7d20ec546e44695983fe0508c6f904248)
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>
142bf6a8faSLinas Vepstas #include <asm/pci-bridge.h>
1592eb4602SJohn Rose #include <asm/ppc-pci.h>
16e8222502SBenjamin Herrenschmidt #include <asm/firmware.h>
17c3b9d9abSOlaf Hering #include <asm/eeh.h>
182bf6a8faSLinas Vepstas 
1938ae9ec4SDaniel Axtens #include "pseries.h"
2038ae9ec4SDaniel Axtens 
init_phb_dynamic(struct device_node * dn)21cad5cef6SGreg Kroah-Hartman struct pci_controller *init_phb_dynamic(struct device_node *dn)
2292eb4602SJohn Rose {
2392eb4602SJohn Rose 	struct pci_controller *phb;
2492eb4602SJohn Rose 
25b7c670d6SRob Herring 	pr_debug("PCI: Initializing new hotplug PHB %pOF\n", dn);
26fd6852c8SBenjamin Herrenschmidt 
2792eb4602SJohn Rose 	phb = pcibios_alloc_controller(dn);
2892eb4602SJohn Rose 	if (!phb)
2992eb4602SJohn Rose 		return NULL;
304c9d2800SBenjamin Herrenschmidt 	rtas_setup_phb(phb);
3192eb4602SJohn Rose 	pci_process_bridge_OF_ranges(phb, dn, 0);
3238ae9ec4SDaniel Axtens 	phb->controller_ops = pseries_pci_controller_ops;
3392eb4602SJohn Rose 
3492eb4602SJohn Rose 	pci_devs_phb_init_dynamic(phb);
3592eb4602SJohn Rose 
36174db9e7SCédric Le Goater 	pseries_msi_allocate_domains(phb);
37174db9e7SCédric Le Goater 
38*b8315b2eSGaurav Batra 	ppc_iommu_register_device(phb);
39*b8315b2eSGaurav Batra 
40eb740b5fSGavin Shan 	/* Create EEH devices for the PHB */
41475028efSOliver O'Halloran 	eeh_phb_pe_create(phb);
42eb740b5fSGavin Shan 
4392eb4602SJohn Rose 	if (dn->child)
44b6eebb09SOliver O'Halloran 		pseries_eeh_init_edev_recursive(PCI_DN(dn));
4592eb4602SJohn Rose 
46b5d937deSGrant Likely 	pcibios_scan_phb(phb);
47fd6852c8SBenjamin Herrenschmidt 	pcibios_finish_adding_to_bus(phb->bus);
4892eb4602SJohn Rose 
4992eb4602SJohn Rose 	return phb;
5092eb4602SJohn Rose }
5192eb4602SJohn Rose EXPORT_SYMBOL_GPL(init_phb_dynamic);
52fd6852c8SBenjamin Herrenschmidt 
53fd6852c8SBenjamin Herrenschmidt /* RPA-specific bits for removing PHBs */
remove_phb_dynamic(struct pci_controller * phb)54fd6852c8SBenjamin Herrenschmidt int remove_phb_dynamic(struct pci_controller *phb)
55fd6852c8SBenjamin Herrenschmidt {
56fd6852c8SBenjamin Herrenschmidt 	struct pci_bus *b = phb->bus;
5738d0b1c9STyrel Datwyler 	struct pci_host_bridge *host_bridge = to_pci_host_bridge(b->bridge);
58fd6852c8SBenjamin Herrenschmidt 	struct resource *res;
59fd6852c8SBenjamin Herrenschmidt 	int rc, i;
60fd6852c8SBenjamin Herrenschmidt 
61fd6852c8SBenjamin Herrenschmidt 	pr_debug("PCI: Removing PHB %04x:%02x...\n",
62fd6852c8SBenjamin Herrenschmidt 		 pci_domain_nr(b), b->number);
63fd6852c8SBenjamin Herrenschmidt 
64fd6852c8SBenjamin Herrenschmidt 	/* We cannot to remove a root bus that has children */
65fd6852c8SBenjamin Herrenschmidt 	if (!(list_empty(&b->children) && list_empty(&b->devices)))
66fd6852c8SBenjamin Herrenschmidt 		return -EBUSY;
67fd6852c8SBenjamin Herrenschmidt 
68fd6852c8SBenjamin Herrenschmidt 	/* We -know- there aren't any child devices anymore at this stage
69fd6852c8SBenjamin Herrenschmidt 	 * and thus, we can safely unmap the IO space as it's not in use
70fd6852c8SBenjamin Herrenschmidt 	 */
71fd6852c8SBenjamin Herrenschmidt 	res = &phb->io_resource;
72fd6852c8SBenjamin Herrenschmidt 	if (res->flags & IORESOURCE_IO) {
73fd6852c8SBenjamin Herrenschmidt 		rc = pcibios_unmap_io_space(b);
74fd6852c8SBenjamin Herrenschmidt 		if (rc) {
75fd6852c8SBenjamin Herrenschmidt 			printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
76fd6852c8SBenjamin Herrenschmidt 			       __func__, b->name);
77fd6852c8SBenjamin Herrenschmidt 			return 1;
78fd6852c8SBenjamin Herrenschmidt 		}
79fd6852c8SBenjamin Herrenschmidt 	}
80fd6852c8SBenjamin Herrenschmidt 
81*b8315b2eSGaurav Batra 	ppc_iommu_unregister_device(phb);
82*b8315b2eSGaurav Batra 
83174db9e7SCédric Le Goater 	pseries_msi_free_domains(phb);
84174db9e7SCédric Le Goater 
85fe2640bdSMichael Ellerman 	/* Keep a reference so phb isn't freed yet */
86fe2640bdSMichael Ellerman 	get_device(&host_bridge->dev);
87fe2640bdSMichael Ellerman 
8873400565STyrel Datwyler 	/* Remove the PCI bus and unregister the bridge device from sysfs */
89fd6852c8SBenjamin Herrenschmidt 	phb->bus = NULL;
90fd6852c8SBenjamin Herrenschmidt 	pci_remove_bus(b);
9138d0b1c9STyrel Datwyler 	host_bridge->bus = NULL;
9238d0b1c9STyrel Datwyler 	device_unregister(&host_bridge->dev);
93fd6852c8SBenjamin Herrenschmidt 
94fd6852c8SBenjamin Herrenschmidt 	/* Now release the IO resource */
95fd6852c8SBenjamin Herrenschmidt 	if (res->flags & IORESOURCE_IO)
96fd6852c8SBenjamin Herrenschmidt 		release_resource(res);
97fd6852c8SBenjamin Herrenschmidt 
98fd6852c8SBenjamin Herrenschmidt 	/* Release memory resources */
99fd6852c8SBenjamin Herrenschmidt 	for (i = 0; i < 3; ++i) {
100fd6852c8SBenjamin Herrenschmidt 		res = &phb->mem_resources[i];
101fd6852c8SBenjamin Herrenschmidt 		if (!(res->flags & IORESOURCE_MEM))
102fd6852c8SBenjamin Herrenschmidt 			continue;
103fd6852c8SBenjamin Herrenschmidt 		release_resource(res);
104fd6852c8SBenjamin Herrenschmidt 	}
105fd6852c8SBenjamin Herrenschmidt 
1062dd9c11bSMauricio Faria de Oliveira 	/*
1072dd9c11bSMauricio Faria de Oliveira 	 * The pci_controller data structure is freed by
1082dd9c11bSMauricio Faria de Oliveira 	 * the pcibios_free_controller_deferred() callback;
1092dd9c11bSMauricio Faria de Oliveira 	 * see pseries_root_bridge_prepare().
1102dd9c11bSMauricio Faria de Oliveira 	 */
111fe2640bdSMichael Ellerman 	put_device(&host_bridge->dev);
112fd6852c8SBenjamin Herrenschmidt 
113fd6852c8SBenjamin Herrenschmidt 	return 0;
114fd6852c8SBenjamin Herrenschmidt }
115fd6852c8SBenjamin Herrenschmidt EXPORT_SYMBOL_GPL(remove_phb_dynamic);
116