Intel frequency scaling stuck at stock

I dialed in my 9900k overclock years back on Windows, but just noticed that it’s not behaving the same on Fedora 35 (dual-boot). The initial observation was that the frequency is changing dynamically—I have it set to a static 5.1GHz in UEFI, which Windows doesn’t interfere with, but Linux apparently does. Further investigation with turbostat reveals that the CPU is using low-power C-states, something else I turned off in UEFI. So the goal is to get Linux back in line.

Archwiki is helpful as always: CPU frequency scaling - ArchWiki

First thing was switching the idle driver from intel_idle to acpi_idle. The ACPI driver correctly sticks to C0/C1. However, this had no impact on the core clocks.

The best way I’ve found to monitor the CPU clock is this oneliner: watch -n.1 "grep \"^[c]pu MHz\" /proc/cpuinfo". The update rate is fast enough to see if the frequency is really stable, or if each core is just turbo-ing for a fraction of a second. This is the behavior at idle, kind of a turbo-boost round robin. Under load, all the cores briefly go to 5.1GHz (good!), then drop to 3.6GHz stable seconds later (bad!). The temps never get above 65-70C during this period.

Stuff I’ve tried:

  • Changing frequency driver from intel_pstate to acpi-cpufreq
    • I had to enable EIST to get the ACPI driver to work
    • Surprisingly, any change in behavior is minimal and I didn’t notice it
  • Changing scaling governor from powersave to performance
    • Again, no real change that I noticed? Maybe something subtle.
    • Tried with Intel and ACPI freq drivers
  • Setting min/max scaling frequency
    • Higher frequencies are clamped to 3.6GHz, so best I can do is 3.6–3.6GHz (instead of 0.8GHz–3.6GHz)
  • Setting ignore_ppc=1
    • Really bummed about this one…was sure it would work. More details below.

With the Intel freq driver…no clue what the problem is. But if it ignores the C-states from the UEFI, it may as well ignore the CPU multiplier.

With the ACPI driver, I think I can tell what’s going on:

Summary
# cpupower frequency-info
analyzing CPU 0:
  driver: acpi-cpufreq
  CPUs which run at the same hardware frequency: 0
  CPUs which need to have their frequency coordinated by software: 0
  maximum transition latency: 10.0 us
  hardware limits: 800 MHz - 3.60 GHz
  available frequency steps:  3.60 GHz, 3.60 GHz, 3.40 GHz, 3.20 GHz, 3.00 GHz, 2.80 GHz, 2.60 GHz, 2.40 GHz, 2.20 GHz, 2.00 GHz, 1.80 GHz, 1.60 GHz, 1.40 GHz, 1.20 GHz, 1000 MHz, 800 MHz
  available cpufreq governors: conservative ondemand userspace powersave performance schedutil
  current policy: frequency should be within 3.60 GHz and 3.60 GHz.
                  The governor "performance" may decide which speed to use
                  within this range.
  current CPU frequency: 3.60 GHz (asserted by call to hardware)
  boost state support:
    Supported: yes
    Active: yes

The “hardware limits” line is suspicious, since it’s demonstrably false. I can trace these numbers back to /sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq and scaling_min_freq. Editing these files as root immediately changes the output of cpufreq. However, it’s impossible to raise scaling_max_freq to anything above 3601000 (~3.6GHz). It is writable by root—larger values are clamped.

This brings me to bios_limit, a read-only file (even for root) in the same directory. It’s also set to 3601000. It seems like this number is driven by the _PPC number in the ACPI spec, so that the mobo can throttle the CPU when it’s on battery vs AC power. But putting ignore_ppc=1 in my kernel commandline didn’t do anything, so maybe Linux is setting this number on its own. I verified that I didn’t typo it at the grub prompt by checking /sys/module/processor/parameters/ignore_ppc (file equals 1).

Any ideas? I wasn’t expecting it to be this tough to set a static frequency.

I take back what I said…intel_pstate actually works much different (better!) under load. I must have gotten confused by the behavior at idle.

Summary
# cpupower frequency-info
analyzing CPU 0:
  driver: intel_pstate
  CPUs which run at the same hardware frequency: 0
  CPUs which need to have their frequency coordinated by software: 0
  maximum transition latency:  Cannot determine or is not supported.
  hardware limits: 800 MHz - 5.10 GHz
  available cpufreq governors: performance powersave
  current policy: frequency should be within 5.10 GHz and 5.10 GHz.
                  The governor "performance" may decide which speed to use
                  within this range.
  current CPU frequency: Unable to call hardware
  current CPU frequency: 5.10 GHz (asserted by call to kernel)
  boost state support:
    Supported: yes
    Active: yes

Unlike acpi-cpufreq, the (so-called) hardware limits correctly go up to 5.1GHz. This lets me set the min/max scaling frequency to my desired setpoint. The bios_limit file is absent when using the pstate driver, though the base_frequency file (3600000) is new.

Idle behavior is unchanged compared to ACPI, but the load behavior is much better. It still isn’t rock-solid at 5.1 (some brief, intermittent dips back to 3.6GHz), but it looks more like thermal/power throttling. I think that’s how Intel’s P-states are supposed to work, right?

Still puzzled why the simplest possible frequency-scaling approach (i.e. no scaling) is impossible in Linux, while it seems to be the only option in Windows on the same hardware. I would still like to find a way to get there, so that both OSes use the CPU the same way. The ACPI driver might be able to provide that if it worked…ah well.

I also have to concede that some of this frequency-scaling behavior might be present in Windows as well, just not picked up by HWiNFO. I would be pretty shocked if the downclocking under load, which affects all cores for a few seconds, is obfuscated in Windows, but the idle behavior could conceivably be covered up.

Still interested in suggestions if anyone else has dealt with this before.