• Welcome to TechPowerUp Forums, Guest! Please check out our forum guidelines for info related to our community.

How can I enable "Disable and Lock Turbo Power Limits" in Linux based system to solve 6 watt throttling issue on 8250u.

Shymon

New Member
Joined
Apr 11, 2021
Messages
3 (0.00/day)
Hello, I have an issue with my laptop asus x411un with i5-8250u processor. I recently noticed that it's working quite slowly and started investigation. It turned out that under load laptop is throttled by power to only 6 watts on processor (clock drops to 0.8 - 1.2 Ghz). For example when I start benchmark temps stay at about 55 degrees Celsius, cpu clock is about 1Ghz and of course performance is quite bad. Running on battery or plugged it, changing power plans does not make any difference, and it happens on both windows and linux. Today I tried Throttlestop, nothing worked until I checked "Disable and Lock Turbo Power Limits" then processor began behaving as expected, power jumped to about 40 watts, temps jumped to 95 degrees, it throttled a bit, and switched to 15 / 20 watt (depends what I set) temps stayed at about 80 degrees. Most importantly performance got restored and it didn't feel like 10 y. old laptop.

So "Disable and Lock Turbo Power Limits" seems to fix my problem, but I only use linux on this laptop and I need to apply it there. I tried searching forum and internet to find how to apply it or which registers to edit, but I couldn't find enough information to do it myself. I've got some experience in programming but never played with stuff like that. Could anyone provide some information how to change it on linux based system?

Screenshot from Throttlestop before enabling "Disable and Lock Turbo Power Limits":
throttlestop.png
 

unclewebb

ThrottleStop & RealTemp Author
Joined
Jun 1, 2008
Messages
7,336 (1.26/day)
The ThrottleStop Disable and Lock feature sets a couple of memory locations. I can show you where these memory locations are in Windows but they might be somewhere completely different in Linux. I have zero experience with Linux so I do not know how to set these.

In Windows you can use the RW Everything utility to set these limits without needing to use ThrottleStop.


1618157788232.png
 

Shymon

New Member
Joined
Apr 11, 2021
Messages
3 (0.00/day)
Okay, it would be really nice if you could give me memory locations and possibly values if you know them, otherwise I will look for them on running system. As I see these aren't MSR registers, but just some data in memory? I don't have much experience with modifying such things on linux, but maybe I will find how to do that.
 

unclewebb

ThrottleStop & RealTemp Author
Joined
Jun 1, 2008
Messages
7,336 (1.26/day)
it would be really nice if you could give me memory locations and possibly values if you know them
The picture I posted shows the two memory locations and it shows the values that these two memory locations are set to when you use the Disable and Lock feature.

FED159A0 - 0x00000000
FED159A4 - 0x80000000

these aren't MSR registers, but just some data in memory?
That is correct. I have no idea how to legally access and modify memory locations in Linux.

These are called Memory Mapped IO. Windows maps these to memory location 0xFED15900. Linux might map this information to some other memory block.
 

Shymon

New Member
Joined
Apr 11, 2021
Messages
3 (0.00/day)
Thanks for your help!

I checked values of FED159A0 and FED159A4 under linux and these had the same values as under windows before fix, so I went ahead and changed it to proper values (0x0 and 0x8). It seems it worked! Cpu stopped throttling to 0,8Ghz but after a while it started happening again. I checked and somehow pl1 set itself to 6w, so I changed it to 15w and then cpu again began to work as it should.
I used devmem2 to read:
sudo devmem2 0x00000000FED159A0 w
sudo devmem2 0x00000000FED159A4 w
and change values in memory:
sudo devmem2 0x00000000FED159A0 w 0x00000000
sudo devmem2 0x00000000FED159A4 w 0x80000000
To change pl1 I followed "tutorial" on https://github.com/erpalma/throttled, and set it like that:
echo 15000000 | tee /sys/devices/virtual/powercap/intel-rapl/intel-rapl:0/constraint_0_power_limit_uw
That is 15w.
Seems like system for some reason keeps lowering it to 5 or 6 watt, so I will have to set up some script to monitor it's value. Actually this problem is quite similar to one described in repo I linked above, where there is also script that changes pl1 and pl2 every 5 seconds to override values from embedded controller.
I haven't also carried out proper tests, as I don't have time today, I will see how it performs in real work during next week.
 

