How to reduce annoying fan noise

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 ask.do

#!/bin/bash

# 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
fi

# turbo is on if bit 38 of the register 0x1A0 is 0
on=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

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

			block="${bit}${block}"
			chrlen=${#block}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

				block=""
			fi
		done

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

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

		# make sure it is written
		sleep 1
	fi
done

exit 0
2 Likes

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.

What if the system when executing wrmsr returns

wrmsr: pwrite: Operation not permitted

This is a lenovo Thinkpad X1 Yoga

Whoever is running the command needs root privelege.

Are you using a script?

If so how are you running it?

sudo wrmsr -a 0x1A0 0x4000850089
on KUbuntu

It would help a lot if you would answer questions.

If you are using a script running automatically sudo does not work.

Sorry I did not answer. It was sleep time here :slight_smile:
But I wrote
sudo wrmsr -a 0x1A0 0x4000850089
not a script. So it seems it should have worked, yes? OK I will try again, maybe I did something wrong with sudo (password maybe…). I will retry and report back.

Nope. It does not work. To make sure I switch to root:
$ sudo /bin/bash
# wrmsr -a 0x1A0 0x4000850089
wrmsr: pwrite: Operation not permitted
#
However, this works fine on Librem13. It fails on a lenovo Thinkpad X1 Yoga. Could it be some Bios setting preventng this? On the other side cpupower-gui works and reduces the max frequency. So I am OK with this. I just though I would report that issue with wrmsr…maybe we learn something more from this problem.

Now, I wish someone could share the same script but for Qubes OS…

1 Like

It is something to do with the Thinkpad X1, which may have a different CPU. MSR is machine specific register.

What are the results of
grep -i ghz /proc/cpuinfo | head -1
and
sudo rdmsr -p0 0x1A0

grep -i ghz /proc/cpuinfo | head -1
Intel® Core™ i7-8565U CPU @ 1.80GHz

sudo rdmsr -p0 0x1A0
850089

It might be something to do with the Thinkpad or maybe something about KUbuntu or some difference between the i7-7500U and the i7-8565U.

If the last, the reason might be buried somewhere in the 5000+ pages of the “Intel® 64 and IA-32 Architectures Software Developer Manuals” at:

OK, Thanks. I will try another distro using a USB stick to rule it out as a KUbuntu problem.

something different but relative: When I run the above on LIbrem13v4 it says
model name : Intel® Core™ i7-7500U CPU @ 2.70GHz
When in Turbo mode it goes up to 3.60 and I use msr to bring it down to 2.7

On Yoga it replies
Intel® Core™ i7-8565U CPU @ 1.80GHz
But when in turbo mode it goes up to 4.60 (this is what cpupower-gui reports).

What is the explanation. How on the one system it is rated 2.7 and goes up to 3.6 and the other is rated 1.80 (lower than 2.7) but it goes up to 4.60 ???

Even in the same model line in the same year intel makes CPUs with different base frequencies and different peak frequencies and the base and peak frequencies are not directly related. Besides that, there is a minimum frequency that is different still.

Intel is not using some fixed architecture that they keep over time, only shrinking to improve speed and power consumption.