aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2012-02-27 15:04:00 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-03-08 19:11:01 -0500
commit8d633291b4fc0539ecad31f972447104be6953ec (patch)
tree7be9e4d58a8289ba843e632974873bead839a458 /arch/powerpc
parent2652481f75186940c4608f68c9fd76b32ec9b159 (diff)
powerpc/eeh: pseries platform EEH error log retrieval
On RTAS compliant pSeries platform, one dedicated RTAS call has been introduced to retrieve EEH temporary or permanent error log. The patch implements the function of retriving EEH error log through RTAS call. Besides, it has been abstracted by struct eeh_ops::get_log so that 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>
Diffstat (limited to 'arch/powerpc')
-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;
52#define EEH_RESET_DEACTIVATE 0 /* Deactivate the PE reset */ 52#define EEH_RESET_DEACTIVATE 0 /* Deactivate the PE reset */
53#define EEH_RESET_HOT 1 /* Hot reset */ 53#define EEH_RESET_HOT 1 /* Hot reset */
54#define EEH_RESET_FUNDAMENTAL 3 /* Fundamental reset */ 54#define EEH_RESET_FUNDAMENTAL 3 /* Fundamental reset */
55#define EEH_LOG_TEMP 1 /* EEH temporary error log */
56#define EEH_LOG_PERM 2 /* EEH permanent error log */
55 57
56struct eeh_ops { 58struct eeh_ops {
57 char *name; 59 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);
53void pci_addr_cache_remove_device(struct pci_dev *dev); 53void pci_addr_cache_remove_device(struct pci_dev *dev);
54void pci_addr_cache_build(void); 54void pci_addr_cache_build(void);
55struct pci_dev *pci_get_device_by_addr(unsigned long addr); 55struct pci_dev *pci_get_device_by_addr(unsigned long addr);
56#define EEH_LOG_TEMP_FAILURE 1
57#define EEH_LOG_PERM_FAILURE 2
58void eeh_slot_error_detail (struct pci_dn *pdn, int severity); 56void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
59int eeh_pci_enable(struct pci_dn *pdn, int function); 57int eeh_pci_enable(struct pci_dn *pdn, int function);
60int eeh_reset_pe(struct pci_dn *); 58int 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 @@
87#define PCI_BUS_RESET_WAIT_MSEC (60*1000) 87#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
88 88
89/* RTAS tokens */ 89/* RTAS tokens */
90static int ibm_slot_error_detail;
91static int ibm_configure_bridge; 90static int ibm_configure_bridge;
92static int ibm_configure_pe; 91static int ibm_configure_pe;
93 92
@@ -100,14 +99,6 @@ EXPORT_SYMBOL(eeh_subsystem_enabled);
100/* Lock to avoid races due to multiple reports of an error */ 99/* Lock to avoid races due to multiple reports of an error */
101static DEFINE_RAW_SPINLOCK(confirm_error_lock); 100static DEFINE_RAW_SPINLOCK(confirm_error_lock);
102 101
103/* Buffer for reporting slot-error-detail rtas calls. Its here
104 * in BSS, and not dynamically alloced, so that it ends up in
105 * RMO where RTAS can access it.
106 */
107static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
108static DEFINE_SPINLOCK(slot_errbuf_lock);
109static int eeh_error_buf_size;
110
111/* Buffer for reporting pci register dumps. Its here in BSS, and 102/* Buffer for reporting pci register dumps. Its here in BSS, and
112 * not dynamically alloced, so that it ends up in RMO where RTAS 103 * not dynamically alloced, so that it ends up in RMO where RTAS
113 * can access it. 104 * can access it.
@@ -127,46 +118,6 @@ static unsigned long slot_resets;
127#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) 118#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)
128 119
129/** 120/**
130 * eeh_rtas_slot_error_detail - Retrieve error log through RTAS call
131 * @pdn: device node
132 * @severity: temporary or permanent error log
133 * @driver_log: driver log to be combined with the retrieved error log
134 * @loglen: length of driver log
135 *
136 * This routine should be called to retrieve error log through the dedicated
137 * RTAS call.
138 */
139static void eeh_rtas_slot_error_detail(struct pci_dn *pdn, int severity,
140 char *driver_log, size_t loglen)
141{
142 int config_addr;
143 unsigned long flags;
144 int rc;
145
146 /* Log the error with the rtas logger */
147 spin_lock_irqsave(&slot_errbuf_lock, flags);
148 memset(slot_errbuf, 0, eeh_error_buf_size);
149
150 /* Use PE configuration address, if present */
151 config_addr = pdn->eeh_config_addr;
152 if (pdn->eeh_pe_config_addr)
153 config_addr = pdn->eeh_pe_config_addr;
154
155 rc = rtas_call(ibm_slot_error_detail,
156 8, 1, NULL, config_addr,
157 BUID_HI(pdn->phb->buid),
158 BUID_LO(pdn->phb->buid),
159 virt_to_phys(driver_log), loglen,
160 virt_to_phys(slot_errbuf),
161 eeh_error_buf_size,
162 severity);
163
164 if (rc == 0)
165 log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
166 spin_unlock_irqrestore(&slot_errbuf_lock, flags);
167}
168
169/**
170 * eeh_gather_pci_data - Copy assorted PCI config space registers to buff 121 * eeh_gather_pci_data - Copy assorted PCI config space registers to buff
171 * @pdn: device to report data for 122 * @pdn: device to report data for
172 * @buf: point to buffer in which to log 123 * @buf: point to buffer in which to log
@@ -282,7 +233,7 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
282 eeh_restore_bars(pdn); 233 eeh_restore_bars(pdn);
283 loglen = eeh_gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); 234 loglen = eeh_gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
284 235
285 eeh_rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); 236 eeh_ops->get_log(pdn->node, severity, pci_regs_buf, loglen);
286} 237}
287 238
288/** 239/**
@@ -1071,26 +1022,14 @@ void __init eeh_init(void)
1071 } 1022 }
1072 1023
1073 raw_spin_lock_init(&confirm_error_lock); 1024 raw_spin_lock_init(&confirm_error_lock);
1074 spin_lock_init(&slot_errbuf_lock);
1075 1025
1076 np = of_find_node_by_path("/rtas"); 1026 np = of_find_node_by_path("/rtas");
1077 if (np == NULL) 1027 if (np == NULL)
1078 return; 1028 return;
1079 1029
1080 ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");
1081 ibm_configure_bridge = rtas_token("ibm,configure-bridge"); 1030 ibm_configure_bridge = rtas_token("ibm,configure-bridge");
1082 ibm_configure_pe = rtas_token("ibm,configure-pe"); 1031 ibm_configure_pe = rtas_token("ibm,configure-pe");
1083 1032
1084 eeh_error_buf_size = rtas_token("rtas-error-log-max");
1085 if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
1086 eeh_error_buf_size = 1024;
1087 }
1088 if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
1089 printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated "
1090 "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
1091 eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
1092 }
1093
1094 /* Enable EEH for all adapters. Note that eeh requires buid's */ 1033 /* Enable EEH for all adapters. Note that eeh requires buid's */
1095 for (phb = of_find_node_by_name(NULL, "pci"); phb; 1034 for (phb = of_find_node_by_name(NULL, "pci"); phb;
1096 phb = of_find_node_by_name(phb, "pci")) { 1035 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)
406 * don't post the error log until after all dev drivers 406 * don't post the error log until after all dev drivers
407 * have been informed. 407 * have been informed.
408 */ 408 */
409 eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE); 409 eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP);
410 410
411 /* If all device drivers were EEH-unaware, then shut 411 /* If all device drivers were EEH-unaware, then shut
412 * down all of the device drivers, and hope they 412 * down all of the device drivers, and hope they
@@ -497,7 +497,7 @@ hard_fail:
497 location, drv_str, pci_str); 497 location, drv_str, pci_str);
498 498
499perm_error: 499perm_error:
500 eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE); 500 eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM);
501 501
502 /* Notify all devices that they're about to go down. */ 502 /* Notify all devices that they're about to go down. */
503 pci_walk_bus(frozen_bus, eeh_report_failure, NULL); 503 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;
56static int ibm_configure_bridge; 56static int ibm_configure_bridge;
57static int ibm_configure_pe; 57static int ibm_configure_pe;
58 58
59/*
60 * Buffer for reporting slot-error-detail rtas calls. Its here
61 * in BSS, and not dynamically alloced, so that it ends up in
62 * RMO where RTAS can access it.
63 */
64static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
65static DEFINE_SPINLOCK(slot_errbuf_lock);
66static int eeh_error_buf_size;
67
59/** 68/**
60 * pseries_eeh_init - EEH platform dependent initialization 69 * pseries_eeh_init - EEH platform dependent initialization
61 * 70 *
@@ -107,6 +116,19 @@ static int pseries_eeh_init(void)
107 return -EINVAL; 116 return -EINVAL;
108 } 117 }
109 118
119 /* Initialize error log lock and size */
120 spin_lock_init(&slot_errbuf_lock);
121 eeh_error_buf_size = rtas_token("rtas-error-log-max");
122 if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
123 pr_warning("%s: unknown EEH error log size\n",
124 __func__);
125 eeh_error_buf_size = 1024;
126 } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
127 pr_warning("%s: EEH error log size %d exceeds the maximal %d\n",
128 __func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
129 eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
130 }
131
110 return 0; 132 return 0;
111} 133}
112 134
@@ -415,7 +437,30 @@ static int pseries_eeh_wait_state(struct device_node *dn, int max_wait)
415 */ 437 */
416static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len) 438static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len)
417{ 439{
418 return 0; 440 struct pci_dn *pdn;
441 int config_addr;
442 unsigned long flags;
443 int ret;
444
445 pdn = PCI_DN(dn);
446 spin_lock_irqsave(&slot_errbuf_lock, flags);
447 memset(slot_errbuf, 0, eeh_error_buf_size);
448
449 /* Figure out the PE address */
450 config_addr = pdn->eeh_config_addr;
451 if (pdn->eeh_pe_config_addr)
452 config_addr = pdn->eeh_pe_config_addr;
453
454 ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr,
455 BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid),
456 virt_to_phys(drv_log), len,
457 virt_to_phys(slot_errbuf), eeh_error_buf_size,
458 severity);
459 if (!ret)
460 log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
461 spin_unlock_irqrestore(&slot_errbuf_lock, flags);
462
463 return ret;
419} 464}
420 465
421/** 466/**