#! /bin/sh
#
# Laptop mode tools module to handle CPU frequency settings.
#

# Set kernel setting, showing an error if this fails.
# Parameter 1: sysctl/proc path
# Parameter 2: the value
set_sysctl() {
	log "VERBOSE" "Executing: echo $2 > $1"
	if ! echo "$2" > "$1" ; then
		echo "SETTING OF KERNEL PARAMETER FAILED: echo $2 \> $1"
	fi
}


#
# get_medium_value
#
#   Get the medium value from a list of numerical values.
#   $1 = file containing the list of values
#
get_medium_value() {
	cat "$1" | tr ' ' '\n' | sort -n | awk -v RS="" '{n=split($0,a); print a[int((n+1)/2)]}'
}


if [ x$CONTROL_CPU_FREQUENCY = x1 ] || [ x$ENABLE_AUTO_MODULES = x1 -a x$CONTROL_CPU_FREQUENCY = xauto ]; then
	if [ $ON_AC -eq 1 ] ; then
		if [ "$ACTIVATE" -eq 1 ] ; then
			CPU_MAXFREQ="$LM_AC_CPU_MAXFREQ"
			CPU_MINFREQ="$LM_AC_CPU_MINFREQ"
			CPU_GOVERNOR="$LM_AC_CPU_GOVERNOR"
			CPU_IGNORE_NICE_LOAD="$LM_AC_CPU_IGNORE_NICE_LOAD"
		else
			CPU_MAXFREQ="$NOLM_AC_CPU_MAXFREQ"
			CPU_MINFREQ="$NOLM_AC_CPU_MINFREQ"
			CPU_GOVERNOR="$NOLM_AC_CPU_GOVERNOR"
			CPU_IGNORE_NICE_LOAD="$NOLM_AC_CPU_IGNORE_NICE_LOAD"
		fi
	else
		CPU_MAXFREQ="$BATT_CPU_MAXFREQ"
		CPU_MINFREQ="$BATT_CPU_MINFREQ"
		CPU_GOVERNOR="$BATT_CPU_GOVERNOR"
		CPU_IGNORE_NICE_LOAD="$BATT_CPU_IGNORE_NICE_LOAD"
	fi
	for THISCPU in /sys/devices/system/cpu/* ; do
		if [ -f "$THISCPU/cpufreq/scaling_driver" ] &&
		   [ "$(cat $THISCPU/cpufreq/scaling_driver)" = "intel_pstate" ]
		then
			continue # intel_pstate is a bit different - so it should be handled by its own module
		fi
		if [ -e $THISCPU/cpufreq/cpuinfo_min_freq ]; then
			THIS_CPU_MAXFREQ="$CPU_MAXFREQ"
			THIS_CPU_MINFREQ="$CPU_MINFREQ"
			THIS_CPU_GOVERNOR="$CPU_GOVERNOR"
			THIS_CPU_IGNORE_NICE_LOAD="$CPU_IGNORE_NICE_LOAD"

			case "$CPU_MAXFREQ" in
			"slowest")
				THIS_CPU_MAXFREQ=`cat $THISCPU/cpufreq/cpuinfo_min_freq`
				;;
			"medium")
				THIS_CPU_MAXFREQ=$(get_medium_value $THISCPU/cpufreq/scaling_available_frequencies)
				;;
			"fastest")
				THIS_CPU_MAXFREQ=`cat $THISCPU/cpufreq/cpuinfo_max_freq`
				;;
			esac

			case "$CPU_MINFREQ" in
			"slowest")
				THIS_CPU_MINFREQ=`cat $THISCPU/cpufreq/cpuinfo_min_freq`
				;;
			"medium")
				THIS_CPU_MINFREQ=$(get_medium_value $THISCPU/cpufreq/scaling_available_frequencies)
				;;
			"fastest")
				THIS_CPU_MINFREQ=`cat $THISCPU/cpufreq/cpuinfo_max_freq`
				;;
			esac

			log "VERBOSE" "Setting CPU maximum frequency for cpu $THISCPU to $THIS_CPU_MAXFREQ."
			set_sysctl $THISCPU/cpufreq/scaling_max_freq $THIS_CPU_MAXFREQ
			log "VERBOSE" "Setting CPU minimum frequency for cpu $THISCPU to $THIS_CPU_MINFREQ."
			set_sysctl $THISCPU/cpufreq/scaling_min_freq $THIS_CPU_MINFREQ
			log "VERBOSE" "Setting CPU frequency governor for cpu $THISCPU to $THIS_CPU_GOVERNOR."
			log "VERBOSE" "`/sbin/modprobe -q cpufreq_$THIS_CPU_GOVERNOR 2>&1`"
			set_sysctl $THISCPU/cpufreq/scaling_governor $THIS_CPU_GOVERNOR

			# Retain for backward compatibility
			if [ -f "$THISCPU/cpufreq/$THIS_CPU_GOVERNOR/ignore_nice_load" ] ; then
				log "VERBOSE" "Setting CPU ignore_nice_load for cpu $THISCPU to $THIS_CPU_IGNORE_NICE_LOAD."
				set_sysctl $THISCPU/cpufreq/$THIS_CPU_GOVERNOR/ignore_nice_load $THIS_CPU_IGNORE_NICE_LOAD
			else
				log "VERBOSE" "Not setting CPU ignore_nice_load for cpu $THISCPU."
				log "VERBOSE" "File $THISCPU/cpufreq/$THIS_CPU_GOVERNOR/ignore_nice_load does not exist."
			fi
		fi
	done

	# For kernels 2.6.32 and above, the sysfs interface for OnDemand per-core power savings has changed.
	# Instead of per-core, the new interface is generic and a single one
	if [ -f "/sys/devices/system/cpu/cpufreq/$THIS_CPU_GOVERNOR/ignore_nice_load" ]; then
		log "VERBOSE" "Setting CPU ignore_nice_load for all cpus"
		set_sysctl /sys/devices/system/cpu/cpufreq/$THIS_CPU_GOVERNOR/ignore_nice_load $CPU_IGNORE_NICE_LOAD
	else
		log "VERBOSE" "No generic CPU ignore_nice_load interface available"
	fi
fi

if [ x$CONTROL_CPU_THROTTLING = x1 ]  || [ x$ENABLE_AUTO_MODULES = x1 -a x$CONTROL_CPU_THROTTLING = xauto ]; then
	if [ $ON_AC -eq 1 ] ; then
		if [ "$ACTIVATE" -eq 1 ] ; then
			CPU_THROTTLING="$LM_AC_CPU_THROTTLING"
		else
			CPU_THROTTLING="$NOLM_AC_CPU_THROTTLING"
		fi
	else
		CPU_THROTTLING="$BATT_CPU_THROTTLING"
	fi
	for THISCPU in /proc/acpi/processor/* ; do
		if [ -e $THISCPU/throttling ]; then
			NUM_LEVELS=`cat $THISCPU/throttling | grep "T[0123456789]*\:" | wc -l`
			case "$CPU_THROTTLING" in
			"minimum")
				THIS_CPU_THROTTLING=0
				;;
			"medium")
				# Divide but round up: that way, "medium" on a two-level system will
				# lead to full throttling -- which is 50% on my system, quite reasonable.
				THIS_CPU_THROTTLING=$(( ($NUM_LEVELS / 2 ) ))
				;;
			"maximum")
				THIS_CPU_THROTTLING=$(($NUM_LEVELS - 1))
				;;
			*)
				THIS_CPU_THROTTLING="$CPU_THROTTLING"
			esac

			log "VERBOSE" "Setting throttling level for cpu $THISCPU to $THIS_CPU_THROTTLING."
			set_sysctl $THISCPU/throttling $THIS_CPU_THROTTLING
		fi
	done
fi

