powerpc/eeh: Add EEH operations to notify resume
When pseries SR-IOV is enabled and after a PF driver has resumed from EEH, platform has to be notified of the event so the child VFs can be allowed to resume their normal recovery path. This patch makes the EEH operation allow unfreeze platform dependent code and adds the call to pseries EEH code. 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
565a744dd2
commit
67923cfcfa
@ -214,6 +214,7 @@ struct eeh_ops {
|
|||||||
int (*write_config)(struct pci_dn *pdn, int where, int size, u32 val);
|
int (*write_config)(struct pci_dn *pdn, int where, int size, u32 val);
|
||||||
int (*next_error)(struct eeh_pe **pe);
|
int (*next_error)(struct eeh_pe **pe);
|
||||||
int (*restore_config)(struct pci_dn *pdn);
|
int (*restore_config)(struct pci_dn *pdn);
|
||||||
|
int (*notify_resume)(struct pci_dn *pdn);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int eeh_subsystem_flags;
|
extern int eeh_subsystem_flags;
|
||||||
|
@ -1704,7 +1704,8 @@ static struct eeh_ops pnv_eeh_ops = {
|
|||||||
.read_config = pnv_eeh_read_config,
|
.read_config = pnv_eeh_read_config,
|
||||||
.write_config = pnv_eeh_write_config,
|
.write_config = pnv_eeh_write_config,
|
||||||
.next_error = pnv_eeh_next_error,
|
.next_error = pnv_eeh_next_error,
|
||||||
.restore_config = pnv_eeh_restore_config
|
.restore_config = pnv_eeh_restore_config,
|
||||||
|
.notify_resume = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_IOV
|
#ifdef CONFIG_PCI_IOV
|
||||||
|
@ -750,6 +750,97 @@ static int pseries_eeh_restore_config(struct pci_dn *pdn)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PCI_IOV
|
||||||
|
int pseries_send_allow_unfreeze(struct pci_dn *pdn,
|
||||||
|
u16 *vf_pe_array, int cur_vfs)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int ibm_allow_unfreeze = rtas_token("ibm,open-sriov-allow-unfreeze");
|
||||||
|
unsigned long buid, addr;
|
||||||
|
|
||||||
|
addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
|
||||||
|
buid = pdn->phb->buid;
|
||||||
|
spin_lock(&rtas_data_buf_lock);
|
||||||
|
memcpy(rtas_data_buf, vf_pe_array, RTAS_DATA_BUF_SIZE);
|
||||||
|
rc = rtas_call(ibm_allow_unfreeze, 5, 1, NULL,
|
||||||
|
addr,
|
||||||
|
BUID_HI(buid),
|
||||||
|
BUID_LO(buid),
|
||||||
|
rtas_data_buf, cur_vfs * sizeof(u16));
|
||||||
|
spin_unlock(&rtas_data_buf_lock);
|
||||||
|
if (rc)
|
||||||
|
pr_warn("%s: Failed to allow unfreeze for PHB#%x-PE#%lx, rc=%x\n",
|
||||||
|
__func__,
|
||||||
|
pdn->phb->global_number, addr, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pseries_call_allow_unfreeze(struct eeh_dev *edev)
|
||||||
|
{
|
||||||
|
struct pci_dn *pdn, *tmp, *parent, *physfn_pdn;
|
||||||
|
int cur_vfs = 0, rc = 0, vf_index, bus, devfn;
|
||||||
|
u16 *vf_pe_array;
|
||||||
|
|
||||||
|
vf_pe_array = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
|
||||||
|
if (!vf_pe_array)
|
||||||
|
return -ENOMEM;
|
||||||
|
if (pci_num_vf(edev->physfn ? edev->physfn : edev->pdev)) {
|
||||||
|
if (edev->pdev->is_physfn) {
|
||||||
|
cur_vfs = pci_num_vf(edev->pdev);
|
||||||
|
pdn = eeh_dev_to_pdn(edev);
|
||||||
|
parent = pdn->parent;
|
||||||
|
for (vf_index = 0; vf_index < cur_vfs; vf_index++)
|
||||||
|
vf_pe_array[vf_index] =
|
||||||
|
cpu_to_be16(pdn->pe_num_map[vf_index]);
|
||||||
|
rc = pseries_send_allow_unfreeze(pdn, vf_pe_array,
|
||||||
|
cur_vfs);
|
||||||
|
pdn->last_allow_rc = rc;
|
||||||
|
for (vf_index = 0; vf_index < cur_vfs; vf_index++) {
|
||||||
|
list_for_each_entry_safe(pdn, tmp,
|
||||||
|
&parent->child_list,
|
||||||
|
list) {
|
||||||
|
bus = pci_iov_virtfn_bus(edev->pdev,
|
||||||
|
vf_index);
|
||||||
|
devfn = pci_iov_virtfn_devfn(edev->pdev,
|
||||||
|
vf_index);
|
||||||
|
if (pdn->busno != bus ||
|
||||||
|
pdn->devfn != devfn)
|
||||||
|
continue;
|
||||||
|
pdn->last_allow_rc = rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pdn = pci_get_pdn(edev->pdev);
|
||||||
|
vf_pe_array[0] = cpu_to_be16(pdn->pe_number);
|
||||||
|
physfn_pdn = pci_get_pdn(edev->physfn);
|
||||||
|
rc = pseries_send_allow_unfreeze(physfn_pdn,
|
||||||
|
vf_pe_array, 1);
|
||||||
|
pdn->last_allow_rc = rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(vf_pe_array);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pseries_notify_resume(struct pci_dn *pdn)
|
||||||
|
{
|
||||||
|
struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
|
||||||
|
|
||||||
|
if (!edev)
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
if (rtas_token("ibm,open-sriov-allow-unfreeze")
|
||||||
|
== RTAS_UNKNOWN_SERVICE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (edev->pdev->is_physfn || edev->pdev->is_virtfn)
|
||||||
|
return pseries_call_allow_unfreeze(edev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
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,
|
||||||
@ -765,7 +856,10 @@ 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 = pseries_eeh_restore_config
|
.restore_config = pseries_eeh_restore_config,
|
||||||
|
#ifdef CONFIG_PCI_IOV
|
||||||
|
.notify_resume = pseries_notify_resume
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user