mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 03:10:12 +00:00
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: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
8d633291b4
commit
1823fbf119
4 changed files with 30 additions and 46 deletions
|
@ -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 = {
|
||||
|
|
Loading…
Reference in a new issue