Hello,
I have recently bought latitude 5401 with i7-9850H and nvidia MX150 + WD19TB 180W dock (replacing latitude e5470). Currently I have it hooked up to 4k display @60hz (using docks hdmi), with plans to use second 4k screen once my forced homeoffice (thanks to coronacrisis) is over.
Since installing linux, I have immediately noticed that my fan is spining like crazy on its maximum setting, which is LOUD. Like a lot. I work in quiet environment and it sounds like the laptop is about to take off and fly away.
First thing I tried was to update bios, only to find that I am already running latest version (1.6.1). Next thing I went for was manual fan control, because with fans up the temps were around 60°C, which seems like a lot, as the cpu was idling, but I guess there is still some headroom.
So, by disabling bios fan cotrol (lets say by cctk --FanCtrlOvrd=Enabled), I was able to use PWM to control fan, however it seems that dell laptops support only 3 pwm modes (off, quiet, max) - I have set up fan profile to kick in full speed once 85°C was reached, and bring it down to 70°C before switching back to quiet mode.
This certainly, helped, however quiet speed seems a bit too quiet, so temperature slowly rises even when idling, forcing fans to go into maximum performance mode every now and then.
Overall the temperature laptop produces seems to be too high for thermal solution in this laptop, or some hw issue is present.
What I have checked so far:
I will be glad for any possible solutions that will result in decrese of temperature or at least higher flexibility of fan control (really, if the quiet mode was little bit faster, I belive it could at least idle without reaching max fan speed thermal limit).
Solved! Go to Solution.
Would like to share solution which I will be sticking to:
It involves editing of MSR registers described in Intel 64 and IA-32 Architectures Software Developers Manual, specificaly Volume 3, Chapter 14.4.4.
First you should make sure that Intel Speed Shift is enabled by seting bit 0 of IA32_PM_ENABLE (that should be 0x770) to 1 - that should be already set.
Than query IA32_HWP_CAPABILITIES (0x771) to get Lowest_Performance, Most_Efficient_Performance, Guaranteed_Performance and Highest_Performance values. My guess is these represent maximum allowed TDP.
Last thing is to modify IA32_HWP_REQUEST (0x774) according to your needs for each CPU. My CPU supports only Minimum_Performance, Maximum_Performance, Desired_Performance, Energy_Performance_Preference and Activity_Window fields.
You should set Minimum_Performance = IA32_HWP_CAPABILITIES.Lowest_Performance, Maximum_Performance = IA32_HWP_CAPABILITIES.Highest_Performance, or any other value you find fitting within range provided by IA32_HWP_CAPABILITIES. Seting Maximum_Performance to Guaranteed_Performance effectively disables turboboost.
The most important field is Energy_Performance_Preference (EEP) which affects how aggressively is CPU managing its frequencies, with 0 being performance mode and 255 powersaving. I find that for me value of 128 works well, plus I still get the ability to set it to performance mode should I require.
With these tweaks, CPU manages to stay around 60 degrees most of the time (which results in quieter fan even with automatic BIOS fan control). Might still add cooling pad, but these settings are deffinitely better suited to the cooling solution in this laptop.
There is quick mockup based on msr_tools, will finish it when I have more time:
#include <cstdlib>
#include <unistd.h>
#include <cerrno>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdio>
#include <cstdint>
#include <inttypes.h>
#define PRIX64_2 "08X%08X"
#define PRIX64_VAL(val) ((uint32_t)(val >> 32) & 0xFFFFFFFF), ((uint32_t)(val >> 0) & 0xFFFFFFFF)
#define CRLF "\r" CRLF
#define IA32_PM_ENABLE 0x770
#define IA32_HWP_CAPABILITIES 0x771
#define IA32_HWP_REQUEST 0x774
#define MSR_FILENAME_MAX_LEN 64
#define CPU_COUNT 12
typedef struct ia32_pm_enable {
union {
struct {
uint64_t pm_enable:1;
uint64_t :63;
};
struct {
uint64_t dw;
};
};
} ia32_pm_enable;
typedef struct ia32_hwp_capabilities {
union {
struct {
uint64_t highest_perf:8;
uint64_t guaranteed_perf:8;
uint64_t efficent_perf:8;
uint64_t lowest_perf:8;
uint64_t :32;
};
struct {
uint64_t dw;
};
};
} ia32_hwp_capabilities;
typedef struct ia32_hwp_request {
union {
struct {
uint64_t minimum_perf:8;
uint64_t maximum_perf:8;
uint64_t desired_perf:8;
uint64_t efficent_perf:8;
uint64_t activity_window:10;
uint64_t package_control:1;
uint64_t :16;
uint64_t activity_window_valid:1;
uint64_t efficent_valid:1;
uint64_t desired_valid:1;
uint64_t maximum_valid:1;
uint64_t minimum_valid:1;
};
struct {
uint64_t dw;
};
};
} ia32_hwp_request;
int msr_write_cpu(uint64_t val, uint32_t reg, uint8_t cpu) {
int fd;
char msr_file_name[MSR_FILENAME_MAX_LEN + 1];
snprintf(msr_file_name, MSR_FILENAME_MAX_LEN, "/dev/cpu/%d/msr", cpu);
msr_file_name[MSR_FILENAME_MAX_LEN] = 0;
fd = open(msr_file_name, O_WRONLY);
if (fd < 0) {
if (errno == ENXIO) {
fprintf(stderr, "wrmsr: No CPU %d" CRLF, cpu);
return -2;
} else if (errno == EIO) {
fprintf(stderr, "wrmsr: CPU %d doesn't support MSRs" CRLF, cpu);
return -3;
} else {
perror("wrmsr: open");
return -127;
}
}
if (pwrite(fd, &val, sizeof(uint64_t), reg) != sizeof(uint64_t)) {
if (errno == EIO) {
fprintf(stderr, "wrmsr: CPU %d cannot set MSR 0x%08" PRIx32 " to %" PRIX64_2 CRLF, cpu, reg, PRIX64_VAL(val));
return -4;
} else {
perror("wrmsr: pwrite");
return -127;
}
}
close(fd);
return 0;
}
int msr_write_all_cpus(uint64_t val, uint32_t reg) {
int failed = 0;
for(size_t i = 0; i < CPU_COUNT; i++) {
if(msr_write_cpu(val, reg, i) < 0)
failed++;
}
return -failed;
}
int msr_read_cpu(uint64_t * dst, uint32_t reg, uint8_t cpu) {
*dst = 0;
int fd;
char msr_file_name[MSR_FILENAME_MAX_LEN + 1];
snprintf(msr_file_name, MSR_FILENAME_MAX_LEN, "/dev/cpu/%d/msr", cpu);
msr_file_name[MSR_FILENAME_MAX_LEN] = 0;
fd = open(msr_file_name, O_RDONLY);
if (fd < 0) {
if (errno == ENXIO) {
fprintf(stderr, "rdmsr: No CPU %d" CRLF, cpu);
return -2;
} else if (errno == EIO) {
fprintf(stderr, "rdmsr: CPU %d doesn't support MSRs" CRLF, cpu);
return -3;
} else {
perror("rdmsr: open");
return -127;
}
}
if (pread(fd, dst, sizeof(uint64_t), reg) != sizeof(uint64_t)) {
if (errno == EIO) {
fprintf(stderr, "rdmsr: CPU %d cannot read MSR 0x%08" PRIX32 CRLF, cpu, reg);
return -4;
} else {
perror("rdmsr: pread");
return -127;
}
}
close(fd);
return 0;
}
int main(int argc, char** argv) {
ia32_pm_enable pm_enable;
msr_read_cpu(&pm_enable.dw, IA32_PM_ENABLE, 0);
ia32_hwp_capabilities hwp_capabilities;
msr_read_cpu(&hwp_capabilities.dw, IA32_HWP_CAPABILITIES, 0);
ia32_hwp_request hwp_request;
msr_read_cpu(&hwp_request.dw, IA32_HWP_REQUEST, 0);
hwp_request.minimum_perf = hwp_capabilities.lowest_perf;
hwp_request.maximum_perf = hwp_capabilities.highest_perf;
hwp_request.efficent_perf = 128;
msr_write_all_cpus(hwp_request.dw, IA32_HWP_REQUEST);
return 0;
}
Have you tried disabling fast boot and secure boot.
When the system is inside the BIOS setup, it creates lots of heat and fans fly fast.
This happens because the manufacturers don't want you to use anything other than Windows that comes pre-installed on your system.
I have had that problem myself and have not been able to solve it.
Well, secureboot is disabled, as it is required for installation and if I remember correctly it is also neccessary to have it disabled in order to get access to fan pwm setting.
Not quite sure how having fastboot enabled would result in permanent temperature increase once the system has booted? I understand that with fastboot on, it just skips some system checks.
I cant see how any of these suggestions would help, I am afraid.
Did you try to limit the CPU speeds, maybe even disable turboboost? I set my CPU limit to 3GHz and undervolt -120 mV to keep temps below 80C while gaming. Works pretty good, but i have a i5-9400h + MX150 combo. Not sure if Linux has tools to limit CPU / undervolt, but a lot of laptops have the option in the BIOS to turn off turboboost. Don't think this will harm the system, but do you homework first since it's at your own risk.
Thanks for suggestion - maybe should have mentioned it, already tried undervolting by about -100mv, without noticeable effects on temperature, other than system crashing while playing youtube video, at which point I reverted the undervolt.
I would like to avoid having to disable turboboost, as it can have great impact on system responsiveness. However might give it a try if no other solution is avaiable - but than whats the point in geting cpu that can turboboost to 4.6Ghz? Might as well start shuting down cores, but than whats the point in geting six core cpu?
I have found throttlestop utility for linux, which allows tweaking tdp, temperature offsets and voltages - but not sure if I really want to go down that path on $1500 machine. Might as well check if thermal compound is correctly applied, but still, would expect it to be.
Just to give update, I have applied some tweaks which I am testing at the moment using throttlestop:
So far, after several hours, fan speed appears to stay at 4000 rpm (was around 4700 before). Its certainly audible, but deffinitely better. I will see what the stability will be, maybe making more tweaks later. Temperatures seem to stick around 65°C.
Still, its quite disappointing having to make such low level tweaks so the temperatures wouldnt be going insane.
Would like to share solution which I will be sticking to:
It involves editing of MSR registers described in Intel 64 and IA-32 Architectures Software Developers Manual, specificaly Volume 3, Chapter 14.4.4.
First you should make sure that Intel Speed Shift is enabled by seting bit 0 of IA32_PM_ENABLE (that should be 0x770) to 1 - that should be already set.
Than query IA32_HWP_CAPABILITIES (0x771) to get Lowest_Performance, Most_Efficient_Performance, Guaranteed_Performance and Highest_Performance values. My guess is these represent maximum allowed TDP.
Last thing is to modify IA32_HWP_REQUEST (0x774) according to your needs for each CPU. My CPU supports only Minimum_Performance, Maximum_Performance, Desired_Performance, Energy_Performance_Preference and Activity_Window fields.
You should set Minimum_Performance = IA32_HWP_CAPABILITIES.Lowest_Performance, Maximum_Performance = IA32_HWP_CAPABILITIES.Highest_Performance, or any other value you find fitting within range provided by IA32_HWP_CAPABILITIES. Seting Maximum_Performance to Guaranteed_Performance effectively disables turboboost.
The most important field is Energy_Performance_Preference (EEP) which affects how aggressively is CPU managing its frequencies, with 0 being performance mode and 255 powersaving. I find that for me value of 128 works well, plus I still get the ability to set it to performance mode should I require.
With these tweaks, CPU manages to stay around 60 degrees most of the time (which results in quieter fan even with automatic BIOS fan control). Might still add cooling pad, but these settings are deffinitely better suited to the cooling solution in this laptop.
There is quick mockup based on msr_tools, will finish it when I have more time:
#include <cstdlib>
#include <unistd.h>
#include <cerrno>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdio>
#include <cstdint>
#include <inttypes.h>
#define PRIX64_2 "08X%08X"
#define PRIX64_VAL(val) ((uint32_t)(val >> 32) & 0xFFFFFFFF), ((uint32_t)(val >> 0) & 0xFFFFFFFF)
#define CRLF "\r" CRLF
#define IA32_PM_ENABLE 0x770
#define IA32_HWP_CAPABILITIES 0x771
#define IA32_HWP_REQUEST 0x774
#define MSR_FILENAME_MAX_LEN 64
#define CPU_COUNT 12
typedef struct ia32_pm_enable {
union {
struct {
uint64_t pm_enable:1;
uint64_t :63;
};
struct {
uint64_t dw;
};
};
} ia32_pm_enable;
typedef struct ia32_hwp_capabilities {
union {
struct {
uint64_t highest_perf:8;
uint64_t guaranteed_perf:8;
uint64_t efficent_perf:8;
uint64_t lowest_perf:8;
uint64_t :32;
};
struct {
uint64_t dw;
};
};
} ia32_hwp_capabilities;
typedef struct ia32_hwp_request {
union {
struct {
uint64_t minimum_perf:8;
uint64_t maximum_perf:8;
uint64_t desired_perf:8;
uint64_t efficent_perf:8;
uint64_t activity_window:10;
uint64_t package_control:1;
uint64_t :16;
uint64_t activity_window_valid:1;
uint64_t efficent_valid:1;
uint64_t desired_valid:1;
uint64_t maximum_valid:1;
uint64_t minimum_valid:1;
};
struct {
uint64_t dw;
};
};
} ia32_hwp_request;
int msr_write_cpu(uint64_t val, uint32_t reg, uint8_t cpu) {
int fd;
char msr_file_name[MSR_FILENAME_MAX_LEN + 1];
snprintf(msr_file_name, MSR_FILENAME_MAX_LEN, "/dev/cpu/%d/msr", cpu);
msr_file_name[MSR_FILENAME_MAX_LEN] = 0;
fd = open(msr_file_name, O_WRONLY);
if (fd < 0) {
if (errno == ENXIO) {
fprintf(stderr, "wrmsr: No CPU %d" CRLF, cpu);
return -2;
} else if (errno == EIO) {
fprintf(stderr, "wrmsr: CPU %d doesn't support MSRs" CRLF, cpu);
return -3;
} else {
perror("wrmsr: open");
return -127;
}
}
if (pwrite(fd, &val, sizeof(uint64_t), reg) != sizeof(uint64_t)) {
if (errno == EIO) {
fprintf(stderr, "wrmsr: CPU %d cannot set MSR 0x%08" PRIx32 " to %" PRIX64_2 CRLF, cpu, reg, PRIX64_VAL(val));
return -4;
} else {
perror("wrmsr: pwrite");
return -127;
}
}
close(fd);
return 0;
}
int msr_write_all_cpus(uint64_t val, uint32_t reg) {
int failed = 0;
for(size_t i = 0; i < CPU_COUNT; i++) {
if(msr_write_cpu(val, reg, i) < 0)
failed++;
}
return -failed;
}
int msr_read_cpu(uint64_t * dst, uint32_t reg, uint8_t cpu) {
*dst = 0;
int fd;
char msr_file_name[MSR_FILENAME_MAX_LEN + 1];
snprintf(msr_file_name, MSR_FILENAME_MAX_LEN, "/dev/cpu/%d/msr", cpu);
msr_file_name[MSR_FILENAME_MAX_LEN] = 0;
fd = open(msr_file_name, O_RDONLY);
if (fd < 0) {
if (errno == ENXIO) {
fprintf(stderr, "rdmsr: No CPU %d" CRLF, cpu);
return -2;
} else if (errno == EIO) {
fprintf(stderr, "rdmsr: CPU %d doesn't support MSRs" CRLF, cpu);
return -3;
} else {
perror("rdmsr: open");
return -127;
}
}
if (pread(fd, dst, sizeof(uint64_t), reg) != sizeof(uint64_t)) {
if (errno == EIO) {
fprintf(stderr, "rdmsr: CPU %d cannot read MSR 0x%08" PRIX32 CRLF, cpu, reg);
return -4;
} else {
perror("rdmsr: pread");
return -127;
}
}
close(fd);
return 0;
}
int main(int argc, char** argv) {
ia32_pm_enable pm_enable;
msr_read_cpu(&pm_enable.dw, IA32_PM_ENABLE, 0);
ia32_hwp_capabilities hwp_capabilities;
msr_read_cpu(&hwp_capabilities.dw, IA32_HWP_CAPABILITIES, 0);
ia32_hwp_request hwp_request;
msr_read_cpu(&hwp_request.dw, IA32_HWP_REQUEST, 0);
hwp_request.minimum_perf = hwp_capabilities.lowest_perf;
hwp_request.maximum_perf = hwp_capabilities.highest_perf;
hwp_request.efficent_perf = 128;
msr_write_all_cpus(hwp_request.dw, IA32_HWP_REQUEST);
return 0;
}