moved config to /etc
This commit is contained in:
9
Makefile
9
Makefile
@@ -2,6 +2,11 @@ all: install
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
install -d /usr/local/sbin/
|
install -d /usr/local/sbin/
|
||||||
install -m 700 lenovo_fix.py /usr/local/sbin/
|
|
||||||
install -d /etc/systemd/system/
|
install -d /etc/systemd/system/
|
||||||
install -m 644 lenovo_fix.service /etc/systemd/system/
|
install -m 700 lenovo_fix.py /usr/local/sbin/
|
||||||
|
install -m 644 systemd/lenovo_fix.service /etc/systemd/system/
|
||||||
|
@if test -f /etc/lenovo_fix.conf; then \
|
||||||
|
echo "/etc/lenovo_fix.conf already exists; overwrite manually"; \
|
||||||
|
else \
|
||||||
|
install -m 644 etc/lenovo_fix.conf /etc/; \
|
||||||
|
fi
|
||||||
|
|||||||
32
etc/lenovo_fix.conf
Normal file
32
etc/lenovo_fix.conf
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
[GENERAL]
|
||||||
|
Enabled: True
|
||||||
|
|
||||||
|
## Settings to apply while connected to Battery power
|
||||||
|
[BATTERY]
|
||||||
|
# Update the registers every this many seconds
|
||||||
|
Update_Rate_s: 30
|
||||||
|
# Max package power for time window #1
|
||||||
|
PL1_Tdp_W: 29
|
||||||
|
# Time window #1 duration
|
||||||
|
PL1_Duration_s: 28
|
||||||
|
# Max package power for time window #2
|
||||||
|
PL2_Tdp_W: 44
|
||||||
|
# Time window #2 duration
|
||||||
|
PL2_Duration_S: 0.002
|
||||||
|
# Max allowed temperature before throttling
|
||||||
|
Trip_Temp_C: 85
|
||||||
|
|
||||||
|
## Settings to apply while connected to AC power
|
||||||
|
[AC]
|
||||||
|
# Update the registers every this many seconds
|
||||||
|
Update_Rate_s: 5
|
||||||
|
# Max package power for time window #1
|
||||||
|
PL1_Tdp_W: 44
|
||||||
|
# Time window #1 duration
|
||||||
|
PL1_Duration_s: 28
|
||||||
|
# Max package power for time window #2
|
||||||
|
PL2_Tdp_W: 44
|
||||||
|
# Time window #2 duration
|
||||||
|
PL2_Duration_S: 0.002
|
||||||
|
# Max allowed temperature before throttling
|
||||||
|
Trip_Temp_C: 97
|
||||||
@@ -1,30 +1,16 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
|
import ConfigParser
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
from periphery import MMIO
|
from periphery import MMIO
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
config = {
|
SYSFS_POWER_PATH = '/sys/class/power_supply/AC/online'
|
||||||
'AC': {
|
CONFIG_PATH = '/etc/lenovo_fix.conf'
|
||||||
'UPDATE_RATE_SEC': 5, # Update the registers every this many seconds
|
|
||||||
'PL1_TDP_W': 44, # Max package power for time window #1
|
|
||||||
'PL1_DURATION_S': 28, # Time window #1 duration
|
|
||||||
'PL2_TDP_W': 44, # Max package power for time window #2
|
|
||||||
'PL2_DURATION_S': 0.002, # Time window #2 duration
|
|
||||||
'TRIP_TEMP_C': 97 # Max allowed temperature before throttling
|
|
||||||
},
|
|
||||||
'BATTERY': {
|
|
||||||
'UPDATE_RATE_SEC': 30, # Update the registers every this many seconds
|
|
||||||
'PL1_TDP_W': 29, # Max package power for time window #1
|
|
||||||
'PL1_DURATION_S': 28, # Time window #1 duration
|
|
||||||
'PL2_TDP_W': 44, # Max package power for time window #2
|
|
||||||
'PL2_DURATION_S': 0.002, # Time window #2 duration
|
|
||||||
'TRIP_TEMP_C': 85 # Max allowed temperature before throttling
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def writemsr(msr, val):
|
def writemsr(msr, val):
|
||||||
@@ -39,7 +25,7 @@ def writemsr(msr, val):
|
|||||||
|
|
||||||
|
|
||||||
def is_on_battery():
|
def is_on_battery():
|
||||||
with open('/sys/class/power_supply/AC/online') as f:
|
with open(SYSFS_POWER_PATH) as f:
|
||||||
return not bool(int(f.read()))
|
return not bool(int(f.read()))
|
||||||
|
|
||||||
|
|
||||||
@@ -51,52 +37,64 @@ def calc_time_window_vars(t):
|
|||||||
raise Exception('Unable to find a good combination!')
|
raise Exception('Unable to find a good combination!')
|
||||||
|
|
||||||
|
|
||||||
def check_config():
|
def load_config():
|
||||||
for k in config:
|
config = ConfigParser.ConfigParser()
|
||||||
assert 0 < config[k]['UPDATE_RATE_SEC']
|
config.read(CONFIG_PATH)
|
||||||
assert 0 < config[k]['PL1_TDP_W']
|
|
||||||
assert 0 < config[k]['PL2_TDP_W']
|
for power_source in ('AC', 'BATTERY'):
|
||||||
assert 0 < config[k]['PL1_DURATION_S']
|
assert 0 < config.getfloat(power_source, 'Update_Rate_s')
|
||||||
assert 0 < config[k]['PL2_DURATION_S']
|
assert 0 < config.getfloat(power_source, 'PL1_Tdp_W')
|
||||||
assert 40 < config[k]['TRIP_TEMP_C'] < 98
|
assert 0 < config.getfloat(power_source, 'PL1_Duration_s')
|
||||||
|
assert 0 < config.getfloat(power_source, 'PL2_Tdp_W')
|
||||||
|
assert 0 < config.getfloat(power_source, 'PL2_Duration_S')
|
||||||
|
assert 40 < config.getfloat(power_source, 'Trip_Temp_C') < 98
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
def calc_reg_values():
|
def calc_reg_values(config):
|
||||||
for k in config:
|
regs = defaultdict(dict)
|
||||||
|
for power_source in ('AC', 'BATTERY'):
|
||||||
# the critical temperature for this CPU is 100 C
|
# the critical temperature for this CPU is 100 C
|
||||||
trip_offset = int(round(100 - config[k]['TRIP_TEMP_C']))
|
trip_offset = int(round(100 - config.getfloat(power_source, 'Trip_Temp_C')))
|
||||||
config[k]['MSR_TEMPERATURE_TARGET'] = trip_offset << 24
|
regs[power_source]['MSR_TEMPERATURE_TARGET'] = trip_offset << 24
|
||||||
|
|
||||||
# 0.125 is the power unit of this CPU
|
# 0.125 is the power unit of this CPU
|
||||||
PL1 = int(round(config[k]['PL1_TDP_W'] / 0.125))
|
PL1 = int(round(config.getfloat(power_source, 'PL1_Tdp_W') / 0.125))
|
||||||
Y, Z = calc_time_window_vars(config[k]['PL1_DURATION_S'])
|
Y, Z = calc_time_window_vars(config.getfloat(power_source, 'PL1_Duration_s'))
|
||||||
TW1 = Y | (Z << 5)
|
TW1 = Y | (Z << 5)
|
||||||
|
|
||||||
PL2 = int(round(config[k]['PL2_TDP_W'] / 0.125))
|
PL2 = int(round(config.getfloat(power_source, 'PL2_Tdp_W') / 0.125))
|
||||||
Y, Z = calc_time_window_vars(config[k]['PL2_DURATION_S'])
|
Y, Z = calc_time_window_vars(config.getfloat(power_source, 'PL2_Duration_s'))
|
||||||
TW2 = Y | (Z << 5)
|
TW2 = Y | (Z << 5)
|
||||||
|
|
||||||
config[k]['MSR_PKG_POWER_LIMIT'] = PL1 | (1 << 15) | (TW1 << 17) | (PL2 << 32) | (1 << 47) | (TW2 << 49)
|
regs[power_source]['MSR_PKG_POWER_LIMIT'] = PL1 | (1 << 15) | (TW1 << 17) | (PL2 << 32) | (1 << 47) | (
|
||||||
|
TW2 << 49)
|
||||||
|
|
||||||
|
return regs
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
check_config()
|
config = load_config()
|
||||||
calc_reg_values()
|
regs = calc_reg_values(config)
|
||||||
|
|
||||||
|
if not config.getboolean('GENERAL', 'Enabled'):
|
||||||
|
return
|
||||||
|
|
||||||
mchbar_mmio = MMIO(0xfed159a0, 8)
|
mchbar_mmio = MMIO(0xfed159a0, 8)
|
||||||
while True:
|
while True:
|
||||||
cur_config = config['BATTERY' if is_on_battery() else 'AC']
|
power_source = 'BATTERY' if is_on_battery() else 'AC'
|
||||||
|
|
||||||
# set temperature trip point
|
# set temperature trip point
|
||||||
writemsr(0x1a2, cur_config['MSR_TEMPERATURE_TARGET'])
|
writemsr(0x1a2, regs[power_source]['MSR_TEMPERATURE_TARGET'])
|
||||||
|
|
||||||
# set PL1/2 on MSR
|
# set PL1/2 on MSR
|
||||||
writemsr(0x610, cur_config['MSR_PKG_POWER_LIMIT'])
|
writemsr(0x610, regs[power_source]['MSR_PKG_POWER_LIMIT'])
|
||||||
# set MCHBAR register to the same PL1/2 values
|
# set MCHBAR register to the same PL1/2 values
|
||||||
mchbar_mmio.write32(0, cur_config['MSR_PKG_POWER_LIMIT'] & 0xffffffff)
|
mchbar_mmio.write32(0, regs[power_source]['MSR_PKG_POWER_LIMIT'] & 0xffffffff)
|
||||||
mchbar_mmio.write32(4, cur_config['MSR_PKG_POWER_LIMIT'] >> 32)
|
mchbar_mmio.write32(4, regs[power_source]['MSR_PKG_POWER_LIMIT'] >> 32)
|
||||||
|
|
||||||
sleep(cur_config['UPDATE_RATE_SEC'])
|
sleep(config.getfloat(power_source, 'Update_Rate_s'))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
Reference in New Issue
Block a user