aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2015-02-15 22:45:41 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2015-03-16 19:31:18 -0400
commit4cf17445589932155797444687dca1ef2dd47f10 (patch)
treec956950ab218c9ca63a52480cfd59eac22eb1f3b /arch
parentfa646c3cab032caf94184aef728d7275164c437e (diff)
powerpc/powernv: Drop PHB operation post_init()
The patch drops PHB EEH operation post_init() and merge its logic to eeh_ops::post_init(). Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/powernv/eeh-ioda.c193
-rw-r--r--arch/powerpc/platforms/powernv/eeh-powernv.c184
-rw-r--r--arch/powerpc/platforms/powernv/pci.h1
3 files changed, 179 insertions, 199 deletions
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index dd154cf98085..bd509ad08211 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -34,198 +34,6 @@
34#include "powernv.h" 34#include "powernv.h"
35#include "pci.h" 35#include "pci.h"
36 36
37static int ioda_eeh_nb_init = 0;
38
39static int ioda_eeh_event(struct notifier_block *nb,
40 unsigned long events, void *change)
41{
42 uint64_t changed_evts = (uint64_t)change;
43
44 /*
45 * We simply send special EEH event if EEH has
46 * been enabled, or clear pending events in
47 * case that we enable EEH soon
48 */
49 if (!(changed_evts & OPAL_EVENT_PCI_ERROR) ||
50 !(events & OPAL_EVENT_PCI_ERROR))
51 return 0;
52
53 if (eeh_enabled())
54 eeh_send_failure_event(NULL);
55 else
56 opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
57
58 return 0;
59}
60
61static struct notifier_block ioda_eeh_nb = {
62 .notifier_call = ioda_eeh_event,
63 .next = NULL,
64 .priority = 0
65};
66
67#ifdef CONFIG_DEBUG_FS
68static ssize_t ioda_eeh_ei_write(struct file *filp,
69 const char __user *user_buf,
70 size_t count, loff_t *ppos)
71{
72 struct pci_controller *hose = filp->private_data;
73 struct eeh_dev *edev;
74 struct eeh_pe *pe;
75 int pe_no, type, func;
76 unsigned long addr, mask;
77 char buf[50];
78 int ret;
79
80 if (!eeh_ops || !eeh_ops->err_inject)
81 return -ENXIO;
82
83 ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count);
84 if (!ret)
85 return -EFAULT;
86
87 /* Retrieve parameters */
88 ret = sscanf(buf, "%x:%x:%x:%lx:%lx",
89 &pe_no, &type, &func, &addr, &mask);
90 if (ret != 5)
91 return -EINVAL;
92
93 /* Retrieve PE */
94 edev = kzalloc(sizeof(*edev), GFP_KERNEL);
95 if (!edev)
96 return -ENOMEM;
97 edev->phb = hose;
98 edev->pe_config_addr = pe_no;
99 pe = eeh_pe_get(edev);
100 kfree(edev);
101 if (!pe)
102 return -ENODEV;
103
104 /* Do error injection */
105 ret = eeh_ops->err_inject(pe, type, func, addr, mask);
106 return ret < 0 ? ret : count;
107}
108
109static const struct file_operations ioda_eeh_ei_fops = {
110 .open = simple_open,
111 .llseek = no_llseek,
112 .write = ioda_eeh_ei_write,
113};
114
115static int ioda_eeh_dbgfs_set(void *data, int offset, u64 val)
116{
117 struct pci_controller *hose = data;
118 struct pnv_phb *phb = hose->private_data;
119
120 out_be64(phb->regs + offset, val);
121 return 0;
122}
123
124static int ioda_eeh_dbgfs_get(void *data, int offset, u64 *val)
125{
126 struct pci_controller *hose = data;
127 struct pnv_phb *phb = hose->private_data;
128
129 *val = in_be64(phb->regs + offset);
130 return 0;
131}
132
133static int ioda_eeh_outb_dbgfs_set(void *data, u64 val)
134{
135 return ioda_eeh_dbgfs_set(data, 0xD10, val);
136}
137
138static int ioda_eeh_outb_dbgfs_get(void *data, u64 *val)
139{
140 return ioda_eeh_dbgfs_get(data, 0xD10, val);
141}
142
143static int ioda_eeh_inbA_dbgfs_set(void *data, u64 val)
144{
145 return ioda_eeh_dbgfs_set(data, 0xD90, val);
146}
147
148static int ioda_eeh_inbA_dbgfs_get(void *data, u64 *val)
149{
150 return ioda_eeh_dbgfs_get(data, 0xD90, val);
151}
152
153static int ioda_eeh_inbB_dbgfs_set(void *data, u64 val)
154{
155 return ioda_eeh_dbgfs_set(data, 0xE10, val);
156}
157
158static int ioda_eeh_inbB_dbgfs_get(void *data, u64 *val)
159{
160 return ioda_eeh_dbgfs_get(data, 0xE10, val);
161}
162
163DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_outb_dbgfs_ops, ioda_eeh_outb_dbgfs_get,
164 ioda_eeh_outb_dbgfs_set, "0x%llx\n");
165DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbA_dbgfs_ops, ioda_eeh_inbA_dbgfs_get,
166 ioda_eeh_inbA_dbgfs_set, "0x%llx\n");
167DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbB_dbgfs_ops, ioda_eeh_inbB_dbgfs_get,
168 ioda_eeh_inbB_dbgfs_set, "0x%llx\n");
169#endif /* CONFIG_DEBUG_FS */
170
171
172/**
173 * ioda_eeh_post_init - Chip dependent post initialization
174 * @hose: PCI controller
175 *
176 * The function will be called after eeh PEs and devices
177 * have been built. That means the EEH is ready to supply
178 * service with I/O cache.
179 */
180static int ioda_eeh_post_init(struct pci_controller *hose)
181{
182 struct pnv_phb *phb = hose->private_data;
183 int ret;
184
185 /* Register OPAL event notifier */
186 if (!ioda_eeh_nb_init) {
187 ret = opal_notifier_register(&ioda_eeh_nb);
188 if (ret) {
189 pr_err("%s: Can't register OPAL event notifier (%d)\n",
190 __func__, ret);
191 return ret;
192 }
193
194 ioda_eeh_nb_init = 1;
195 }
196
197#ifdef CONFIG_DEBUG_FS
198 if (!phb->has_dbgfs && phb->dbgfs) {
199 phb->has_dbgfs = 1;
200
201 debugfs_create_file("err_injct", 0200,
202 phb->dbgfs, hose,
203 &ioda_eeh_ei_fops);
204
205 debugfs_create_file("err_injct_outbound", 0600,
206 phb->dbgfs, hose,
207 &ioda_eeh_outb_dbgfs_ops);
208 debugfs_create_file("err_injct_inboundA", 0600,
209 phb->dbgfs, hose,
210 &ioda_eeh_inbA_dbgfs_ops);
211 debugfs_create_file("err_injct_inboundB", 0600,
212 phb->dbgfs, hose,
213 &ioda_eeh_inbB_dbgfs_ops);
214 }
215#endif
216
217 /* If EEH is enabled, we're going to rely on that.
218 * Otherwise, we restore to conventional mechanism
219 * to clear frozen PE during PCI config access.
220 */
221 if (eeh_enabled())
222 phb->flags |= PNV_PHB_FLAG_EEH;
223 else
224 phb->flags &= ~PNV_PHB_FLAG_EEH;
225
226 return 0;
227}
228
229/** 37/**
230 * ioda_eeh_set_option - Set EEH operation or I/O setting 38 * ioda_eeh_set_option - Set EEH operation or I/O setting
231 * @pe: EEH PE 39 * @pe: EEH PE
@@ -1094,7 +902,6 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
1094} 902}
1095 903
1096struct pnv_eeh_ops ioda_eeh_ops = { 904struct pnv_eeh_ops ioda_eeh_ops = {
1097 .post_init = ioda_eeh_post_init,
1098 .set_option = ioda_eeh_set_option, 905 .set_option = ioda_eeh_set_option,
1099 .get_state = ioda_eeh_get_state, 906 .get_state = ioda_eeh_get_state,
1100 .reset = ioda_eeh_reset, 907 .reset = ioda_eeh_reset,
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index df33daab381c..641ba3378ccf 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -12,6 +12,7 @@
12 */ 12 */
13 13
14#include <linux/atomic.h> 14#include <linux/atomic.h>
15#include <linux/debugfs.h>
15#include <linux/delay.h> 16#include <linux/delay.h>
16#include <linux/export.h> 17#include <linux/export.h>
17#include <linux/init.h> 18#include <linux/init.h>
@@ -38,6 +39,8 @@
38#include "powernv.h" 39#include "powernv.h"
39#include "pci.h" 40#include "pci.h"
40 41
42static bool pnv_eeh_nb_init = false;
43
41/** 44/**
42 * pnv_eeh_init - EEH platform dependent initialization 45 * pnv_eeh_init - EEH platform dependent initialization
43 * 46 *
@@ -85,6 +88,139 @@ static int pnv_eeh_init(void)
85 return 0; 88 return 0;
86} 89}
87 90
91static int pnv_eeh_event(struct notifier_block *nb,
92 unsigned long events, void *change)
93{
94 uint64_t changed_evts = (uint64_t)change;
95
96 /*
97 * We simply send special EEH event if EEH has
98 * been enabled, or clear pending events in
99 * case that we enable EEH soon
100 */
101 if (!(changed_evts & OPAL_EVENT_PCI_ERROR) ||
102 !(events & OPAL_EVENT_PCI_ERROR))
103 return 0;
104
105 if (eeh_enabled())
106 eeh_send_failure_event(NULL);
107 else
108 opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
109
110 return 0;
111}
112
113static struct notifier_block pnv_eeh_nb = {
114 .notifier_call = pnv_eeh_event,
115 .next = NULL,
116 .priority = 0
117};
118
119#ifdef CONFIG_DEBUG_FS
120static ssize_t pnv_eeh_ei_write(struct file *filp,
121 const char __user *user_buf,
122 size_t count, loff_t *ppos)
123{
124 struct pci_controller *hose = filp->private_data;
125 struct eeh_dev *edev;
126 struct eeh_pe *pe;
127 int pe_no, type, func;
128 unsigned long addr, mask;
129 char buf[50];
130 int ret;
131
132 if (!eeh_ops || !eeh_ops->err_inject)
133 return -ENXIO;
134
135 /* Copy over argument buffer */
136 ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count);
137 if (!ret)
138 return -EFAULT;
139
140 /* Retrieve parameters */
141 ret = sscanf(buf, "%x:%x:%x:%lx:%lx",
142 &pe_no, &type, &func, &addr, &mask);
143 if (ret != 5)
144 return -EINVAL;
145
146 /* Retrieve PE */
147 edev = kzalloc(sizeof(*edev), GFP_KERNEL);
148 if (!edev)
149 return -ENOMEM;
150 edev->phb = hose;
151 edev->pe_config_addr = pe_no;
152 pe = eeh_pe_get(edev);
153 kfree(edev);
154 if (!pe)
155 return -ENODEV;
156
157 /* Do error injection */
158 ret = eeh_ops->err_inject(pe, type, func, addr, mask);
159 return ret < 0 ? ret : count;
160}
161
162static const struct file_operations pnv_eeh_ei_fops = {
163 .open = simple_open,
164 .llseek = no_llseek,
165 .write = pnv_eeh_ei_write,
166};
167
168static int pnv_eeh_dbgfs_set(void *data, int offset, u64 val)
169{
170 struct pci_controller *hose = data;
171 struct pnv_phb *phb = hose->private_data;
172
173 out_be64(phb->regs + offset, val);
174 return 0;
175}
176
177static int pnv_eeh_dbgfs_get(void *data, int offset, u64 *val)
178{
179 struct pci_controller *hose = data;
180 struct pnv_phb *phb = hose->private_data;
181
182 *val = in_be64(phb->regs + offset);
183 return 0;
184}
185
186static int pnv_eeh_outb_dbgfs_set(void *data, u64 val)
187{
188 return pnv_eeh_dbgfs_set(data, 0xD10, val);
189}
190
191static int pnv_eeh_outb_dbgfs_get(void *data, u64 *val)
192{
193 return pnv_eeh_dbgfs_get(data, 0xD10, val);
194}
195
196static int pnv_eeh_inbA_dbgfs_set(void *data, u64 val)
197{
198 return pnv_eeh_dbgfs_set(data, 0xD90, val);
199}
200
201static int pnv_eeh_inbA_dbgfs_get(void *data, u64 *val)
202{
203 return pnv_eeh_dbgfs_get(data, 0xD90, val);
204}
205
206static int pnv_eeh_inbB_dbgfs_set(void *data, u64 val)
207{
208 return pnv_eeh_dbgfs_set(data, 0xE10, val);
209}
210
211static int pnv_eeh_inbB_dbgfs_get(void *data, u64 *val)
212{
213 return pnv_eeh_dbgfs_get(data, 0xE10, val);
214}
215
216DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_outb_dbgfs_ops, pnv_eeh_outb_dbgfs_get,
217 pnv_eeh_outb_dbgfs_set, "0x%llx\n");
218DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_inbA_dbgfs_ops, pnv_eeh_inbA_dbgfs_get,
219 pnv_eeh_inbA_dbgfs_set, "0x%llx\n");
220DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_inbB_dbgfs_ops, pnv_eeh_inbB_dbgfs_get,
221 pnv_eeh_inbB_dbgfs_set, "0x%llx\n");
222#endif /* CONFIG_DEBUG_FS */
223
88/** 224/**
89 * pnv_eeh_post_init - EEH platform dependent post initialization 225 * pnv_eeh_post_init - EEH platform dependent post initialization
90 * 226 *
@@ -99,16 +235,54 @@ static int pnv_eeh_post_init(void)
99 struct pnv_phb *phb; 235 struct pnv_phb *phb;
100 int ret = 0; 236 int ret = 0;
101 237
238 /* Register OPAL event notifier */
239 if (!pnv_eeh_nb_init) {
240 ret = opal_notifier_register(&pnv_eeh_nb);
241 if (ret) {
242 pr_warn("%s: Can't register OPAL event notifier (%d)\n",
243 __func__, ret);
244 return ret;
245 }
246
247 pnv_eeh_nb_init = true;
248 }
249
102 list_for_each_entry(hose, &hose_list, list_node) { 250 list_for_each_entry(hose, &hose_list, list_node) {
103 phb = hose->private_data; 251 phb = hose->private_data;
104 252
105 if (phb->eeh_ops && phb->eeh_ops->post_init) { 253 /*
106 ret = phb->eeh_ops->post_init(hose); 254 * If EEH is enabled, we're going to rely on that.
107 if (ret) 255 * Otherwise, we restore to conventional mechanism
108 break; 256 * to clear frozen PE during PCI config access.
109 } 257 */
258 if (eeh_enabled())
259 phb->flags |= PNV_PHB_FLAG_EEH;
260 else
261 phb->flags &= ~PNV_PHB_FLAG_EEH;
262
263 /* Create debugfs entries */
264#ifdef CONFIG_DEBUG_FS
265 if (phb->has_dbgfs || !phb->dbgfs)
266 continue;
267
268 phb->has_dbgfs = 1;
269 debugfs_create_file("err_injct", 0200,
270 phb->dbgfs, hose,
271 &pnv_eeh_ei_fops);
272
273 debugfs_create_file("err_injct_outbound", 0600,
274 phb->dbgfs, hose,
275 &pnv_eeh_outb_dbgfs_ops);
276 debugfs_create_file("err_injct_inboundA", 0600,
277 phb->dbgfs, hose,
278 &pnv_eeh_inbA_dbgfs_ops);
279 debugfs_create_file("err_injct_inboundB", 0600,
280 phb->dbgfs, hose,
281 &pnv_eeh_inbB_dbgfs_ops);
282#endif /* CONFIG_DEBUG_FS */
110 } 283 }
111 284
285
112 return ret; 286 return ret;
113} 287}
114 288
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index a9f236229fe0..c7e047f19528 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -78,7 +78,6 @@ struct pnv_ioda_pe {
78/* IOC dependent EEH operations */ 78/* IOC dependent EEH operations */
79#ifdef CONFIG_EEH 79#ifdef CONFIG_EEH
80struct pnv_eeh_ops { 80struct pnv_eeh_ops {
81 int (*post_init)(struct pci_controller *hose);
82 int (*set_option)(struct eeh_pe *pe, int option); 81 int (*set_option)(struct eeh_pe *pe, int option);
83 int (*get_state)(struct eeh_pe *pe); 82 int (*get_state)(struct eeh_pe *pe);
84 int (*reset)(struct eeh_pe *pe, int option); 83 int (*reset)(struct eeh_pe *pe, int option);