a5c57fd2e9
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 Commita940904443
("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:a940904443
("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
116 lines
2.8 KiB
C
116 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* 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>
|
|
#include <linux/export.h>
|
|
#include <asm/pci-bridge.h>
|
|
#include <asm/ppc-pci.h>
|
|
#include <asm/firmware.h>
|
|
#include <asm/eeh.h>
|
|
|
|
#include "pseries.h"
|
|
|
|
struct pci_controller *init_phb_dynamic(struct device_node *dn)
|
|
{
|
|
struct pci_controller *phb;
|
|
|
|
pr_debug("PCI: Initializing new hotplug PHB %pOF\n", dn);
|
|
|
|
phb = pcibios_alloc_controller(dn);
|
|
if (!phb)
|
|
return NULL;
|
|
rtas_setup_phb(phb);
|
|
pci_process_bridge_OF_ranges(phb, dn, 0);
|
|
phb->controller_ops = pseries_pci_controller_ops;
|
|
|
|
pci_devs_phb_init_dynamic(phb);
|
|
|
|
pseries_msi_allocate_domains(phb);
|
|
|
|
ppc_iommu_register_device(phb);
|
|
|
|
/* Create EEH devices for the PHB */
|
|
eeh_phb_pe_create(phb);
|
|
|
|
if (dn->child)
|
|
pseries_eeh_init_edev_recursive(PCI_DN(dn));
|
|
|
|
pcibios_scan_phb(phb);
|
|
pcibios_finish_adding_to_bus(phb->bus);
|
|
|
|
return phb;
|
|
}
|
|
EXPORT_SYMBOL_GPL(init_phb_dynamic);
|
|
|
|
/* RPA-specific bits for removing PHBs */
|
|
int remove_phb_dynamic(struct pci_controller *phb)
|
|
{
|
|
struct pci_bus *b = phb->bus;
|
|
struct pci_host_bridge *host_bridge = to_pci_host_bridge(b->bridge);
|
|
struct resource *res;
|
|
int rc, i;
|
|
|
|
pr_debug("PCI: Removing PHB %04x:%02x...\n",
|
|
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;
|
|
}
|
|
}
|
|
|
|
ppc_iommu_unregister_device(phb);
|
|
|
|
pseries_msi_free_domains(phb);
|
|
|
|
/* Keep a reference so phb isn't freed yet */
|
|
get_device(&host_bridge->dev);
|
|
|
|
/* Remove the PCI bus and unregister the bridge device from sysfs */
|
|
phb->bus = NULL;
|
|
pci_remove_bus(b);
|
|
host_bridge->bus = NULL;
|
|
device_unregister(&host_bridge->dev);
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/*
|
|
* The pci_controller data structure is freed by
|
|
* the pcibios_free_controller_deferred() callback;
|
|
* see pseries_root_bridge_prepare().
|
|
*/
|
|
put_device(&host_bridge->dev);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(remove_phb_dynamic);
|