How to reduce annoying fan noise

Ha ha ha, Thanks. I am a Mathematician and 005 and 5 can be different in certain situations (depends what every digit means).

Now let me ask this. When I do what you suggest (disable the turbo mode) I see that the CPU stays around 2.7 GHz and below it. Is there a difference between this and use cpupower program to reduce the frequency to 2.7 ? When I reduce it using cpupower and test the mode it still returns 0, that is it stays on. Do you know if there are differences?

Moreover, if I reduce frequency to 1.79 and disable turbo is this better than just reducing to 1.79?

1 Like

Strange… when I do both, disable turbo and reduce freq to 1.79, the frequency drops to around 2.3. When I bring freq to 3.5 (with turbo disabled) it gets back to 2.7

Before Turbo, there were only CPU P states, P0 through P3. P0 was the top frequency, which is the frequency that you would see printed on the chip itself. It could be sustained indefinitely, so long as the thermal spec was met in terms of thermal paste, sink, and fan. P1 through P3 were progressively slower and thus consumed (much) less power, which is great if you’re just typing an email and don’t need blistering performance.

Intel then realized that they could improve benchmarks by “cheating” a little here and there. It’s possible to exceed the thermal spec, provided you only do so for a very short time. That’s where Turbo comes in. It is, by definition, an unsustainably high frequency. However, if you happen to be working in a cool environment, you can get away with it for a while – at a tremendous cost in power, and in this case, noise – so as to perform a bit better on average.

When Turbo is enabled, you might max out at 3 GHz, whereas when it’s not, the ceiling might be 2 GHz. Independent of this, you can still set any other P state you want, so it’s possible to have Turbo enabled but decide you only need 500 MHz for the time being. Certain utilities exist to constrain the allowed P states. (And my “utility” toggles Turbo.) These are independent controls. But while Turbo is a hard switch, P states are much more fluid. Absent any constraints at the OS level, you might be in P2 right now, but P1 a few seconds later. It all depends on exactly what occurs when you use a power utility to “set” a frequency.

On a related note, recent Intel CPUs feature AVX512 instructions. They’re great if you’re doing a lot of vector math, but not so great if you’re not because merely enabling them results in a haircut to maximum frequency. Fortunately, I believe they’re off by default, but they make the silicon look fancy so you can be happy paying more for it.


Or enable /etc/rc.local and put there any script you want. Can someone explain to me why this simple functionality (rc.local) had to be removed from modern Linux systems? Sometimes I do not understand community decisions. Simplicity is part of beauty. Why one has to go extra miles to run something simple as the above with crontab, /etc/modules etc ?

Yes I know, there is another better mechanism to boot up now, but this great mechanism has added extra complications just to run a simple command at boot time. They could provide an alternative if the name rc.local bothered them.

To enable rc.local on PureOS create a file /etc/systemd/system/rc-local.service
with contents:

ExecStart=/etc/rc.local start


Now enable the service:

systemctl enable rc-local

Then create a script /etc/rc.local
put anything you want to be executed at boot time in it and make it executable.
Reboot or
systemctl start rc-local

Not to start a religious war but … because a random shell script with a grab bag of shell commands in it cannot correctly participate in the dependency graph - hence it may run before it is ready to run (and one or more commands will fail), if anything is dependent on it then that other thing may run before it is ready to run, it won’t necessarily be triggered by the right conditions (won’t necessarily run when it is supposed to in all circumstances).

I’m a bit unconvinced that creating rc-local.service is better than using crontab @reboot - if you just want to run a shell script at boot time and you really don’t care about dependencies (either way your shell script may fail but crontab is less messing around).

1 Like

OK. No, no it is not religious. Only practical. Forget about rc.local. The thing is this: why there is no mechanism to run something simple after boot completes and all services are up and running? Because the /etc/modules and crontab solution attempts to cure exactly this shortcoming.

The problem then is that there seems to be no proper way to do it. Is there? I do not mind quitting rc.local. But I want to have the ability to run something after system boots.

I think that may not be ideal design. One goal (my assertion) of the dependency graph is to take advantage of multi-core computers. Computers are getting more cores but not necessarily getting dramatically faster cores … so parallelism is king.

A service that runs after all other services is by definition not parallel, it is serial.

That means that they don’t want you to say “my service depends on 6 zillion other services / all services whatever that means”. They want you to say “my service really and specifically depends on service X and service Y and service Z”.

All that said, there is nothing stopping you writing a service definition that does depend on all the other explicitly identified services.

The challenge, if doing it properly, is knowing what your dependencies really are, particularly in the case of writing to some random MSR. In terms of dependencies, going off could be about right (will execute in parallel with lots of services and potentially early on, which is what you want) but you don’t know for sure that something else won’t write the same MSR as part of its startup.

But your service should not be rc-local, because many other potential commands that you could run at startup might depend, for example, on the network being up / specific interfaces being up / specific local or remote disks being mounted / DNS resolution being operational / the time being correct / …

