mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-02-11 01:05:25 +07:00
![Oliver O'Halloran](/assets/img/avatar_default.png)
The eeh_ops->probe() function is called from two different contexts: 1. On pseries, where we set EEH_PROBE_MODE_DEVTREE, it's called in eeh_add_device_early() which is supposed to run before we create a pci_dev. 2. On PowerNV, where we set EEH_PROBE_MODE_DEV, it's called in eeh_device_add_late() which is supposed to run *after* the pci_dev is created. The "early" probe is required because PAPR requires that we perform an RTAS call to enable EEH support on a device before we start interacting with it via config space or MMIO. This requirement doesn't exist on PowerNV and shoehorning two completely separate initialisation paths into a common interface just results in a convoluted code everywhere. Additionally the early probe requires the probe function to take an pci_dn rather than a pci_dev argument. We'd like to make pci_dn a pseries specific data structure since there's no real requirement for them on PowerNV. To help both goals move the early probe into the pseries containment zone so the platform depedence is more explicit. Reviewed-by: Sam Bobroff <sbobroff@linux.ibm.com> Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20200306073904.4737-5-oohall@gmail.com
102 lines
2.4 KiB
C
102 lines
2.4 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);
|
|
|
|
/* Create EEH devices for the PHB */
|
|
eeh_dev_phb_init_dynamic(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 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;
|
|
}
|
|
}
|
|
|
|
/* Remove the PCI bus and unregister the bridge device from sysfs */
|
|
phb->bus = NULL;
|
|
pci_remove_bus(b);
|
|
device_unregister(b->bridge);
|
|
|
|
/* 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().
|
|
*/
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(remove_phb_dynamic);
|