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: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
Signed-off-by: Juan J. Alvarez <jjalvare@linux.vnet.ibm.com>
Acked-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
Bryant G. Ly 2018-01-05 10:45:46 -06:00 committed by Michael Ellerman
parent 6385d6f85f
commit 64ba3dc7bf
4 changed files with 88 additions and 63 deletions

View File

@ -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_configure(struct eeh_pe *pe);
int eeh_pe_inject_err(struct eeh_pe *pe, int type, int func, int eeh_pe_inject_err(struct eeh_pe *pe, int type, int func,
unsigned long addr, unsigned long mask); unsigned long addr, unsigned long mask);
int eeh_restore_vf_config(struct pci_dn *pdn);
/** /**
* EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.

View File

@ -740,6 +740,65 @@ static void *eeh_restore_dev_state(void *data, void *userdata)
return NULL; 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 * pcibios_set_pcie_reset_state - Set PCI-E reset state
* @dev: pci device struct * @dev: pci device struct

View File

@ -1655,70 +1655,11 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
return ret; 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) static int pnv_eeh_restore_config(struct pci_dn *pdn)
{ {
struct eeh_dev *edev = pdn_to_eeh_dev(pdn); struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
struct pnv_phb *phb; struct pnv_phb *phb;
s64 ret; s64 ret = 0;
int config_addr = (pdn->busno << 8) | (pdn->devfn); int config_addr = (pdn->busno << 8) | (pdn->devfn);
if (!edev) if (!edev)
@ -1732,7 +1673,7 @@ static int pnv_eeh_restore_config(struct pci_dn *pdn)
* to be exported by firmware in extendible way. * to be exported by firmware in extendible way.
*/ */
if (edev->physfn) { if (edev->physfn) {
ret = pnv_eeh_restore_vf_config(pdn); ret = eeh_restore_vf_config(pdn);
} else { } else {
phb = pdn->phb->private_data; phb = pdn->phb->private_data;
ret = opal_pci_reinit(phb->opal_id, ret = opal_pci_reinit(phb->opal_id,
@ -1745,7 +1686,7 @@ static int pnv_eeh_restore_config(struct pci_dn *pdn)
return -EIO; return -EIO;
} }
return 0; return ret;
} }
static struct eeh_ops pnv_eeh_ops = { static struct eeh_ops pnv_eeh_ops = {

View File

@ -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); 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 = { static struct eeh_ops pseries_eeh_ops = {
.name = "pseries", .name = "pseries",
.init = pseries_eeh_init, .init = pseries_eeh_init,
@ -723,7 +747,7 @@ static struct eeh_ops pseries_eeh_ops = {
.read_config = pseries_eeh_read_config, .read_config = pseries_eeh_read_config,
.write_config = pseries_eeh_write_config, .write_config = pseries_eeh_write_config,
.next_error = NULL, .next_error = NULL,
.restore_config = NULL .restore_config = pseries_eeh_restore_config
}; };
/** /**