diff --git a/etc/lenovo_fix.conf b/etc/throttled.conf similarity index 100% rename from etc/lenovo_fix.conf rename to etc/throttled.conf diff --git a/install.sh b/install.sh index f57b4a2..132e355 100755 --- a/install.sh +++ b/install.sh @@ -1,41 +1,54 @@ #!/bin/sh -INSTALL_DIR="/opt/lenovo_fix" +LEGACY_INSTALL_DIR="/opt/lenovo_fix" +INSTALL_DIR="/opt/throttled" if pidof systemd 2>&1 1>/dev/null; then systemctl stop lenovo_fix.service >/dev/null 2>&1 + systemctl stop throttled.service >/dev/null 2>&1 elif pidof runit 2>&1 1>/dev/null; then sv down lenovo_fix >/dev/null 2>&1 + sv down throttled >/dev/null 2>&1 elif pidof openrc 2>&1 1>/dev/null; then rc-service lenovo_fix stop >/dev/null 2>&1 + rc-service throttled stop >/dev/null 2>&1 fi +mv "$LEGACY_INSTALL_DIR" "$INSTALL_DIR" >/dev/null 2>&1 +rm "$INSTALL_DIR/lenovo_fix.py" >/dev/null 2>&1 mkdir -p "$INSTALL_DIR" >/dev/null 2>&1 set -e cd "$(dirname "$0")" +if [ -f /etc/lenovo_fix.conf ]; then + echo "Updating config filename" + mv etc/lenovo_fix.conf /etc/throttled.conf +fi echo "Copying config file" -if [ ! -f /etc/lenovo_fix.conf ]; then - cp etc/lenovo_fix.conf /etc +if [ ! -f /etc/throttled.conf ]; then + cp etc/throttled.conf /etc else echo "Config file already exists, skipping" fi if pidof systemd 2>&1 1>/dev/null; then echo "Copying systemd service file" - cp systemd/lenovo_fix.service /etc/systemd/system + cp systemd/throttled.service /etc/systemd/system + rm /etc/systemd/system/lenovo_fix.service >/dev/null 2>&1 elif pidof runit 2>&1 1>/dev/null; then echo "Copying runit service file" - cp -R runit/lenovo_fix /etc/sv/ + cp -R runit/throttled /etc/sv/ + rm -r /etc/sv/lenovo_fix >/dev/null 2>&1 elif pidof openrc-init 2>&1 1>/dev/null; then echo "Copying OpenRC service file" - cp -R openrc/lenovo_fix /etc/init.d/lenovo_fix - chmod 755 /etc/init.d/lenovo_fix + cp -R openrc/throttled /etc/init.d/throttled + rm /etc/init.d/lenovo_fix >/dev/null 2>&1 + chmod 755 /etc/init.d/throttled fi echo "Copying core files" -cp requirements.txt lenovo_fix.py mmio.py "$INSTALL_DIR" +cp requirements.txt throttled.py mmio.py "$INSTALL_DIR" echo "Building virtualenv" cd "$INSTALL_DIR" /usr/bin/python3 -m venv venv @@ -46,16 +59,16 @@ pip install -r requirements.txt if pidof systemd 2>&1 1>/dev/null; then echo "Enabling and starting systemd service" systemctl daemon-reload - systemctl enable lenovo_fix.service - systemctl restart lenovo_fix.service + systemctl enable throttled.service + systemctl restart throttled.service elif pidof runit 2>&1 1>/dev/null; then echo "Enabling and starting runit service" - ln -sv /etc/sv/lenovo_fix /var/service/ - sv up lenovo_fix + ln -sv /etc/sv/throttled /var/service/ + sv up throttled elif pidof openrc-init 2>&1 1>/dev/null; then echo "Enabling and starting OpenRC service" - rc-update add lenovo_fix default - rc-service lenovo_fix start + rc-update add throttled default + rc-service throttled start fi echo "All done." diff --git a/openrc/lenovo_fix b/openrc/lenovo_fix deleted file mode 100644 index 7bbbe2a..0000000 --- a/openrc/lenovo_fix +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/openrc-run -command="env python3 /usr/lib/throttled/lenovo_fix.py" -pidfile=${pidfile-/var/run/lenovo_fix.pid} -description="Stop Intel throttling" -command_background="yes" diff --git a/openrc/throttled b/openrc/throttled new file mode 100644 index 0000000..5551d36 --- /dev/null +++ b/openrc/throttled @@ -0,0 +1,5 @@ +#!/usr/bin/openrc-run +command="env python3 /usr/lib/throttled/throttled.py" +pidfile=${pidfile-/var/run/throttled.pid} +description="Stop Intel throttling" +command_background="yes" diff --git a/runit/lenovo_fix/run b/runit/lenovo_fix/run deleted file mode 100755 index cd2412a..0000000 --- a/runit/lenovo_fix/run +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -PYTHONUNBUFFERED=1 exec /opt/lenovo_fix/venv/bin/python3 /opt/lenovo_fix/lenovo_fix.py diff --git a/runit/throttled/run b/runit/throttled/run new file mode 100755 index 0000000..2d4abf3 --- /dev/null +++ b/runit/throttled/run @@ -0,0 +1,2 @@ +#!/bin/sh +PYTHONUNBUFFERED=1 exec /opt/throttled/venv/bin/python3 /opt/throttled/throttled.py diff --git a/systemd/lenovo_fix.service b/systemd/throttled.service similarity index 75% rename from systemd/lenovo_fix.service rename to systemd/throttled.service index 28b8a47..17ea49c 100644 --- a/systemd/lenovo_fix.service +++ b/systemd/throttled.service @@ -3,7 +3,7 @@ Description=Stop Intel throttling [Service] Type=simple -ExecStart=/opt/lenovo_fix/venv/bin/python3 /opt/lenovo_fix/lenovo_fix.py +ExecStart=/opt/throttled/venv/bin/python3 /opt/throttled/throttled.py # Setting PYTHONUNBUFFERED is necessary to see the output of this service in the journal Environment=PYTHONUNBUFFERED=1 diff --git a/lenovo_fix.py b/throttled.py similarity index 96% rename from lenovo_fix.py rename to throttled.py index 9558151..25f961f 100755 --- a/lenovo_fix.py +++ b/throttled.py @@ -165,6 +165,9 @@ supported_cpus = { (6, 167, 1): 'RocketLake', } +TESTMSR = False +UNSUPPORTED_FEATURES = [] + class bcolors: YELLOW = '\033[93m' @@ -221,6 +224,8 @@ def writemsr(msr, val): os.write(f, struct.pack('Q', val)) os.close(f) except (IOError, OSError) as e: + if TESTMSR: + raise e if e.errno == EPERM or e.errno == EACCES: fatal( 'Unable to write to MSR {} ({:x}). Try to disable Secure Boot ' @@ -257,6 +262,8 @@ def readmsr(msr, from_bit=0, to_bit=63, cpu=None, flatten=False): return output[0] return output[cpu] if cpu is not None else output except (IOError, OSError) as e: + if TESTMSR: + raise e if e.errno == EPERM or e.errno == EACCES: fatal('Unable to read from MSR {} ({:x}). Try to disable Secure Boot.'.format(msr, MSR_DICT[msr])) elif e.errno == EIO: @@ -394,6 +401,8 @@ def calc_undervolt_mv(msr_value): def get_undervolt(plane=None, convert=False): + if 'UNDERVOLT' in UNSUPPORTED_FEATURES: + return 0 planes = [plane] if plane in VOLTAGE_PLANES else VOLTAGE_PLANES out = {} for plane in planes: @@ -405,7 +414,9 @@ def get_undervolt(plane=None, convert=False): def undervolt(config): - if 'UNDERVOLT.{:s}'.format(power['source']) not in config and 'UNDERVOLT' not in config: + if ('UNDERVOLT.{:s}'.format(power['source']) not in config and 'UNDERVOLT' not in config) or ( + 'UNDERVOLT' in UNSUPPORTED_FEATURES + ): return for plane in VOLTAGE_PLANES: write_offset_mv = config.getfloat( @@ -624,11 +635,11 @@ def calc_reg_values(platform_info, config): def set_hwp(performance_mode): - if performance_mode is None: + if performance_mode not in (True, False) or 'HWP' in UNSUPPORTED_FEATURES: return # set HWP energy performance preference cur_val = readmsr('IA32_HWP_REQUEST', cpu=0) - hwp_mode = HWP_PERFORMANCE_VALUE if performance_mode else HWP_DEFAULT_VALUE + hwp_mode = HWP_PERFORMANCE_VALUE if performance_mode is True else HWP_DEFAULT_VALUE new_val = (cur_val & 0xFFFFFFFF00FFFFFF) | (hwp_mode << 24) writemsr('IA32_HWP_REQUEST', new_val) @@ -699,7 +710,7 @@ def power_thread(config, regs, exit_event): power['source'] = 'BATTERY' if is_on_battery(config) else 'AC' # set temperature trip point - if 'MSR_TEMPERATURE_TARGET' in regs[power['source']]: + if 's' in regs[power['source']]: write_value = regs[power['source']]['MSR_TEMPERATURE_TARGET'] writemsr('MSR_TEMPERATURE_TARGET', write_value) if args.debug: @@ -834,6 +845,27 @@ def check_cpu(): fatal('Unable to identify CPU model.') +def test_msr_rw_capabilities(): + TESTMSR = True + + try: + log('[I] Testing if undervolt is supported...') + get_undervolt() + except: + warning('Undervolt seems not to be supported by your system, disabling.') + UNSUPPORTED_FEATURES.append('UNDERVOLT') + + try: + log('[I] Testing if HWP is supported...') + cur_val = readmsr('IA32_HWP_REQUEST', cpu=0) + writemsr('IA32_HWP_REQUEST', cur_val) + except: + warning('HWP seems not to be supported by your system, disabling.') + UNSUPPORTED_FEATURES.append('HWP') + + TESTMSR = False + + def monitor(exit_event, wait): wait = max(0.1, wait) rapl_power_unit = 0.5 ** readmsr('MSR_RAPL_POWER_UNIT', from_bit=8, to_bit=12, cpu=0) @@ -896,7 +928,7 @@ def main(): nargs='?', help='realtime monitoring of throttling causes (default 1s)', ) - parser.add_argument('--config', default='/etc/lenovo_fix.conf', help='override default config file path') + parser.add_argument('--config', default='/etc/throttled.conf', help='override default config file path') parser.add_argument('--force', action='store_true', help='bypass compatibility checks (EXPERTS only)') parser.add_argument('--log', metavar='/path/to/file', help='log to file instead of stdout') args = parser.parse_args() @@ -914,6 +946,8 @@ def main(): set_msr_allow_writes() + test_msr_rw_capabilities() + log('[I] Loading config file.') config = load_config() power['source'] = 'BATTERY' if is_on_battery(config) else 'AC'