blob: bf4ec23918686a3a8c84b5165a4cdd83b94320fd [file] [log] [blame]
#!/usr/bin/python3
# SPDX-License-Identifier: MIT
"""TTM configuration tool"""
import os
import argparse
from amd_debug.common import (
AmdTool,
bytes_to_gb,
gb_to_pages,
get_system_mem,
relaunch_sudo,
print_color,
reboot,
version,
)
TTM_PARAM_PATH = "/sys/module/ttm/parameters/pages_limit"
MODPROBE_CONF_PATH = "/etc/modprobe.d/ttm.conf"
# Maximum percentage of total system memory to allow for TTM
MAX_MEMORY_PERCENTAGE = 90
def maybe_reboot() -> bool:
"""Prompt to reboot system"""
response = input("Would you like to reboot the system now? (y/n): ").strip().lower()
if response in ("y", "yes"):
return reboot()
return True
class AmdTtmTool(AmdTool):
"""Class for handling TTM page configuration"""
def __init__(self, logging):
log_prefix = "ttm" if logging else None
super().__init__(log_prefix)
def get(self) -> bool:
"""Read current page limit"""
try:
with open(TTM_PARAM_PATH, "r", encoding="utf-8") as f:
pages = int(f.read().strip())
gb_value = bytes_to_gb(pages)
print_color(
f"Current TTM pages limit: {pages} pages ({gb_value:.2f} GB)", "💻"
)
except FileNotFoundError:
print_color(f"Error: Could not find {TTM_PARAM_PATH}", "❌")
return False
total = get_system_mem()
if total > 0:
print_color(f"Total system memory: {total:.2f} GB", "💻")
return True
def set(self, gb_value) -> bool:
"""Set a new page limit"""
relaunch_sudo()
# Check against system memory
total = get_system_mem()
if total > 0:
max_recommended_gb = total * MAX_MEMORY_PERCENTAGE / 100
if gb_value > total:
print_color(
f"{gb_value:.2f} GB is greater than total system memory ({total:.2f} GB)",
"❌",
)
return False
if gb_value > max_recommended_gb:
print_color(
f"Warning: The requested value ({gb_value:.2f} GB) exceeds {MAX_MEMORY_PERCENTAGE}% of your system memory ({max_recommended_gb:.2f} GB).",
"🚦",
)
response = (
input(
"This could cause system instability. Continue anyway? (y/n): "
)
.strip()
.lower()
)
if response not in ("y", "yes"):
print_color("Operation cancelled.", "🚦")
return False
pages = gb_to_pages(gb_value)
with open(MODPROBE_CONF_PATH, "w", encoding="utf-8") as f:
f.write(f"options ttm pages_limit={pages}\n")
print_color(
f"Successfully set TTM pages limit to {pages} pages ({gb_value:.2f} GB)",
"🐧",
)
print_color(f"Configuration written to {MODPROBE_CONF_PATH}", "🐧")
print_color("NOTE: You need to reboot for changes to take effect.", "○")
return maybe_reboot()
def clear(self) -> bool:
"""Clears the page limit"""
if not os.path.exists(MODPROBE_CONF_PATH):
print_color(f"{MODPROBE_CONF_PATH} doesn't exist", "❌")
return False
relaunch_sudo()
os.remove(MODPROBE_CONF_PATH)
print_color(f"Configuration {MODPROBE_CONF_PATH} removed", "🐧")
return maybe_reboot()
def parse_args():
"""Parse command line arguments."""
parser = argparse.ArgumentParser(description="Manage TTM pages limit")
parser.add_argument("--set", type=float, help="Set pages limit in GB")
parser.add_argument(
"--clear", action="store_true", help="Clear a previously set page limit"
)
parser.add_argument(
"--version", action="store_true", help="Show version information"
)
parser.add_argument(
"--tool-debug",
action="store_true",
help="Enable tool debug logging",
)
return parser.parse_args()
def main() -> None | int:
"""Main function"""
args = parse_args()
tool = AmdTtmTool(args.tool_debug)
ret = False
if args.version:
print(version())
return
elif args.set is not None:
if args.set <= 0:
print("Error: GB value must be greater than 0")
return 1
ret = tool.set(args.set)
elif args.clear:
ret = tool.clear()
else:
ret = tool.get()
if ret is False:
return 1
return