Understood and it makes sense. Still this leaves a hole in the design. The system has no idea when the bootup is complete. The condition of something like rc.local is “run me when you are done with everything else”. It seems to me that a hook is missing. A condition that declares that the bootup is finished.

Is there such a condition? Because this is the proper condition for rc.local or similar.

So this howto that disables Turbo mode is magical. It is 4 days now I have done this, and I have been compiling source code of projects that need at least 20-25 minutes to compile, I participated in Jitsi conferences and some zoom, and all these days I haven’t heard the fan at all.

I come to ask… does Librem13 actually have a fan? :joy:

1 Like

Isn’t that a self-contradictory idea? Run this service as part of bootup when the bootup is complete?

Start this service when all services are complete?

OK, you might get away with it for one service but what if two packages that you install both create a service and both want their service to start when all services are complete?

(I think bootup might be complete when you shutdown the computer. :wink: )

That is only safe if nothing depends on the execution of the commands in rc.local (that is, nothing outside of rc.local itself, since obviously rc.local itself is internally serialized).

Ironically, updating this particular MSR probably is safe to run in a completely unsynchronized way, in the sense that nothing will fail if it runs before, during or after the MSR is updated. So just create a service, update-msr.service, and make it wanted by and “what happens happens”. Just don’t call it rc-local.service.

1 Like

I’m pleased to have relieved your ears!

I suspect that the Turbo bit was provided merely as a failsafe mechanism with no intention that it be used for actual power management, mainly because its effects are opportunistic rather than specific. Therefore you should be able to manipulate it at any time during the boot process and remain relatively confident that no other process will interfere with it. The only real risk is that one could have 2 processes modifying different bits of the same MSR, resulting in a write conflict. This can be prevented by disabling interrupts across the entire read-modify-write. In practice, though, the race window probably doesn’t exist, or is negligibly narrow if it does. This should be good enough for practical purposes unless of course one intends to publish this feature into an environment in which there’s a possibility of malicious exploitation of the race.

Hi there,

Thanks for the insights about the turbo bit and the good ideas above. I wrote a little bash script to disable the turbo bit without rigorously setting the value to something hardcoded and put it together as follows:


for proc in $(seq 0 3); do
turbo_status=$(/usr/sbin/rdmsr -p${proc} 0x1A0 -f 38:38)
if (( turbo_status >= on )); then
value=$(/usr/sbin/rdmsr -p${proc} 0x1A0)
value=$(printf “%010d” ${value})
if (( first == 0 )); then
/usr/sbin/wrmsr -p${proc} 0x1A0 ${value}

exit 0

(sorry, the identation does not work in the blockquote)

You can adjust the number of processors in the for loop:

$(seq 0 3) is what I needed to disable the turbo bit on all 4 procs.


  • put the script somewhere where root can find it and make it executable
  • apt-get install msr-tools
  • add ‘msr’ to /etc/modules, so that rdmsr, wrmsr will work
  • add to the crontab of root:
    @reboot /bin/bash /root/turbo_off

and last but not least:

  • put on Simon and Garfunkel’s “The sound of silence”

Thanks and enjoy.


Hello lamp post, my old friend…

Nice contribution. Technically it contains a read-modify-write race, but I really don’t think it will matter.

Hi friends,

@whistler you are right about the read-modify-write race. Of course, I already read the whole thing before modifying it and writing it back, but still it could be that I’m writing something back that has been modified in the meantime or other nasty things. I take my chances at the moment as it seems very stable.

I have to make a little correction to the script I posted.

The line

if (( turbo_status >= on )); then

should be

if (( turbo_status == on )); then

I temporarily put in the ‘>=’ in for testing purposes. Of course, in my case the script is only run at boot time when the value is ‘0’ so it will not make a difference in practice.

But the ‘==’ should be more safe if you run the script more often as it will write to the memory if the turbo bit is still set.

Have fun.

1 Like

@purelibrem I think you mean you mean:

(( turbo_status == 1 ))

Also, I get this complaint about “if (( first == 0 )); then”:

