From 3662033599d05e5da9ba8c7bb48107835cc0a2a1 Mon Sep 17 00:00:00 2001 From: Nate Lawson Date: Thu, 18 Dec 2003 04:39:57 +0000 Subject: [PATCH] Add power_profile, a script that changes the ACPI CPU Cx idle state and/or the throttling state in response to line transitions. Future plans include adding support for CPU frequency changes. Add a devd.conf entry for calling this script. The default values for this are: performance_cx_lowest="HIGH" # Use HLT (C0) online performance_throttle_state="HIGH" # 100% (no throttling) economy_cx_lowest="LOW" # Use the lowest Cx state possible economy_throttle_state="HIGH" # 100% (no throttling) --- etc/defaults/rc.conf | 4 ++ etc/devd.conf | 7 ++++ etc/rc.d/Makefile | 2 +- etc/rc.d/power_profile | 86 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 etc/rc.d/power_profile diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf index bf013d4d4871..4146e30b98d8 100644 --- a/etc/defaults/rc.conf +++ b/etc/defaults/rc.conf @@ -441,6 +441,10 @@ watchdogd_enable="NO" # Start the software watchdog daemon devfs_rulesets="/etc/defaults/devfs.rules /etc/devfs.rules" # Files containing # devfs(8) rules. devfs_system_ruleset="" # The name of a ruleset to apply to /dev +performance_cx_lowest="HIGH" # Online CPU idle state +performance_throttle_state="HIGH" # Online throttling state +economy_cx_lowest="LOW" # Offline CPU idle state +economy_throttle_state="HIGH" # Offline throttling state ############################################################## ### Jail Configuration ####################################### diff --git a/etc/devd.conf b/etc/devd.conf index 4f4641578aa1..cc7a20871a26 100644 --- a/etc/devd.conf +++ b/etc/devd.conf @@ -70,6 +70,13 @@ nomatch 0 { # action "logger Unknown device: $pnpinfo $location $bus"; }; +# Switch power profiles when the AC line state changes +notify 10 { + match "system" "ACPI"; + match "subsystem" "ACAD"; + action "/etc/rc.d/power_profile $notify"; +}; + /* EXAMPLES TO END OF FILE # The following might be an example of something that a vendor might diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index c790741f79a5..c9c57ad24a78 100755 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -26,7 +26,7 @@ FILES= DAEMON LOGIN NETWORKING SERVERS \ network_ipv6 nfsclient nfsd \ nfslocking nfsserver nisdomain ntpd ntpdate \ othermta \ - pccard pcvt ppp-user pppoed pwcheck \ + pccard pcvt power_profile ppp-user pppoed pwcheck \ quota \ random rarpd rcconf.sh root \ route6d routed routing rpcbind rtadvd rwho \ diff --git a/etc/rc.d/power_profile b/etc/rc.d/power_profile new file mode 100644 index 000000000000..52bc93d49499 --- /dev/null +++ b/etc/rc.d/power_profile @@ -0,0 +1,86 @@ +#!/bin/sh +# +# Modify the power profile based on AC line state. This script is +# usually called from devd(8). +# +# Arguments: 0x00 (AC offline, economy) or 0x01 (AC online, performance) +# +# $FreeBSD$ +# + +# PROVIDE: power_profile +# KEYWORD: FreeBSD nostart + +. /etc/rc.subr + +name="power_profile" +LOGGER="logger -t power_profile -p daemon.notice" + +# Set a given sysctl node to a value. +# +# Variables: +# $node: sysctl node to set with the new value +# $value: HIGH for the highest performance value, LOW for the best +# economy value, or the value itself. +# $highest_value: maximum value for this sysctl, when $value is "HIGH" +# $lowest_value: minimum value for this sysctl, when $value is "LOW" +# +sysctl_set () +{ + # Check if the node exists + if [ -z "$(sysctl -n ${node} 2> /dev/null)" ]; then + return + fi + + # Get the new value, checking for special types HIGH or LOW + case ${value} in + [Hh][Ii][Gg][Hh]) + value=${highest_value} + ;; + [Ll][Oo][Ww]) + value=${lowest_value} + ;; + *) + ;; + esac + + # Set the desired value + [ -n "${value}" ] && sysctl ${node}=${value} +} + +if [ $# -ne 1 ]; then + err 1 "Usage: $0 [0x00|0x01]" +fi +load_rc_config $name + +# Find the next state (performance or economy). +state=$1 +case ${state} in +0x01 | '') + ${LOGGER} "changed to 'performance'" + profile="performance" + ;; +0x00) + ${LOGGER} "changed to 'economy'" + profile="economy" + ;; +*) + echo "Usage: $0 [0x00|0x01]" + exit 1 +esac + +# Set the various sysctls based on the profile's values. +node="hw.acpi.cpu.cx_lowest" +highest_value=0 +lowest_value="$(sysctl -n hw.acpi.cpu.cx_supported | \ + awk '{ print split($0, a) - 1 }' - 2> /dev/null)" +eval value=\$${profile}_cx_lowest +sysctl_set + +node="hw.acpi.cpu.throttle_state" +highest_value="$(sysctl -n hw.acpi.cpu.throttle_max 2> /dev/null)" +lowest_value="1" +eval value=\$${profile}_throttle_state +sysctl_set + +exit 0