blob: 0b0cf8168b475361f8c5915116b82d204830ef38 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Gavin Shan317f06d2013-06-20 13:20:52 +08002/*
3 * Derived from "arch/powerpc/platforms/pseries/pci_dlpar.c"
4 *
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 * Updates, 2013, Gavin Shan <shangw@linux.vnet.ibm.com>
Gavin Shan317f06d2013-06-20 13:20:52 +080011 */
12
13#include <linux/pci.h>
14#include <linux/export.h>
15#include <asm/pci-bridge.h>
16#include <asm/ppc-pci.h>
17#include <asm/firmware.h>
18#include <asm/eeh.h>
19
Gavin Shan6384d972016-05-03 15:41:39 +100020static struct pci_bus *find_bus_among_children(struct pci_bus *bus,
21 struct device_node *dn)
22{
23 struct pci_bus *child = NULL;
24 struct pci_bus *tmp;
25
26 if (pci_bus_to_OF_node(bus) == dn)
27 return bus;
28
29 list_for_each_entry(tmp, &bus->children, node) {
30 child = find_bus_among_children(tmp, dn);
31 if (child)
32 break;
33 }
34
35 return child;
36}
37
38struct pci_bus *pci_find_bus_by_node(struct device_node *dn)
39{
40 struct pci_dn *pdn = PCI_DN(dn);
41
42 if (!pdn || !pdn->phb || !pdn->phb->bus)
43 return NULL;
44
45 return find_bus_among_children(pdn->phb->bus, dn);
46}
47EXPORT_SYMBOL_GPL(pci_find_bus_by_node);
48
Gavin Shan317f06d2013-06-20 13:20:52 +080049/**
Gavin Shan008a4932013-07-24 10:24:53 +080050 * pcibios_release_device - release PCI device
51 * @dev: PCI device
52 *
53 * The function is called before releasing the indicated PCI device.
54 */
55void pcibios_release_device(struct pci_dev *dev)
56{
Michael Neuling10e79632015-05-27 16:06:57 +100057 struct pci_controller *phb = pci_bus_to_host(dev->bus);
58
Gavin Shan807a8272013-07-24 10:24:55 +080059 eeh_remove_device(dev);
Michael Neuling10e79632015-05-27 16:06:57 +100060
61 if (phb->controller_ops.release_device)
62 phb->controller_ops.release_device(dev);
Gavin Shan317f06d2013-06-20 13:20:52 +080063}
64
65/**
Gavin Shanbd251b82016-05-03 15:41:37 +100066 * pci_hp_remove_devices - remove all devices under this bus
Gavin Shan317f06d2013-06-20 13:20:52 +080067 * @bus: the indicated PCI bus
68 *
69 * Remove all of the PCI devices under this bus both from the
70 * linux pci device tree, and from the powerpc EEH address cache.
71 */
Gavin Shanbd251b82016-05-03 15:41:37 +100072void pci_hp_remove_devices(struct pci_bus *bus)
Gavin Shan317f06d2013-06-20 13:20:52 +080073{
Gavin Shan807a8272013-07-24 10:24:55 +080074 struct pci_dev *dev, *tmp;
75 struct pci_bus *child_bus;
76
77 /* First go down child busses */
78 list_for_each_entry(child_bus, &bus->children, node)
Gavin Shanbd251b82016-05-03 15:41:37 +100079 pci_hp_remove_devices(child_bus);
Gavin Shan807a8272013-07-24 10:24:55 +080080
81 pr_debug("PCI: Removing devices on bus %04x:%02x\n",
82 pci_domain_nr(bus), bus->number);
Wei Yang971427f52016-03-04 10:53:05 +110083 list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) {
Gavin Shan807a8272013-07-24 10:24:55 +080084 pr_debug(" Removing %s...\n", pci_name(dev));
85 pci_stop_and_remove_bus_device(dev);
86 }
Gavin Shan317f06d2013-06-20 13:20:52 +080087}
Gavin Shanbd251b82016-05-03 15:41:37 +100088EXPORT_SYMBOL_GPL(pci_hp_remove_devices);
Gavin Shan317f06d2013-06-20 13:20:52 +080089
90/**
Gavin Shanbd251b82016-05-03 15:41:37 +100091 * pci_hp_add_devices - adds new pci devices to bus
Gavin Shan317f06d2013-06-20 13:20:52 +080092 * @bus: the indicated PCI bus
93 *
94 * This routine will find and fixup new pci devices under
95 * the indicated bus. This routine presumes that there
96 * might already be some devices under this bridge, so
97 * it carefully tries to add only new devices. (And that
98 * is how this routine differs from other, similar pcibios
99 * routines.)
100 */
Gavin Shanbd251b82016-05-03 15:41:37 +1000101void pci_hp_add_devices(struct pci_bus *bus)
Gavin Shan317f06d2013-06-20 13:20:52 +0800102{
Andy Shevchenko9d987eb2017-11-10 19:52:30 +0200103 int slotno, mode, max;
Gavin Shan317f06d2013-06-20 13:20:52 +0800104 struct pci_dev *dev;
Daniel Axtens467efc22015-03-31 16:00:56 +1100105 struct pci_controller *phb;
Gavin Shan317f06d2013-06-20 13:20:52 +0800106 struct device_node *dn = pci_bus_to_OF_node(bus);
107
Gavin Shanff57b452015-03-17 16:15:06 +1100108 eeh_add_device_tree_early(PCI_DN(dn));
Gavin Shan317f06d2013-06-20 13:20:52 +0800109
Daniel Axtens467efc22015-03-31 16:00:56 +1100110 phb = pci_bus_to_host(bus);
111
Gavin Shan317f06d2013-06-20 13:20:52 +0800112 mode = PCI_PROBE_NORMAL;
Daniel Axtens467efc22015-03-31 16:00:56 +1100113 if (phb->controller_ops.probe_mode)
114 mode = phb->controller_ops.probe_mode(bus);
Gavin Shan317f06d2013-06-20 13:20:52 +0800115
116 if (mode == PCI_PROBE_DEVTREE) {
117 /* use ofdt-based probe */
118 of_rescan_bus(dn, bus);
Gavin Shan4a5954e2016-05-03 15:41:43 +1000119 } else if (mode == PCI_PROBE_NORMAL &&
120 dn->child && PCI_DN(dn->child)) {
Gavin Shanab444ec2013-07-24 10:24:57 +0800121 /*
122 * Use legacy probe. In the partial hotplug case, we
123 * probably have grandchildren devices unplugged. So
124 * we don't check the return value from pci_scan_slot() in
125 * order for fully rescan all the way down to pick them up.
126 * They can have been removed during partial hotplug.
127 */
Gavin Shan317f06d2013-06-20 13:20:52 +0800128 slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
Gavin Shanab444ec2013-07-24 10:24:57 +0800129 pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
Gavin Shan317f06d2013-06-20 13:20:52 +0800130 pcibios_setup_bus_devices(bus);
131 max = bus->busn_res.start;
Andy Shevchenko9d987eb2017-11-10 19:52:30 +0200132 /*
133 * Scan bridges that are already configured. We don't touch
134 * them unless they are misconfigured (which will be done in
135 * the second scan below).
136 */
137 for_each_pci_bridge(dev, bus)
138 max = pci_scan_bridge(bus, dev, max, 0);
139
140 /* Scan bridges that need to be reconfigured */
141 for_each_pci_bridge(dev, bus)
142 max = pci_scan_bridge(bus, dev, max, 1);
Gavin Shan317f06d2013-06-20 13:20:52 +0800143 }
144 pcibios_finish_adding_to_bus(bus);
145}
Gavin Shanbd251b82016-05-03 15:41:37 +1000146EXPORT_SYMBOL_GPL(pci_hp_add_devices);