#!/bin/sh /etc/rc.common

START=13

APP_NAME="cpu-perf"
SYSFS_CPU_DIR="/sys/devices/system/cpu"
SYSFS_CPU_FREQ_DIR="${SYSFS_CPU_DIR}/cpufreq"

OD_CPU_FREQ_DIR="${SYSFS_CPU_DIR}/cpufreq/ondemand"
OD_UP_THRESHOLD_FILE="${OD_CPU_FREQ_DIR}/up_threshold"
OD_IGN_NICE_LOAD_FILE="${OD_CPU_FREQ_DIR}/ignore_nice_load"
OD_SAMPLING_DOWN_FACTOR_FILE="${OD_CPU_FREQ_DIR}/sampling_down_factor"
OD_POWERSAVE_BIAS_FILE="${OD_CPU_FREQ_DIR}/powersave_bias"
OD_UP_THRESHOLD_DEF=95
OD_IGN_NICE_LOAD_DEF=0
OD_SAMPLING_DOWN_FACTOR_DEF=1
OD_POWERSAVE_BIAS_DEF=0

CO_CPU_FREQ_DIR="${SYSFS_CPU_DIR}/cpufreq/conservative"
CO_FREQ_STEP_FILE="${CO_CPU_FREQ_DIR}/freq_step"
CO_DOWN_THRESHOLD_FILE="${CO_CPU_FREQ_DIR}/down_threshold"
CO_SAMPLING_DOWN_FACTOR_FILE="${CO_CPU_FREQ_DIR}/sampling_down_factor"
CO_FREQ_STEP_DEF=5
CO_DOWN_THRESHOLD_DEF=20
CO_SAMPLING_DOWN_FACTOR_DEF=1

PA_POLICY_FILE="/sys/module/pcie_aspm/parameters/policy"
PA_POLICY_DEF="default"

EAS_FILE="/proc/sys/kernel/sched_energy_aware"
EAS_DEF=1


config_load $APP_NAME

get_cpu_freq_policies() {
	[ ! -d "$SYSFS_CPU_FREQ_DIR" ] && return
	echo $(ls "$SYSFS_CPU_FREQ_DIR" | grep "^policy[0-9]*$")
}

reset_cpu_freq_policy_config() {
	while uci -q delete ${APP_NAME}.@cpu_freq_policy[0]; do :; done
	for i in $(get_cpu_freq_policies)
	do
		uci set ${APP_NAME}.${i}="cpu_freq_policy"
	done
	uci commit "$APP_NAME"
}

CPU_FREQ_POLICY_UCI_SECTIONS=0
CPU_FREQ_POLICIES=$(get_cpu_freq_policies | wc -w)

cpu_freq_policy_section_counter() {
	CPU_FREQ_POLICY_UCI_SECTIONS=$(($CPU_FREQ_POLICY_UCI_SECTIONS + 1))
}

check_cpu_freq_policy_sections() {
	CPU_FREQ_POLICY_UCI_SECTIONS=0
	config_foreach cpu_freq_policy_section_counter cpu_freq_policy
	if [ $CPU_FREQ_POLICY_UCI_SECTIONS -ne $CPU_FREQ_POLICIES ]; then
		reset_cpu_freq_policy_config
	fi
}

set_cpu_freq_policy() {
	local policy="$1"
	local scaling_min_freq scaling_max_freq scaling_governor
	local policy_dir="${SYSFS_CPU_FREQ_DIR}/${policy}"

	[ ! -d "$policy_dir" ] && return

	local scaling_min_freq_file="${policy_dir}/scaling_min_freq"
	local scaling_max_freq_file="${policy_dir}/scaling_max_freq"
	local scaling_governor_file="${policy_dir}/scaling_governor"

	config_get scaling_min_freq $policy scaling_min_freq
	config_get scaling_max_freq $policy scaling_max_freq
	config_get scaling_governor $policy scaling_governor

	if [ -n "$scaling_min_freq" -a -w "$scaling_min_freq_file" ]; then
		echo "$scaling_min_freq" > "$scaling_min_freq_file"
	fi
	if [ -n "$scaling_max_freq" -a -w "$scaling_max_freq_file" ]; then
		echo "$scaling_max_freq" > "$scaling_max_freq_file"
	fi
	if [ -n "$scaling_governor" -a -w "$scaling_governor_file" ]; then
		echo "$scaling_governor" > "$scaling_governor_file"
	fi
}

reset_cpu_freq_policy() {
	local policy="$1"
	local policy_dir="${SYSFS_CPU_FREQ_DIR}/${policy}"

	[ ! -d "$policy_dir" ] && return

	local min_freq_file="${policy_dir}/cpuinfo_min_freq"
	local max_freq_file="${policy_dir}/cpuinfo_max_freq"
	local scaling_min_freq_file="${policy_dir}/scaling_min_freq"
	local scaling_max_freq_file="${policy_dir}/scaling_max_freq"
	local scaling_governor_file="${policy_dir}/scaling_governor"

	if [ -r "$min_freq_file" -a -w "$scaling_min_freq_file" ]; then
		echo "$(cat $min_freq_file)" > "$scaling_min_freq_file"
	fi
	if [ -r "$max_freq_file" -a -w "$scaling_max_freq_file" ]; then
		echo "$(cat $max_freq_file)" > "$scaling_max_freq_file"
	fi
	if [ -w "$scaling_governor_file" ]; then
		echo "schedutil" > "$scaling_governor_file" 2> /dev/null
		if [ $? -ne 0 ]; then
			echo "ondemand" > "$scaling_governor_file" 2> /dev/null
			if [ $? -ne 0 ]; then
				echo "conservative" > "$scaling_governor_file" 2> /dev/null
				if [ $? -ne 0 ]; then
					echo "userspace" > "$scaling_governor_file" 2> /dev/null
				fi
			fi
		fi
	fi
}

