aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries/setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/pseries/setup.c')
-rw-r--r--arch/powerpc/platforms/pseries/setup.c77
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 */
378static 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
402static 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
414static 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
370static void __init pSeries_setup_arch(void) 430static 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
407static int __init pSeries_init_panel(void) 475static 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};