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;