diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/setup.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 77 |
1 files changed, 74 insertions, 3 deletions
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index e3cb7ae61658..ca55882465d6 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include <linux/seq_file.h> | 40 | #include <linux/seq_file.h> |
41 | #include <linux/root_dev.h> | 41 | #include <linux/root_dev.h> |
42 | #include <linux/cpuidle.h> | 42 | #include <linux/cpuidle.h> |
43 | #include <linux/of.h> | ||
44 | #include <linux/kexec.h> | ||
43 | 45 | ||
44 | #include <asm/mmu.h> | 46 | #include <asm/mmu.h> |
45 | #include <asm/processor.h> | 47 | #include <asm/processor.h> |
@@ -63,7 +65,6 @@ | |||
63 | #include <asm/smp.h> | 65 | #include <asm/smp.h> |
64 | #include <asm/firmware.h> | 66 | #include <asm/firmware.h> |
65 | #include <asm/eeh.h> | 67 | #include <asm/eeh.h> |
66 | #include <asm/pSeries_reconfig.h> | ||
67 | 68 | ||
68 | #include "plpar_wrappers.h" | 69 | #include "plpar_wrappers.h" |
69 | #include "pseries.h" | 70 | #include "pseries.h" |
@@ -258,7 +259,7 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act | |||
258 | int err = NOTIFY_OK; | 259 | int err = NOTIFY_OK; |
259 | 260 | ||
260 | switch (action) { | 261 | switch (action) { |
261 | case PSERIES_RECONFIG_ADD: | 262 | case OF_RECONFIG_ATTACH_NODE: |
262 | pci = np->parent->data; | 263 | pci = np->parent->data; |
263 | if (pci) { | 264 | if (pci) { |
264 | update_dn_pci_info(np, pci->phb); | 265 | update_dn_pci_info(np, pci->phb); |
@@ -367,6 +368,65 @@ static void pSeries_idle(void) | |||
367 | } | 368 | } |
368 | } | 369 | } |
369 | 370 | ||
371 | /* | ||
372 | * Enable relocation on during exceptions. This has partition wide scope and | ||
373 | * may take a while to complete, if it takes longer than one second we will | ||
374 | * just give up rather than wasting any more time on this - if that turns out | ||
375 | * to ever be a problem in practice we can move this into a kernel thread to | ||
376 | * finish off the process later in boot. | ||
377 | */ | ||
378 | static int __init pSeries_enable_reloc_on_exc(void) | ||
379 | { | ||
380 | long rc; | ||
381 | unsigned int delay, total_delay = 0; | ||
382 | |||
383 | while (1) { | ||
384 | rc = enable_reloc_on_exceptions(); | ||
385 | if (!H_IS_LONG_BUSY(rc)) | ||
386 | return rc; | ||
387 | |||
388 | delay = get_longbusy_msecs(rc); | ||
389 | total_delay += delay; | ||
390 | if (total_delay > 1000) { | ||
391 | pr_warn("Warning: Giving up waiting to enable " | ||
392 | "relocation on exceptions (%u msec)!\n", | ||
393 | total_delay); | ||
394 | return rc; | ||
395 | } | ||
396 | |||
397 | mdelay(delay); | ||
398 | } | ||
399 | } | ||
400 | |||
401 | #ifdef CONFIG_KEXEC | ||
402 | static long pSeries_disable_reloc_on_exc(void) | ||
403 | { | ||
404 | long rc; | ||
405 | |||
406 | while (1) { | ||
407 | rc = disable_reloc_on_exceptions(); | ||
408 | if (!H_IS_LONG_BUSY(rc)) | ||
409 | return rc; | ||
410 | mdelay(get_longbusy_msecs(rc)); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | static void pSeries_machine_kexec(struct kimage *image) | ||
415 | { | ||
416 | long rc; | ||
417 | |||
418 | if (firmware_has_feature(FW_FEATURE_SET_MODE) && | ||
419 | (image->type != KEXEC_TYPE_CRASH)) { | ||
420 | rc = pSeries_disable_reloc_on_exc(); | ||
421 | if (rc != H_SUCCESS) | ||
422 | pr_warning("Warning: Failed to disable relocation on " | ||
423 | "exceptions: %ld\n", rc); | ||
424 | } | ||
425 | |||
426 | default_machine_kexec(image); | ||
427 | } | ||
428 | #endif | ||
429 | |||
370 | static void __init pSeries_setup_arch(void) | 430 | static void __init pSeries_setup_arch(void) |
371 | { | 431 | { |
372 | panic_timeout = 10; | 432 | panic_timeout = 10; |
@@ -389,7 +449,7 @@ static void __init pSeries_setup_arch(void) | |||
389 | /* Find and initialize PCI host bridges */ | 449 | /* Find and initialize PCI host bridges */ |
390 | init_pci_config_tokens(); | 450 | init_pci_config_tokens(); |
391 | find_and_init_phbs(); | 451 | find_and_init_phbs(); |
392 | pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); | 452 | of_reconfig_notifier_register(&pci_dn_reconfig_nb); |
393 | 453 | ||
394 | pSeries_nvram_init(); | 454 | pSeries_nvram_init(); |
395 | 455 | ||
@@ -402,6 +462,14 @@ static void __init pSeries_setup_arch(void) | |||
402 | ppc_md.enable_pmcs = pseries_lpar_enable_pmcs; | 462 | ppc_md.enable_pmcs = pseries_lpar_enable_pmcs; |
403 | else | 463 | else |
404 | ppc_md.enable_pmcs = power4_enable_pmcs; | 464 | ppc_md.enable_pmcs = power4_enable_pmcs; |
465 | |||
466 | if (firmware_has_feature(FW_FEATURE_SET_MODE)) { | ||
467 | long rc; | ||
468 | if ((rc = pSeries_enable_reloc_on_exc()) != H_SUCCESS) { | ||
469 | pr_warn("Unable to enable relocation on exceptions: " | ||
470 | "%ld\n", rc); | ||
471 | } | ||
472 | } | ||
405 | } | 473 | } |
406 | 474 | ||
407 | static int __init pSeries_init_panel(void) | 475 | static int __init pSeries_init_panel(void) |
@@ -659,4 +727,7 @@ define_machine(pseries) { | |||
659 | .progress = rtas_progress, | 727 | .progress = rtas_progress, |
660 | .system_reset_exception = pSeries_system_reset_exception, | 728 | .system_reset_exception = pSeries_system_reset_exception, |
661 | .machine_check_exception = pSeries_machine_check_exception, | 729 | .machine_check_exception = pSeries_machine_check_exception, |
730 | #ifdef CONFIG_KEXEC | ||
731 | .machine_kexec = pSeries_machine_kexec, | ||
732 | #endif | ||
662 | }; | 733 | }; |