Commit 344eb010b2e399069bac474a9fd0ba04908a2601

Authored by Benjamin Herrenschmidt
1 parent 78b782cb78

powerpc/powernv: Add CPU hotplug support

Unplugged CPU go into NAP mode in a loop until woken up

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Showing 2 changed files with 78 additions and 2 deletions Side-by-side Diff

arch/powerpc/Kconfig
... ... @@ -323,7 +323,7 @@
323 323  
324 324 config HOTPLUG_CPU
325 325 bool "Support for enabling/disabling CPUs"
326   - depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
  326 + depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC || PPC_POWERNV)
327 327 ---help---
328 328 Say Y here to be able to disable and re-enable individual
329 329 CPUs at runtime on SMP machines.
arch/powerpc/platforms/powernv/smp.c
... ... @@ -33,7 +33,14 @@
33 33  
34 34 #include "powernv.h"
35 35  
36   -static void __devinit pnv_smp_setup_cpu(int cpu)
  36 +#ifdef DEBUG
  37 +#include <asm/udbg.h>
  38 +#define DBG(fmt...) udbg_printf(fmt)
  39 +#else
  40 +#define DBG(fmt...)
  41 +#endif
  42 +
  43 +static void __cpuinit pnv_smp_setup_cpu(int cpu)
37 44 {
38 45 if (cpu != boot_cpuid)
39 46 xics_setup_cpu();
... ... @@ -55,6 +62,67 @@
55 62 return 1;
56 63 }
57 64  
  65 +#ifdef CONFIG_HOTPLUG_CPU
  66 +
  67 +static int pnv_smp_cpu_disable(void)
  68 +{
  69 + int cpu = smp_processor_id();
  70 +
  71 + /* This is identical to pSeries... might consolidate by
  72 + * moving migrate_irqs_away to a ppc_md with default to
  73 + * the generic fixup_irqs. --BenH.
  74 + */
  75 + set_cpu_online(cpu, false);
  76 + vdso_data->processorCount--;
  77 + if (cpu == boot_cpuid)
  78 + boot_cpuid = cpumask_any(cpu_online_mask);
  79 + xics_migrate_irqs_away();
  80 + return 0;
  81 +}
  82 +
  83 +static void pnv_smp_cpu_kill_self(void)
  84 +{
  85 + unsigned int cpu;
  86 +
  87 + /* If powersave_nap is enabled, use NAP mode, else just
  88 + * spin aimlessly
  89 + */
  90 + if (!powersave_nap) {
  91 + generic_mach_cpu_die();
  92 + return;
  93 + }
  94 +
  95 + /* Standard hot unplug procedure */
  96 + local_irq_disable();
  97 + idle_task_exit();
  98 + current->active_mm = NULL; /* for sanity */
  99 + cpu = smp_processor_id();
  100 + DBG("CPU%d offline\n", cpu);
  101 + generic_set_cpu_dead(cpu);
  102 + smp_wmb();
  103 +
  104 + /* We don't want to take decrementer interrupts while we are offline,
  105 + * so clear LPCR:PECE1. We keep PECE2 enabled.
  106 + */
  107 + mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);
  108 + while (!generic_check_cpu_restart(cpu)) {
  109 + power7_idle();
  110 + if (!generic_check_cpu_restart(cpu)) {
  111 + DBG("CPU%d Unexpected exit while offline !\n", cpu);
  112 + /* We may be getting an IPI, so we re-enable
  113 + * interrupts to process it, it will be ignored
  114 + * since we aren't online (hopefully)
  115 + */
  116 + local_irq_enable();
  117 + local_irq_disable();
  118 + }
  119 + }
  120 + mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1);
  121 + DBG("CPU%d coming online...\n", cpu);
  122 +}
  123 +
  124 +#endif /* CONFIG_HOTPLUG_CPU */
  125 +
58 126 static struct smp_ops_t pnv_smp_ops = {
59 127 .message_pass = smp_muxed_ipi_message_pass,
60 128 .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */
... ... @@ -62,6 +130,10 @@
62 130 .kick_cpu = smp_generic_kick_cpu,
63 131 .setup_cpu = pnv_smp_setup_cpu,
64 132 .cpu_bootable = pnv_smp_cpu_bootable,
  133 +#ifdef CONFIG_HOTPLUG_CPU
  134 + .cpu_disable = pnv_smp_cpu_disable,
  135 + .cpu_die = generic_cpu_die,
  136 +#endif /* CONFIG_HOTPLUG_CPU */
65 137 };
66 138  
67 139 /* This is called very early during platform setup_arch */
... ... @@ -80,5 +152,9 @@
80 152 smp_ops->take_timebase = rtas_take_timebase;
81 153 }
82 154 #endif /* CONFIG_PPC_RTAS */
  155 +
  156 +#ifdef CONFIG_HOTPLUG_CPU
  157 + ppc_md.cpu_die = pnv_smp_cpu_kill_self;
  158 +#endif
83 159 }