It would be nice if someone running i386 could apply this diff, run
without apmd and check that setting sysctl hw.setperf to different
values between 0 and 100 works and changes hw.cpuspeed as expected.
hw.cpuspeed should take on the all the values reported in dmesg, e.g.,

cpu0: Enhanced SpeedStep 1599 MHz: speeds: 1600, 1400, 1200, 1000, 800, 600 MHz

Then run apmd -A and check that running md5 -ttt makes hw.cpuspeed go
to the maximum and back down to the minimum once md5 is done.

Thanks

Index: sys/arch/i386/i386/est.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/est.c,v
retrieving revision 1.53
diff -u -p -r1.53 est.c
--- sys/arch/i386/i386/est.c    12 Aug 2021 15:16:23 -0000      1.53
+++ sys/arch/i386/i386/est.c    12 Aug 2021 15:42:17 -0000
@@ -78,6 +78,7 @@
 struct est_op {
        uint16_t ctrl;
        uint16_t mhz;
+       uint16_t pct;
 };
 
 /* Ultra Low Voltage Intel Pentium M processor 900 MHz */
@@ -973,10 +974,16 @@ est_acpi_init(void)
        struct acpicpu_pss *pss;
        struct fqlist *acpilist;
        int nstates, i;
+       int high, low;
 
        if ((nstates = acpicpu_fetch_pss(&pss)) == 0)
                goto nolist;
 
+       high = pss[0].pss_core_freq;
+       low = pss[nstates - 1].pss_core_freq;
+       if (high - low <= 0)
+               goto nolist;
+
        if ((acpilist = malloc(sizeof(struct fqlist), M_DEVBUF, M_NOWAIT))
            == NULL)
                goto nolist;
@@ -990,6 +997,8 @@ est_acpi_init(void)
        for (i = 0; i < nstates; i++) {
                acpilist->table[i].mhz = pss[i].pss_core_freq;
                acpilist->table[i].ctrl = pss[i].pss_ctrl;
+               acpilist->table[i].pct =
+                   (pss[i].pss_core_freq - low) * 100 / (high - low);
        }
 
        acpicpu_set_notify(est_acpi_pss_changed);
@@ -1008,12 +1017,21 @@ est_acpi_pss_changed(struct acpicpu_pss 
 {
        struct fqlist *acpilist;
        int needtran = 1, i;
+       int high, low;
        u_int64_t msr;
        u_int16_t cur;
 
        msr = rdmsr(MSR_PERF_STATUS);
        cur = msr & 0xffff;
 
+       high = pss[0].pss_core_freq;
+       low = pss[npss - 1].pss_core_freq;
+       if (high - low <= 0) {
+               printf("est_acpi_pss_changed: new est state has no "
+                   "speed step\n");
+               return;
+       }
+
        if ((acpilist = malloc(sizeof(struct fqlist), M_DEVBUF, M_NOWAIT))
            == NULL) {
                printf("est_acpi_pss_changed: cannot allocate memory for new "
@@ -1032,6 +1050,8 @@ est_acpi_pss_changed(struct acpicpu_pss 
        for (i = 0; i < npss; i++) {
                acpilist->table[i].mhz = pss[i].pss_core_freq;
                acpilist->table[i].ctrl = pss[i].pss_ctrl;
+               acpilist->table[i].pct =
+                   (pss[i].pss_core_freq - low) * 100 / (high - low);
                if (pss[i].pss_ctrl == cur)
                        needtran = 0;
        }
@@ -1152,18 +1172,25 @@ est_init(struct cpu_info *ci, int vendor
                        printf("%s: using only highest and lowest power "
                               "states\n", cpu_device);
 
+                       fake_table[0].pct = 51;
+
                        fake_table[1].ctrl = idlo;
                        fake_table[1].mhz = MSR2MHZ(idlo, bus_clock);
+                       fake_table[1].pct = 0;
                        fake_fqlist->n = 2;
                } else {
                        printf("%s: using only highest, current and lowest "
                            "power states\n", cpu_device);
 
+                       fake_table[0].pct = 67;
+
                        fake_table[1].ctrl = cur;
                        fake_table[1].mhz = MSR2MHZ(cur, bus_clock);
+                       fake_table[1].pct = 34;
 
                        fake_table[2].ctrl = idlo;
                        fake_table[2].mhz = MSR2MHZ(idlo, bus_clock);
+                       fake_table[2].pct = 0;
                        fake_fqlist->n = 3;
                }
 
@@ -1218,10 +1245,10 @@ est_setperf(int level)
        if (est_fqlist == NULL)
                return;
 
-       i = ((level * est_fqlist->n) + 1) / 101;
-       if (i >= est_fqlist->n)
-               i = est_fqlist->n - 1;
-       i = est_fqlist->n - 1 - i;
+       for (i = 0; i < est_fqlist->n; i++) {
+               if (level >= est_fqlist->table[i].pct)
+                       break;
+       }
 
        msr = rdmsr(MSR_PERF_CTL);
        msr &= ~0xffffULL;

Reply via email to