Commit 64ba3dc7 authored by Bryant G. Ly's avatar Bryant G. Ly Committed by Michael Ellerman

powerpc/eeh: Update VF config space after EEH

Add EEH platform operations for pseries to update VF config space.
With this change after EEH, the VF will have updated config space for
pseries platform.
Signed-off-by: default avatarBryant G. Ly <bryantly@linux.vnet.ibm.com>
Signed-off-by: default avatarJuan J. Alvarez <jjalvare@linux.vnet.ibm.com>
Acked-by: default avatarRussell Currey <ruscur@russell.cc>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 6385d6f8
......@@ -297,6 +297,7 @@ int eeh_pe_reset(struct eeh_pe *pe, int option);
int eeh_pe_configure(struct eeh_pe *pe);
int eeh_pe_inject_err(struct eeh_pe *pe, int type, int func,
unsigned long addr, unsigned long mask);
int eeh_restore_vf_config(struct pci_dn *pdn);
/**
* EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
......
......@@ -740,6 +740,65 @@ static void *eeh_restore_dev_state(void *data, void *userdata)
return NULL;
}
int eeh_restore_vf_config(struct pci_dn *pdn)
{
struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
u32 devctl, cmd, cap2, aer_capctl;
int old_mps;
if (edev->pcie_cap) {
/* Restore MPS */
old_mps = (ffs(pdn->mps) - 8) << 5;
eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
2, &devctl);
devctl &= ~PCI_EXP_DEVCTL_PAYLOAD;
devctl |= old_mps;
eeh_ops->write_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
2, devctl);
/* Disable Completion Timeout */
eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCAP2,
4, &cap2);
if (cap2 & 0x10) {
eeh_ops->read_config(pdn,
edev->pcie_cap + PCI_EXP_DEVCTL2,
4, &cap2);
cap2 |= 0x10;
eeh_ops->write_config(pdn,
edev->pcie_cap + PCI_EXP_DEVCTL2,
4, cap2);
}
}
/* Enable SERR and parity checking */
eeh_ops->read_config(pdn, PCI_COMMAND, 2, &cmd);
cmd |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
eeh_ops->write_config(pdn, PCI_COMMAND, 2, cmd);
/* Enable report various errors */
if (edev->pcie_cap) {
eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
2, &devctl);
devctl &= ~PCI_EXP_DEVCTL_CERE;
devctl |= (PCI_EXP_DEVCTL_NFERE |
PCI_EXP_DEVCTL_FERE |
PCI_EXP_DEVCTL_URRE);
eeh_ops->write_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
2, devctl);
}
/* Enable ECRC generation and check */
if (edev->pcie_cap && edev->aer_cap) {
eeh_ops->read_config(pdn, edev->aer_cap + PCI_ERR_CAP,
4, &aer_capctl);
aer_capctl |= (PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
eeh_ops->write_config(pdn, edev->aer_cap + PCI_ERR_CAP,
4, aer_capctl);
}
return 0;
}
/**
* pcibios_set_pcie_reset_state - Set PCI-E reset state
* @dev: pci device struct
......
......@@ -1655,70 +1655,11 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
return ret;
}
static int pnv_eeh_restore_vf_config(struct pci_dn *pdn)
{
struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
u32 devctl, cmd, cap2, aer_capctl;
int old_mps;
if (edev->pcie_cap) {
/* Restore MPS */
old_mps = (ffs(pdn->mps) - 8) << 5;
eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
2, &devctl);
devctl &= ~PCI_EXP_DEVCTL_PAYLOAD;
devctl |= old_mps;
eeh_ops->write_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
2, devctl);
/* Disable Completion Timeout */
eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCAP2,
4, &cap2);
if (cap2 & 0x10) {
eeh_ops->read_config(pdn,
edev->pcie_cap + PCI_EXP_DEVCTL2,
4, &cap2);
cap2 |= 0x10;
eeh_ops->write_config(pdn,
edev->pcie_cap + PCI_EXP_DEVCTL2,
4, cap2);
}
}
/* Enable SERR and parity checking */
eeh_ops->read_config(pdn, PCI_COMMAND, 2, &cmd);
cmd |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
eeh_ops->write_config(pdn, PCI_COMMAND, 2, cmd);
/* Enable report various errors */
if (edev->pcie_cap) {
eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
2, &devctl);
devctl &= ~PCI_EXP_DEVCTL_CERE;
devctl |= (PCI_EXP_DEVCTL_NFERE |
PCI_EXP_DEVCTL_FERE |
PCI_EXP_DEVCTL_URRE);
eeh_ops->write_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
2, devctl);
}
/* Enable ECRC generation and check */
if (edev->pcie_cap && edev->aer_cap) {
eeh_ops->read_config(pdn, edev->aer_cap + PCI_ERR_CAP,
4, &aer_capctl);
aer_capctl |= (PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
eeh_ops->write_config(pdn, edev->aer_cap + PCI_ERR_CAP,
4, aer_capctl);
}
return 0;
}
static int pnv_eeh_restore_config(struct pci_dn *pdn)
{
struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
struct pnv_phb *phb;
s64 ret;
s64 ret = 0;
int config_addr = (pdn->busno << 8) | (pdn->devfn);
if (!edev)
......@@ -1732,7 +1673,7 @@ static int pnv_eeh_restore_config(struct pci_dn *pdn)
* to be exported by firmware in extendible way.
*/
if (edev->physfn) {
ret = pnv_eeh_restore_vf_config(pdn);
ret = eeh_restore_vf_config(pdn);
} else {
phb = pdn->phb->private_data;
ret = opal_pci_reinit(phb->opal_id,
......@@ -1745,7 +1686,7 @@ static int pnv_eeh_restore_config(struct pci_dn *pdn)
return -EIO;
}
return 0;
return ret;
}
static struct eeh_ops pnv_eeh_ops = {
......
......@@ -708,6 +708,30 @@ static int pseries_eeh_write_config(struct pci_dn *pdn, int where, int size, u32
return rtas_write_config(pdn, where, size, val);
}
static int pseries_eeh_restore_config(struct pci_dn *pdn)
{
struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
s64 ret = 0;
if (!edev)
return -EEXIST;
/*
* FIXME: The MPS, error routing rules, timeout setting are worthy
* to be exported by firmware in extendible way.
*/
if (edev->physfn)
ret = eeh_restore_vf_config(pdn);
if (ret) {
pr_warn("%s: Can't reinit PCI dev 0x%x (%lld)\n",
__func__, edev->pe_config_addr, ret);
return -EIO;
}
return ret;
}
static struct eeh_ops pseries_eeh_ops = {
.name = "pseries",
.init = pseries_eeh_init,
......@@ -723,7 +747,7 @@ static struct eeh_ops pseries_eeh_ops = {
.read_config = pseries_eeh_read_config,
.write_config = pseries_eeh_write_config,
.next_error = NULL,
.restore_config = NULL
.restore_config = pseries_eeh_restore_config
};
/**
......
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