amdgpu-clocks 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #!/bin/bash
  2. USER_STATES_PATH=${USER_STATES_PATH:-/etc/default/amdgpu-custom-state}
  3. SYS_PPFMASK=/sys/module/amdgpu/parameters/ppfeaturemask
  4. [ ! -r ${SYS_PPFMASK} ] && echo "Can't access ${SYS_PPFMASK}" && exit 2
  5. if [ "$1" == "restore" ]; then
  6. RESTORE=true
  7. fi
  8. function check_ppfeaturemask() {
  9. CURRENT_HEX_MASK=$(printf '%#x' "$(( $(cat ${SYS_PPFMASK}) ))")
  10. # 0x4000 or 14th bit is one indicating if OverDrive has been enabled
  11. OVERDRIVE_MASK=$(printf '%#x' "$(( CURRENT_HEX_MASK & 0x4000 ))")
  12. [ "${OVERDRIVE_MASK}" == "0x4000" ] && return 0
  13. WANTED_MASK=$(printf '%#x' "$(( CURRENT_HEX_MASK | 0x4000 ))")
  14. echo -n "In order to set custom amdgpu power states, enable OverDrive by "
  15. echo -n "booting the machine with amdgpu.ppfeaturemask=${WANTED_MASK} "
  16. echo "kernel option" && exit 2
  17. }
  18. function fill_sclks() {
  19. if [ -z "${3}" ]; then # Vega20 and later ASICs
  20. echo " SCLK state ${1}: ${2}"
  21. SCLK[${1}]="s ${1} ${2%*M[Hh]z}"
  22. else # Vega10 and previous ASICs
  23. echo " SCLK state ${1}: ${2}, ${3}"
  24. SCLK[${1}]="s ${1} ${2%*M[Hh]z} ${3%*mV}"
  25. fi
  26. }
  27. function fill_mclks() {
  28. if [ -z "${3}" ]; then # Vega20 and later ASICs
  29. echo " MCLK state ${1}: ${2}"
  30. MCLK[${1}]="m ${1} ${2%*M[Hh]z}"
  31. else # Vega10 and previous ASICs
  32. echo " MCLK state ${1}: ${2}, ${3}"
  33. MCLK[${1}]="m ${1} ${2%*M[Hh]z} ${3%*mV}"
  34. fi
  35. }
  36. function fill_vddccurve() {
  37. echo " VDDC Curve state $1: ${2}, ${4}"
  38. VDDC_CURVE[${1}]="vc ${1} ${2%*M[Hh]z} ${4%*mV}"
  39. }
  40. function parse_states() {
  41. mapfile -t STATE_LINES < $1
  42. for LNNO in "${!STATE_LINES[@]}"; do
  43. LINE="${STATE_LINES[$LNNO]}"
  44. case ${LINE} in
  45. "OD_SCLK:")
  46. state_fill_func=fill_sclks ;;
  47. "OD_MCLK:")
  48. state_fill_func=fill_mclks ;;
  49. "OD_VDDC_CURVE:")
  50. state_fill_func=fill_vddccurve ;;
  51. "VDDC_CURVE_SCLK["[012]"]: "*)
  52. ;; # Just ignoring these for now
  53. "VDDC_CURVE_VOLT["[012]"]: "*)
  54. ;; # Just ignoring these for now
  55. "OD_RANGE:")
  56. echo " Maximum clocks & voltages:";;
  57. "SCLK: "*)
  58. echo " SCLK clock ${LINE##* }"
  59. MAX_SCLK=${LINE##* }
  60. MAX_SCLK=${MAX_SCLK%*M[Hh]z}
  61. ;;
  62. "MCLK: "*)
  63. echo " MCLK clock ${LINE##* }"
  64. MAX_MCLK=${LINE##* }
  65. MAX_MCLK=${MAX_MCLK%*M[Hh]z}
  66. ;;
  67. "VDDC: "*)
  68. echo " VDDC voltage ${LINE##* }"
  69. MAX_VDDC=${LINE##* }
  70. MAX_VDDC=${MAX_VDDC%*mV}
  71. ;;
  72. [0-9]": "*)
  73. $state_fill_func ${LINE%%:*} ${LINE#* }
  74. ;;
  75. "FORCE_SCLK: "[0-9]*)
  76. echo " Force SCLK state to ${LINE#* }"
  77. FORCE_SCLK=${LINE#* }
  78. ;;
  79. "FORCE_MCLK: "[0-9]*)
  80. echo " Force MCLK state to ${LINE#* }"
  81. FORCE_MCLK=${LINE#* }
  82. ;;
  83. "FORCE_POWER_CAP: "[0-9]*)
  84. MICROWATTS=${LINE#* }
  85. echo " Force power cap to ${MICROWATTS%*000000}W"
  86. FORCE_POWER_CAP=${LINE#* }
  87. ;;
  88. "FORCE_PERF_LEVEL: "[a-z]*)
  89. echo " Force performance level to ${LINE#* }"
  90. FORCE_LEVEL=${LINE#* }
  91. ;;
  92. "FORCE_POWER_PROFILE: "[0-9]*)
  93. echo " Force power profile to ${LINE#* }"
  94. FORCE_PROFILE=${LINE#* }
  95. ;;
  96. "#"*) ;;
  97. "") ;;
  98. *)
  99. let "LINE_NUMBER = ${LNNO} + 1"
  100. echo " Unexpected value in ${1}:${LINE_NUMBER}"
  101. exit 2
  102. ;;
  103. esac
  104. done
  105. if [ "$1" == "${SYS_PP_OD_CLK}" ]; then
  106. POWER_LIMIT=$(cat $PWR_CAP_FILE)
  107. echo " Curent power cap: ${POWER_LIMIT%*000000}W"
  108. fi
  109. }
  110. function set_custom_states() {
  111. if [ "${FORCE_LEVEL}" ]; then
  112. echo ${FORCE_LEVEL} > ${PWR_LEVEL}
  113. fi
  114. if [ "${FORCE_PROFILE}" ]; then
  115. echo ${FORCE_PROFILE} > ${PWR_PROFILE}
  116. fi
  117. for CSTATE in "${SCLK[@]}"; do
  118. echo ${CSTATE} > ${SYS_PP_OD_CLK}
  119. done
  120. for MSTATE in "${MCLK[@]}"; do
  121. echo ${MSTATE} > ${SYS_PP_OD_CLK}
  122. done
  123. for VDDC_CURVE_STATE in "${VDDC_CURVE[@]}"; do
  124. echo ${VDDC_CURVE_STATE} > ${SYS_PP_OD_CLK}
  125. done
  126. echo 'c' > ${SYS_PP_OD_CLK}
  127. if [ "${FORCE_SCLK}" ]; then
  128. echo ${FORCE_SCLK} > ${SYS_DPM_SCLK}
  129. fi
  130. if [ "${FORCE_MCLK}" ]; then
  131. echo ${FORCE_MCLK} > ${SYS_DPM_MCLK}
  132. fi
  133. if [ "${FORCE_POWER_CAP}" ]; then
  134. echo ${FORCE_POWER_CAP} > ${PWR_CAP_FILE}
  135. fi
  136. }
  137. function backup_states() {
  138. if [ ! -r ${BACKUP_STATE_FILE} ]; then
  139. cp ${SYS_PP_OD_CLK} ${BACKUP_STATE_FILE}
  140. if [ "${PWR_LEVEL}" == "manual" ]; then
  141. echo "FORCE_POWER_PROFILE: 0" >> ${BACKUP_STATE_FILE}
  142. fi
  143. echo "FORCE_PERF_LEVEL: $(cat ${PWR_LEVEL})" >> ${BACKUP_STATE_FILE}
  144. echo "FORCE_POWER_CAP: $(cat ${PWR_CAP_FILE})" >> ${BACKUP_STATE_FILE}
  145. echo "Writen initial backup states to ${BACKUP_STATE_FILE}"
  146. else
  147. echo "Won't write initial state to ${BACKUP_STATE_FILE}, it already exists."
  148. fi
  149. }
  150. function restore_states() {
  151. if [ -f ${BACKUP_STATE_FILE} ]; then
  152. echo "Restoring all states to the initial defaults from ${BACKUP_STATE_FILE}"
  153. USER_STATE_FILE=${BACKUP_STATE_FILE}
  154. else
  155. echo "Cant't access initial defaults at ${BACKUP_STATE_FILE}, aborting."
  156. exit 2
  157. fi
  158. }
  159. check_ppfeaturemask
  160. for USER_STATE_FILE in $(ls -1 ${USER_STATES_PATH}*.card*); do
  161. BACKUP_STATE_FILE=/tmp/${USER_STATE_FILE##*/}.initial
  162. SYS_PP_OD_CLK=/sys/class/drm/${USER_STATE_FILE##*.}/device/pp_od_clk_voltage
  163. PWR_LEVEL=/sys/class/drm/${USER_STATE_FILE##*.}/device/power_dpm_force_performance_level
  164. PWR_PROFILE=/sys/class/drm/${USER_STATE_FILE##*.}/device/pp_power_profile_mode
  165. SYS_DPM_SCLK=/sys/class/drm/${USER_STATE_FILE##*.}/device/pp_dpm_sclk
  166. SYS_DPM_MCLK=/sys/class/drm/${USER_STATE_FILE##*.}/device/pp_dpm_mclk
  167. HWMON_PATH=/sys/class/drm/${USER_STATE_FILE##*.}/device/hwmon
  168. HWMON_ID=$(ls -1 /sys/class/drm/${USER_STATE_FILE##*.}/device/hwmon)
  169. PWR_CAP_FILE=/sys/class/drm/${USER_STATE_FILE##*.}/device/hwmon/${HWMON_ID}/power1_cap
  170. if [ -f ${SYS_PP_OD_CLK} ]; then
  171. if [ "${RESTORE}" == "true" ]; then
  172. restore_states
  173. else
  174. backup_states
  175. fi
  176. echo "Detecting the state values at ${SYS_PP_OD_CLK}:"
  177. parse_states ${SYS_PP_OD_CLK}
  178. echo "Verifying user state values at ${USER_STATE_FILE}:"
  179. parse_states ${USER_STATE_FILE}
  180. echo "Committing custom states to ${SYS_PP_OD_CLK}:"
  181. set_custom_states
  182. echo " Done"
  183. else
  184. echo "WARNING: ${SYS_PP_OD_CLK} does not exist, skipping!"
  185. fi
  186. done