Coelacanth's Dream

AMDGPUドライバーに SMU 13.0.5 のサポートを追加するパッチ

AMDGPUドライバーに SMU (System Management Unit) 13.0.5 のサポートを追加するパッチが、amd-gfxメーリングリストにて公開されている。
SMU 13.0.5 では、Yellow Carp (Rembrandt) に採用されている SMU 13.0.{1,3} とは別の電力管理テーブル、インターフェイスを用いる。
最近では SMU 13.0.8 のサポートを追加するパッチも公開されているが、機能的には SMU 13.0.{1,3} と共通としている。1

Index

SMU 13.0.5

まず、SMU 13.0.5 は以下引用部から、APU に採用されることを想定した IPブロックとされる。
だが、他 APU の SMU とは違う部分がいくつか見られる。

 +void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu)
 +{
 +	smu->ppt_funcs = &smu_v13_0_5_ppt_funcs;
 +	smu->message_map = smu_v13_0_5_message_map;
 +	smu->feature_map = smu_v13_0_5_feature_mask_map;
 +	smu->table_map = smu_v13_0_5_table_map;
 +	smu->is_apu = true;
 +}

SmartShift をサポートせず?

パッチでは、SMU 13.0.5 は SmartShift用のインターフェイスをサポートしないとしている。

SmartShift は APU と dGPU を組み合わせたプラットフォーム向けの機能であり、全体での消費電力枠をワークロードに応じて APU, dGPU に適切に割り振ることで性能を最適化する。
Linux Kernel における AMDGPUドライバーでは、SamrtShift のバイアスを変更するためのインターフェイスと、SmartShift下で APU, dGPU がどれだけ電力枠を使っているかを出力するインターフェイスが実装されている。
AMD Smart Shift への対応を進める Linux AMDGPU ドライバー | Coelacanth’s Dream

SMU 12.0.{1,2} を採用する Renoir, Lucienne, Green Sardine (Cezanne), Barcelo APU 、SMU 13.0.{1,3} を採用する Yellow Carp (Rembrandt) APU ではサポートされており、SMU 13.0.5 ではそこから削除した形となっている。
後のパッチで削除されているが、元から #if 0 .. #endif マクロで無効化されていた部分であり、最初から SmartShift をサポートしないことは明確に決まっていたのかもしれない。

 -#if 0
 -	case METRICS_SS_APU_SHARE:
 -		/* return the percentage of APU power with respect to APU's power limit.
 -		 * percentage is reported, this isn't boost value. Smartshift power
 -		 * boost/shift is only when the percentage is more than 100.
 -		 */
 -		if (metrics->StapmOpnLimit > 0)
 -			*value =  (metrics->ApuPower * 100) / metrics->StapmOpnLimit;
 -		else
 -			*value = 0;
 -		break;
 -	case METRICS_SS_DGPU_SHARE:
 -		/* return the percentage of dGPU power with respect to dGPU's power limit.
 -		 * percentage is reported, this isn't boost value. Smartshift power
 -		 * boost/shift is only when the percentage is more than 100.
 -		 */
 -		if ((metrics->dGpuPower > 0) &&
 -		    (metrics->StapmCurrentLimit > metrics->StapmOpnLimit))
 -			*value = (metrics->dGpuPower * 100) /
 -				  (metrics->StapmCurrentLimit - metrics->StapmOpnLimit);
 -		else
 -			*value = 0;
 -		break;
 -#endif

CPU, L3キャッシュ

APU に採用される SMU には CPUコア、L3キャッシュのクロック、消費電力、温度用の値がテーブル内に用意されているが、SMU 13.0.5 では現時点で当該部をコメントアウトしている。
この部分から Yellow Caro (Rembrandt) は 8-Core, L3キャッシュ 1基、VanGogh (Aerith) は 4-Core, L3キャッシュ 1基ということを読み取ることが可能だった。

SMU 13.0.5 がここで用いている構造体 (struct) gpu_metrics_v2_1 は、8-Core、L3キャッシュ 2基までを想定している。2
そのため、SMU 13.0.5 を採用する APU ではそれに収まらないか、先の SmartShift のことと合わせて、CPU部周りのセンサーをサポートしていないことが考えられる。

 +	/*
 +	memcpy(&gpu_metrics->temperature_core[0],
 +		&metrics.CoreTemperature[0],
 +		sizeof(uint16_t) * 8);
 +	gpu_metrics->temperature_l3[0] = metrics.L3Temperature;
 +	*/

GPUクロック

SMU_13_0_5_UMD_PSTATE_GFXCLK 1100 というマクロが追加されているが、これは中間的な仮の GPUクロックを示していると思われる。

  #define __SMU_V13_0_5_PPT_H__
	
  extern void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu);
 +#define SMU_13_0_5_UMD_PSTATE_GFXCLK   1100
	
  #endif

SMU_13_0_5_UMD_PSTATE_GFXCLK は以下引用部で使われている。
変数 i は GPUクロックのレベル、cur_value はクロックを読み取った時点でのクロックを示していると思われる。
変数 i が設定された最大 GPUクロックに一致する場合は 2、最小 GPUクロックに一致する場合は 0 が、それ以外の場合は 1 が代入され、それを元に現在のクロックレベルを示す * を追加で出力する。

 +	case SMU_GFXCLK:
 +	case SMU_SCLK:
 +		ret = smu_v13_0_5_get_current_clk_freq(smu, clk_type, &cur_value);
 +		if (ret)
 +			goto print_clk_out;
 +		min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
 +		max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
 +		if (cur_value  == max)
 +			i = 2;
 +		else if (cur_value == min)
 +			i = 0;
 +		else
 +			i = 1;
 +		size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min,
 +				i == 0 ? "*" : "");
 +		size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
 +				i == 1 ? cur_value : SMU_13_0_5_UMD_PSTATE_GFXCLK,
 +				i == 1 ? "*" : "");
 +		size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max,
 +				i == 2 ? "*" : "");
 +		break;

i == 1 の場合、つまりは現在の GPUクロックが最小でも最大でもない場合、クロックレベル 1: には、現在の GPUクロックがそのまま出力される。
そして SMU_13_0_5_UMD_PSTATE_GFXCLK は、三項演算子であるから、i == 1 でない場合、GPUクロックが最小か最大の状態にあるときに出力される。
現在の GPUクロックが最小か最大の場合に使われる値であるため、実際の GPUクロックの範囲内にあるかはチェックされず、またその必要もない。
以上のことから、中間的な、それっぽい仮の GPUクロックが 1100 (MHz) ということと思われる。

  +		size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
  +				i == 1 ? cur_value : SMU_13_0_5_UMD_PSTATE_GFXCLK,
  +				i == 1 ? "*" : "");

同様の値は Yellow Carp (Rembrandt)VanGogh (Aerith) にも用意されているが、どちらも SMU 13.0.5 と同じ 1100 (MHz) に設定されており、単にドライバー開発者が決めている仮クロックとも考えられる。3 4

 /* UMD PState Vangogh Msg Parameters in MHz */
 #define VANGOGH_UMD_PSTATE_STANDARD_GFXCLK       1100
 #define VANGOGH_UMD_PSTATE_STANDARD_SOCCLK       600
 #define VANGOGH_UMD_PSTATE_STANDARD_FCLK         800
 #define VANGOGH_UMD_PSTATE_STANDARD_VCLK         705
 #define VANGOGH_UMD_PSTATE_STANDARD_DCLK         600