aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/rtas.c
diff options
context:
space:
mode:
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 d0516dbee762..41048de3c6c3 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)