Commit b905f8cd authored by Sam Bobroff's avatar Sam Bobroff Committed by Michael Ellerman

powerpc/eeh: EEH for pSeries hot plug

On PowerNV and pSeries, devices currently acquire EEH support from
several different places: Boot-time devices from eeh_probe_devices()
and eeh_addr_cache_build(), Virtual Function devices from the pcibios
bus add device hooks and hot plugged devices from pci_hp_add_devices()
(with other platforms using other methods as well).  Unfortunately,
pSeries machines currently discover hot plugged devices using
pci_rescan_bus(), not pci_hp_add_devices(), and so those devices do
not receive EEH support.

Rather than adding another case for pci_rescan_bus(), this change
widens the scope of the pcibios bus add device hooks so that they can
handle all devices. As a side effect this also supports devices
discovered after manually rescanning via /sys/bus/pci/rescan.

Note that on PowerNV, this change allows the EEH subsystem to become
enabled after boot as long as it has not been forced off, which was
not previously possible (it was already possible on pSeries).
Signed-off-by: default avatarSam Bobroff <sbobroff@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/72ae8ae9c54097158894a52de23690448de38ea9.1565930772.git.sbobroff@linux.ibm.com
parent 685a0bc0
...@@ -1192,7 +1192,7 @@ void eeh_add_device_late(struct pci_dev *dev) ...@@ -1192,7 +1192,7 @@ void eeh_add_device_late(struct pci_dev *dev)
struct pci_dn *pdn; struct pci_dn *pdn;
struct eeh_dev *edev; struct eeh_dev *edev;
if (!dev || !eeh_enabled()) if (!dev)
return; return;
pr_debug("EEH: Adding device %s\n", pci_name(dev)); pr_debug("EEH: Adding device %s\n", pci_name(dev));
...@@ -1248,6 +1248,8 @@ void eeh_add_device_tree_late(struct pci_bus *bus) ...@@ -1248,6 +1248,8 @@ void eeh_add_device_tree_late(struct pci_bus *bus)
{ {
struct pci_dev *dev; struct pci_dev *dev;
if (eeh_has_flag(EEH_FORCE_DISABLED))
return;
list_for_each_entry(dev, &bus->devices, bus_list) { list_for_each_entry(dev, &bus->devices, bus_list) {
eeh_add_device_late(dev); eeh_add_device_late(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
......
...@@ -41,7 +41,7 @@ void pnv_pcibios_bus_add_device(struct pci_dev *pdev) ...@@ -41,7 +41,7 @@ void pnv_pcibios_bus_add_device(struct pci_dev *pdev)
{ {
struct pci_dn *pdn = pci_get_pdn(pdev); struct pci_dn *pdn = pci_get_pdn(pdev);
if (!pdev->is_virtfn) if (eeh_has_flag(EEH_FORCE_DISABLED))
return; return;
pr_debug("%s: EEH: Setting up device %s.\n", __func__, pci_name(pdev)); pr_debug("%s: EEH: Setting up device %s.\n", __func__, pci_name(pdev));
...@@ -196,6 +196,25 @@ PNV_EEH_DBGFS_ENTRY(inbB, 0xE10); ...@@ -196,6 +196,25 @@ PNV_EEH_DBGFS_ENTRY(inbB, 0xE10);
#endif /* CONFIG_DEBUG_FS */ #endif /* CONFIG_DEBUG_FS */
void pnv_eeh_enable_phbs(void)
{
struct pci_controller *hose;
struct pnv_phb *phb;
list_for_each_entry(hose, &hose_list, list_node) {
phb = hose->private_data;
/*
* If EEH is enabled, we're going to rely on that.
* Otherwise, we restore to conventional mechanism
* to clear frozen PE during PCI config access.
*/
if (eeh_enabled())
phb->flags |= PNV_PHB_FLAG_EEH;
else
phb->flags &= ~PNV_PHB_FLAG_EEH;
}
}
/** /**
* pnv_eeh_post_init - EEH platform dependent post initialization * pnv_eeh_post_init - EEH platform dependent post initialization
* *
...@@ -234,19 +253,11 @@ int pnv_eeh_post_init(void) ...@@ -234,19 +253,11 @@ int pnv_eeh_post_init(void)
if (!eeh_enabled()) if (!eeh_enabled())
disable_irq(eeh_event_irq); disable_irq(eeh_event_irq);
pnv_eeh_enable_phbs();
list_for_each_entry(hose, &hose_list, list_node) { list_for_each_entry(hose, &hose_list, list_node) {
phb = hose->private_data; phb = hose->private_data;
/*
* If EEH is enabled, we're going to rely on that.
* Otherwise, we restore to conventional mechanism
* to clear frozen PE during PCI config access.
*/
if (eeh_enabled())
phb->flags |= PNV_PHB_FLAG_EEH;
else
phb->flags &= ~PNV_PHB_FLAG_EEH;
/* Create debugfs entries */ /* Create debugfs entries */
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
if (phb->has_dbgfs || !phb->dbgfs) if (phb->has_dbgfs || !phb->dbgfs)
...@@ -454,7 +465,11 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data) ...@@ -454,7 +465,11 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data)
* Enable EEH explicitly so that we will do EEH check * Enable EEH explicitly so that we will do EEH check
* while accessing I/O stuff * while accessing I/O stuff
*/ */
eeh_add_flag(EEH_ENABLED); if (!eeh_has_flag(EEH_ENABLED)) {
enable_irq(eeh_event_irq);
pnv_eeh_enable_phbs();
eeh_add_flag(EEH_ENABLED);
}
/* Save memory bars */ /* Save memory bars */
eeh_save_bars(edev); eeh_save_bars(edev);
......
...@@ -42,44 +42,44 @@ static int ibm_get_config_addr_info; ...@@ -42,44 +42,44 @@ static int ibm_get_config_addr_info;
static int ibm_get_config_addr_info2; static int ibm_get_config_addr_info2;
static int ibm_configure_pe; static int ibm_configure_pe;
#ifdef CONFIG_PCI_IOV
void pseries_pcibios_bus_add_device(struct pci_dev *pdev) void pseries_pcibios_bus_add_device(struct pci_dev *pdev)
{ {
struct pci_dn *pdn = pci_get_pdn(pdev); struct pci_dn *pdn = pci_get_pdn(pdev);
struct pci_dn *physfn_pdn;
struct eeh_dev *edev;
if (!pdev->is_virtfn) if (eeh_has_flag(EEH_FORCE_DISABLED))
return; return;
pr_debug("%s: EEH: Setting up device %s.\n", __func__, pci_name(pdev)); pr_debug("%s: EEH: Setting up device %s.\n", __func__, pci_name(pdev));
#ifdef CONFIG_PCI_IOV
if (pdev->is_virtfn) {
struct pci_dn *physfn_pdn;
pdn->device_id = pdev->device; pdn->device_id = pdev->device;
pdn->vendor_id = pdev->vendor; pdn->vendor_id = pdev->vendor;
pdn->class_code = pdev->class; pdn->class_code = pdev->class;
/* /*
* Last allow unfreeze return code used for retrieval * Last allow unfreeze return code used for retrieval
* by user space in eeh-sysfs to show the last command * by user space in eeh-sysfs to show the last command
* completion from platform. * completion from platform.
*/ */
pdn->last_allow_rc = 0; pdn->last_allow_rc = 0;
physfn_pdn = pci_get_pdn(pdev->physfn); physfn_pdn = pci_get_pdn(pdev->physfn);
pdn->pe_number = physfn_pdn->pe_num_map[pdn->vf_index]; pdn->pe_number = physfn_pdn->pe_num_map[pdn->vf_index];
edev = pdn_to_eeh_dev(pdn); }
#endif
/*
* The following operations will fail if VF's sysfs files
* aren't created or its resources aren't finalized.
*/
eeh_add_device_early(pdn); eeh_add_device_early(pdn);
eeh_add_device_late(pdev); eeh_add_device_late(pdev);
edev->pe_config_addr = (pdn->busno << 16) | (pdn->devfn << 8); #ifdef CONFIG_PCI_IOV
eeh_rmv_from_parent_pe(edev); /* Remove as it is adding to bus pe */ if (pdev->is_virtfn) {
eeh_add_to_parent_pe(edev); /* Add as VF PE type */ struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
eeh_sysfs_add_device(pdev);
} edev->pe_config_addr = (pdn->busno << 16) | (pdn->devfn << 8);
eeh_rmv_from_parent_pe(edev); /* Remove as it is adding to bus pe */
eeh_add_to_parent_pe(edev); /* Add as VF PE type */
}
#endif #endif
eeh_sysfs_add_device(pdev);
}
/* /*
* Buffer for reporting slot-error-detail rtas calls. Its here * Buffer for reporting slot-error-detail rtas calls. Its here
...@@ -146,10 +146,8 @@ static int pseries_eeh_init(void) ...@@ -146,10 +146,8 @@ static int pseries_eeh_init(void)
/* Set EEH probe mode */ /* Set EEH probe mode */
eeh_add_flag(EEH_PROBE_MODE_DEVTREE | EEH_ENABLE_IO_FOR_LOG); eeh_add_flag(EEH_PROBE_MODE_DEVTREE | EEH_ENABLE_IO_FOR_LOG);
#ifdef CONFIG_PCI_IOV
/* Set EEH machine dependent code */ /* Set EEH machine dependent code */
ppc_md.pcibios_bus_add_device = pseries_pcibios_bus_add_device; ppc_md.pcibios_bus_add_device = pseries_pcibios_bus_add_device;
#endif
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment