diff options
Diffstat (limited to 'arch/powerpc/platforms/powernv/setup.c')
| -rw-r--r-- | arch/powerpc/platforms/powernv/setup.c | 56 |
1 files changed, 54 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 8723d32632f5..8c16a5f96728 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
| 28 | #include <linux/bug.h> | 28 | #include <linux/bug.h> |
| 29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
| 30 | #include <linux/cpufreq.h> | ||
| 30 | 31 | ||
| 31 | #include <asm/machdep.h> | 32 | #include <asm/machdep.h> |
| 32 | #include <asm/firmware.h> | 33 | #include <asm/firmware.h> |
| @@ -98,11 +99,32 @@ static void pnv_show_cpuinfo(struct seq_file *m) | |||
| 98 | of_node_put(root); | 99 | of_node_put(root); |
| 99 | } | 100 | } |
| 100 | 101 | ||
| 102 | static void pnv_prepare_going_down(void) | ||
| 103 | { | ||
| 104 | /* | ||
| 105 | * Disable all notifiers from OPAL, we can't | ||
| 106 | * service interrupts anymore anyway | ||
| 107 | */ | ||
| 108 | opal_notifier_disable(); | ||
| 109 | |||
| 110 | /* Soft disable interrupts */ | ||
| 111 | local_irq_disable(); | ||
| 112 | |||
| 113 | /* | ||
| 114 | * Return secondary CPUs to firwmare if a flash update | ||
| 115 | * is pending otherwise we will get all sort of error | ||
| 116 | * messages about CPU being stuck etc.. This will also | ||
| 117 | * have the side effect of hard disabling interrupts so | ||
| 118 | * past this point, the kernel is effectively dead. | ||
| 119 | */ | ||
| 120 | opal_flash_term_callback(); | ||
| 121 | } | ||
| 122 | |||
| 101 | static void __noreturn pnv_restart(char *cmd) | 123 | static void __noreturn pnv_restart(char *cmd) |
| 102 | { | 124 | { |
| 103 | long rc = OPAL_BUSY; | 125 | long rc = OPAL_BUSY; |
| 104 | 126 | ||
| 105 | opal_notifier_disable(); | 127 | pnv_prepare_going_down(); |
| 106 | 128 | ||
| 107 | while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { | 129 | while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { |
| 108 | rc = opal_cec_reboot(); | 130 | rc = opal_cec_reboot(); |
| @@ -119,7 +141,7 @@ static void __noreturn pnv_power_off(void) | |||
| 119 | { | 141 | { |
| 120 | long rc = OPAL_BUSY; | 142 | long rc = OPAL_BUSY; |
| 121 | 143 | ||
| 122 | opal_notifier_disable(); | 144 | pnv_prepare_going_down(); |
| 123 | 145 | ||
| 124 | while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { | 146 | while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { |
| 125 | rc = opal_cec_power_down(0); | 147 | rc = opal_cec_power_down(0); |
| @@ -222,6 +244,13 @@ static void pnv_kexec_cpu_down(int crash_shutdown, int secondary) | |||
| 222 | } | 244 | } |
| 223 | #endif /* CONFIG_KEXEC */ | 245 | #endif /* CONFIG_KEXEC */ |
| 224 | 246 | ||
| 247 | #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE | ||
| 248 | static unsigned long pnv_memory_block_size(void) | ||
| 249 | { | ||
| 250 | return 256UL * 1024 * 1024; | ||
| 251 | } | ||
| 252 | #endif | ||
| 253 | |||
| 225 | static void __init pnv_setup_machdep_opal(void) | 254 | static void __init pnv_setup_machdep_opal(void) |
| 226 | { | 255 | { |
| 227 | ppc_md.get_boot_time = opal_get_boot_time; | 256 | ppc_md.get_boot_time = opal_get_boot_time; |
| @@ -269,6 +298,25 @@ static int __init pnv_probe(void) | |||
| 269 | return 1; | 298 | return 1; |
| 270 | } | 299 | } |
| 271 | 300 | ||
| 301 | /* | ||
| 302 | * Returns the cpu frequency for 'cpu' in Hz. This is used by | ||
| 303 | * /proc/cpuinfo | ||
| 304 | */ | ||
| 305 | unsigned long pnv_get_proc_freq(unsigned int cpu) | ||
| 306 | { | ||
| 307 | unsigned long ret_freq; | ||
| 308 | |||
| 309 | ret_freq = cpufreq_quick_get(cpu) * 1000ul; | ||
| 310 | |||
| 311 | /* | ||
| 312 | * If the backend cpufreq driver does not exist, | ||
| 313 | * then fallback to old way of reporting the clockrate. | ||
| 314 | */ | ||
| 315 | if (!ret_freq) | ||
| 316 | ret_freq = ppc_proc_freq; | ||
| 317 | return ret_freq; | ||
| 318 | } | ||
| 319 | |||
| 272 | define_machine(powernv) { | 320 | define_machine(powernv) { |
| 273 | .name = "PowerNV", | 321 | .name = "PowerNV", |
| 274 | .probe = pnv_probe, | 322 | .probe = pnv_probe, |
| @@ -276,6 +324,7 @@ define_machine(powernv) { | |||
| 276 | .setup_arch = pnv_setup_arch, | 324 | .setup_arch = pnv_setup_arch, |
| 277 | .init_IRQ = pnv_init_IRQ, | 325 | .init_IRQ = pnv_init_IRQ, |
| 278 | .show_cpuinfo = pnv_show_cpuinfo, | 326 | .show_cpuinfo = pnv_show_cpuinfo, |
| 327 | .get_proc_freq = pnv_get_proc_freq, | ||
| 279 | .progress = pnv_progress, | 328 | .progress = pnv_progress, |
| 280 | .machine_shutdown = pnv_shutdown, | 329 | .machine_shutdown = pnv_shutdown, |
| 281 | .power_save = power7_idle, | 330 | .power_save = power7_idle, |
| @@ -284,4 +333,7 @@ define_machine(powernv) { | |||
| 284 | #ifdef CONFIG_KEXEC | 333 | #ifdef CONFIG_KEXEC |
| 285 | .kexec_cpu_down = pnv_kexec_cpu_down, | 334 | .kexec_cpu_down = pnv_kexec_cpu_down, |
| 286 | #endif | 335 | #endif |
| 336 | #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE | ||
| 337 | .memory_block_size = pnv_memory_block_size, | ||
| 338 | #endif | ||
| 287 | }; | 339 | }; |
