@@ -47,14 +47,6 @@ struct rtas_t rtas = {
4747};
4848EXPORT_SYMBOL (rtas );
4949
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-
5850DEFINE_SPINLOCK (rtas_data_buf_lock );
5951EXPORT_SYMBOL (rtas_data_buf_lock );
6052
@@ -714,22 +706,61 @@ void rtas_os_term(char *str)
714706
715707static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE ;
716708#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 )
718752{
719753 long rc = H_SUCCESS ;
720754 unsigned long msr_save ;
721- u16 slb_size = mmu_slb_size ;
722755 int cpu ;
723- struct rtas_suspend_me_data * data =
724- (struct rtas_suspend_me_data * )info ;
725756
726757 atomic_inc (& data -> working );
727758
728759 /* really need to ensure MSR.EE is off for H_JOIN */
729760 msr_save = mfmsr ();
730761 mtmsr (msr_save & ~(MSR_EE ));
731762
732- while (rc == H_SUCCESS && !atomic_read (& data -> done ))
763+ while (rc == H_SUCCESS && !atomic_read (& data -> done ) && ! atomic_read ( & data -> error ) )
733764 rc = plpar_hcall_norets (H_JOIN );
734765
735766 mtmsr (msr_save );
@@ -741,33 +772,37 @@ static void rtas_percpu_suspend_me(void *info)
741772 /* All other cpus are in H_JOIN, this cpu does
742773 * the suspend.
743774 */
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 );
754776 } else {
755777 printk (KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n" ,
756778 smp_processor_id (), rc );
757- data -> error = rc ;
779+ atomic_set ( & data -> error , rc ) ;
758780 }
759781
760- atomic_set (& data -> done , 1 );
782+ if (wake_when_done ) {
783+ atomic_set (& data -> done , 1 );
761784
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+ }
768792out :
769793 if (atomic_dec_return (& data -> working ) == 0 )
770794 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 );
771806}
772807
773808static int rtas_ibm_suspend_me (struct rtas_args * args )
@@ -802,22 +837,22 @@ static int rtas_ibm_suspend_me(struct rtas_args *args)
802837
803838 atomic_set (& data .working , 0 );
804839 atomic_set (& data .done , 0 );
840+ atomic_set (& data .error , 0 );
805841 data .token = rtas_token ("ibm,suspend-me" );
806- data .error = 0 ;
807842 data .complete = & done ;
808843
809844 /* Call function on all CPUs. One of us will make the
810845 * rtas call
811846 */
812847 if (on_each_cpu (rtas_percpu_suspend_me , & data , 0 ))
813- data .error = - EINVAL ;
848+ atomic_set ( & data .error , - EINVAL ) ;
814849
815850 wait_for_completion (& done );
816851
817- if (data .error != 0 )
852+ if (atomic_read ( & data .error ) != 0 )
818853 printk (KERN_ERR "Error doing global join\n" );
819854
820- return data .error ;
855+ return atomic_read ( & data .error ) ;
821856}
822857#else /* CONFIG_PPC_PSERIES */
823858static int rtas_ibm_suspend_me (struct rtas_args * args )
0 commit comments