diff options
author | Gavin Shan <gwshan@linux.vnet.ibm.com> | 2015-02-15 22:45:41 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2015-03-16 19:31:18 -0400 |
commit | 4cf17445589932155797444687dca1ef2dd47f10 (patch) | |
tree | c956950ab218c9ca63a52480cfd59eac22eb1f3b /arch | |
parent | fa646c3cab032caf94184aef728d7275164c437e (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.c | 193 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/eeh-powernv.c | 184 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.h | 1 |
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 | ||
37 | static int ioda_eeh_nb_init = 0; | ||
38 | |||
39 | static 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 | |||
61 | static 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 | ||
68 | static 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 | |||
109 | static const struct file_operations ioda_eeh_ei_fops = { | ||
110 | .open = simple_open, | ||
111 | .llseek = no_llseek, | ||
112 | .write = ioda_eeh_ei_write, | ||
113 | }; | ||
114 | |||
115 | static 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 | |||
124 | static 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 | |||
133 | static int ioda_eeh_outb_dbgfs_set(void *data, u64 val) | ||
134 | { | ||
135 | return ioda_eeh_dbgfs_set(data, 0xD10, val); | ||
136 | } | ||
137 | |||
138 | static int ioda_eeh_outb_dbgfs_get(void *data, u64 *val) | ||
139 | { | ||
140 | return ioda_eeh_dbgfs_get(data, 0xD10, val); | ||
141 | } | ||
142 | |||
143 | static int ioda_eeh_inbA_dbgfs_set(void *data, u64 val) | ||
144 | { | ||
145 | return ioda_eeh_dbgfs_set(data, 0xD90, val); | ||
146 | } | ||
147 | |||
148 | static int ioda_eeh_inbA_dbgfs_get(void *data, u64 *val) | ||
149 | { | ||
150 | return ioda_eeh_dbgfs_get(data, 0xD90, val); | ||
151 | } | ||
152 | |||
153 | static int ioda_eeh_inbB_dbgfs_set(void *data, u64 val) | ||
154 | { | ||
155 | return ioda_eeh_dbgfs_set(data, 0xE10, val); | ||
156 | } | ||
157 | |||
158 | static int ioda_eeh_inbB_dbgfs_get(void *data, u64 *val) | ||
159 | { | ||
160 | return ioda_eeh_dbgfs_get(data, 0xE10, val); | ||
161 | } | ||
162 | |||
163 | DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_outb_dbgfs_ops, ioda_eeh_outb_dbgfs_get, | ||
164 | ioda_eeh_outb_dbgfs_set, "0x%llx\n"); | ||
165 | DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbA_dbgfs_ops, ioda_eeh_inbA_dbgfs_get, | ||
166 | ioda_eeh_inbA_dbgfs_set, "0x%llx\n"); | ||
167 | DEFINE_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 | */ | ||
180 | static 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 | ||
1096 | struct pnv_eeh_ops ioda_eeh_ops = { | 904 | struct 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 | ||
42 | static 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 | ||
91 | static 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 | |||
113 | static 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 | ||
120 | static 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 | |||
162 | static const struct file_operations pnv_eeh_ei_fops = { | ||
163 | .open = simple_open, | ||
164 | .llseek = no_llseek, | ||
165 | .write = pnv_eeh_ei_write, | ||
166 | }; | ||
167 | |||
168 | static 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 | |||
177 | static 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 | |||
186 | static int pnv_eeh_outb_dbgfs_set(void *data, u64 val) | ||
187 | { | ||
188 | return pnv_eeh_dbgfs_set(data, 0xD10, val); | ||
189 | } | ||
190 | |||
191 | static int pnv_eeh_outb_dbgfs_get(void *data, u64 *val) | ||
192 | { | ||
193 | return pnv_eeh_dbgfs_get(data, 0xD10, val); | ||
194 | } | ||
195 | |||
196 | static int pnv_eeh_inbA_dbgfs_set(void *data, u64 val) | ||
197 | { | ||
198 | return pnv_eeh_dbgfs_set(data, 0xD90, val); | ||
199 | } | ||
200 | |||
201 | static int pnv_eeh_inbA_dbgfs_get(void *data, u64 *val) | ||
202 | { | ||
203 | return pnv_eeh_dbgfs_get(data, 0xD90, val); | ||
204 | } | ||
205 | |||
206 | static int pnv_eeh_inbB_dbgfs_set(void *data, u64 val) | ||
207 | { | ||
208 | return pnv_eeh_dbgfs_set(data, 0xE10, val); | ||
209 | } | ||
210 | |||
211 | static int pnv_eeh_inbB_dbgfs_get(void *data, u64 *val) | ||
212 | { | ||
213 | return pnv_eeh_dbgfs_get(data, 0xE10, val); | ||
214 | } | ||
215 | |||
216 | DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_outb_dbgfs_ops, pnv_eeh_outb_dbgfs_get, | ||
217 | pnv_eeh_outb_dbgfs_set, "0x%llx\n"); | ||
218 | DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_inbA_dbgfs_ops, pnv_eeh_inbA_dbgfs_get, | ||
219 | pnv_eeh_inbA_dbgfs_set, "0x%llx\n"); | ||
220 | DEFINE_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 |
80 | struct pnv_eeh_ops { | 80 | struct 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); |