1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code |
4 | * for RPA-compliant PPC64 platform. |
5 | * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com> |
6 | * Copyright (C) 2005 International Business Machines |
7 | * |
8 | * Updates, 2005, John Rose <johnrose@austin.ibm.com> |
9 | * Updates, 2005, Linas Vepstas <linas@austin.ibm.com> |
10 | */ |
11 | |
12 | #include <linux/pci.h> |
13 | #include <linux/export.h> |
14 | #include <asm/pci-bridge.h> |
15 | #include <asm/ppc-pci.h> |
16 | #include <asm/firmware.h> |
17 | #include <asm/eeh.h> |
18 | |
19 | #include "pseries.h" |
20 | |
21 | struct pci_controller *init_phb_dynamic(struct device_node *dn) |
22 | { |
23 | struct pci_controller *phb; |
24 | |
25 | pr_debug("PCI: Initializing new hotplug PHB %pOF\n" , dn); |
26 | |
27 | phb = pcibios_alloc_controller(dn); |
28 | if (!phb) |
29 | return NULL; |
30 | rtas_setup_phb(phb); |
31 | pci_process_bridge_OF_ranges(phb, dn, 0); |
32 | phb->controller_ops = pseries_pci_controller_ops; |
33 | |
34 | pci_devs_phb_init_dynamic(phb); |
35 | |
36 | pseries_msi_allocate_domains(phb); |
37 | |
38 | ppc_iommu_register_device(phb); |
39 | |
40 | /* Create EEH devices for the PHB */ |
41 | eeh_phb_pe_create(phb); |
42 | |
43 | if (dn->child) |
44 | pseries_eeh_init_edev_recursive(PCI_DN(dn)); |
45 | |
46 | pcibios_scan_phb(phb); |
47 | pcibios_finish_adding_to_bus(phb->bus); |
48 | |
49 | return phb; |
50 | } |
51 | EXPORT_SYMBOL_GPL(init_phb_dynamic); |
52 | |
53 | /* RPA-specific bits for removing PHBs */ |
54 | int remove_phb_dynamic(struct pci_controller *phb) |
55 | { |
56 | struct pci_bus *b = phb->bus; |
57 | struct pci_host_bridge *host_bridge = to_pci_host_bridge(b->bridge); |
58 | struct resource *res; |
59 | int rc, i; |
60 | |
61 | pr_debug("PCI: Removing PHB %04x:%02x...\n" , |
62 | pci_domain_nr(b), b->number); |
63 | |
64 | /* We cannot to remove a root bus that has children */ |
65 | if (!(list_empty(head: &b->children) && list_empty(head: &b->devices))) |
66 | return -EBUSY; |
67 | |
68 | /* We -know- there aren't any child devices anymore at this stage |
69 | * and thus, we can safely unmap the IO space as it's not in use |
70 | */ |
71 | res = &phb->io_resource; |
72 | if (res->flags & IORESOURCE_IO) { |
73 | rc = pcibios_unmap_io_space(b); |
74 | if (rc) { |
75 | printk(KERN_ERR "%s: failed to unmap IO on bus %s\n" , |
76 | __func__, b->name); |
77 | return 1; |
78 | } |
79 | } |
80 | |
81 | ppc_iommu_unregister_device(phb); |
82 | |
83 | pseries_msi_free_domains(phb); |
84 | |
85 | /* Keep a reference so phb isn't freed yet */ |
86 | get_device(dev: &host_bridge->dev); |
87 | |
88 | /* Remove the PCI bus and unregister the bridge device from sysfs */ |
89 | phb->bus = NULL; |
90 | pci_remove_bus(b); |
91 | host_bridge->bus = NULL; |
92 | device_unregister(dev: &host_bridge->dev); |
93 | |
94 | /* Now release the IO resource */ |
95 | if (res->flags & IORESOURCE_IO) |
96 | release_resource(new: res); |
97 | |
98 | /* Release memory resources */ |
99 | for (i = 0; i < 3; ++i) { |
100 | res = &phb->mem_resources[i]; |
101 | if (!(res->flags & IORESOURCE_MEM)) |
102 | continue; |
103 | release_resource(new: res); |
104 | } |
105 | |
106 | /* |
107 | * The pci_controller data structure is freed by |
108 | * the pcibios_free_controller_deferred() callback; |
109 | * see pseries_root_bridge_prepare(). |
110 | */ |
111 | put_device(dev: &host_bridge->dev); |
112 | |
113 | return 0; |
114 | } |
115 | EXPORT_SYMBOL_GPL(remove_phb_dynamic); |
116 | |