Commit 1823fbf1 authored by Gavin Shan's avatar Gavin Shan Committed by Benjamin Herrenschmidt

powerpc/eeh: pseries platform EEH configure bridge

In order to enable particular PCI device, which has been included
in the parent PE. The involved PCI bridges should be enabled explicitly
if there has. On pSeries platform, there're dedicated RTAS calls
to fulfil the purpose.

The patch implements the function of configuring PCI bridges through
the dedicated RTAS calls. Besides, the function has been abstracted
by struct eeh_ops::configure_bridge so that the EEH core components
could support multiple platforms in future.
Signed-off-by: default avatarGavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 8d633291
......@@ -57,7 +57,6 @@ void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
int eeh_pci_enable(struct pci_dn *pdn, int function);
int eeh_reset_pe(struct pci_dn *);
void eeh_restore_bars(struct pci_dn *);
void eeh_configure_bridge(struct pci_dn *);
int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
void eeh_mark_slot(struct device_node *dn, int mode_flag);
......
......@@ -86,10 +86,6 @@
/* Time to wait for a PCI slot to report status, in milliseconds */
#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
/* RTAS tokens */
static int ibm_configure_bridge;
static int ibm_configure_pe;
/* Platform dependent EEH operations */
struct eeh_ops *eeh_ops = NULL;
......@@ -229,7 +225,7 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
pci_regs_buf[0] = 0;
eeh_pci_enable(pdn, EEH_OPT_THAW_MMIO);
eeh_configure_bridge(pdn);
eeh_ops->configure_bridge(pdn->node);
eeh_restore_bars(pdn);
loglen = eeh_gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
......@@ -809,41 +805,6 @@ static void eeh_save_bars(struct pci_dn *pdn)
rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]);
}
/**
* eeh_configure_bridge - Configure PCI bridges for the indicated PE
* @pdn: PCI device node
*
* PCI bridges might be included in PE. In order to make the PE work
* again. The included PCI bridges should be recovered after the PE
* encounters frozen state.
*/
void eeh_configure_bridge(struct pci_dn *pdn)
{
int config_addr;
int rc;
int token;
/* Use PE configuration address, if present */
config_addr = pdn->eeh_config_addr;
if (pdn->eeh_pe_config_addr)
config_addr = pdn->eeh_pe_config_addr;
/* Use new configure-pe function, if supported */
if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE)
token = ibm_configure_pe;
else
token = ibm_configure_bridge;
rc = rtas_call(token, 3, 1, NULL,
config_addr,
BUID_HI(pdn->phb->buid),
BUID_LO(pdn->phb->buid));
if (rc) {
printk(KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n",
rc, pdn->node->full_name);
}
}
/**
* eeh_early_enable - Early enable EEH on the indicated device
* @dn: device node
......@@ -1027,9 +988,6 @@ void __init eeh_init(void)
if (np == NULL)
return;
ibm_configure_bridge = rtas_token("ibm,configure-bridge");
ibm_configure_pe = rtas_token("ibm,configure-pe");
/* Enable EEH for all adapters. Note that eeh requires buid's */
for (phb = of_find_node_by_name(NULL, "pci"); phb;
phb = of_find_node_by_name(phb, "pci")) {
......
......@@ -295,7 +295,7 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
struct pci_dn *ppe = PCI_DN(dn);
/* On Power4, always true because eeh_pe_config_addr=0 */
if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
eeh_configure_bridge(ppe);
eeh_ops->configure_bridge(dn);
eeh_restore_bars(ppe);
}
dn = dn->sibling;
......
......@@ -473,7 +473,34 @@ static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_l
*/
static int pseries_eeh_configure_bridge(struct device_node *dn)
{
return 0;
struct pci_dn *pdn;
int config_addr;
int ret;
/* Figure out the PE address */
pdn = PCI_DN(dn);
config_addr = pdn->eeh_config_addr;
if (pdn->eeh_pe_config_addr)
config_addr = pdn->eeh_pe_config_addr;
/* Use new configure-pe function, if supported */
if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) {
ret = rtas_call(ibm_configure_pe, 3, 1, NULL,
config_addr, BUID_HI(pdn->phb->buid),
BUID_LO(pdn->phb->buid));
} else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) {
ret = rtas_call(ibm_configure_bridge, 3, 1, NULL,
config_addr, BUID_HI(pdn->phb->buid),
BUID_LO(pdn->phb->buid));
} else {
return -EFAULT;
}
if (ret)
pr_warning("%s: Unable to configure bridge %d for %s\n",
__func__, ret, dn->full_name);
return ret;
}
static struct eeh_ops pseries_eeh_ops = {
......
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