2019-08-28 08:07:37 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2005-11-03 18:52:16 -06: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 16:19:31 +10:00
|
|
|
#include <linux/export.h>
|
2024-05-17 19:55:23 +05:30
|
|
|
#include <linux/node.h>
|
2005-11-03 18:52:16 -06:00
|
|
|
#include <asm/pci-bridge.h>
|
2006-03-14 17:46:45 -06:00
|
|
|
#include <asm/ppc-pci.h>
|
2006-03-28 23:15:54 +11:00
|
|
|
#include <asm/firmware.h>
|
2007-03-22 23:14:07 +01:00
|
|
|
#include <asm/eeh.h>
|
2005-11-03 18:52:16 -06:00
|
|
|
|
2015-03-31 16:00:50 +11:00
|
|
|
#include "pseries.h"
|
|
|
|
|
2012-12-21 14:04:10 -08:00
|
|
|
struct pci_controller *init_phb_dynamic(struct device_node *dn)
|
2006-03-14 17:46:45 -06:00
|
|
|
{
|
|
|
|
struct pci_controller *phb;
|
2024-05-17 19:55:23 +05:30
|
|
|
int nid;
|
2006-03-14 17:46:45 -06:00
|
|
|
|
2017-08-21 10:16:47 -05:00
|
|
|
pr_debug("PCI: Initializing new hotplug PHB %pOF\n", dn);
|
2008-10-27 19:48:52 +00:00
|
|
|
|
2024-05-17 19:55:23 +05:30
|
|
|
nid = of_node_to_nid(dn);
|
|
|
|
if (likely((nid) >= 0)) {
|
|
|
|
if (!node_online(nid)) {
|
2025-05-28 12:18:04 -05:00
|
|
|
if (register_one_node(nid)) {
|
2024-05-17 19:55:23 +05:30
|
|
|
pr_err("PCI: Failed to register node %d\n", nid);
|
|
|
|
} else {
|
|
|
|
update_numa_distance(dn);
|
|
|
|
node_set_online(nid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-14 17:46:45 -06:00
|
|
|
phb = pcibios_alloc_controller(dn);
|
|
|
|
if (!phb)
|
|
|
|
return NULL;
|
2006-11-11 17:25:08 +11:00
|
|
|
rtas_setup_phb(phb);
|
2006-03-14 17:46:45 -06:00
|
|
|
pci_process_bridge_OF_ranges(phb, dn, 0);
|
2015-03-31 16:00:50 +11:00
|
|
|
phb->controller_ops = pseries_pci_controller_ops;
|
2006-03-14 17:46:45 -06:00
|
|
|
|
|
|
|
pci_devs_phb_init_dynamic(phb);
|
|
|
|
|
2021-07-01 15:27:28 +02:00
|
|
|
pseries_msi_allocate_domains(phb);
|
|
|
|
|
powerpc/pseries/iommu: DLPAR add doesn't completely initialize pci_controller
When a PCI device is dynamically added, the kernel oopses with a NULL
pointer dereference:
BUG: Kernel NULL pointer dereference on read at 0x00000030
Faulting instruction address: 0xc0000000006bbe5c
Oops: Kernel access of bad area, sig: 11 [#1]
LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA pSeries
Modules linked in: rpadlpar_io rpaphp rpcsec_gss_krb5 auth_rpcgss nfsv4 dns_resolver nfs lockd grace fscache netfs xsk_diag bonding nft_compat nf_tables nfnetlink rfkill binfmt_misc dm_multipath rpcrdma sunrpc rdma_ucm ib_srpt ib_isert iscsi_target_mod target_core_mod ib_umad ib_iser libiscsi scsi_transport_iscsi ib_ipoib rdma_cm iw_cm ib_cm mlx5_ib ib_uverbs ib_core pseries_rng drm drm_panel_orientation_quirks xfs libcrc32c mlx5_core mlxfw sd_mod t10_pi sg tls ibmvscsi ibmveth scsi_transport_srp vmx_crypto pseries_wdt psample dm_mirror dm_region_hash dm_log dm_mod fuse
CPU: 17 PID: 2685 Comm: drmgr Not tainted 6.7.0-203405+ #66
Hardware name: IBM,9080-HEX POWER10 (raw) 0x800200 0xf000006 of:IBM,FW1060.00 (NH1060_008) hv:phyp pSeries
NIP: c0000000006bbe5c LR: c000000000a13e68 CTR: c0000000000579f8
REGS: c00000009924f240 TRAP: 0300 Not tainted (6.7.0-203405+)
MSR: 8000000000009033 <SF,EE,ME,IR,DR,RI,LE> CR: 24002220 XER: 20040006
CFAR: c000000000a13e64 DAR: 0000000000000030 DSISR: 40000000 IRQMASK: 0
...
NIP sysfs_add_link_to_group+0x34/0x94
LR iommu_device_link+0x5c/0x118
Call Trace:
iommu_init_device+0x26c/0x318 (unreliable)
iommu_device_link+0x5c/0x118
iommu_init_device+0xa8/0x318
iommu_probe_device+0xc0/0x134
iommu_bus_notifier+0x44/0x104
notifier_call_chain+0xb8/0x19c
blocking_notifier_call_chain+0x64/0x98
bus_notify+0x50/0x7c
device_add+0x640/0x918
pci_device_add+0x23c/0x298
of_create_pci_dev+0x400/0x884
of_scan_pci_dev+0x124/0x1b0
__of_scan_bus+0x78/0x18c
pcibios_scan_phb+0x2a4/0x3b0
init_phb_dynamic+0xb8/0x110
dlpar_add_slot+0x170/0x3b8 [rpadlpar_io]
add_slot_store.part.0+0xb4/0x130 [rpadlpar_io]
kobj_attr_store+0x2c/0x48
sysfs_kf_write+0x64/0x78
kernfs_fop_write_iter+0x1b0/0x290
vfs_write+0x350/0x4a0
ksys_write+0x84/0x140
system_call_exception+0x124/0x330
system_call_vectored_common+0x15c/0x2ec
Commit a940904443e4 ("powerpc/iommu: Add iommu_ops to report capabilities
and allow blocking domains") broke DLPAR add of PCI devices.
The above added iommu_device structure to pci_controller. During
system boot, PCI devices are discovered and this newly added iommu_device
structure is initialized by a call to iommu_device_register().
During DLPAR add of a PCI device, a new pci_controller structure is
allocated but there are no calls made to iommu_device_register()
interface.
Fix is to register the iommu device during DLPAR add as well.
Fixes: a940904443e4 ("powerpc/iommu: Add iommu_ops to report capabilities and allow blocking domains")
Signed-off-by: Gaurav Batra <gbatra@linux.ibm.com>
Reviewed-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240215221833.4817-1-gbatra@linux.ibm.com
2024-02-15 16:18:33 -06:00
|
|
|
ppc_iommu_register_device(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-27 20:04:04 +00:00
|
|
|
/* Create EEH devices for the PHB */
|
2020-07-25 18:12:18 +10: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-27 20:04:04 +00:00
|
|
|
|
2006-03-14 17:46:45 -06:00
|
|
|
if (dn->child)
|
2020-03-06 18:39:03 +11:00
|
|
|
pseries_eeh_init_edev_recursive(PCI_DN(dn));
|
2006-03-14 17:46:45 -06:00
|
|
|
|
2011-02-04 11:24:11 -07:00
|
|
|
pcibios_scan_phb(phb);
|
2008-10-27 19:48:52 +00:00
|
|
|
pcibios_finish_adding_to_bus(phb->bus);
|
2006-03-14 17:46:45 -06:00
|
|
|
|
|
|
|
return phb;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(init_phb_dynamic);
|
2008-10-27 19:48:52 +00:00
|
|
|
|
|
|
|
/* RPA-specific bits for removing PHBs */
|
|
|
|
int remove_phb_dynamic(struct pci_controller *phb)
|
|
|
|
{
|
|
|
|
struct pci_bus *b = phb->bus;
|
2021-02-11 12:24:35 -06:00
|
|
|
struct pci_host_bridge *host_bridge = to_pci_host_bridge(b->bridge);
|
2008-10-27 19:48:52 +00:00
|
|
|
struct resource *res;
|
|
|
|
int rc, i;
|
|
|
|
|
2010-02-06 07:47:20 +00:00
|
|
|
pr_debug("PCI: Removing PHB %04x:%02x...\n",
|
2008-10-27 19:48:52 +00: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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
powerpc/pseries/iommu: DLPAR add doesn't completely initialize pci_controller
When a PCI device is dynamically added, the kernel oopses with a NULL
pointer dereference:
BUG: Kernel NULL pointer dereference on read at 0x00000030
Faulting instruction address: 0xc0000000006bbe5c
Oops: Kernel access of bad area, sig: 11 [#1]
LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA pSeries
Modules linked in: rpadlpar_io rpaphp rpcsec_gss_krb5 auth_rpcgss nfsv4 dns_resolver nfs lockd grace fscache netfs xsk_diag bonding nft_compat nf_tables nfnetlink rfkill binfmt_misc dm_multipath rpcrdma sunrpc rdma_ucm ib_srpt ib_isert iscsi_target_mod target_core_mod ib_umad ib_iser libiscsi scsi_transport_iscsi ib_ipoib rdma_cm iw_cm ib_cm mlx5_ib ib_uverbs ib_core pseries_rng drm drm_panel_orientation_quirks xfs libcrc32c mlx5_core mlxfw sd_mod t10_pi sg tls ibmvscsi ibmveth scsi_transport_srp vmx_crypto pseries_wdt psample dm_mirror dm_region_hash dm_log dm_mod fuse
CPU: 17 PID: 2685 Comm: drmgr Not tainted 6.7.0-203405+ #66
Hardware name: IBM,9080-HEX POWER10 (raw) 0x800200 0xf000006 of:IBM,FW1060.00 (NH1060_008) hv:phyp pSeries
NIP: c0000000006bbe5c LR: c000000000a13e68 CTR: c0000000000579f8
REGS: c00000009924f240 TRAP: 0300 Not tainted (6.7.0-203405+)
MSR: 8000000000009033 <SF,EE,ME,IR,DR,RI,LE> CR: 24002220 XER: 20040006
CFAR: c000000000a13e64 DAR: 0000000000000030 DSISR: 40000000 IRQMASK: 0
...
NIP sysfs_add_link_to_group+0x34/0x94
LR iommu_device_link+0x5c/0x118
Call Trace:
iommu_init_device+0x26c/0x318 (unreliable)
iommu_device_link+0x5c/0x118
iommu_init_device+0xa8/0x318
iommu_probe_device+0xc0/0x134
iommu_bus_notifier+0x44/0x104
notifier_call_chain+0xb8/0x19c
blocking_notifier_call_chain+0x64/0x98
bus_notify+0x50/0x7c
device_add+0x640/0x918
pci_device_add+0x23c/0x298
of_create_pci_dev+0x400/0x884
of_scan_pci_dev+0x124/0x1b0
__of_scan_bus+0x78/0x18c
pcibios_scan_phb+0x2a4/0x3b0
init_phb_dynamic+0xb8/0x110
dlpar_add_slot+0x170/0x3b8 [rpadlpar_io]
add_slot_store.part.0+0xb4/0x130 [rpadlpar_io]
kobj_attr_store+0x2c/0x48
sysfs_kf_write+0x64/0x78
kernfs_fop_write_iter+0x1b0/0x290
vfs_write+0x350/0x4a0
ksys_write+0x84/0x140
system_call_exception+0x124/0x330
system_call_vectored_common+0x15c/0x2ec
Commit a940904443e4 ("powerpc/iommu: Add iommu_ops to report capabilities
and allow blocking domains") broke DLPAR add of PCI devices.
The above added iommu_device structure to pci_controller. During
system boot, PCI devices are discovered and this newly added iommu_device
structure is initialized by a call to iommu_device_register().
During DLPAR add of a PCI device, a new pci_controller structure is
allocated but there are no calls made to iommu_device_register()
interface.
Fix is to register the iommu device during DLPAR add as well.
Fixes: a940904443e4 ("powerpc/iommu: Add iommu_ops to report capabilities and allow blocking domains")
Signed-off-by: Gaurav Batra <gbatra@linux.ibm.com>
Reviewed-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240215221833.4817-1-gbatra@linux.ibm.com
2024-02-15 16:18:33 -06:00
|
|
|
ppc_iommu_unregister_device(phb);
|
|
|
|
|
2021-07-01 15:27:28 +02:00
|
|
|
pseries_msi_free_domains(phb);
|
|
|
|
|
2022-03-18 14:42:19 +11:00
|
|
|
/* Keep a reference so phb isn't freed yet */
|
|
|
|
get_device(&host_bridge->dev);
|
|
|
|
|
2014-07-29 13:48:13 -04:00
|
|
|
/* Remove the PCI bus and unregister the bridge device from sysfs */
|
2008-10-27 19:48:52 +00:00
|
|
|
phb->bus = NULL;
|
|
|
|
pci_remove_bus(b);
|
2021-02-11 12:24:35 -06:00
|
|
|
host_bridge->bus = NULL;
|
|
|
|
device_unregister(&host_bridge->dev);
|
2008-10-27 19:48:52 +00: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-11 17:25:40 -03:00
|
|
|
/*
|
|
|
|
* The pci_controller data structure is freed by
|
|
|
|
* the pcibios_free_controller_deferred() callback;
|
|
|
|
* see pseries_root_bridge_prepare().
|
|
|
|
*/
|
2022-03-18 14:42:19 +11:00
|
|
|
put_device(&host_bridge->dev);
|
2008-10-27 19:48:52 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(remove_phb_dynamic);
|