aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/rtas.c
diff options
context:
space:
mode:
authorBrian King <brking@linux.vnet.ibm.com>2010-07-07 08:31:01 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-07-08 21:26:17 -0400
commit8fe93f8d850a24581e9d47df5814b257fe451052 (patch)
tree7f768ca93e9ebaee0324d60f1349498c8d3cce59 /arch/powerpc/kernel/rtas.c
parentc1aa687d499a8bce55cb8cf962f0b72c0f933f14 (diff)
powerpc/pseries: Migration code reorganization / hibernation prep
Partition hibernation will use some of the same code as is currently used for Live Partition Migration. This function further abstracts this code such that code outside of rtas.c can utilize it. It also changes the error field in the suspend me data structure to be an atomic type, since it is set and checked on different cpus without any barriers or locking. Signed-off-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/rtas.c')
-rw-r--r--arch/powerpc/kernel/rtas.c105
1 files changed, 70 insertions, 35 deletions
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 0e1ec6f746f6..41cfde0ca11b 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -47,14 +47,6 @@ struct rtas_t rtas = {
47}; 47};
48EXPORT_SYMBOL(rtas); 48EXPORT_SYMBOL(rtas);
49 49
50struct rtas_suspend_me_data {
51 atomic_t working; /* number of cpus accessing this struct */
52 atomic_t done;
53 int token; /* ibm,suspend-me */
54 int error;
55 struct completion *complete; /* wait on this until working == 0 */
56};
57
58DEFINE_SPINLOCK(rtas_data_buf_lock); 50DEFINE_SPINLOCK(rtas_data_buf_lock);
59EXPORT_SYMBOL(rtas_data_buf_lock); 51EXPORT_SYMBOL(rtas_data_buf_lock);
60 52
@@ -714,14 +706,53 @@ void rtas_os_term(char *str)
714 706
715static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; 707static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
716#ifdef CONFIG_PPC_PSERIES 708#ifdef CONFIG_PPC_PSERIES
717static void rtas_percpu_suspend_me(void *info) 709static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_when_done)
710{
711 u16 slb_size = mmu_slb_size;
712 int rc = H_MULTI_THREADS_ACTIVE;
713 int cpu;
714
715 slb_set_size(SLB_MIN_SIZE);
716 printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n", smp_processor_id());
717
718 while (rc == H_MULTI_THREADS_ACTIVE && !atomic_read(&data->done) &&
719 !atomic_read(&data->error))
720 rc = rtas_call(data->token, 0, 1, NULL);
721
722 if (rc || atomic_read(&data->error)) {
723 printk(KERN_DEBUG "ibm,suspend-me returned %d\n", rc);
724 slb_set_size(slb_size);
725 }
726
727 if (atomic_read(&data->error))
728 rc = atomic_read(&data->error);
729
730 atomic_set(&data->error, rc);
731
732 if (wake_when_done) {
733 atomic_set(&data->done, 1);
734
735 for_each_online_cpu(cpu)
736 plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));
737 }
738
739 if (atomic_dec_return(&data->working) == 0)
740 complete(data->complete);
741
742 return rc;
743}
744
745int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data)
746{
747 atomic_inc(&data->working);
748 return __rtas_suspend_last_cpu(data, 0);
749}
750
751static int __rtas_suspend_cpu(struct rtas_suspend_me_data *data, int wake_when_done)
718{ 752{
719 long rc = H_SUCCESS; 753 long rc = H_SUCCESS;
720 unsigned long msr_save; 754 unsigned long msr_save;
721 u16 slb_size = mmu_slb_size;
722 int cpu; 755 int cpu;
723 struct rtas_suspend_me_data *data =
724 (struct rtas_suspend_me_data *)info;
725 756
726 atomic_inc(&data->working); 757 atomic_inc(&data->working);
727 758
@@ -729,7 +760,7 @@ static void rtas_percpu_suspend_me(void *info)
729 msr_save = mfmsr(); 760 msr_save = mfmsr();
730 mtmsr(msr_save & ~(MSR_EE)); 761 mtmsr(msr_save & ~(MSR_EE));
731 762
732 while (rc == H_SUCCESS && !atomic_read(&data->done)) 763 while (rc == H_SUCCESS && !atomic_read(&data->done) && !atomic_read(&data->error))
733 rc = plpar_hcall_norets(H_JOIN); 764 rc = plpar_hcall_norets(H_JOIN);
734 765
735 mtmsr(msr_save); 766 mtmsr(msr_save);
@@ -741,33 +772,37 @@ static void rtas_percpu_suspend_me(void *info)
741 /* All other cpus are in H_JOIN, this cpu does 772 /* All other cpus are in H_JOIN, this cpu does
742 * the suspend. 773 * the suspend.
743 */ 774 */
744 slb_set_size(SLB_MIN_SIZE); 775 return __rtas_suspend_last_cpu(data, wake_when_done);
745 printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n",
746 smp_processor_id());
747 data->error = rtas_call(data->token, 0, 1, NULL);
748
749 if (data->error) {
750 printk(KERN_DEBUG "ibm,suspend-me returned %d\n",
751 data->error);
752 slb_set_size(slb_size);
753 }
754 } else { 776 } else {
755 printk(KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n", 777 printk(KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n",
756 smp_processor_id(), rc); 778 smp_processor_id(), rc);
757 data->error = rc; 779 atomic_set(&data->error, rc);
758 } 780 }
759 781
760 atomic_set(&data->done, 1); 782 if (wake_when_done) {
783 atomic_set(&data->done, 1);
761 784
762 /* This cpu did the suspend or got an error; in either case, 785 /* This cpu did the suspend or got an error; in either case,
763 * we need to prod all other other cpus out of join state. 786 * we need to prod all other other cpus out of join state.
764 * Extra prods are harmless. 787 * Extra prods are harmless.
765 */ 788 */
766 for_each_online_cpu(cpu) 789 for_each_online_cpu(cpu)
767 plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu)); 790 plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));
791 }
768out: 792out:
769 if (atomic_dec_return(&data->working) == 0) 793 if (atomic_dec_return(&data->working) == 0)
770 complete(data->complete); 794 complete(data->complete);
795 return rc;
796}
797
798int rtas_suspend_cpu(struct rtas_suspend_me_data *data)
799{
800 return __rtas_suspend_cpu(data, 0);
801}
802
803static void rtas_percpu_suspend_me(void *info)
804{
805 __rtas_suspend_cpu((struct rtas_suspend_me_data *)info, 1);
771} 806}
772 807
773static int rtas_ibm_suspend_me(struct rtas_args *args) 808static int rtas_ibm_suspend_me(struct rtas_args *args)
@@ -802,22 +837,22 @@ static int rtas_ibm_suspend_me(struct rtas_args *args)
802 837
803 atomic_set(&data.working, 0); 838 atomic_set(&data.working, 0);
804 atomic_set(&data.done, 0); 839 atomic_set(&data.done, 0);
840 atomic_set(&data.error, 0);
805 data.token = rtas_token("ibm,suspend-me"); 841 data.token = rtas_token("ibm,suspend-me");
806 data.error = 0;
807 data.complete = &done; 842 data.complete = &done;
808 843
809 /* Call function on all CPUs. One of us will make the 844 /* Call function on all CPUs. One of us will make the
810 * rtas call 845 * rtas call
811 */ 846 */
812 if (on_each_cpu(rtas_percpu_suspend_me, &data, 0)) 847 if (on_each_cpu(rtas_percpu_suspend_me, &data, 0))
813 data.error = -EINVAL; 848 atomic_set(&data.error, -EINVAL);
814 849
815 wait_for_completion(&done); 850 wait_for_completion(&done);
816 851
817 if (data.error != 0) 852 if (atomic_read(&data.error) != 0)
818 printk(KERN_ERR "Error doing global join\n"); 853 printk(KERN_ERR "Error doing global join\n");
819 854
820 return data.error; 855 return atomic_read(&data.error);
821} 856}
822#else /* CONFIG_PPC_PSERIES */ 857#else /* CONFIG_PPC_PSERIES */
823static int rtas_ibm_suspend_me(struct rtas_args *args) 858static int rtas_ibm_suspend_me(struct rtas_args *args)