unclewebb

ThrottleStop & RealTemp Author
Joined
Jun 1, 2008
Messages
7,336 (1.26/day)
@Shymon - Interesting stuff.

MSR 0x610 contains both power limits, PL1 and PL2. Intel is nice enough to publicly document this register. Setting bit[63] locks this register so it cannot be changed. Linux has command line tools to change MSR values so you are set. If you are in Windows you can adjust PL1 and PL2 in the ThrottleStop TPL window and then have a look at what value MSR 0x610 is set to and you can apply that same value to that MSR register in Linux. Once this register is locked, no need to keep monitoring it.

Here is a simple tool to Dump the contents of your MSR registers while in Windows.
It was written by a smart guy called Dufus who used to hang out in the Notebook Review forums. Handy tool or you can use RW Everything.

 

hugodlc

New Member
Joined
Oct 19, 2020
Messages
8 (0.01/day)
FED159A0 - 0x00000000
FED159A4 - 0x80000000

Thank you for sharing this, it allowed me to create an SSDT and patch my power throttled ZBook when running OSX.

Before the patch:
Screen Shot 2021-11-22 at 2.46.52 PM.png
After the patch
Screen Shot 2021-11-22 at 2.48.35 PM.png

The SSDT:
POWA.jpg

The EC enabled the limiter on boot and after wake, so I had to replace the RDSS Method to remove the limit on boot (RDSS gets executed after EC is up and done messing with things)
And then I hijacked one of the wake sub methods that also happens after EC is online again.
The SSDT method could help someone with a similar problem.
 
Last edited:

Mussels

