powerpc/pseries: Fix cpu hotplug
[safe/jmp/linux-2.6] / arch / powerpc / platforms / pseries / hotplug-cpu.c
index e78e8ac..a20ead8 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/vdso_datapage.h>
 #include <asm/pSeries_reconfig.h>
 #include "xics.h"
+#include "plpar_wrappers.h"
 
 /* This version can't take the spinlock, because it never returns */
 static struct rtas_args rtas_stop_self_args = {
@@ -53,11 +54,12 @@ static void rtas_stop_self(void)
        panic("Alas, I survived.\n");
 }
 
-static void pSeries_mach_cpu_die(void)
+static void pseries_mach_cpu_die(void)
 {
        local_irq_disable();
        idle_task_exit();
-       xics_teardown_cpu(0);
+       xics_teardown_cpu();
+       unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow()));
        rtas_stop_self();
        /* Should never get here... */
        BUG();
@@ -88,7 +90,7 @@ static int query_cpu_stopped(unsigned int pcpu)
        return cpu_status;
 }
 
-static int pSeries_cpu_disable(void)
+static int pseries_cpu_disable(void)
 {
        int cpu = smp_processor_id();
 
@@ -104,7 +106,7 @@ static int pSeries_cpu_disable(void)
        return 0;
 }
 
-static void pSeries_cpu_die(unsigned int cpu)
+static void pseries_cpu_die(unsigned int cpu)
 {
        int tries;
        int cpu_status;
@@ -114,7 +116,7 @@ static void pSeries_cpu_die(unsigned int cpu)
                cpu_status = query_cpu_stopped(pcpu);
                if (cpu_status == 0 || cpu_status == -1)
                        break;
-               msleep(200);
+               cpu_relax();
        }
        if (cpu_status != 0) {
                printk("Querying DEAD? cpu %i (%i) shows %i\n",
@@ -136,14 +138,14 @@ static void pSeries_cpu_die(unsigned int cpu)
  * the logical ids for sibling SMT threads x and y are adjacent, such
  * that x^1 == y and y^1 == x.
  */
-static int pSeries_add_processor(struct device_node *np)
+static int pseries_add_processor(struct device_node *np)
 {
        unsigned int cpu;
        cpumask_t candidate_map, tmp = CPU_MASK_NONE;
        int err = -ENOSPC, len, nthreads, i;
        const u32 *intserv;
 
-       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+       intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
        if (!intserv)
                return 0;
 
@@ -151,7 +153,7 @@ static int pSeries_add_processor(struct device_node *np)
        for (i = 0; i < nthreads; i++)
                cpu_set(i, tmp);
 
-       lock_cpu_hotplug();
+       cpu_maps_update_begin();
 
        BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
 
@@ -188,7 +190,7 @@ static int pSeries_add_processor(struct device_node *np)
        }
        err = 0;
 out_unlock:
-       unlock_cpu_hotplug();
+       cpu_maps_update_done();
        return err;
 }
 
@@ -197,19 +199,19 @@ out_unlock:
  * the hard id in the paca(s) to -1 to be consistent with boot time
  * convention for non-present cpus.
  */
-static void pSeries_remove_processor(struct device_node *np)
+static void pseries_remove_processor(struct device_node *np)
 {
        unsigned int cpu;
        int len, nthreads, i;
        const u32 *intserv;
 
-       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+       intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
        if (!intserv)
                return;
 
        nthreads = len / sizeof(u32);
 
-       lock_cpu_hotplug();
+       cpu_maps_update_begin();
        for (i = 0; i < nthreads; i++) {
                for_each_present_cpu(cpu) {
                        if (get_hard_smp_processor_id(cpu) != intserv[i])
@@ -223,20 +225,21 @@ static void pSeries_remove_processor(struct device_node *np)
                        printk(KERN_WARNING "Could not find cpu to remove "
                               "with physical id 0x%x\n", intserv[i]);
        }
-       unlock_cpu_hotplug();
+       cpu_maps_update_done();
 }
 
-static int pSeries_smp_notifier(struct notifier_block *nb, unsigned long action, void *node)
+static int pseries_smp_notifier(struct notifier_block *nb,
+                               unsigned long action, void *node)
 {
        int err = NOTIFY_OK;
 
        switch (action) {
        case PSERIES_RECONFIG_ADD:
-               if (pSeries_add_processor(node))
+               if (pseries_add_processor(node))
                        err = NOTIFY_BAD;
                break;
        case PSERIES_RECONFIG_REMOVE:
-               pSeries_remove_processor(node);
+               pseries_remove_processor(node);
                break;
        default:
                err = NOTIFY_DONE;
@@ -245,12 +248,26 @@ static int pSeries_smp_notifier(struct notifier_block *nb, unsigned long action,
        return err;
 }
 
-static struct notifier_block pSeries_smp_nb = {
-       .notifier_call = pSeries_smp_notifier,
+static struct notifier_block pseries_smp_nb = {
+       .notifier_call = pseries_smp_notifier,
 };
 
 static int __init pseries_cpu_hotplug_init(void)
 {
+       struct device_node *np;
+       const char *typep;
+
+       for_each_node_by_name(np, "interrupt-controller") {
+               typep = of_get_property(np, "compatible", NULL);
+               if (strstr(typep, "open-pic")) {
+                       of_node_put(np);
+
+                       printk(KERN_INFO "CPU Hotplug not supported on "
+                               "systems using MPIC\n");
+                       return 0;
+               }
+       }
+
        rtas_stop_self_args.token = rtas_token("stop-self");
        qcss_tok = rtas_token("query-cpu-stopped-state");
 
@@ -261,13 +278,13 @@ static int __init pseries_cpu_hotplug_init(void)
                return 0;
        }
 
-       ppc_md.cpu_die = pSeries_mach_cpu_die;
-       smp_ops->cpu_disable = pSeries_cpu_disable;
-       smp_ops->cpu_die = pSeries_cpu_die;
+       ppc_md.cpu_die = pseries_mach_cpu_die;
+       smp_ops->cpu_disable = pseries_cpu_disable;
+       smp_ops->cpu_die = pseries_cpu_die;
 
        /* Processors can be added/removed only on LPAR */
        if (firmware_has_feature(FW_FEATURE_LPAR))
-               pSeries_reconfig_notifier_register(&pSeries_smp_nb);
+               pSeries_reconfig_notifier_register(&pseries_smp_nb);
 
        return 0;
 }