Morce323
1 Copper

Latitude 5401 - fan noise

Jump to solution

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:

  • CPU correctly downclocks down to 800Mhz when idling, yet temperature still rises on quiet fan settings.
  • GPU is running at highest PowerMizer level and is not clocking down, which seems to be issue introduced aboud 100 driver revisions ago (running v435.21 of nvidia driver) and is related to high screen resolution. When I attempted to force certain PowerMizer level (not doing any gaming), it worked, but clocks were stuck at too low value to redraw screen without lag
  • When switching to adaptive/integrated GPU, temperature seems to rise even faster
  • No combination of disabling speedstep, speedshift helped

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).

0 Kudos
1 Solution

Accepted Solutions
Morce323
1 Copper

Re: Latitude 5401 - fan noise

Jump 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;
}

 

View solution in original post

0 Kudos
6 Replies
RuskinF
1 Copper

Re: Latitude 5401 - fan noise

Jump to solution

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.

0 Kudos
Morce323
1 Copper

Re: Latitude 5401 - fan noise

Jump to solution

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.

0 Kudos
Ainu
1 Copper

Re: Latitude 5401 - fan noise

Jump to solution

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.

0 Kudos
Morce323
1 Copper

Re: Latitude 5401 - fan noise

Jump to solution

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.

0 Kudos
Morce323
1 Copper

Re: Latitude 5401 - fan noise

Jump to solution

Just to give update, I have applied some tweaks which I am testing at the moment using throttlestop:

  • I have locked cpu TDP to 35W (was up to 45W before)
  • Disabled alternate TDP limit (was up to 75W with timewindow being fraction of second)
  • Applied undervolt again: -120mV on CPU, -100mV on cache
  • Kept BIOS fan control on

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.

0 Kudos
Morce323
1 Copper

Re: Latitude 5401 - fan noise

Jump 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;
}

 

View solution in original post

0 Kudos