aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--arch/powerpc/include/asm/eeh.h2
-rw-r--r--arch/powerpc/include/asm/ppc-pci.h2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c63
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c4
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c47
5 files changed, 51 insertions, 67 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 894ea6c662cc..ad8f31834e00 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -52,6 +52,8 @@ struct device_node;
#define EEH_RESET_DEACTIVATE 0 /* Deactivate the PE reset */
#define EEH_RESET_HOT 1 /* Hot reset */
#define EEH_RESET_FUNDAMENTAL 3 /* Fundamental reset */
+#define EEH_LOG_TEMP 1 /* EEH temporary error log */
+#define EEH_LOG_PERM 2 /* EEH permanent error log */
struct eeh_ops {
char *name;
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h
index 1cfb2b09bbd9..bd1a84f65292 100644
--- a/arch/powerpc/include/asm/ppc-pci.h
+++ b/arch/powerpc/include/asm/ppc-pci.h
@@ -53,8 +53,6 @@ void pci_addr_cache_insert_device(struct pci_dev *dev);
void pci_addr_cache_remove_device(struct pci_dev *dev);
void pci_addr_cache_build(void);
struct pci_dev *pci_get_device_by_addr(unsigned long addr);
-#define EEH_LOG_TEMP_FAILURE 1
-#define EEH_LOG_PERM_FAILURE 2
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 *);
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 4f329f548816..39fcecb1c16b 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -87,7 +87,6 @@
#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
/* RTAS tokens */
-static int ibm_slot_error_detail;
static int ibm_configure_bridge;
static int ibm_configure_pe;
@@ -100,14 +99,6 @@ EXPORT_SYMBOL(eeh_subsystem_enabled);
/* Lock to avoid races due to multiple reports of an error */
static DEFINE_RAW_SPINLOCK(confirm_error_lock);
-/* Buffer for reporting slot-error-detail rtas calls. Its here
- * in BSS, and not dynamically alloced, so that it ends up in
- * RMO where RTAS can access it.
- */
-static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
-static DEFINE_SPINLOCK(slot_errbuf_lock);
-static int eeh_error_buf_size;
-
/* Buffer for reporting pci register dumps. Its here in BSS, and
* not dynamically alloced, so that it ends up in RMO where RTAS
* can access it.
@@ -127,46 +118,6 @@ static unsigned long slot_resets;
#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)
/**
- * eeh_rtas_slot_error_detail - Retrieve error log through RTAS call
- * @pdn: device node
- * @severity: temporary or permanent error log
- * @driver_log: driver log to be combined with the retrieved error log
- * @loglen: length of driver log
- *
- * This routine should be called to retrieve error log through the dedicated
- * RTAS call.
- */
-static void eeh_rtas_slot_error_detail(struct pci_dn *pdn, int severity,
- char *driver_log, size_t loglen)
-{
- int config_addr;
- unsigned long flags;
- int rc;
-
- /* Log the error with the rtas logger */
- spin_lock_irqsave(&slot_errbuf_lock, flags);
- memset(slot_errbuf, 0, eeh_error_buf_size);
-
- /* 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;
-
- rc = rtas_call(ibm_slot_error_detail,
- 8, 1, NULL, config_addr,
- BUID_HI(pdn->phb->buid),
- BUID_LO(pdn->phb->buid),
- virt_to_phys(driver_log), loglen,
- virt_to_phys(slot_errbuf),
- eeh_error_buf_size,
- severity);
-
- if (rc == 0)
- log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
- spin_unlock_irqrestore(&slot_errbuf_lock, flags);
-}
-
-/**
* eeh_gather_pci_data - Copy assorted PCI config space registers to buff
* @pdn: device to report data for
* @buf: point to buffer in which to log
@@ -282,7 +233,7 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
eeh_restore_bars(pdn);
loglen = eeh_gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
- eeh_rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen);
+ eeh_ops->get_log(pdn->node, severity, pci_regs_buf, loglen);
}
/**
@@ -1071,26 +1022,14 @@ void __init eeh_init(void)
}
raw_spin_lock_init(&confirm_error_lock);
- spin_lock_init(&slot_errbuf_lock);
np = of_find_node_by_path("/rtas");
if (np == NULL)
return;
- ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");
ibm_configure_bridge = rtas_token("ibm,configure-bridge");
ibm_configure_pe = rtas_token("ibm,configure-pe");
- eeh_error_buf_size = rtas_token("rtas-error-log-max");
- if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
- eeh_error_buf_size = 1024;
- }
- if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
- printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated "
- "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
- eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
- }
-
/* 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")) {
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 584defe14930..68403573a1f4 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -406,7 +406,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
* don't post the error log until after all dev drivers
* have been informed.
*/
- eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE);
+ eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP);
/* If all device drivers were EEH-unaware, then shut
* down all of the device drivers, and hope they
@@ -497,7 +497,7 @@ hard_fail:
location, drv_str, pci_str);
perm_error:
- eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE);
+ eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM);
/* Notify all devices that they're about to go down. */
pci_walk_bus(frozen_bus, eeh_report_failure, NULL);
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 6643e0677e95..7c8434f902bc 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -56,6 +56,15 @@ static int ibm_get_config_addr_info2;
static int ibm_configure_bridge;
static int ibm_configure_pe;
+/*
+ * Buffer for reporting slot-error-detail rtas calls. Its here
+ * in BSS, and not dynamically alloced, so that it ends up in
+ * RMO where RTAS can access it.
+ */
+static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
+static DEFINE_SPINLOCK(slot_errbuf_lock);
+static int eeh_error_buf_size;
+
/**
* pseries_eeh_init - EEH platform dependent initialization
*
@@ -107,6 +116,19 @@ static int pseries_eeh_init(void)
return -EINVAL;
}
+ /* Initialize error log lock and size */
+ spin_lock_init(&slot_errbuf_lock);
+ eeh_error_buf_size = rtas_token("rtas-error-log-max");
+ if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
+ pr_warning("%s: unknown EEH error log size\n",
+ __func__);
+ eeh_error_buf_size = 1024;
+ } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
+ pr_warning("%s: EEH error log size %d exceeds the maximal %d\n",
+ __func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
+ eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
+ }
+
return 0;
}
@@ -415,7 +437,30 @@ static int pseries_eeh_wait_state(struct device_node *dn, int max_wait)
*/
static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len)
{
- return 0;
+ struct pci_dn *pdn;
+ int config_addr;
+ unsigned long flags;
+ int ret;
+
+ pdn = PCI_DN(dn);
+ spin_lock_irqsave(&slot_errbuf_lock, flags);
+ memset(slot_errbuf, 0, eeh_error_buf_size);
+
+ /* Figure out the PE address */
+ config_addr = pdn->eeh_config_addr;
+ if (pdn->eeh_pe_config_addr)
+ config_addr = pdn->eeh_pe_config_addr;
+
+ ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr,
+ BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid),
+ virt_to_phys(drv_log), len,
+ virt_to_phys(slot_errbuf), eeh_error_buf_size,
+ severity);
+ if (!ret)
+ log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
+ spin_unlock_irqrestore(&slot_errbuf_lock, flags);
+
+ return ret;
}
/**