This diff will allow EST to use ACPI _PSS if its available, you should
notice no change running this diff and thats exactly what supposed to
happen a later diff will enable the set _PDC stuff which will allow est
to use the states from acpi.

Please make sure that your system still has the highest and lowest
states after you apply this.

gwk

Index: sys/arch/amd64/amd64/est.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/est.c,v
retrieving revision 1.11
diff -u -p -u sys/arch/amd64/amd64/est.c
--- sys/arch/amd64/amd64/est.c  23 Apr 2009 07:30:03 -0000      1.11
+++ sys/arch/amd64/amd64/est.c  30 May 2009 20:07:00 -0000
@@ -56,15 +56,23 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/sysctl.h>
+#include <sys/malloc.h>
 
 #include <machine/cpu.h>
 #include <machine/cpufunc.h>
 #include <machine/specialreg.h>
+#include <machine/bus.h>
 
 #define CPUVENDOR_INTEL 0
 #define CPUVENDOR_VIA 8
 
+#include "acpicpu.h"
 
+#if NACPICPU > 0
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/acpivar.h>
+#endif
+
 /* Convert MHz and mV into IDs for passing to the MSR. */
 #define ID16(MHz, mV, bus_clk) \
        ((((MHz * 100 + 50) / bus_clk) << 8) | ((mV ? mV - 700 : 0) >> 4))
@@ -78,21 +86,22 @@
 #define BUS333 33333
 
 #define MSR2MHZ(msr, bus) \
-       (((((int) (msr) >> 8) & 0xff) * (bus) + 50) / 100)
-#define MSR2MV(msr) \
-       (((int) (msr) & 0xff) * 16 + 700)
+       (((((int)(msr) >> 8) & 0xff) * (bus) + 50) / 100)
 
+struct est_op {
+       uint16_t ctrl;
+       uint16_t mhz;
+};
+
 struct fqlist {
        int vendor: 5;
        unsigned bus_clk : 1;
        unsigned n : 5;
-       const u_int16_t *table;
+       struct est_op *table;
 };
 
-static const struct fqlist *est_fqlist;
 
-static u_int16_t fake_table[3];
-static struct fqlist fake_fqlist;
+struct fqlist *est_fqlist;
 
 extern int setperf_prio;
 extern int perflevel;
@@ -206,21 +215,104 @@ p3_get_bus_clock(struct cpu_info *ci)
                        break;
                }
                break;
-       default: 
+       default:
                printf("%s: unknown i686 model 0x%x, can't get bus clock\n",
                    ci->ci_dev->dv_xname, ci->ci_model);
        }
 }
 
+#if NACPICPU > 0
+struct fqlist * est_acpi_init(void);
+void est_acpi_pss_changed(struct acpicpu_pss *, int);
+
+struct fqlist *
+est_acpi_init()
+{
+       struct acpicpu_pss *pss;
+       struct fqlist *acpilist;
+       int nstates, i;
+
+       if ((nstates = acpicpu_fetch_pss(&pss)) == 0)
+               goto nolist;
+
+       if ((acpilist = malloc(sizeof(struct fqlist), M_DEVBUF, M_NOWAIT))
+           == NULL)
+               goto nolist;
+
+       if ((acpilist->table = malloc(sizeof(struct est_op) * nstates, M_DEVBUF,
+          M_NOWAIT)) == NULL)
+               goto notable;
+
+       acpilist->n = nstates;
+
+       for (i = 0; i < nstates; i++) {
+               acpilist->table[i].mhz = pss[i].pss_core_freq;
+               acpilist->table[i].ctrl = pss[i].pss_ctrl;
+       }
+
+       acpicpu_set_notify(est_acpi_pss_changed);
+
+       return acpilist;
+
+notable:
+       free(acpilist, M_DEVBUF);
+       acpilist = NULL;
+nolist:
+       return NULL;
+}
+
 void
