@@ -47,14 +47,6 @@ struct rtas_t rtas = {
47
47
};
48
48
EXPORT_SYMBOL (rtas );
49
49
50
- struct 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
-
58
50
DEFINE_SPINLOCK (rtas_data_buf_lock );
59
51
EXPORT_SYMBOL (rtas_data_buf_lock );
60
52
@@ -714,22 +706,61 @@ void rtas_os_term(char *str)
714
706
715
707
static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE ;
716
708
#ifdef CONFIG_PPC_PSERIES
717
- static void rtas_percpu_suspend_me (void * info )
709
+ static 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
+
745
+ int 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
+
751
+ static int __rtas_suspend_cpu (struct rtas_suspend_me_data * data , int wake_when_done )
718
752
{
719
753
long rc = H_SUCCESS ;
720
754
unsigned long msr_save ;
721
- u16 slb_size = mmu_slb_size ;
722
755
int cpu ;
723
- struct rtas_suspend_me_data * data =
724
- (struct rtas_suspend_me_data * )info ;
725
756
726
757
atomic_inc (& data -> working );
727
758
728
759
/* really need to ensure MSR.EE is off for H_JOIN */
729
760
msr_save = mfmsr ();
730
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
764
rc = plpar_hcall_norets (H_JOIN );
734
765
735
766
mtmsr (msr_save );
@@ -741,33 +772,37 @@ static void rtas_percpu_suspend_me(void *info)
741
772
/* All other cpus are in H_JOIN, this cpu does
742
773
* the suspend.
743
774
*/
744
- slb_set_size (SLB_MIN_SIZE );
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
- }
775
+ return __rtas_suspend_last_cpu (data , wake_when_done );
754
776
} else {
755
777
printk (KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n" ,
756
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,
763
- * we need to prod all other other cpus out of join state.
764
- * Extra prods are harmless.
765
- */
766
- for_each_online_cpu (cpu )
767
- plpar_hcall_norets (H_PROD , get_hard_smp_processor_id (cpu ));
785
+ /* This cpu did the suspend or got an error; in either case,
786
+ * we need to prod all other other cpus out of join state.
787
+ * Extra prods are harmless.
788
+ */
789
+ for_each_online_cpu (cpu )
790
+ plpar_hcall_norets (H_PROD , get_hard_smp_processor_id (cpu ));
791
+ }
768
792
out :
769
793
if (atomic_dec_return (& data -> working ) == 0 )
770
794
complete (data -> complete );
795
+ return rc ;
796
+ }
797
+
798
+ int rtas_suspend_cpu (struct rtas_suspend_me_data * data )
799
+ {
800
+ return __rtas_suspend_cpu (data , 0 );
801
+ }
802
+
803
+ static void rtas_percpu_suspend_me (void * info )
804
+ {
805
+ __rtas_suspend_cpu ((struct rtas_suspend_me_data * )info , 1 );
771
806
}
772
807
773
808
static 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
838
atomic_set (& data .working , 0 );
804
839
atomic_set (& data .done , 0 );
840
+ atomic_set (& data .error , 0 );
805
841
data .token = rtas_token ("ibm,suspend-me" );
806
- data .error = 0 ;
807
842
data .complete = & done ;
808
843
809
844
/* Call function on all CPUs. One of us will make the
810
845
* rtas call
811
846
*/
812
847
if (on_each_cpu (rtas_percpu_suspend_me , & data , 0 ))
813
- data .error = - EINVAL ;
848
+ atomic_set ( & data .error , - EINVAL ) ;
814
849
815
850
wait_for_completion (& done );
816
851
817
- if (data .error != 0 )
852
+ if (atomic_read ( & data .error ) != 0 )
818
853
printk (KERN_ERR "Error doing global join\n" );
819
854
820
- return data .error ;
855
+ return atomic_read ( & data .error ) ;
821
856
}
822
857
#else /* CONFIG_PPC_PSERIES */
823
858
static int rtas_ibm_suspend_me (struct rtas_args * args )
0 commit comments