((: “: syntax error: operand expected (error token is ““”)

I was doing some batch processing yesterday which was mostly memory-bound, but occasionally needed a lot of CPU. I turned on Turbo to get it done faster, but ended up dozing off at my desk. After a while the CPU cranked up and the fan kicked in, startling me awake. Well, that’s the last straw! Who wants a feature that inhibits snoozing on the job?!

Hi @whistler,

no, I really meant

if (( turbo_status == on )); then

I especially declared ‘on=0’ to make this possible. The reason is that we want to do something if the turbo is on, meaning the bit is 0. Thus, for readability, i declared ‘on=0’ and checked if turbo_status is ‘on’.

I am not sure about the syntax error that you are experiencing yet. Could be a copy paste error or a difference in shells we are using (the script is rather done on the happy-flow for librem 15 v 4, not on compatibility). We could try to sort this out, or you could try the new script that i will publish in the next post.

In fact, your question about the script did make think a lot about it and made me rewrite it. The questions I encountered were:

  1. I could not find a manual on how the msr registers controlling the turbo work on different processors. I was hoping for a table, telling me ‘bit X is for Y on processor type Z’

  2. If it is just bit 38 that controls whether turbo is on or off, why would we prepend the hexadecimal value with a ‘4’? Yes, I could do the math that 0x4000850089 means there is a 1 on the 38th bit but actually 0x5000850089 does the trick as well (and also: 6,7,C,D,E,F instead of ‘4’ or ‘5’). It was a bit puzzling due to the lack of documentation what the 64 bits are really doing, so I decided to rewrite the script, purely on setting bit 38 to ‘1’. This would not just set ‘4’ on the 10th place in hexadecimal notation but create the hexadecimal value after the 38th bit was set to ‘1’.

  3. and some more questions but in the end every time it was a lack of documentation.

So, I thought it is a good idea to rewrite the script to just manipulate the bit on position 38, even if in practice, probably it is just a complicated way to do the same as before…:wink:

Let me know if it works for you and if you have some more information about the different bits in the register, please let me know.

Hi everybody,

You will find attached the next version of the script that would precisely set bit 38 to ‘1’ instead of manipulating hexadecimal numbers.

This is an extensive change to the script and perhaps it was not necessary, but it makes a lot more sense if the only thing you want to do is setting bit 38 to value ‘1’.

If somebody has more information on the topic, let me know.

In the meantime I hope you can use one of the scripts to disable the fan noise…:wink:

Best, purelibrem

PS: oh darn, attaching files other than pictures is not allowed. I will think of something else tomorrow.

I found how to post it, so here is the script.

There are some differences with the simple script I posted earlier:

  • it checks if the msr-tools are installed
  • it is automatically aware of the number of processor cores
  • it will actually change bit 38 instead of writing a 4 in the 10th position of the hex value
  • it will wait a while after changing the bit of core one. This makes sure the bit is written before the next core is checked for the bit. Actually, i found out that by setting the bit for the first core, it will also be set for all the others and the computer does not like it if you set the bit if it is already set.

Is it really better than the one before? Perhaps it does the same, so you could also use the prior one. But while making this one I learned a lot and had lots of fun.

Hope you enjoy it as well.

If you have any questions, just


# check whether the msr-tools package is installed

installed=$(/usr/bin/dpkg -l | /usr/bin/grep msr-tools)
if [[ "${installed}" == "" ]]; then
	echo "package msr-tools is not installed..please run: apt-get install msr-tools"
	exit 1

# turbo is on if bit 38 of the register 0x1A0 is 0

# get the number of cores
cores=$(cat /proc/cpuinfo | egrep "^processor\s*:" | awk -F":" '{print $2}' | sed 's/\s//g')

# for each core set bit 38 of register 0x1A0 to 1.
# Actually by setting it for one core will also set it for all other cores
# but to make sure we will loop through all the cores.
# Be sure to check if the bit is already set as the computer will crash
# if you do it twice.
for core in ${cores}; do

	turbo_status=$(/usr/sbin/rdmsr -p${core} 0x1A0 -f 38:38)

	if [[ "$turbo_status" == "$on" ]]; then

		for nr in {0..63}; do
			bit=$(/usr/sbin/rdmsr -p${core} 0x1A0 -f ${nr}:${nr})
			if [[ "$nr" == "38" ]]; then


			if [[ "${chrlen}" == "4" ]]; then

				if [[ "${block}" == "0000" ]]; then

				if [[ "${block}" == "0001" ]]; then

				if [[ "${block}" == "0010" ]]; then

				if [[ "${block}" == "0011" ]]; then

				if [[ "${block}" == "0100" ]]; then

				if [[ "${block}" == "0101" ]]; then

				if [[ "${block}" == "0110" ]]; then

				if [[ "${block}" == "0111" ]]; then

				if [[ "${block}" == "1000" ]]; then

				if [[ "${block}" == "1001" ]]; then

				if [[ "${block}" == "1010" ]]; then

				if [[ "${block}" == "1011" ]]; then

				if [[ "${block}" == "1100" ]]; then

				if [[ "${block}" == "1101" ]]; then

				if [[ "${block}" == "1110" ]]; then

				if [[ "${block}" == "1111" ]]; then


		hex=$(echo ${hex} | sed 's/^0*//')

		# write the value to the register
		/usr/sbin/wrmsr -p${core} 0x1A0 ${hex}

		# make sure it is written
		sleep 1

exit 0

Surely there’s an easier way of setting a bit? See for example: MAC address randomization script

Sorry for the late reply.

Anyways, thanks for the updated script. I would just recommend removing the “sleep 1”. It’s unnecessary.

As to setting one to set all Turbo bits, I guess that’s because all the cores are connected to the same phase locked loop. Granted, it’s possible that that won’t always be the case going forward, so your script does the right thing.

I don’t see the harm in attempting to set it multiple times. Better just to eliminate the sleep and let it rip.

Also, bash seems to like this one better. No weird syntax errors.