aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/eeh.h32
-rw-r--r--arch/powerpc/platforms/pseries/Makefile2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c53
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c183
-rw-r--r--arch/powerpc/platforms/pseries/setup.c1
5 files changed, 270 insertions, 1 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 232887721ff4..0666c52b8f14 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -31,6 +31,26 @@ struct device_node;
31 31
32#ifdef CONFIG_EEH 32#ifdef CONFIG_EEH
33 33
34/*
35 * The struct is used to trace the registered EEH operation
36 * callback functions. Actually, those operation callback
37 * functions are heavily platform dependent. That means the
38 * platform should register its own EEH operation callback
39 * functions before any EEH further operations.
40 */
41struct eeh_ops {
42 char *name;
43 int (*init)(void);
44 int (*set_option)(struct device_node *dn, int option);
45 int (*get_pe_addr)(struct device_node *dn);
46 int (*get_state)(struct device_node *dn, int *state);
47 int (*reset)(struct device_node *dn, int option);
48 int (*wait_state)(struct device_node *dn, int max_wait);
49 int (*get_log)(struct device_node *dn, int severity, char *drv_log, unsigned long len);
50 int (*configure_bridge)(struct device_node *dn);
51};
52
53extern struct eeh_ops *eeh_ops;
34extern int eeh_subsystem_enabled; 54extern int eeh_subsystem_enabled;
35 55
36/* Values for eeh_mode bits in device_node */ 56/* Values for eeh_mode bits in device_node */
@@ -47,6 +67,11 @@ extern int eeh_subsystem_enabled;
47#define EEH_MAX_ALLOWED_FREEZES 5 67#define EEH_MAX_ALLOWED_FREEZES 5
48 68
49void __init eeh_init(void); 69void __init eeh_init(void);
70#ifdef CONFIG_PPC_PSERIES
71int __init eeh_pseries_init(void);
72#endif
73int __init eeh_ops_register(struct eeh_ops *ops);
74int __exit eeh_ops_unregister(const char *name);
50unsigned long eeh_check_failure(const volatile void __iomem *token, 75unsigned long eeh_check_failure(const volatile void __iomem *token,
51 unsigned long val); 76 unsigned long val);
52int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev); 77int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev);
@@ -73,6 +98,13 @@ void eeh_remove_bus_device(struct pci_dev *);
73#else /* !CONFIG_EEH */ 98#else /* !CONFIG_EEH */
74static inline void eeh_init(void) { } 99static inline void eeh_init(void) { }
75 100
101#ifdef CONFIG_PPC_PSERIES
102static inline int eeh_pseries_init(void)
103{
104 return 0;
105}
106#endif /* CONFIG_PPC_PSERIES */
107
76static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) 108static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val)
77{ 109{
78 return val; 110 return val;
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 67b3e6e0cf3f..ee873cf4fe46 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -6,7 +6,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \
6 firmware.o power.o dlpar.o mobility.o 6 firmware.o power.o dlpar.o mobility.o
7obj-$(CONFIG_SMP) += smp.o 7obj-$(CONFIG_SMP) += smp.o
8obj-$(CONFIG_SCANLOG) += scanlog.o 8obj-$(CONFIG_SCANLOG) += scanlog.o
9obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o 9obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o eeh_pseries.o
10obj-$(CONFIG_KEXEC) += kexec.o 10obj-$(CONFIG_KEXEC) += kexec.o
11obj-$(CONFIG_PCI) += pci.o pci_dlpar.o 11obj-$(CONFIG_PCI) += pci.o pci_dlpar.o
12obj-$(CONFIG_PSERIES_MSI) += msi.o 12obj-$(CONFIG_PSERIES_MSI) += msi.o
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index fa885891e1c3..b0e3fb0b32a5 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -97,6 +97,9 @@ static int ibm_get_config_addr_info2;
97static int ibm_configure_bridge; 97static int ibm_configure_bridge;
98static int ibm_configure_pe; 98static int ibm_configure_pe;
99 99
100/* Platform dependent EEH operations */
101struct eeh_ops *eeh_ops = NULL;
102
100int eeh_subsystem_enabled; 103int eeh_subsystem_enabled;
101EXPORT_SYMBOL(eeh_subsystem_enabled); 104EXPORT_SYMBOL(eeh_subsystem_enabled);
102 105
@@ -1208,6 +1211,56 @@ static void *eeh_early_enable(struct device_node *dn, void *data)
1208} 1211}
1209 1212
1210/** 1213/**
1214 * eeh_ops_register - Register platform dependent EEH operations
1215 * @ops: platform dependent EEH operations
1216 *
1217 * Register the platform dependent EEH operation callback
1218 * functions. The platform should call this function before
1219 * any other EEH operations.
1220 */
1221int __init eeh_ops_register(struct eeh_ops *ops)
1222{
1223 if (!ops->name) {
1224 pr_warning("%s: Invalid EEH ops name for %p\n",
1225 __func__, ops);
1226 return -EINVAL;
1227 }
1228
1229 if (eeh_ops && eeh_ops != ops) {
1230 pr_warning("%s: EEH ops of platform %s already existing (%s)\n",
1231 __func__, eeh_ops->name, ops->name);
1232 return -EEXIST;
1233 }
1234
1235 eeh_ops = ops;
1236
1237 return 0;
1238}
1239
1240/**
1241 * eeh_ops_unregister - Unreigster platform dependent EEH operations
1242 * @name: name of EEH platform operations
1243 *
1244 * Unregister the platform dependent EEH operation callback
1245 * functions.
1246 */
1247int __exit eeh_ops_unregister(const char *name)
1248{
1249 if (!name || !strlen(name)) {
1250 pr_warning("%s: Invalid EEH ops name\n",
1251 __func__);
1252 return -EINVAL;
1253 }
1254
1255 if (eeh_ops && !strcmp(eeh_ops->name, name)) {
1256 eeh_ops = NULL;
1257 return 0;
1258 }
1259
1260 return -EEXIST;
1261}
1262
1263/**
1211 * eeh_init - EEH initialization 1264 * eeh_init - EEH initialization
1212 * 1265 *
1213 * Initialize EEH by trying to enable it for all of the adapters in the system. 1266 * Initialize EEH by trying to enable it for all of the adapters in the system.
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
new file mode 100644
index 000000000000..61a9050ba969
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -0,0 +1,183 @@
1/*
2 * The file intends to implement the platform dependent EEH operations on pseries.
3 * Actually, the pseries platform is built based on RTAS heavily. That means the
4 * pseries platform dependent EEH operations will be built on RTAS calls. The functions
5 * are devired from arch/powerpc/platforms/pseries/eeh.c and necessary cleanup has
6 * been done.
7 *
8 * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2011.
9 * Copyright IBM Corporation 2001, 2005, 2006
10 * Copyright Dave Engebretsen & Todd Inglett 2001
11 * Copyright Linas Vepstas 2005, 2006
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28#include <linux/atomic.h>
29#include <linux/delay.h>
30#include <linux/export.h>
31#include <linux/init.h>
32#include <linux/list.h>
33#include <linux/of.h>
34#include <linux/pci.h>
35#include <linux/proc_fs.h>
36#include <linux/rbtree.h>
37#include <linux/sched.h>
38#include <linux/seq_file.h>
39#include <linux/spinlock.h>
40
41#include <asm/eeh.h>
42#include <asm/eeh_event.h>
43#include <asm/io.h>
44#include <asm/machdep.h>
45#include <asm/ppc-pci.h>
46#include <asm/rtas.h>
47
48/**
49 * pseries_eeh_init - EEH platform dependent initialization
50 *
51 * EEH platform dependent initialization on pseries.
52 */
53static int pseries_eeh_init(void)
54{
55 return 0;
56}
57
58/**
59 * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable
60 * @dn: device node
61 * @option: operation to be issued
62 *
63 * The function is used to control the EEH functionality globally.
64 * Currently, following options are support according to PAPR:
65 * Enable EEH, Disable EEH, Enable MMIO and Enable DMA
66 */
67static int pseries_eeh_set_option(struct device_node *dn, int option)
68{
69 return 0;
70}
71
72/**
73 * pseries_eeh_get_pe_addr - Retrieve PE address
74 * @dn: device node
75 *
76 * Retrieve the assocated PE address. Actually, there're 2 RTAS
77 * function calls dedicated for the purpose. We need implement
78 * it through the new function and then the old one. Besides,
79 * you should make sure the config address is figured out from
80 * FDT node before calling the function.
81 *
82 * It's notable that zero'ed return value means invalid PE config
83 * address.
84 */
85static int pseries_eeh_get_pe_addr(struct device_node *dn)
86{
87 return 0;
88}
89
90/**
91 * pseries_eeh_get_state - Retrieve PE state
92 * @dn: PE associated device node
93 * @state: return value
94 *
95 * Retrieve the state of the specified PE. On RTAS compliant
96 * pseries platform, there already has one dedicated RTAS function
97 * for the purpose. It's notable that the associated PE config address
98 * might be ready when calling the function. Therefore, endeavour to
99 * use the PE config address if possible. Further more, there're 2
100 * RTAS calls for the purpose, we need to try the new one and back
101 * to the old one if the new one couldn't work properly.
102 */
103static int pseries_eeh_get_state(struct device_node *dn, int *state)
104{
105 return 0;
106}
107
108/**
109 * pseries_eeh_reset - Reset the specified PE
110 * @dn: PE associated device node
111 * @option: reset option
112 *
113 * Reset the specified PE
114 */
115static int pseries_eeh_reset(struct device_node *dn, int option)
116{
117 return 0;
118}
119
120/**
121 * pseries_eeh_wait_state - Wait for PE state
122 * @dn: PE associated device node
123 * @max_wait: maximal period in microsecond
124 *
125 * Wait for the state of associated PE. It might take some time
126 * to retrieve the PE's state.
127 */
128static int pseries_eeh_wait_state(struct device_node *dn, int max_wait)
129{
130 return 0;
131}
132
133/**
134 * pseries_eeh_get_log - Retrieve error log
135 * @dn: device node
136 * @severity: temporary or permanent error log
137 * @drv_log: driver log to be combined with retrieved error log
138 * @len: length of driver log
139 *
140 * Retrieve the temporary or permanent error from the PE.
141 * Actually, the error will be retrieved through the dedicated
142 * RTAS call.
143 */
144static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len)
145{
146 return 0;
147}
148
149/**
150 * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE
151 * @dn: PE associated device node
152 *
153 * The function will be called to reconfigure the bridges included
154 * in the specified PE so that the mulfunctional PE would be recovered
155 * again.
156 */
157static int pseries_eeh_configure_bridge(struct device_node *dn)
158{
159 return 0;
160}
161
162static struct eeh_ops pseries_eeh_ops = {
163 .name = "pseries",
164 .init = pseries_eeh_init,
165 .set_option = pseries_eeh_set_option,
166 .get_pe_addr = pseries_eeh_get_pe_addr,
167 .get_state = pseries_eeh_get_state,
168 .reset = pseries_eeh_reset,
169 .wait_state = pseries_eeh_wait_state,
170 .get_log = pseries_eeh_get_log,
171 .configure_bridge = pseries_eeh_configure_bridge
172};
173
174/**
175 * eeh_pseries_init - Register platform dependent EEH operations
176 *
177 * EEH initialization on pseries platform. This function should be
178 * called before any EEH related functions.
179 */
180int __init eeh_pseries_init(void)
181{
182 return eeh_ops_register(&pseries_eeh_ops);
183}
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index d928412cfb32..62b827626ca6 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -381,6 +381,7 @@ static void __init pSeries_setup_arch(void)
381 381
382 /* Find and initialize PCI host bridges */ 382 /* Find and initialize PCI host bridges */
383 init_pci_config_tokens(); 383 init_pci_config_tokens();
384 eeh_pseries_init();
384 find_and_init_phbs(); 385 find_and_init_phbs();
385 pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); 386 pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb);
386 eeh_init(); 387 eeh_init();