powerpc/powernv: Drop PHB operation reset()
The patch drops PHB EEH operation reset() and merges its logic to eeh_ops::reset(). Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
2a485ad7c8
commit
cadf364d14
|
@ -34,240 +34,5 @@
|
|||
#include "powernv.h"
|
||||
#include "pci.h"
|
||||
|
||||
static s64 ioda_eeh_phb_poll(struct pnv_phb *phb)
|
||||
{
|
||||
s64 rc = OPAL_HARDWARE;
|
||||
|
||||
while (1) {
|
||||
rc = opal_pci_poll(phb->opal_id);
|
||||
if (rc <= 0)
|
||||
break;
|
||||
|
||||
if (system_state < SYSTEM_RUNNING)
|
||||
udelay(1000 * rc);
|
||||
else
|
||||
msleep(rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
|
||||
{
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
s64 rc = OPAL_HARDWARE;
|
||||
|
||||
pr_debug("%s: Reset PHB#%x, option=%d\n",
|
||||
__func__, hose->global_number, option);
|
||||
|
||||
/* Issue PHB complete reset request */
|
||||
if (option == EEH_RESET_FUNDAMENTAL ||
|
||||
option == EEH_RESET_HOT)
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PHB_COMPLETE,
|
||||
OPAL_ASSERT_RESET);
|
||||
else if (option == EEH_RESET_DEACTIVATE)
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PHB_COMPLETE,
|
||||
OPAL_DEASSERT_RESET);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Poll state of the PHB until the request is done
|
||||
* successfully. The PHB reset is usually PHB complete
|
||||
* reset followed by hot reset on root bus. So we also
|
||||
* need the PCI bus settlement delay.
|
||||
*/
|
||||
rc = ioda_eeh_phb_poll(phb);
|
||||
if (option == EEH_RESET_DEACTIVATE) {
|
||||
if (system_state < SYSTEM_RUNNING)
|
||||
udelay(1000 * EEH_PE_RST_SETTLE_TIME);
|
||||
else
|
||||
msleep(EEH_PE_RST_SETTLE_TIME);
|
||||
}
|
||||
out:
|
||||
if (rc != OPAL_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioda_eeh_root_reset(struct pci_controller *hose, int option)
|
||||
{
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
s64 rc = OPAL_SUCCESS;
|
||||
|
||||
pr_debug("%s: Reset PHB#%x, option=%d\n",
|
||||
__func__, hose->global_number, option);
|
||||
|
||||
/*
|
||||
* During the reset deassert time, we needn't care
|
||||
* the reset scope because the firmware does nothing
|
||||
* for fundamental or hot reset during deassert phase.
|
||||
*/
|
||||
if (option == EEH_RESET_FUNDAMENTAL)
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PCI_FUNDAMENTAL,
|
||||
OPAL_ASSERT_RESET);
|
||||
else if (option == EEH_RESET_HOT)
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PCI_HOT,
|
||||
OPAL_ASSERT_RESET);
|
||||
else if (option == EEH_RESET_DEACTIVATE)
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PCI_HOT,
|
||||
OPAL_DEASSERT_RESET);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
/* Poll state of the PHB until the request is done */
|
||||
rc = ioda_eeh_phb_poll(phb);
|
||||
if (option == EEH_RESET_DEACTIVATE)
|
||||
msleep(EEH_PE_RST_SETTLE_TIME);
|
||||
out:
|
||||
if (rc != OPAL_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option)
|
||||
|
||||
{
|
||||
struct device_node *dn = pci_device_to_OF_node(dev);
|
||||
struct eeh_dev *edev = of_node_to_eeh_dev(dn);
|
||||
int aer = edev ? edev->aer_cap : 0;
|
||||
u32 ctrl;
|
||||
|
||||
pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n",
|
||||
__func__, pci_domain_nr(dev->bus),
|
||||
dev->bus->number, option);
|
||||
|
||||
switch (option) {
|
||||
case EEH_RESET_FUNDAMENTAL:
|
||||
case EEH_RESET_HOT:
|
||||
/* Don't report linkDown event */
|
||||
if (aer) {
|
||||
eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK,
|
||||
4, &ctrl);
|
||||
ctrl |= PCI_ERR_UNC_SURPDN;
|
||||
eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK,
|
||||
4, ctrl);
|
||||
}
|
||||
|
||||
eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl);
|
||||
ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
|
||||
eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl);
|
||||
msleep(EEH_PE_RST_HOLD_TIME);
|
||||
|
||||
break;
|
||||
case EEH_RESET_DEACTIVATE:
|
||||
eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl);
|
||||
ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
|
||||
eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl);
|
||||
msleep(EEH_PE_RST_SETTLE_TIME);
|
||||
|
||||
/* Continue reporting linkDown event */
|
||||
if (aer) {
|
||||
eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK,
|
||||
4, &ctrl);
|
||||
ctrl &= ~PCI_ERR_UNC_SURPDN;
|
||||
eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK,
|
||||
4, ctrl);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pnv_pci_reset_secondary_bus(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_controller *hose;
|
||||
|
||||
if (pci_is_root_bus(dev->bus)) {
|
||||
hose = pci_bus_to_host(dev->bus);
|
||||
ioda_eeh_root_reset(hose, EEH_RESET_HOT);
|
||||
ioda_eeh_root_reset(hose, EEH_RESET_DEACTIVATE);
|
||||
} else {
|
||||
ioda_eeh_bridge_reset(dev, EEH_RESET_HOT);
|
||||
ioda_eeh_bridge_reset(dev, EEH_RESET_DEACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ioda_eeh_reset - Reset the indicated PE
|
||||
* @pe: EEH PE
|
||||
* @option: reset option
|
||||
*
|
||||
* Do reset on the indicated PE. For PCI bus sensitive PE,
|
||||
* we need to reset the parent p2p bridge. The PHB has to
|
||||
* be reinitialized if the p2p bridge is root bridge. For
|
||||
* PCI device sensitive PE, we will try to reset the device
|
||||
* through FLR. For now, we don't have OPAL APIs to do HARD
|
||||
* reset yet, so all reset would be SOFT (HOT) reset.
|
||||
*/
|
||||
static int ioda_eeh_reset(struct eeh_pe *pe, int option)
|
||||
{
|
||||
struct pci_controller *hose = pe->phb;
|
||||
struct pci_bus *bus;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* For PHB reset, we always have complete reset. For those PEs whose
|
||||
* primary bus derived from root complex (root bus) or root port
|
||||
* (usually bus#1), we apply hot or fundamental reset on the root port.
|
||||
* For other PEs, we always have hot reset on the PE primary bus.
|
||||
*
|
||||
* Here, we have different design to pHyp, which always clear the
|
||||
* frozen state during PE reset. However, the good idea here from
|
||||
* benh is to keep frozen state before we get PE reset done completely
|
||||
* (until BAR restore). With the frozen state, HW drops illegal IO
|
||||
* or MMIO access, which can incur recrusive frozen PE during PE
|
||||
* reset. The side effect is that EEH core has to clear the frozen
|
||||
* state explicitly after BAR restore.
|
||||
*/
|
||||
if (pe->type & EEH_PE_PHB) {
|
||||
ret = ioda_eeh_phb_reset(hose, option);
|
||||
} else {
|
||||
struct pnv_phb *phb;
|
||||
s64 rc;
|
||||
|
||||
/*
|
||||
* The frozen PE might be caused by PAPR error injection
|
||||
* registers, which are expected to be cleared after hitting
|
||||
* frozen PE as stated in the hardware spec. Unfortunately,
|
||||
* that's not true on P7IOC. So we have to clear it manually
|
||||
* to avoid recursive EEH errors during recovery.
|
||||
*/
|
||||
phb = hose->private_data;
|
||||
if (phb->model == PNV_PHB_MODEL_P7IOC &&
|
||||
(option == EEH_RESET_HOT ||
|
||||
option == EEH_RESET_FUNDAMENTAL)) {
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PHB_ERROR,
|
||||
OPAL_ASSERT_RESET);
|
||||
if (rc != OPAL_SUCCESS) {
|
||||
pr_warn("%s: Failure %lld clearing "
|
||||
"error injection registers\n",
|
||||
__func__, rc);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
bus = eeh_pe_bus_get(pe);
|
||||
if (pci_is_root_bus(bus) ||
|
||||
pci_is_root_bus(bus->parent))
|
||||
ret = ioda_eeh_root_reset(hose, option);
|
||||
else
|
||||
ret = ioda_eeh_bridge_reset(bus->self, option);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct pnv_eeh_ops ioda_eeh_ops = {
|
||||
.reset = ioda_eeh_reset,
|
||||
};
|
||||
|
|
|
@ -665,21 +665,236 @@ static int pnv_eeh_get_state(struct eeh_pe *pe, int *delay)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static s64 pnv_eeh_phb_poll(struct pnv_phb *phb)
|
||||
{
|
||||
s64 rc = OPAL_HARDWARE;
|
||||
|
||||
while (1) {
|
||||
rc = opal_pci_poll(phb->opal_id);
|
||||
if (rc <= 0)
|
||||
break;
|
||||
|
||||
if (system_state < SYSTEM_RUNNING)
|
||||
udelay(1000 * rc);
|
||||
else
|
||||
msleep(rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int pnv_eeh_phb_reset(struct pci_controller *hose, int option)
|
||||
{
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
s64 rc = OPAL_HARDWARE;
|
||||
|
||||
pr_debug("%s: Reset PHB#%x, option=%d\n",
|
||||
__func__, hose->global_number, option);
|
||||
|
||||
/* Issue PHB complete reset request */
|
||||
if (option == EEH_RESET_FUNDAMENTAL ||
|
||||
option == EEH_RESET_HOT)
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PHB_COMPLETE,
|
||||
OPAL_ASSERT_RESET);
|
||||
else if (option == EEH_RESET_DEACTIVATE)
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PHB_COMPLETE,
|
||||
OPAL_DEASSERT_RESET);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Poll state of the PHB until the request is done
|
||||
* successfully. The PHB reset is usually PHB complete
|
||||
* reset followed by hot reset on root bus. So we also
|
||||
* need the PCI bus settlement delay.
|
||||
*/
|
||||
rc = pnv_eeh_phb_poll(phb);
|
||||
if (option == EEH_RESET_DEACTIVATE) {
|
||||
if (system_state < SYSTEM_RUNNING)
|
||||
udelay(1000 * EEH_PE_RST_SETTLE_TIME);
|
||||
else
|
||||
msleep(EEH_PE_RST_SETTLE_TIME);
|
||||
}
|
||||
out:
|
||||
if (rc != OPAL_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pnv_eeh_root_reset(struct pci_controller *hose, int option)
|
||||
{
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
s64 rc = OPAL_HARDWARE;
|
||||
|
||||
pr_debug("%s: Reset PHB#%x, option=%d\n",
|
||||
__func__, hose->global_number, option);
|
||||
|
||||
/*
|
||||
* During the reset deassert time, we needn't care
|
||||
* the reset scope because the firmware does nothing
|
||||
* for fundamental or hot reset during deassert phase.
|
||||
*/
|
||||
if (option == EEH_RESET_FUNDAMENTAL)
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PCI_FUNDAMENTAL,
|
||||
OPAL_ASSERT_RESET);
|
||||
else if (option == EEH_RESET_HOT)
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PCI_HOT,
|
||||
OPAL_ASSERT_RESET);
|
||||
else if (option == EEH_RESET_DEACTIVATE)
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PCI_HOT,
|
||||
OPAL_DEASSERT_RESET);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
/* Poll state of the PHB until the request is done */
|
||||
rc = pnv_eeh_phb_poll(phb);
|
||||
if (option == EEH_RESET_DEACTIVATE)
|
||||
msleep(EEH_PE_RST_SETTLE_TIME);
|
||||
out:
|
||||
if (rc != OPAL_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pnv_eeh_bridge_reset(struct pci_dev *dev, int option)
|
||||
{
|
||||
struct device_node *dn = pci_device_to_OF_node(dev);
|
||||
struct eeh_dev *edev = of_node_to_eeh_dev(dn);
|
||||
int aer = edev ? edev->aer_cap : 0;
|
||||
u32 ctrl;
|
||||
|
||||
pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n",
|
||||
__func__, pci_domain_nr(dev->bus),
|
||||
dev->bus->number, option);
|
||||
|
||||
switch (option) {
|
||||
case EEH_RESET_FUNDAMENTAL:
|
||||
case EEH_RESET_HOT:
|
||||
/* Don't report linkDown event */
|
||||
if (aer) {
|
||||
eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK,
|
||||
4, &ctrl);
|
||||
ctrl |= PCI_ERR_UNC_SURPDN;
|
||||
eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK,
|
||||
4, ctrl);
|
||||
}
|
||||
|
||||
eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl);
|
||||
ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
|
||||
eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl);
|
||||
|
||||
msleep(EEH_PE_RST_HOLD_TIME);
|
||||
break;
|
||||
case EEH_RESET_DEACTIVATE:
|
||||
eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl);
|
||||
ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
|
||||
eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl);
|
||||
|
||||
msleep(EEH_PE_RST_SETTLE_TIME);
|
||||
|
||||
/* Continue reporting linkDown event */
|
||||
if (aer) {
|
||||
eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK,
|
||||
4, &ctrl);
|
||||
ctrl &= ~PCI_ERR_UNC_SURPDN;
|
||||
eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK,
|
||||
4, ctrl);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pnv_pci_reset_secondary_bus(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_controller *hose;
|
||||
|
||||
if (pci_is_root_bus(dev->bus)) {
|
||||
hose = pci_bus_to_host(dev->bus);
|
||||
pnv_eeh_root_reset(hose, EEH_RESET_HOT);
|
||||
pnv_eeh_root_reset(hose, EEH_RESET_DEACTIVATE);
|
||||
} else {
|
||||
pnv_eeh_bridge_reset(dev, EEH_RESET_HOT);
|
||||
pnv_eeh_bridge_reset(dev, EEH_RESET_DEACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pnv_eeh_reset - Reset the specified PE
|
||||
* @pe: EEH PE
|
||||
* @option: reset option
|
||||
*
|
||||
* Reset the specified PE
|
||||
* Do reset on the indicated PE. For PCI bus sensitive PE,
|
||||
* we need to reset the parent p2p bridge. The PHB has to
|
||||
* be reinitialized if the p2p bridge is root bridge. For
|
||||
* PCI device sensitive PE, we will try to reset the device
|
||||
* through FLR. For now, we don't have OPAL APIs to do HARD
|
||||
* reset yet, so all reset would be SOFT (HOT) reset.
|
||||
*/
|
||||
static int pnv_eeh_reset(struct eeh_pe *pe, int option)
|
||||
{
|
||||
struct pci_controller *hose = pe->phb;
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
int ret = -EEXIST;
|
||||
struct pci_bus *bus;
|
||||
int ret;
|
||||
|
||||
if (phb->eeh_ops && phb->eeh_ops->reset)
|
||||
ret = phb->eeh_ops->reset(pe, option);
|
||||
/*
|
||||
* For PHB reset, we always have complete reset. For those PEs whose
|
||||
* primary bus derived from root complex (root bus) or root port
|
||||
* (usually bus#1), we apply hot or fundamental reset on the root port.
|
||||
* For other PEs, we always have hot reset on the PE primary bus.
|
||||
*
|
||||
* Here, we have different design to pHyp, which always clear the
|
||||
* frozen state during PE reset. However, the good idea here from
|
||||
* benh is to keep frozen state before we get PE reset done completely
|
||||
* (until BAR restore). With the frozen state, HW drops illegal IO
|
||||
* or MMIO access, which can incur recrusive frozen PE during PE
|
||||
* reset. The side effect is that EEH core has to clear the frozen
|
||||
* state explicitly after BAR restore.
|
||||
*/
|
||||
if (pe->type & EEH_PE_PHB) {
|
||||
ret = pnv_eeh_phb_reset(hose, option);
|
||||
} else {
|
||||
struct pnv_phb *phb;
|
||||
s64 rc;
|
||||
|
||||
/*
|
||||
* The frozen PE might be caused by PAPR error injection
|
||||
* registers, which are expected to be cleared after hitting
|
||||
* frozen PE as stated in the hardware spec. Unfortunately,
|
||||
* that's not true on P7IOC. So we have to clear it manually
|
||||
* to avoid recursive EEH errors during recovery.
|
||||
*/
|
||||
phb = hose->private_data;
|
||||
if (phb->model == PNV_PHB_MODEL_P7IOC &&
|
||||
(option == EEH_RESET_HOT ||
|
||||
option == EEH_RESET_FUNDAMENTAL)) {
|
||||
rc = opal_pci_reset(phb->opal_id,
|
||||
OPAL_RESET_PHB_ERROR,
|
||||
OPAL_ASSERT_RESET);
|
||||
if (rc != OPAL_SUCCESS) {
|
||||
pr_warn("%s: Failure %lld clearing "
|
||||
"error injection registers\n",
|
||||
__func__, rc);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
bus = eeh_pe_bus_get(pe);
|
||||
if (pci_is_root_bus(bus) ||
|
||||
pci_is_root_bus(bus->parent))
|
||||
ret = pnv_eeh_root_reset(hose, option);
|
||||
else
|
||||
ret = pnv_eeh_bridge_reset(bus->self, option);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -2121,8 +2121,8 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
|
|||
*/
|
||||
if (is_kdump_kernel()) {
|
||||
pr_info(" Issue PHB reset ...\n");
|
||||
ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL);
|
||||
ioda_eeh_phb_reset(hose, EEH_RESET_DEACTIVATE);
|
||||
pnv_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL);
|
||||
pnv_eeh_phb_reset(hose, EEH_RESET_DEACTIVATE);
|
||||
}
|
||||
|
||||
/* Remove M64 resource if we can't configure it successfully */
|
||||
|
|
|
@ -78,7 +78,6 @@ struct pnv_ioda_pe {
|
|||
/* IOC dependent EEH operations */
|
||||
#ifdef CONFIG_EEH
|
||||
struct pnv_eeh_ops {
|
||||
int (*reset)(struct eeh_pe *pe, int option);
|
||||
};
|
||||
#endif /* CONFIG_EEH */
|
||||
|
||||
|
@ -223,6 +222,6 @@ extern void pnv_pci_init_ioda2_phb(struct device_node *np);
|
|||
extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
|
||||
__be64 *startp, __be64 *endp, bool rm);
|
||||
extern void pnv_pci_reset_secondary_bus(struct pci_dev *dev);
|
||||
extern int ioda_eeh_phb_reset(struct pci_controller *hose, int option);
|
||||
extern int pnv_eeh_phb_reset(struct pci_controller *hose, int option);
|
||||
|
||||
#endif /* __POWERNV_PCI_H */
|
||||
|
|
Loading…
Reference in New Issue