+est_acpi_pss_changed(struct acpicpu_pss *pss, int npss)
+{
+       struct fqlist *acpilist;
+       int needtran = 1, nstates, i;
+       u_int64_t msr;
+       u_int16_t cur;
+
+       msr = rdmsr(MSR_PERF_STATUS);
+       cur = msr & 0xffff;
+
+       if ((acpilist = malloc(sizeof(struct fqlist), M_DEVBUF, M_NOWAIT))
+           == NULL) {
+               printf("est_acpi_pss_changed: cannot allocate memory for new 
est state");
+               return;
+       }
+
+       if ((acpilist->table = malloc(sizeof(struct est_op) * nstates, M_DEVBUF,
+          M_NOWAIT)) == NULL) {
+               printf("est_acpi_pss_changed: cannot allocate memory for new 
operating points");
+               free(acpilist, M_DEVBUF);
+               return;
+       }
+
+       for (i = 0; i < nstates; i++) {
+               acpilist->table[i].mhz = pss[i].pss_core_freq;
+               acpilist->table[i].ctrl = pss[i].pss_ctrl;
+               if (pss[i].pss_ctrl == cur)
+                       needtran = 0;
+       }
+
+       free(est_fqlist->table, M_DEVBUF);
+       free(est_fqlist, M_DEVBUF);
+       est_fqlist = acpilist;
+
+       if (needtran) {
+               est_setperf(perflevel);
+       }
+}
+#endif
+
+void
 est_init(struct cpu_info *ci)
 {
        const char *cpu_device = ci->ci_dev->dv_xname;
        int vendor = -1;
-       int i, mhz, mv, low, high, family;
+       int i, low, high, family;
        u_int64_t msr;
        u_int16_t idhi, idlo, cur;
        u_int8_t crhi, crlo, crcur;
+       struct fqlist *fake_fqlist;
+       struct est_op *fake_table;
 
        if (setperf_prio > 3)
                return;
@@ -243,68 +335,96 @@ est_init(struct cpu_info *ci)
        crhi = (idhi  >> 8) & 0xff;
        crlo = (idlo  >> 8) & 0xff;
        crcur = (cur >> 8) & 0xff;
-       if (crlo == 0 || crhi == crlo) {
-               /*
-                * Don't complain about these cases, and silently disable EST:
-                * - A lowest clock ratio of 0, which seems to happen on all
-                *   Pentium 4's that report EST.
-                * - An equal highest and lowest clock ratio, which happens on
-                *   at least the Core 2 Duo X6800, maybe on newer models too.
-                */
-               return;
-       }
-       if (crhi == 0 || crcur == 0 || crlo > crhi ||
-           crcur < crlo || crcur > crhi) {
-               /*
-                * Do complain about other weirdness, because we first want to
-                * know about it, before we decide what to do with it.
-                */
-               printf("%s: EST: strange msr value 0x%016llx\n",
-                   cpu_device, msr);
-               return;
-       }
+
+#if NACPICPU > 0
+       est_fqlist = est_acpi_init();
+#endif
+
        if (est_fqlist == NULL) {
+               if (crhi == 0 || crcur == 0 || crlo > crhi ||
+                   crcur < crlo || crcur > crhi) {
+                       /*
+                        * Do complain about other weirdness, because we first
+                        * want to know about it, before we decide what to do
+                        * with it.
+                        */
+                       printf("%s: EST: strange msr value 0x%016llx\n",
+                           cpu_device, msr);
+                       return;
+               }
+               if   (crlo == 0 || crhi == crlo) {
+                       /*
+                        * Don't complain about these cases, and silently
+                        * disable EST: - A lowest clock ratio of 0, which seems
+                        * to happen on all Pentium 4's that report EST.  - An
+                        * equal highest and lowest clock ratio, which happens
+                        * on at least the Core 2 Duo X6800, maybe on newer
+                        * models too.
+                        */
+                       return;
+               }
+
                printf("%s: unknown Enhanced SpeedStep CPU, msr 0x%016llx\n",
                    cpu_device, msr);
-
                /*
                 * Generate a fake table with the power states we know.
                 */
-               fake_table[0] = idhi;
+
+               if ((fake_fqlist = malloc(sizeof(struct fqlist), M_DEVBUF,
+                   M_NOWAIT)) == NULL) {
+                       printf("est_init: cannot allocate memory for fake 
list");
+                       return;
+               }
+
+
+               if ((fake_table = malloc(sizeof(struct est_op) * 3, M_DEVBUF,
+                    M_NOWAIT)) == NULL) {
+                       free(fake_fqlist, M_DEVBUF);
+                       printf("est_init: cannot allocate memory for fake 
table");
+                       return;
+               }
+               fake_table[0].ctrl = idhi;
+               fake_table[0].mhz = MSR2MHZ(idhi, bus_clock);
                if (cur == idhi || cur == idlo) {
                        printf("%s: using only highest and lowest power "
-                           "states\n", cpu_device);
+                              "states\n", cpu_device);
 
-                       fake_table[1] = idlo;
-                       fake_fqlist.n = 2;
+                       fake_table[1].ctrl = idlo;
+                       fake_table[1].mhz = MSR2MHZ(idlo, bus_clock);
+                       fake_fqlist->n = 2;
                } else {
                        printf("%s: using only highest, current and lowest "
                            "power states\n", cpu_device);
 
-                       fake_table[1] = cur;
-                       fake_table[2] = idlo;
-                       fake_fqlist.n = 3;
+                       fake_table[1].ctrl = cur;
+                       fake_table[1].mhz = MSR2MHZ(cur, bus_clock);
+
+                       fake_table[2].ctrl = idlo;
+                       fake_table[2].mhz = MSR2MHZ(idlo, bus_clock);
+                       fake_fqlist->n = 3;
                }
-               fake_fqlist.vendor = vendor;
-               fake_fqlist.table = fake_table;
-               est_fqlist = &fake_fqlist;
+
+               fake_fqlist->vendor = vendor;
+               fake_fqlist->table = fake_table;
+               est_fqlist = fake_fqlist;
        }
 
-       mhz = MSR2MHZ(cur, bus_clock);
-       mv = MSR2MV(cur);
-       printf("%s: Enhanced SpeedStep %d MHz (%d mV)", cpu_device, mhz, mv);
+       if (est_fqlist == NULL)
+               return;
 
-       low = MSR2MHZ(est_fqlist->table[est_fqlist->n - 1], bus_clock);
-       high = MSR2MHZ(est_fqlist->table[0], bus_clock);
-       perflevel = (mhz - low) * 100 / (high - low);
+       printf("%s: Enhanced SpeedStep %d MHz", cpu_device, cpuspeed);
 
+       low = est_fqlist->table[est_fqlist->n - 1].mhz;
+       high = est_fqlist->table[0].mhz;
+       perflevel = (cpuspeed - low) * 100 / (high - low);
+
        /*
         * OK, tell the user the available frequencies.
         */
        printf(": speeds: ");
        for (i = 0; i < est_fqlist->n; i++)
-               printf("%d%s", MSR2MHZ(est_fqlist->table[i], bus_clock),
-                   i < est_fqlist->n - 1 ? ", " : " MHz\n");
+               printf("%d%s", est_fqlist->table[i].mhz, i < est_fqlist->n - 1 ?
+                   ", " : " MHz\n");
 
        cpu_setperf = est_setperf;
        setperf_prio = 3;
@@ -326,7 +446,8 @@ est_setperf(int level)
 
        msr = rdmsr(MSR_PERF_CTL);
        msr &= ~0xffffULL;
-       msr |= est_fqlist->table[i];
+       msr |= est_fqlist->table[i].ctrl;
+
        wrmsr(MSR_PERF_CTL, msr);
-       cpuspeed = MSR2MHZ(est_fqlist->table[i], bus_clock);
+       cpuspeed = est_fqlist->table[i].mhz;
 }

Reply via email to