forked from Minki/linux
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:
parent
6385d6f85f
commit
64ba3dc7bf
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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 = {
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user