aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powernv/opal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powernv/opal.c')
-rw-r--r--arch/powerpc/platforms/powernv/opal.c267
1 files changed, 157 insertions, 110 deletions
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 1c798cd55372..65499adaecff 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -18,9 +18,12 @@
18#include <linux/interrupt.h> 18#include <linux/interrupt.h>
19#include <linux/notifier.h> 19#include <linux/notifier.h>
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/sched.h>
21#include <linux/kobject.h> 22#include <linux/kobject.h>
23#include <linux/delay.h>
22#include <asm/opal.h> 24#include <asm/opal.h>
23#include <asm/firmware.h> 25#include <asm/firmware.h>
26#include <asm/mce.h>
24 27
25#include "powernv.h" 28#include "powernv.h"
26 29
@@ -38,6 +41,7 @@ extern u64 opal_mc_secondary_handler[];
38static unsigned int *opal_irqs; 41static unsigned int *opal_irqs;
39static unsigned int opal_irq_count; 42static unsigned int opal_irq_count;
40static ATOMIC_NOTIFIER_HEAD(opal_notifier_head); 43static ATOMIC_NOTIFIER_HEAD(opal_notifier_head);
44static struct atomic_notifier_head opal_msg_notifier_head[OPAL_MSG_TYPE_MAX];
41static DEFINE_SPINLOCK(opal_notifier_lock); 45static DEFINE_SPINLOCK(opal_notifier_lock);
42static uint64_t last_notified_mask = 0x0ul; 46static uint64_t last_notified_mask = 0x0ul;
43static atomic_t opal_notifier_hold = ATOMIC_INIT(0); 47static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
@@ -88,14 +92,10 @@ static int __init opal_register_exception_handlers(void)
88 if (!(powerpc_firmware_features & FW_FEATURE_OPAL)) 92 if (!(powerpc_firmware_features & FW_FEATURE_OPAL))
89 return -ENODEV; 93 return -ENODEV;
90 94
91 /* Hookup some exception handlers. We use the fwnmi area at 0x7000 95 /* Hookup some exception handlers except machine check. We use the
92 * to provide the glue space to OPAL 96 * fwnmi area at 0x7000 to provide the glue space to OPAL
93 */ 97 */
94 glue = 0x7000; 98 glue = 0x7000;
95 opal_register_exception_handler(OPAL_MACHINE_CHECK_HANDLER,
96 __pa(opal_mc_secondary_handler[0]),
97 glue);
98 glue += 128;
99 opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER, 99 opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER,
100 0, glue); 100 0, glue);
101 glue += 128; 101 glue += 128;
@@ -169,6 +169,95 @@ void opal_notifier_disable(void)
169 atomic_set(&opal_notifier_hold, 1); 169 atomic_set(&opal_notifier_hold, 1);
170} 170}
171 171
172/*
173 * Opal message notifier based on message type. Allow subscribers to get
174 * notified for specific messgae type.
175 */
176int opal_message_notifier_register(enum OpalMessageType msg_type,
177 struct notifier_block *nb)
178{
179 if (!nb) {
180 pr_warning("%s: Invalid argument (%p)\n",
181 __func__, nb);
182 return -EINVAL;
183 }
184 if (msg_type > OPAL_MSG_TYPE_MAX) {
185 pr_warning("%s: Invalid message type argument (%d)\n",
186 __func__, msg_type);
187 return -EINVAL;
188 }
189 return atomic_notifier_chain_register(
190 &opal_msg_notifier_head[msg_type], nb);
191}
192
193static void opal_message_do_notify(uint32_t msg_type, void *msg)
194{
195 /* notify subscribers */
196 atomic_notifier_call_chain(&opal_msg_notifier_head[msg_type],
197 msg_type, msg);
198}
199
200static void opal_handle_message(void)
201{
202 s64 ret;
203 /*
204 * TODO: pre-allocate a message buffer depending on opal-msg-size
205 * value in /proc/device-tree.
206 */
207 static struct opal_msg msg;
208
209 ret = opal_get_msg(__pa(&msg), sizeof(msg));
210 /* No opal message pending. */
211 if (ret == OPAL_RESOURCE)
212 return;
213
214 /* check for errors. */
215 if (ret) {
216 pr_warning("%s: Failed to retrive opal message, err=%lld\n",
217 __func__, ret);
218 return;
219 }
220
221 /* Sanity check */
222 if (msg.msg_type > OPAL_MSG_TYPE_MAX) {
223 pr_warning("%s: Unknown message type: %u\n",
224 __func__, msg.msg_type);
225 return;
226 }
227 opal_message_do_notify(msg.msg_type, (void *)&msg);
228}
229
230static int opal_message_notify(struct notifier_block *nb,
231 unsigned long events, void *change)
232{
233 if (events & OPAL_EVENT_MSG_PENDING)
234 opal_handle_message();
235 return 0;
236}
237
238static struct notifier_block opal_message_nb = {
239 .notifier_call = opal_message_notify,
240 .next = NULL,
241 .priority = 0,
242};
243
244static int __init opal_message_init(void)
245{
246 int ret, i;
247
248 for (i = 0; i < OPAL_MSG_TYPE_MAX; i++)
249 ATOMIC_INIT_NOTIFIER_HEAD(&opal_msg_notifier_head[i]);
250
251 ret = opal_notifier_register(&opal_message_nb);
252 if (ret) {
253 pr_err("%s: Can't register OPAL event notifier (%d)\n",
254 __func__, ret);
255 return ret;
256 }
257 return 0;
258}
259early_initcall(opal_message_init);
260
172int opal_get_chars(uint32_t vtermno, char *buf, int count) 261int opal_get_chars(uint32_t vtermno, char *buf, int count)
173{ 262{
174 s64 rc; 263 s64 rc;
@@ -254,119 +343,62 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
254 return written; 343 return written;
255} 344}
256 345
346static int opal_recover_mce(struct pt_regs *regs,
347 struct machine_check_event *evt)
348{
349 int recovered = 0;
350 uint64_t ea = get_mce_fault_addr(evt);
351
352 if (!(regs->msr & MSR_RI)) {
353 /* If MSR_RI isn't set, we cannot recover */
354 recovered = 0;
355 } else if (evt->disposition == MCE_DISPOSITION_RECOVERED) {
356 /* Platform corrected itself */
357 recovered = 1;
358 } else if (ea && !is_kernel_addr(ea)) {
359 /*
360 * Faulting address is not in kernel text. We should be fine.
361 * We need to find which process uses this address.
362 * For now, kill the task if we have received exception when
363 * in userspace.
364 *
365 * TODO: Queue up this address for hwpoisioning later.
366 */
367 if (user_mode(regs) && !is_global_init(current)) {
368 _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
369 recovered = 1;
370 } else
371 recovered = 0;
372 } else if (user_mode(regs) && !is_global_init(current) &&
373 evt->severity == MCE_SEV_ERROR_SYNC) {
374 /*
375 * If we have received a synchronous error when in userspace
376 * kill the task.
377 */
378 _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
379 recovered = 1;
380 }
381 return recovered;
382}
383
257int opal_machine_check(struct pt_regs *regs) 384int opal_machine_check(struct pt_regs *regs)
258{ 385{
259 struct opal_machine_check_event *opal_evt = get_paca()->opal_mc_evt; 386 struct machine_check_event evt;
260 struct opal_machine_check_event evt; 387
261 const char *level, *sevstr, *subtype; 388 if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
262 static const char *opal_mc_ue_types[] = { 389 return 0;
263 "Indeterminate",
264 "Instruction fetch",
265 "Page table walk ifetch",
266 "Load/Store",
267 "Page table walk Load/Store",
268 };
269 static const char *opal_mc_slb_types[] = {
270 "Indeterminate",
271 "Parity",
272 "Multihit",
273 };
274 static const char *opal_mc_erat_types[] = {
275 "Indeterminate",
276 "Parity",
277 "Multihit",
278 };
279 static const char *opal_mc_tlb_types[] = {
280 "Indeterminate",
281 "Parity",
282 "Multihit",
283 };
284
285 /* Copy the event structure and release the original */
286 evt = *opal_evt;
287 opal_evt->in_use = 0;
288 390
289 /* Print things out */ 391 /* Print things out */
290 if (evt.version != OpalMCE_V1) { 392 if (evt.version != MCE_V1) {
291 pr_err("Machine Check Exception, Unknown event version %d !\n", 393 pr_err("Machine Check Exception, Unknown event version %d !\n",
292 evt.version); 394 evt.version);
293 return 0; 395 return 0;
294 } 396 }
295 switch(evt.severity) { 397 machine_check_print_event_info(&evt);
296 case OpalMCE_SEV_NO_ERROR:
297 level = KERN_INFO;
298 sevstr = "Harmless";
299 break;
300 case OpalMCE_SEV_WARNING:
301 level = KERN_WARNING;
302 sevstr = "";
303 break;
304 case OpalMCE_SEV_ERROR_SYNC:
305 level = KERN_ERR;
306 sevstr = "Severe";
307 break;
308 case OpalMCE_SEV_FATAL:
309 default:
310 level = KERN_ERR;
311 sevstr = "Fatal";
312 break;
313 }
314 398
315 printk("%s%s Machine check interrupt [%s]\n", level, sevstr, 399 if (opal_recover_mce(regs, &evt))
316 evt.disposition == OpalMCE_DISPOSITION_RECOVERED ? 400 return 1;
317 "Recovered" : "[Not recovered"); 401 return 0;
318 printk("%s Initiator: %s\n", level,
319 evt.initiator == OpalMCE_INITIATOR_CPU ? "CPU" : "Unknown");
320 switch(evt.error_type) {
321 case OpalMCE_ERROR_TYPE_UE:
322 subtype = evt.u.ue_error.ue_error_type <
323 ARRAY_SIZE(opal_mc_ue_types) ?
324 opal_mc_ue_types[evt.u.ue_error.ue_error_type]
325 : "Unknown";
326 printk("%s Error type: UE [%s]\n", level, subtype);
327 if (evt.u.ue_error.effective_address_provided)
328 printk("%s Effective address: %016llx\n",
329 level, evt.u.ue_error.effective_address);
330 if (evt.u.ue_error.physical_address_provided)
331 printk("%s Physial address: %016llx\n",
332 level, evt.u.ue_error.physical_address);
333 break;
334 case OpalMCE_ERROR_TYPE_SLB:
335 subtype = evt.u.slb_error.slb_error_type <
336 ARRAY_SIZE(opal_mc_slb_types) ?
337 opal_mc_slb_types[evt.u.slb_error.slb_error_type]
338 : "Unknown";
339 printk("%s Error type: SLB [%s]\n", level, subtype);
340 if (evt.u.slb_error.effective_address_provided)
341 printk("%s Effective address: %016llx\n",
342 level, evt.u.slb_error.effective_address);
343 break;
344 case OpalMCE_ERROR_TYPE_ERAT:
345 subtype = evt.u.erat_error.erat_error_type <
346 ARRAY_SIZE(opal_mc_erat_types) ?
347 opal_mc_erat_types[evt.u.erat_error.erat_error_type]
348 : "Unknown";
349 printk("%s Error type: ERAT [%s]\n", level, subtype);
350 if (evt.u.erat_error.effective_address_provided)
351 printk("%s Effective address: %016llx\n",
352 level, evt.u.erat_error.effective_address);
353 break;
354 case OpalMCE_ERROR_TYPE_TLB:
355 subtype = evt.u.tlb_error.tlb_error_type <
356 ARRAY_SIZE(opal_mc_tlb_types) ?
357 opal_mc_tlb_types[evt.u.tlb_error.tlb_error_type]
358 : "Unknown";
359 printk("%s Error type: TLB [%s]\n", level, subtype);
360 if (evt.u.tlb_error.effective_address_provided)
361 printk("%s Effective address: %016llx\n",
362 level, evt.u.tlb_error.effective_address);
363 break;
364 default:
365 case OpalMCE_ERROR_TYPE_UNKNOWN:
366 printk("%s Error type: Unknown\n", level);
367 break;
368 }
369 return evt.severity == OpalMCE_SEV_FATAL ? 0 : 1;
370} 402}
371 403
372static irqreturn_t opal_interrupt(int irq, void *data) 404static irqreturn_t opal_interrupt(int irq, void *data)
@@ -451,10 +483,25 @@ subsys_initcall(opal_init);
451void opal_shutdown(void) 483void opal_shutdown(void)
452{ 484{
453 unsigned int i; 485 unsigned int i;
486 long rc = OPAL_BUSY;
454 487
488 /* First free interrupts, which will also mask them */
455 for (i = 0; i < opal_irq_count; i++) { 489 for (i = 0; i < opal_irq_count; i++) {
456 if (opal_irqs[i]) 490 if (opal_irqs[i])
457 free_irq(opal_irqs[i], NULL); 491 free_irq(opal_irqs[i], NULL);
458 opal_irqs[i] = 0; 492 opal_irqs[i] = 0;
459 } 493 }
494
495 /*
496 * Then sync with OPAL which ensure anything that can
497 * potentially write to our memory has completed such
498 * as an ongoing dump retrieval
499 */
500 while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
501 rc = opal_sync_host_reboot();
502 if (rc == OPAL_BUSY)
503 opal_poll_events(NULL);
504 else
505 mdelay(10);
506 }
460} 507}