The more code & documentation I read, the more I'm convinced that
coordinating state changes between logical processors isn't necessary
and actually is responsible for the hangs people have been seeing.

So here is a diff that does away with it all.  I've tested it on a few
laptops here, but it could use testing on a somewhat wider range of
machines.  I'm especially interested in seeing this tested on a dual
socket machine with apmd -A.


Index: i386/i386/mp_setperf.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/mp_setperf.c,v
retrieving revision 1.5
diff -u -p -r1.5 mp_setperf.c
--- i386/i386/mp_setperf.c      29 Jun 2014 01:01:20 -0000      1.5
+++ i386/i386/mp_setperf.c      8 Sep 2014 20:43:50 -0000
@@ -17,13 +17,10 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/proc.h>
 #include <sys/sysctl.h>
 #include <sys/mutex.h>
 
 #include <machine/cpu.h>
-#include <machine/cpufunc.h>
-
 #include <machine/intr.h>
 
 struct mutex setperf_mp_mutex = MUTEX_INITIALIZER(IPL_HIGH);
@@ -31,14 +28,7 @@ struct mutex setperf_mp_mutex = MUTEX_IN
 /* underlying setperf mechanism e.g. k8_powernow_setperf() */
 void (*ul_setperf)(int);
 
-#define MP_SETPERF_STEADY      0       /* steady state - normal operation */
-#define MP_SETPERF_INTRANSIT   1       /* in transition */
-#define MP_SETPERF_PROCEED     2       /* proceed with transition */
-#define MP_SETPERF_FINISH      3       /* return from IPI */
-
-
 /* protected by setperf_mp_mutex */
-volatile int mp_setperf_state = MP_SETPERF_STEADY;
 volatile int mp_perflevel;
 
 void mp_setperf(int);
@@ -46,102 +36,27 @@ void mp_setperf(int);
 void
 mp_setperf(int level)
 {
-       CPU_INFO_ITERATOR cii;
-       struct cpu_info *ci;
-       int notready, s;
-
-       if (mp_setperf_state == MP_SETPERF_STEADY) {
-               mtx_enter(&setperf_mp_mutex);
-               disable_intr();
-
-               mp_perflevel = level;
-
-               curcpu()->ci_setperf_state = CI_SETPERF_INTRANSIT;
-               /* ask all other processors to drop what they are doing */
-               CPU_INFO_FOREACH(cii, ci) {
-                       if (ci->ci_setperf_state != CI_SETPERF_INTRANSIT) {
-                               ci->ci_setperf_state =
-                                   CI_SETPERF_SHOULDSTOP;
-                               i386_send_ipi(ci, I386_IPI_SETPERF);
-                       }
-               }
-
-
-               /* Loop until all processors report ready */
-               do {
-                       CPU_INFO_FOREACH(cii, ci) {
-                               if ((notready = (ci->ci_setperf_state
-                                   != CI_SETPERF_INTRANSIT)))
-                                       break;
-                       }
-               } while (notready);
-
-               mp_setperf_state = MP_SETPERF_PROCEED; /* release the hounds */
-
-               s = splipi();
-
-               ul_setperf(mp_perflevel);
-
-               splx(s);
-
-               curcpu()->ci_setperf_state = CI_SETPERF_DONE;
-               /* Loop until all processors report done */
-               do {
-                       CPU_INFO_FOREACH(cii, ci) {
-                               if ((notready = (ci->ci_setperf_state
-                                   != CI_SETPERF_DONE)))
-                                       break;
-                       }
-               } while (notready);
-
-               mp_setperf_state = MP_SETPERF_FINISH;
-               /* delay a little for potential straglers */
-               DELAY(2);
-               curcpu()->ci_setperf_state = CI_SETPERF_READY;
-               mp_setperf_state = MP_SETPERF_STEADY; /* restore normallity */
-               enable_intr();
-               mtx_leave(&setperf_mp_mutex);
-       }
+       mtx_enter(&setperf_mp_mutex);
+       mp_perflevel = level;
 
+       ul_setperf(mp_perflevel);
+       i386_broadcast_ipi(I386_IPI_SETPERF);
+       mtx_leave(&setperf_mp_mutex);
 }
 
 void
 i386_setperf_ipi(struct cpu_info *ci)
 {
-
-       disable_intr();
-
-       if (ci->ci_setperf_state == CI_SETPERF_SHOULDSTOP)
-               ci->ci_setperf_state = CI_SETPERF_INTRANSIT;
-
-       while (mp_setperf_state != MP_SETPERF_PROCEED)
-               ;
-
        ul_setperf(mp_perflevel);
-
-       ci->ci_setperf_state = CI_SETPERF_DONE;
-
-       while (mp_setperf_state != MP_SETPERF_FINISH)
-               ;
-       ci->ci_setperf_state = CI_SETPERF_READY;
-
-       enable_intr();
 }
 
 void
