MT7621SでOpenWrtが起動完了しない理由
2016年5月11日(水) 14:21 JST
閲覧数 3,047
何かで情報が流れているのを見た記憶はかすかにあるものの放置していたMT7621Sの問題。
今日、状況を真面目に見始めるまでは、MT7621全体で起きているのかと勘違いしていました。
どうやら実際には、MT7621Aでは発生せず、MT7621Sでのみ発生する模様。
(MT7621Sのボードがそもそも少ないので、手元で現象確認しているのはWSR-600DHPだが、現象からMT7621Sであれば発生すると思われる)
少しばかりソースを追いかけてみました。
ログを吐き出し続けている箇所から、arch/mips/kernel/smp-cps.cが該当。
arch/mips/kernel/smp-cps.c
しかし、存在しないコアの起きるのをひたすら待っていても起きてくる訳はない。
居ない彼女が何時まで待っても来ないのは当たり前である。
なぜ、居ない彼女を待つ様な状況が起きているのだろうか。
以下箇所のboot_core(core);で上記の箇所が呼び出されているのだが、その呼び出し判断基準のtest_bit(core, core_power)が入っている。
arch/mips/kernel/smp-cps.c
MT7621の場合、シングルコア(2スレッド)のMT7621Sであっても、デュアルコア(4スレッド)のMT7621AであってもCONFIG_NR_CPUSを4の状態でビルドを行う為、MT7621Sでは不要なコアについても対象となってしまっている。
しかし、存在するコア数を検出していれば問題は発生しない筈である。
arch/mips/kernel/smp-cps.c
この箇所で取得されている値が常に2となってしまっているのが問題を起こしている事になる。
(この箇所の期待する値は、スレッド数ではなく物理コア数なので、MT7621Aでは2、MT7621Sでは1を返す筈であるが、MT7621Sが2を返してくる。)
arch/mips/kernel/smp-cps.c
mips 1004kコアのGCR_CONFIGレジスタの下位8ビットに物理コア数情報が収められており、この値を使ってコア数検出としている。
ここで問題が起きている。
MT7621Sでも1が返ってきてしまう為、2コア存在すると判断してしまっている。
arch/mips/include/asm/mips-cm.h
こうなると、MT7621では別箇所からコア数を検出するしかなくなる。
せっかくなので、u-bootではどうなっているのかを確認してみる。
CHIP_REV_IDから判別可能な可能性が見られるが、#ifdef RALINK_DUAL_CORE_FUNしてしまっている事から、MT7621AとMT7621Sの判別はできない可能性もある。
このレジスタについては、後程確認予定。
この箇所で判別できない様であれば、寝ているコアか存在しないコアかの判別はできない可能性が高い。
cpu/ralink_soc/start_1004k.S
現状の暫定対策としては、MT7621Sで使用する場合は、CONFIG_NR_CPUS=2を入れてビルドするというのが有効。
OpenWrtに該当しそうなTicketsが見当たらないので、英訳して送っておこうとは考えている。
英語が得意ではないので、変な英訳になるのが心配。
今日、状況を真面目に見始めるまでは、MT7621全体で起きているのかと勘違いしていました。
どうやら実際には、MT7621Aでは発生せず、MT7621Sでのみ発生する模様。
(MT7621Sのボードがそもそも少ないので、手元で現象確認しているのはWSR-600DHPだが、現象からMT7621Sであれば発生すると思われる)
[ 0.200000] Waiting for core 1 to start... STAT_CONF=0x20404 [ 0.200000] Waiting for core 1 to start... STAT_CONF=0x20404 [ 0.200000] Waiting for core 1 to start... STAT_CONF=0x20404 [ 0.200000] Waiting for core 1 to start... STAT_CONF=0x20404 [ 0.200000] Waiting for core 1 to start... STAT_CONF=0x20404 [ 0.200000] Waiting for core 1 to start... STAT_CONF=0x20404この問題により、WSR-600DHPではOpenWrt trunkが使用できない訳ですが、問題自体はかなり前(すくなくとも4か月以上)から発生している模様。
少しばかりソースを追いかけてみました。
ログを吐き出し続けている箇所から、arch/mips/kernel/smp-cps.cが該当。
arch/mips/kernel/smp-cps.c
write_cpc_co_cmd(CPC_Cx_CMD_RESET); timeout = 100; while (true) { stat = read_cpc_co_stat_conf(); seq_state = stat & CPC_Cx_STAT_CONF_SEQSTATE_MSK; /* U6 == coherent execution, ie. the core is up */ if (seq_state == CPC_Cx_STAT_CONF_SEQSTATE_U6) break; /* Delay a little while before we start warning */ if (timeout) { timeout--; mdelay(10); continue; } pr_warn("Waiting for core %u to start... STAT_CONF=0x%x\n", core, stat); mdelay(1000); }何やら、マルチコアの眠っているコアを叩き起こして、起きてくるのを待っている模様。
しかし、存在しないコアの起きるのをひたすら待っていても起きてくる訳はない。
居ない彼女が何時まで待っても来ないのは当たり前である。
なぜ、居ない彼女を待つ様な状況が起きているのだろうか。
以下箇所のboot_core(core);で上記の箇所が呼び出されているのだが、その呼び出し判断基準のtest_bit(core, core_power)が入っている。
arch/mips/kernel/smp-cps.c
if (!test_bit(core, core_power)) { /* Boot a VPE on a powered down core */ boot_core(core); goto out; }core_powerは、NR_CPUSをそのまま入れている。
MT7621の場合、シングルコア(2スレッド)のMT7621Sであっても、デュアルコア(4スレッド)のMT7621AであってもCONFIG_NR_CPUSを4の状態でビルドを行う為、MT7621Sでは不要なコアについても対象となってしまっている。
しかし、存在するコア数を検出していれば問題は発生しない筈である。
arch/mips/kernel/smp-cps.c
static DECLARE_BITMAP(core_power, NR_CPUS);コア数を検出するコードは既に存在している。
この箇所で取得されている値が常に2となってしまっているのが問題を起こしている事になる。
(この箇所の期待する値は、スレッド数ではなく物理コア数なので、MT7621Aでは2、MT7621Sでは1を返す筈であるが、MT7621Sが2を返してくる。)
arch/mips/kernel/smp-cps.c
ncores = mips_cm_numcores();mips_cm_numcores()が何をしているのかを読み進める。
mips 1004kコアのGCR_CONFIGレジスタの下位8ビットに物理コア数情報が収められており、この値を使ってコア数検出としている。
ここで問題が起きている。
MT7621Sでも1が返ってきてしまう為、2コア存在すると判断してしまっている。
arch/mips/include/asm/mips-cm.h
/** * mips_cm_numcores - return the number of cores present in the system * * Returns the value of the PCORES field of the GCR_CONFIG register plus 1, or * zero if no Coherence Manager is present. */ static inline unsigned mips_cm_numcores(void) { if (!mips_cm_present()) return 0; return ((read_gcr_config() & CM_GCR_CONFIG_PCORES_MSK) >> CM_GCR_CONFIG_PCORES_SHF) + 1; }
こうなると、MT7621では別箇所からコア数を検出するしかなくなる。
せっかくなので、u-bootではどうなっているのかを確認してみる。
CHIP_REV_IDから判別可能な可能性が見られるが、#ifdef RALINK_DUAL_CORE_FUNしてしまっている事から、MT7621AとMT7621Sの判別はできない可能性もある。
このレジスタについては、後程確認予定。
この箇所で判別できない様であれば、寝ているコアか存在しないコアかの判別はできない可能性が高い。
cpu/ralink_soc/start_1004k.S
gcr_found: # Every vpe will set up the following to simplify resource initialization. li r22_gcr_addr, GCR_CONFIG lw r16_core_num, 0x2028(r22_gcr_addr) # Load GCR_CL_ID lw r4_temp_data, 0(r22_gcr_addr) # Load GCR_CONFIG #ifdef RALINK_DUAL_CORE_FUN li r5_temp_addr, RALINK_SYSCTL_BASE lw r4_temp_data, 0x000c(r5_temp_addr) #CHIP_REV_ID ext r19_more_cores, r4_temp_data, 17, 1 #else li r19_more_cores, 0 #endif
現状の暫定対策としては、MT7621Sで使用する場合は、CONFIG_NR_CPUS=2を入れてビルドするというのが有効。
OpenWrtに該当しそうなTicketsが見当たらないので、英訳して送っておこうとは考えている。
英語が得意ではないので、変な英訳になるのが心配。