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



## Shymon (Apr 11, 2021)

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":


----------



## unclewebb (Apr 11, 2021)

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.



			RWEverything – Read & Write Everything


----------



## Shymon (Apr 11, 2021)

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 (Apr 11, 2021)

Shymon said:


> 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



Shymon said:


> 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 (Apr 11, 2021)

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 (Apr 11, 2021)

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






						Dump.zip
					






					drive.google.com


----------



## hugodlc (Nov 23, 2021)

unclewebb said:


> 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:

After the patch


The SSDT:


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.


----------



## Mussels (Nov 23, 2021)

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 (Nov 23, 2021)

Mussels said:


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





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)


```
/*
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:


```
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
    }
}
```


----------



## unclewebb (Nov 23, 2021)

hugodlc said:


> LKZ2 = 0x00800000


Should this variable be set to 0x80000000


----------



## hugodlc (Nov 23, 2021)

unclewebb said:


> Should this variable be set to 0x80000000


Fixed, thank you!

(Late night typing)


----------



## Mussels (Nov 24, 2021)

hugodlc said:


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


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 (Nov 24, 2021)

My pleasure, I found my fix the same way thanks to unclewebb sharing the patch. (Pay it forward as they say!)


----------