-mp_setperf_init()
+mp_setperf_init(void)
 {
-       CPU_INFO_ITERATOR cii;
-       struct cpu_info *ci;
-
        if (!cpu_setperf)
                return;
-       ul_setperf = cpu_setperf;
 
+       ul_setperf = cpu_setperf;
        cpu_setperf = mp_setperf;
-
-       CPU_INFO_FOREACH(cii, ci) {
-               ci->ci_setperf_state = CI_SETPERF_READY;
-       }
        mtx_init(&setperf_mp_mutex, IPL_HIGH);
 }
Index: i386/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/i386/include/cpu.h,v
retrieving revision 1.134
diff -u -p -r1.134 cpu.h
--- i386/include/cpu.h  11 Jul 2014 10:53:07 -0000      1.134
+++ i386/include/cpu.h  8 Sep 2014 20:43:50 -0000
@@ -147,12 +147,6 @@ struct cpu_info {
 #define CI_DDB_ENTERDDB                3
 #define CI_DDB_INDDB           4
 
-       volatile int ci_setperf_state;
-#define CI_SETPERF_READY       0
-#define CI_SETPERF_SHOULDSTOP  1
-#define CI_SETPERF_INTRANSIT   2
-#define CI_SETPERF_DONE                3
-
        struct ksensordev       ci_sensordev;
        struct ksensor          ci_sensor;
 #ifdef GPROF
Index: amd64/amd64/mp_setperf.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/mp_setperf.c,v
retrieving revision 1.4
diff -u -p -r1.4 mp_setperf.c
--- amd64/amd64/mp_setperf.c    29 Jun 2014 01:01:20 -0000      1.4
+++ amd64/amd64/mp_setperf.c    8 Sep 2014 20:43:50 -0000
@@ -17,13 +17,10 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/proc.h>
 #include <sys/sysctl.h>
 #include <sys/mutex.h>
 
 #include <machine/cpu.h>
-#include <machine/cpufunc.h>
-
 #include <machine/intr.h>
 
 struct mutex setperf_mp_mutex = MUTEX_INITIALIZER(IPL_HIGH);
@@ -31,14 +28,7 @@ struct mutex setperf_mp_mutex = MUTEX_IN
 /* underlying setperf mechanism e.g. k8_powernow_setperf() */
 void (*ul_setperf)(int);
 
-#define MP_SETPERF_STEADY      0       /* steady state - normal operation */
-#define MP_SETPERF_INTRANSIT   1       /* in transition */
-#define MP_SETPERF_PROCEED     2       /* proceed with transition */
-#define MP_SETPERF_FINISH      3       /* return from IPI */
-
-
 /* protected by setperf_mp_mutex */
-volatile int mp_setperf_state = MP_SETPERF_STEADY;
 volatile int mp_perflevel;
 
 void mp_setperf(int);
@@ -46,101 +36,28 @@ void mp_setperf(int);
 void
 mp_setperf(int level)
 {
-       CPU_INFO_ITERATOR cii;
-       struct cpu_info *ci;
-       int notready, s;
-
-       if (mp_setperf_state == MP_SETPERF_STEADY) {
-               mtx_enter(&setperf_mp_mutex);
-               disable_intr();
-               mp_perflevel = level;
-
-               curcpu()->ci_setperf_state = CI_SETPERF_INTRANSIT;
-               /* ask all other processors to drop what they are doing */
-               CPU_INFO_FOREACH(cii, ci) {
-                       if (ci->ci_setperf_state != CI_SETPERF_INTRANSIT) {
-                               ci->ci_setperf_state =
-                                   CI_SETPERF_SHOULDSTOP;
-                               x86_send_ipi(ci, X86_IPI_SETPERF);
-                       }
-               }
-
-
-               /* Loop until all processors report ready */
-               do {
-                       CPU_INFO_FOREACH(cii, ci) {
-                               if ((notready = (ci->ci_setperf_state
-                                   != CI_SETPERF_INTRANSIT)))
-                                       break;
-                       }
-               } while (notready);
-
-               mp_setperf_state = MP_SETPERF_PROCEED; /* release the hounds */
-
-               s = splipi();
-
-               ul_setperf(mp_perflevel);
-
-               splx(s);
-
-               curcpu()->ci_setperf_state = CI_SETPERF_DONE;
-               /* Loop until all processors report done */
-               do {
-                       CPU_INFO_FOREACH(cii, ci) {
-                               if ((notready = (ci->ci_setperf_state
-                                   != CI_SETPERF_DONE)))
-                                       break;
-                       }
-               } while (notready);
-
-               mp_setperf_state = MP_SETPERF_FINISH;
-               /* delay a little for potential straglers */
-               DELAY(2);
-               curcpu()->ci_setperf_state = CI_SETPERF_READY;
-               mp_setperf_state = MP_SETPERF_STEADY; /* restore normallity */
-               enable_intr();
-               mtx_leave(&setperf_mp_mutex);
-       }
+       mtx_enter(&setperf_mp_mutex);
+       mp_perflevel = level;
+
+       ul_setperf(mp_perflevel);
+       x86_broadcast_ipi(X86_IPI_SETPERF);
 
+       mtx_leave(&setperf_mp_mutex);
 }
 
 void
 x86_setperf_ipi(struct cpu_info *ci)
 {
-
-       disable_intr();
-
-       if (ci->ci_setperf_state == CI_SETPERF_SHOULDSTOP)
-               ci->ci_setperf_state = CI_SETPERF_INTRANSIT;
-
-       while (mp_setperf_state != MP_SETPERF_PROCEED)
-               ;
-
        ul_setperf(mp_perflevel);
-
-       ci->ci_setperf_state = CI_SETPERF_DONE;
-
-       while (mp_setperf_state != MP_SETPERF_FINISH)
-               ;
-       ci->ci_setperf_state = CI_SETPERF_READY;
-
-       enable_intr();
 }
 
 void
-mp_setperf_init()
+mp_setperf_init(void)
 {
-       CPU_INFO_ITERATOR cii;
-       struct cpu_info *ci;
-
        if (!cpu_setperf)
                return;
-       ul_setperf = cpu_setperf;
 
+       ul_setperf = cpu_setperf;
        cpu_setperf = mp_setperf;
-
-       CPU_INFO_FOREACH(cii, ci) {
-               ci->ci_setperf_state = CI_SETPERF_READY;
-       }
        mtx_init(&setperf_mp_mutex, IPL_HIGH);
 }
Index: amd64/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/include/cpu.h,v
retrieving revision 1.85
diff -u -p -r1.85 cpu.h
--- amd64/include/cpu.h 11 Jul 2014 10:53:07 -0000      1.85
+++ amd64/include/cpu.h 8 Sep 2014 20:43:50 -0000
@@ -136,12 +136,6 @@ struct cpu_info {
 #define CI_DDB_ENTERDDB                3
 #define CI_DDB_INDDB           4
 
-       volatile int ci_setperf_state;
-#define CI_SETPERF_READY       0
-#define CI_SETPERF_SHOULDSTOP  1
-#define CI_SETPERF_INTRANSIT   2
-#define CI_SETPERF_DONE                3
-
        struct ksensordev       ci_sensordev;
        struct ksensor          ci_sensor;
 #ifdef GPROF

Reply via email to