+static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
+#ifdef CONFIG_PPC_PSERIES
+static void rtas_percpu_suspend_me(void *info)
+{
+ int i;
+ long rc;
+ long flags;
+ struct rtas_suspend_me_data *data =
+ (struct rtas_suspend_me_data *)info;
+
+ /*
+ * We use "waiting" to indicate our state. As long
+ * as it is >0, we are still trying to all join up.
+ * If it goes to 0, we have successfully joined up and
+ * one thread got H_Continue. If any error happens,
+ * we set it to <0.
+ */
+ local_irq_save(flags);
+ do {
+ rc = plpar_hcall_norets(H_JOIN);
+ smp_rmb();
+ } while (rc == H_Success && data->waiting > 0);
+ if (rc == H_Success)
+ goto out;
+
+ if (rc == H_Continue) {
+ data->waiting = 0;
+ data->args->args[data->args->nargs] =
+ rtas_call(ibm_suspend_me_token, 0, 1, NULL);
+ for_each_cpu(i)
+ plpar_hcall_norets(H_PROD,i);
+ } else {
+ data->waiting = -EBUSY;
+ printk(KERN_ERR "Error on H_Join hypervisor call\n");
+ }
+
+out:
+ local_irq_restore(flags);
+ return;
+}
+
+static int rtas_ibm_suspend_me(struct rtas_args *args)
+{
+ int i;
+
+ struct rtas_suspend_me_data data;
+
+ data.waiting = 1;
+ data.args = args;
+
+ /* Call function on all CPUs. One of us will make the
+ * rtas call
+ */
+ if (on_each_cpu(rtas_percpu_suspend_me, &data, 1, 0))
+ data.waiting = -EINVAL;
+
+ if (data.waiting != 0)
+ printk(KERN_ERR "Error doing global join\n");
+
+ /* Prod each CPU. This won't hurt, and will wake
+ * anyone we successfully put to sleep with H_Join
+ */
+ for_each_cpu(i)
+ plpar_hcall_norets(H_PROD, i);
+
+ return data.waiting;
+}
+#else /* CONFIG_PPC_PSERIES */
+static int rtas_ibm_suspend_me(struct rtas_args *args)
+{
+ return -ENOSYS;
+}
+#endif