set_ondemand_tunables() {
	local up_threshold ignore_nice_load sampling_down_factor powersave_bias

	[ ! -d "$OD_CPU_FREQ_DIR" ] && return 0

	config_get up_threshold ondemand up_threshold
	config_get ignore_nice_load ondemand ignore_nice_load
	config_get sampling_down_factor ondemand sampling_down_factor
	config_get powersave_bias ondemand powersave_bias

	if [ -n "$up_threshold" -a -w "$OD_UP_THRESHOLD_FILE" ]; then
		echo "$up_threshold" > "$OD_UP_THRESHOLD_FILE"
	fi
	if [ -n "$ignore_nice_load" -a -w "$OD_IGN_NICE_LOAD_FILE" ]; then
		echo "$ignore_nice_load" > "$OD_IGN_NICE_LOAD_FILE"
	fi
	if [ -n "$sampling_down_factor" -a -w "$OD_SAMPLING_DOWN_FACTOR_FILE" ]; then
		echo "$sampling_down_factor" > "$OD_SAMPLING_DOWN_FACTOR_FILE"
	fi
	if [ -n "$powersave_bias" -a -w "$OD_POWERSAVE_BIAS_FILE" ]; then
		echo "$powersave_bias" > "$OD_POWERSAVE_BIAS_FILE"
	fi
}

reset_ondemand_tunables() {
	[ ! -d "$OD_CPU_FREQ_DIR" ] && return 0

	if [ -w "$OD_UP_THRESHOLD_FILE" ]; then
		echo "$OD_UP_THRESHOLD_DEF" > "$OD_UP_THRESHOLD_FILE"
	fi
	if [ -w "$OD_IGN_NICE_LOAD_FILE" ]; then
		echo "$OD_IGN_NICE_LOAD_DEF" > "$OD_IGN_NICE_LOAD_FILE"
	fi
	if [ -w "$OD_SAMPLING_DOWN_FACTOR_FILE" ]; then
		echo "$OD_SAMPLING_DOWN_FACTOR_DEF" > "$OD_SAMPLING_DOWN_FACTOR_FILE"
	fi
	if [ -w "$OD_POWERSAVE_BIAS_FILE" ]; then
		echo "$OD_POWERSAVE_BIAS_DEF" > "$OD_POWERSAVE_BIAS_FILE"
	fi
}

set_conservative_tunables() {
	local freq_step down_threshold sampling_down_factor

	[ ! -d "$CO_CPU_FREQ_DIR" ] && return 0

	config_get freq_step conservative freq_step
	config_get down_threshold conservative down_threshold
	config_get sampling_down_factor conservative sampling_down_factor

	if [ -n "$freq_step" -a -w "$CO_FREQ_STEP_FILE" ]; then
		echo "$freq_step" > "$CO_FREQ_STEP_FILE"
	fi
	if [ -n "$down_threshold" -a -w "$CO_DOWN_THRESHOLD_FILE" ]; then
		echo "$down_threshold" > "$CO_DOWN_THRESHOLD_FILE"
	fi
	if [ -n "$sampling_down_factor" -a -w "$CO_SAMPLING_DOWN_FACTOR_FILE" ]; then
		echo "$sampling_down_factor" > "$CO_SAMPLING_DOWN_FACTOR_FILE"
	fi
}

reset_conservative_tunables() {
	[ ! -d "$CO_CPU_FREQ_DIR" ] && return 0

	if [ -w "$CO_FREQ_STEP_FILE" ]; then
		echo "$CO_FREQ_STEP_DEF" > "$CO_FREQ_STEP_FILE"
	fi
	if [ -w "$CO_DOWN_THRESHOLD_FILE" ]; then
		echo "$CO_DOWN_THRESHOLD_DEF" > "$CO_DOWN_THRESHOLD_FILE"
	fi
	if [ -w "$CO_SAMPLING_DOWN_FACTOR_FILE" ]; then
		echo "$CO_SAMPLING_DOWN_FACTOR_DEF" > "$CO_SAMPLING_DOWN_FACTOR_FILE"
	fi
}

set_eas() {
	config_get sched_energy_aware eas sched_energy_aware

	if [ -n "$sched_energy_aware" -a -w "$EAS_FILE" ]; then
		echo "$sched_energy_aware" > "$EAS_FILE" 2> /dev/null
	fi
}

reset_eas() {
	if [ -w "$EAS_FILE" ]; then
		echo "$EAS_DEF" > "$EAS_FILE" 2> /dev/null
	fi
}

set_pcie_aspm_policy() {
	config_get policy pcie_aspm policy

	if [ -n "$policy" -a -w "$PA_POLICY_FILE" ]; then
		echo "$policy" > "$PA_POLICY_FILE" 2> /dev/null
	fi
}

reset_pcie_aspm_policy() {
	if [ -w "$PA_POLICY_FILE" ]; then
		echo "$PA_POLICY_DEF" > "$PA_POLICY_FILE" 2> /dev/null
	fi
}

start() {
	local enabled
	if [ -r "/etc/config/${APP_NAME}" ]; then
		check_cpu_freq_policy_sections
		enabled=$(uci get ${APP_NAME}.config.enabled)
		if [ "$enabled" = "1" ]; then
			set_eas
			config_foreach set_cpu_freq_policy cpu_freq_policy
			set_ondemand_tunables
			set_conservative_tunables
			set_pcie_aspm_policy
		fi
	else
		exit 1
	fi
}

stop() {
	reset_eas
	config_foreach reset_cpu_freq_policy cpu_freq_policy
	reset_ondemand_tunables
	reset_conservative_tunables
	reset_pcie_aspm_policy
}