Freshwater Moderator
Staff member
Joined
Oct 6, 2004
Messages
58,413 (8.19/day)
Location
Oystralia
System Name Rainbow Sparkles (Power efficient, <350W gaming load)
Processor Ryzen R7 5800x3D (Undervolted, 4.45GHz all core)
Motherboard Asus x570-F (BIOS Modded)
Cooling Alphacool Apex UV - Alphacool Eisblock XPX Aurora + EK Quantum ARGB 3090 w/ active backplate
Memory 2x32GB DDR4 3600 Corsair Vengeance RGB @3866 C18-22-22-22-42 TRFC704 (1.4V Hynix MJR - SoC 1.15V)
Video Card(s) Galax RTX 3090 SG 24GB: Underclocked to 1700Mhz 0.750v (375W down to 250W))
Storage 2TB WD SN850 NVME + 1TB Sasmsung 970 Pro NVME + 1TB Intel 6000P NVME USB 3.2
Display(s) Phillips 32 32M1N5800A (4k144), LG 32" (4K60) | Gigabyte G32QC (2k165) | Phillips 328m6fjrmb (2K144)
Case Fractal Design R6
Audio Device(s) Logitech G560 | Corsair Void pro RGB |Blue Yeti mic
Power Supply Fractal Ion+ 2 860W (Platinum) (This thing is God-tier. Silent and TINY)
Mouse Logitech G Pro wireless + Steelseries Prisma XL
Keyboard Razer Huntsman TE ( Sexy white keycaps)
VR HMD Oculus Rift S + Quest 2
Software Windows 11 pro x64 (Yes, it's genuinely a good OS) OpenRGB - ditch the branded bloatware!
Benchmark Scores Nyooom.
Any chance you feel like sharing that patch, and writing up a guide on it and how to use it?

I highly doubt you're alone in wanting to fix this issue on linux
 

hugodlc

New Member
Joined
Oct 19, 2020
Messages
8 (0.01/day)
Any chance you feel like sharing that patch, and writing up a guide on it and how to use it?

I highly doubt you're alone in wanting to fix this issue on linux
Hi, this patch is specific to my Zbook. It uses OpenCore or Clover bootloader and Rehabman's hotpatch method, but it can be easily modified to be used on other hardware and/or without a MacOS booter.

In Acpi you can't change a predefined DSDT or SSDT Method (function), so the hotpatch renames a function so it doesn't get called, and then you insert a new function with the original name and new desired code.

Screen Shot 2021-11-23 at 1.35.35 PM.png


In my case when the Embedded Controller (EC) starts up it runs Method (function) RDSS.
I changed the name of the original RDSS Method in Open Core bootloader to RDXX and then I added a new SSDT that has a new RDSS method with an extra line at the end that executes a new XMXX Method.

In this new XMXX method using an ACPI trick, I mapped a chunk of Memory starting at FED159A0 and split it into 2 variables. Then I change the value of these 2 variables, thereby changing the underlying mapped Memory.

I also changed a Method that gets called late in the wake from sleep cycle so the DGPU is powered OFF and also the power limiter is removed when the computer wakes from sleep.

(For this patch to work automatically as I did in my case, there's a few things that also need to be done:
I'm also renaming and changing other SSDT's in OpenCore bootloader config.plist so there's no conflicts with duplicate names (RDSS and CWAK need to be renamed) and I'm also turning OFF the DGPU inside it's own init method, but that's outside the scope of this CPU Power Limit explanation)

Code:
/*
DefinitionBlock ("", "SSDT", 1, "HP", "DGPUOFF", 0x00001000)
{
    External (_SB_.ODGW, MethodObj)    // External declarations
    External (_SB_.PCI0.LPCB.EC__.ECMX, MutexObj)
    External (_SB_.PCI0.LPCB.EC__.ECRG, IntObj)
    External (_SB_.PCI0.LPCB.EC__.TENA, FieldUnitObj)
    External (_SB_.PCI0.PEG0.PEGP, DeviceObj)
    External (_SB_.PCI0.PEG0.PEGP._OFF, MethodObj)
    External (_SB_.PCI0.PEG0.PEGP.VRID, FieldUnitObj)
    External (_SB_.SGOV, MethodObj)
    External (POHB, FieldUnitObj)
    External (POLB, FieldUnitObj)
    External (S3HB, FieldUnitObj)
    External (S3LB, FieldUnitObj)
    External (SDTG, FieldUnitObj)

    Scope (\_SB)
    {

    // CWAK gets called after Embedded Controller wakes and sets the power limit.

        Method (CWAK, 1, Serialized)   // Replacement Method with added code
        {
            ODGW ((0xF0 | Arg0))
            POLB = (0xF0 | Arg0)
            POHB = Zero
            If ((Arg0 == 0x03))
            {
                S3LB = (0xF0 | Arg0)
                S3HB = Zero
            }

            Sleep (0x64)  // Added a small pause to make sure DGPU is On before turning OFF
            If (CondRefOf (\_SB.PCI0.PEG0.PEGP._OFF))
            {
                \_SB.PCI0.PEG0.PEGP._OFF ()   // IF DGPU is enabled, turn it OFF
            }

            XMXX ()   // Execute XMXX method
        }
    }

// RDSS gets called after Embedded Controller starts and sets the power limit.

    Scope (\_SB.PCI0.PEG0.PEGP)
    {
        Method (RDSS, 1, Serialized)  // Replacement Method with added code
        {
            If (\_SB.PCI0.LPCB.EC.ECRG)
            {
                Acquire (\_SB.PCI0.LPCB.EC.ECMX, 0xFFFF)
                If ((Arg0 == One))
                {
                    If ((VRID == 0x1002))
                    {
                        \_SB.PCI0.LPCB.EC.TENA = 0x03
                    }
                    ElseIf ((VRID == 0x10DE))
                    {
                        \_SB.PCI0.LPCB.EC.TENA = 0x05
                    }
                    Else
                    {
                        \_SB.PCI0.LPCB.EC.TENA = One
                    }
                }
                Else
                {
                    \_SB.PCI0.LPCB.EC.TENA = One
                }

                Release (\_SB.PCI0.LPCB.EC.ECMX)
            }

            XMXX () // Execute XMXX method
        }
    }

    Method (XMXX, 0, NotSerialized)
        {
            If (CondRefOf (\_SB.SGOV)) // Flip output Mux to IGPU
            {
                \_SB.SGOV (SDTG, One)
            }

            LKZ1 = Zero          // Remove CPU Power Limit
            LKZ2 = 0x80000000    // Remove CPU Power Limit
        }

    OperationRegion (HPZK, SystemMemory, 0xFED159A0, 0x64)   // Define Memory Region
    Field (HPZK, AnyAcc, Lock, Preserve)
    {
        LKZ1,   32,  // Map Variable
        LKZ2,   32   // Map Variable
    }
}

This same idea can also be done without the hotpatch. Just using a driver or script that can trigger an acpi event, it just needs to call the XMXX function.
And the SSDT is simpler:

Code:
DefinitionBlock ("", "SSDT", 1, "HP", "PWLOFF", 0x00001000)
{
    Method (XMXX, 0, NotSerialized)
        {
            LKZ1 = Zero          // Remove CPU Power Limit
            LKZ2 = 0x80000000    // Remove CPU Power Limit
        }

    OperationRegion (HPZK, SystemMemory, 0xFED159A0, 0x64)   // Define Memory Region
    Field (HPZK, AnyAcc, Lock, Preserve)
    {
        LKZ1,   32,  // Map Variable
        LKZ2,   32   // Map Variable
    }
}
 
Last edited:

Mussels

Freshwater Moderator
Staff member
Joined
Oct 6, 2004
Messages
58,413 (8.19/day)
Location
Oystralia
System Name Rainbow Sparkles (Power efficient, <350W gaming load)
Processor Ryzen R7 5800x3D (Undervolted, 4.45GHz all core)
Motherboard Asus x570-F (BIOS Modded)
Cooling Alphacool Apex UV - Alphacool Eisblock XPX Aurora + EK Quantum ARGB 3090 w/ active backplate
Memory 2x32GB DDR4 3600 Corsair Vengeance RGB @3866 C18-22-22-22-42 TRFC704 (1.4V Hynix MJR - SoC 1.15V)
Video Card(s) Galax RTX 3090 SG 24GB: Underclocked to 1700Mhz 0.750v (375W down to 250W))
Storage 2TB WD SN850 NVME + 1TB Sasmsung 970 Pro NVME + 1TB Intel 6000P NVME USB 3.2
Display(s) Phillips 32 32M1N5800A (4k144), LG 32" (4K60) | Gigabyte G32QC (2k165) | Phillips 328m6fjrmb (2K144)
Case Fractal Design R6
Audio Device(s) Logitech G560 | Corsair Void pro RGB |Blue Yeti mic
Power Supply Fractal Ion+ 2 860W (Platinum) (This thing is God-tier. Silent and TINY)
Mouse Logitech G Pro wireless + Steelseries Prisma XL
Keyboard Razer Huntsman TE ( Sexy white keycaps)
VR HMD Oculus Rift S + Quest 2
Software Windows 11 pro x64 (Yes, it's genuinely a good OS) OpenRGB - ditch the branded bloatware!
Benchmark Scores Nyooom.
Hi, this patch is specific to my Zbook. It uses OpenCore or Clover bootloader and Rehabman's hotpatch method, but it can be easily modified to be used on other hardware and/or without a MacOS booter.

In Acpi you can't change a predefined DSDT or SSDT Method (function), so the hotpatch renames a function so it doesn't get called, and then you insert a new function with the original name and new desired code.

View attachment 226356

In my case when the Embedded Controller (EC) starts up it runs Method (function) RDSS.
I changed the name of the original RDSS Method in Open Core bootloader and I added a new SSDT that has a new RDSS method with an extra line at the end that executes a new XMXX Method.

In this new XMXX method using an ACPI trick, I mapped a chunk of Memory starting at FED159A0 and split it into 2 variables. Then I change the value of these 2 variables, thereby changing the underlying mapped Memory.

I also changed a Method that gets called late in the wake from sleep cycle so the DGPU is powered OFF and also the power limiter is removed when the computer wakes from sleep.

Code:
/*
DefinitionBlock ("", "SSDT", 1, "HP", "DGPUOFF", 0x00001000)
{
    External (_SB_.ODGW, MethodObj)    // External declarations
    External (_SB_.PCI0.LPCB.EC__.ECMX, MutexObj)
    External (_SB_.PCI0.LPCB.EC__.ECRG, IntObj)
    External (_SB_.PCI0.LPCB.EC__.TENA, FieldUnitObj)
    External (_SB_.PCI0.PEG0.PEGP, DeviceObj)
    External (_SB_.PCI0.PEG0.PEGP._OFF, MethodObj)
    External (_SB_.PCI0.PEG0.PEGP.VRID, FieldUnitObj)
    External (_SB_.SGOV, MethodObj)
    External (POHB, FieldUnitObj)
    External (POLB, FieldUnitObj)
    External (S3HB, FieldUnitObj)
    External (S3LB, FieldUnitObj)
    External (SDTG, FieldUnitObj)

    Scope (\_SB)
    {

    // CWAK gets called after Embedded Controller wakes and sets the power limit.

        Method (CWAK, 1, Serialized)   // Replacement Method with added code
        {
            ODGW ((0xF0 | Arg0))
            POLB = (0xF0 | Arg0)
            POHB = Zero
            If ((Arg0 == 0x03))
            {
                S3LB = (0xF0 | Arg0)
                S3HB = Zero
            }

            Sleep (0x64)  // Added a small pause to make sure DGPU is On before turning OFF
            If (CondRefOf (\_SB.PCI0.PEG0.PEGP._OFF))
            {
                \_SB.PCI0.PEG0.PEGP._OFF ()   // IF DGPU is enabled, turn it OFF
            }

            XMXX ()   // Execute XMXX method
        }
    }

// RDSS gets called after Embedded Controller starts and sets the power limit.

    Scope (\_SB.PCI0.PEG0.PEGP)
    {
        Method (RDSS, 1, Serialized)  // Replacement Method with added code
        {
            If (\_SB.PCI0.LPCB.EC.ECRG)
            {
                Acquire (\_SB.PCI0.LPCB.EC.ECMX, 0xFFFF)
                If ((Arg0 == One))
                {
                    If ((VRID == 0x1002))
                    {
                        \_SB.PCI0.LPCB.EC.TENA = 0x03
                    }
                    ElseIf ((VRID == 0x10DE))
                    {
                        \_SB.PCI0.LPCB.EC.TENA = 0x05
                    }
                    Else
                    {
                        \_SB.PCI0.LPCB.EC.TENA = One
                    }
                }
                Else
                {
                    \_SB.PCI0.LPCB.EC.TENA = One
                }

                Release (\_SB.PCI0.LPCB.EC.ECMX)
            }

            XMXX () // Execute XMXX method
        }
    }

    Method (XMXX, 0, NotSerialized)
        {
            If (CondRefOf (\_SB.SGOV)) // Flip output Mux to IGPU
            {
                \_SB.SGOV (SDTG, One)
            }

            LKZ1 = Zero          // Remove CPU Power Limit
            LKZ2 = 0x80000000    // Remove CPU Power Limit
        }

    OperationRegion (HPZK, SystemMemory, 0xFED159A0, 0x64)   // Define Memory Region
    Field (HPZK, AnyAcc, Lock, Preserve)
    {
        LKZ1,   32,  // Map Variable
        LKZ2,   32   // Map Variable
    }
}

This same idea can also be done without the hotpatch. Just using a driver or script that can trigger an acpi event, it just needs to call the XMXX function.
And the SSDT is simpler:

Code:
DefinitionBlock ("", "SSDT", 1, "HP", "PWLOFF", 0x00001000)
{
    Method (XMXX, 0, NotSerialized)
        {
            LKZ1 = Zero          // Remove CPU Power Limit
            LKZ2 = 0x80000000    // Remove CPU Power Limit
        }

    OperationRegion (HPZK, SystemMemory, 0xFED159A0, 0x64)   // Define Memory Region
    Field (HPZK, AnyAcc, Lock, Preserve)
    {
        LKZ1,   32,  // Map Variable
        LKZ2,   32   // Map Variable
    }
}
Hey it's all way beyond me: but sooner or later one other person with the same issue, will have found a fix thanks to you.
It might be 10 years from now, it may be tomorrow... but thanks for sharing that.
 

hugodlc

New Member
Joined
Oct 19, 2020
Messages
8 (0.01/day)
My pleasure, I found my fix the same way thanks to unclewebb sharing the patch. (Pay it forward as they say!)
 

hugodlc

New Member
Joined
Oct 19, 2020
Messages
8 (0.01/day)
Hi @unclewebb, any chance you know if I can use the same trick for undervolting? If so, what would the mapped memory addresses be for undervolting?

Thanks in advance
 
Top