2019-08-28 14:07:37 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2005-11-04 08:52:16 +08:00
|
|
|
/*
|
|
|
|
* PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code
|
|
|
|
* for RPA-compliant PPC64 platform.
|
|
|
|
* Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
|
|
|
|
* Copyright (C) 2005 International Business Machines
|
|
|
|
*
|
|
|
|
* Updates, 2005, John Rose <johnrose@austin.ibm.com>
|
|
|
|
* Updates, 2005, Linas Vepstas <linas@austin.ibm.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/pci.h>
|
2011-07-29 14:19:31 +08:00
|
|
|
#include <linux/export.h>
|
2005-11-04 08:52:16 +08:00
|
|
|
#include <asm/pci-bridge.h>
|
2006-03-15 07:46:45 +08:00
|
|
|
#include <asm/ppc-pci.h>
|
2006-03-28 20:15:54 +08:00
|
|
|
#include <asm/firmware.h>
|
2007-03-23 06:14:07 +08:00
|
|
|
#include <asm/eeh.h>
|
2005-11-04 08:52:16 +08:00
|
|
|
|
2015-03-31 13:00:50 +08:00
|
|
|
#include "pseries.h"
|
|
|
|
|
2012-12-22 06:04:10 +08:00
|
|
|
struct pci_controller *init_phb_dynamic(struct device_node *dn)
|
2006-03-15 07:46:45 +08:00
|
|
|
{
|
|
|
|
struct pci_controller *phb;
|
|
|
|
|
2017-08-21 23:16:47 +08:00
|
|
|
pr_debug("PCI: Initializing new hotplug PHB %pOF\n", dn);
|
2008-10-28 03:48:52 +08:00
|
|
|
|
2006-03-15 07:46:45 +08:00
|
|
|
phb = pcibios_alloc_controller(dn);
|
|
|
|
if (!phb)
|
|
|
|
return NULL;
|
2006-11-11 14:25:08 +08:00
|
|
|
rtas_setup_phb(phb);
|
2006-03-15 07:46:45 +08:00
|
|
|
pci_process_bridge_OF_ranges(phb, dn, 0);
|
2015-03-31 13:00:50 +08:00
|
|
|
phb->controller_ops = pseries_pci_controller_ops;
|
2006-03-15 07:46:45 +08:00
|
|
|
|
|
|
|
pci_devs_phb_init_dynamic(phb);
|
|
|
|
|
powerpc/eeh: Introduce EEH device
Original EEH implementation depends on struct pci_dn heavily. However,
EEH shouldn't depend on that actually because EEH needn't share much
information with other PCI components. That's to say, EEH should have
worked independently.
The patch introduces struct eeh_dev so that EEH core components needn't
be working based on struct pci_dn in future. Also, struct pci_dn, struct
eeh_dev instances are created in dynamic fasion and the binding with EEH
device, OF node, PCI device is implemented as well.
The EEH devices are created after PHBs are detected and initialized, but
PCI emunation hasn't started yet. Apart from that, PHB might be created
dynamically through DLPAR component and the EEH devices should be creatd
as well. Another case might be OF node is created dynamically by DR
(Dynamic Reconfiguration), which has been defined by PAPR. For those OF
nodes created by DR, EEH devices should be also created accordingly. The
binding between EEH device and OF node is done while the EEH device is
initially created.
The binding between EEH device and PCI device should be done after PCI
emunation is done. Besides, PCI hotplug also needs the binding so that
the EEH devices could be traced from the newly coming PCI buses or PCI
devices.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
2012-02-28 04:04:04 +08:00
|
|
|
/* Create EEH devices for the PHB */
|
2020-07-25 16:12:18 +08:00
|
|
|
eeh_phb_pe_create(phb);
|
powerpc/eeh: Introduce EEH device
Original EEH implementation depends on struct pci_dn heavily. However,
EEH shouldn't depend on that actually because EEH needn't share much
information with other PCI components. That's to say, EEH should have
worked independently.
The patch introduces struct eeh_dev so that EEH core components needn't
be working based on struct pci_dn in future. Also, struct pci_dn, struct
eeh_dev instances are created in dynamic fasion and the binding with EEH
device, OF node, PCI device is implemented as well.
The EEH devices are created after PHBs are detected and initialized, but
PCI emunation hasn't started yet. Apart from that, PHB might be created
dynamically through DLPAR component and the EEH devices should be creatd
as well. Another case might be OF node is created dynamically by DR
(Dynamic Reconfiguration), which has been defined by PAPR. For those OF
nodes created by DR, EEH devices should be also created accordingly. The
binding between EEH device and OF node is done while the EEH device is
initially created.
The binding between EEH device and PCI device should be done after PCI
emunation is done. Besides, PCI hotplug also needs the binding so that
the EEH devices could be traced from the newly coming PCI buses or PCI
devices.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
2012-02-28 04:04:04 +08:00
|
|
|
|
2006-03-15 07:46:45 +08:00
|
|
|
if (dn->child)
|
2020-03-06 15:39:03 +08:00
|
|
|
pseries_eeh_init_edev_recursive(PCI_DN(dn));
|
2006-03-15 07:46:45 +08:00
|
|
|
|
2011-02-05 02:24:11 +08:00
|
|
|
pcibios_scan_phb(phb);
|
2008-10-28 03:48:52 +08:00
|
|
|
pcibios_finish_adding_to_bus(phb->bus);
|
2006-03-15 07:46:45 +08:00
|
|
|
|
|
|
|
return phb;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(init_phb_dynamic);
|
2008-10-28 03:48:52 +08:00
|
|
|
|
|
|
|
/* RPA-specific bits for removing PHBs */
|
|
|
|
int remove_phb_dynamic(struct pci_controller *phb)
|
|
|
|
{
|
|
|
|
struct pci_bus *b = phb->bus;
|
|
|
|
struct resource *res;
|
|
|
|
int rc, i;
|
|
|
|
|
2010-02-06 15:47:20 +08:00
|
|
|
pr_debug("PCI: Removing PHB %04x:%02x...\n",
|
2008-10-28 03:48:52 +08:00
|
|
|
pci_domain_nr(b), b->number);
|
|
|
|
|
|
|
|
/* We cannot to remove a root bus that has children */
|
|
|
|
if (!(list_empty(&b->children) && list_empty(&b->devices)))
|
|
|
|
return -EBUSY;
|
|
|
|
|
|
|
|
/* We -know- there aren't any child devices anymore at this stage
|
|
|
|
* and thus, we can safely unmap the IO space as it's not in use
|
|
|
|
*/
|
|
|
|
res = &phb->io_resource;
|
|
|
|
if (res->flags & IORESOURCE_IO) {
|
|
|
|
rc = pcibios_unmap_io_space(b);
|
|
|
|
if (rc) {
|
|
|
|
printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
|
|
|
|
__func__, b->name);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-30 01:48:13 +08:00
|
|
|
/* Remove the PCI bus and unregister the bridge device from sysfs */
|
2008-10-28 03:48:52 +08:00
|
|
|
phb->bus = NULL;
|
|
|
|
pci_remove_bus(b);
|
2014-07-30 01:48:13 +08:00
|
|
|
device_unregister(b->bridge);
|
2008-10-28 03:48:52 +08:00
|
|
|
|
|
|
|
/* Now release the IO resource */
|
|
|
|
if (res->flags & IORESOURCE_IO)
|
|
|
|
release_resource(res);
|
|
|
|
|
|
|
|
/* Release memory resources */
|
|
|
|
for (i = 0; i < 3; ++i) {
|
|
|
|
res = &phb->mem_resources[i];
|
|
|
|
if (!(res->flags & IORESOURCE_MEM))
|
|
|
|
continue;
|
|
|
|
release_resource(res);
|
|
|
|
}
|
|
|
|
|
powerpc/pseries: use pci_host_bridge.release_fn() to kfree(phb)
This patch leverages 'struct pci_host_bridge' from the PCI subsystem
in order to free the pci_controller only after the last reference to
its devices is dropped (avoiding an oops in pcibios_release_device()
if the last reference is dropped after pcibios_free_controller()).
The patch relies on pci_host_bridge.release_fn() (and .release_data),
which is called automatically by the PCI subsystem when the root bus
is released (i.e., the last reference is dropped). Those fields are
set via pci_set_host_bridge_release() (e.g. in the platform-specific
implementation of pcibios_root_bridge_prepare()).
It introduces the 'pcibios_free_controller_deferred()' .release_fn()
and it expects .release_data to hold a pointer to the pci_controller.
The function implictly calls 'pcibios_free_controller()', so an user
must *NOT* explicitly call it if using the new _deferred() callback.
The functionality is enabled for pseries (although it isn't platform
specific, and may be used by cxl).
Details on not-so-elegant design choices:
- Use 'pci_host_bridge.release_data' field as pointer to associated
'struct pci_controller' so *not* to 'pci_bus_to_host(bridge->bus)'
in pcibios_free_controller_deferred().
That's because pci_remove_root_bus() sets 'host_bridge->bus = NULL'
(so, if the last reference is released after pci_remove_root_bus()
runs, which eventually reaches pcibios_free_controller_deferred(),
that would hit a null pointer dereference).
The cxl/vphb.c code calls pci_remove_root_bus(), and the cxl folks
are interested in this fix.
Test-case #1 (hold references)
# ls -ld /sys/block/sd* | grep -m1 0021:01:00.0
<...> /sys/block/sdaa -> ../devices/pci0021:01/0021:01:00.0/<...>
# ls -ld /sys/block/sd* | grep -m1 0021:01:00.1
<...> /sys/block/sdab -> ../devices/pci0021:01/0021:01:00.1/<...>
# cat >/dev/sdaa & pid1=$!
# cat >/dev/sdab & pid2=$!
# drmgr -w 5 -d 1 -c phb -s 'PHB 33' -r
Validating PHB DLPAR capability...yes.
[ 594.306719] pci_hp_remove_devices: PCI: Removing devices on bus 0021:01
[ 594.306738] pci_hp_remove_devices: Removing 0021:01:00.0...
...
[ 598.236381] pci_hp_remove_devices: Removing 0021:01:00.1...
...
[ 611.972077] pci_bus 0021:01: busn_res: [bus 01-ff] is released
[ 611.972140] rpadlpar_io: slot PHB 33 removed
# kill -9 $pid1
# kill -9 $pid2
[ 632.918088] pcibios_free_controller_deferred: domain 33, dynamic 1
Test-case #2 (don't hold references)
# drmgr -w 5 -d 1 -c phb -s 'PHB 33' -r
Validating PHB DLPAR capability...yes.
[ 916.357363] pci_hp_remove_devices: PCI: Removing devices on bus 0021:01
[ 916.357386] pci_hp_remove_devices: Removing 0021:01:00.0...
...
[ 920.566527] pci_hp_remove_devices: Removing 0021:01:00.1...
...
[ 933.955873] pci_bus 0021:01: busn_res: [bus 01-ff] is released
[ 933.955977] pcibios_free_controller_deferred: domain 33, dynamic 1
[ 933.955999] rpadlpar_io: slot PHB 33 removed
Suggested-By: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Mauricio Faria de Oliveira <mauricfo@linux.vnet.ibm.com>
Reviewed-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
Tested-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> # cxl
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
2016-08-12 04:25:40 +08:00
|
|
|
/*
|
|
|
|
* The pci_controller data structure is freed by
|
|
|
|
* the pcibios_free_controller_deferred() callback;
|
|
|
|
* see pseries_root_bridge_prepare().
|
|
|
|
*/
|
2008-10-28 03:48:52 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(remove_phb_dynamic);
|