SH7760_kernel-2.6.15_sh-sci不具合詳細

CAT760向けの linux-2.6.15 カーネルに含まれる、SH内蔵シリアルドライバの不具合詳細について。

  • 対象機種
    • SH7760、SH7780、SH7785搭載ボード全部(シリコンリナックス社 CAT760含む)
  • 対象カーネル
    • 一般的な sh-linuxカーネル 2008年3月リリース以前 (linux-2.6.24)まで
    • シリコンリナックス社 CAT開発CDROM では linux-2.6.15 2008年2月以前のリリース版まで全部
  • 対策版
    • 一般的な sh-linuxカーネル linux-2.6.25 で対策完了
    • シリコンリナックス社 linux-2.6.15-cat_2008年3月6日版で修正完了
  • 現象
    • 以下のシーケンスでカーネルが停止しリセット以外で復旧しない
  1. /dev/ttySC* (内蔵シリアルch0, ch1, ch2のいずれか)を open()する
  2. close()する
  3. close した後に、誰もopen()していない状態で128バイト以上のキャラクタを受信する
  4. 再びopen()した瞬間に受信割り込みがかかりっぱなしとなりカーネルが停止する

追加コメント

  • ttySC0は通常はコンソールとしてopenしっぱなしで close() しませんから問題は起きません。
  • ttySC1,ttySC2を openし、closeしないタイプの組み込みアプリケーションであれば問題は起きません。
  • ttySC1,ttySC2を openするアプリケーションが不正終了した場合でも、すぐに再起動するスクリプトが組まれていれば、
    不正終了〜再起動 の時間内に、相手方機器から送られるデータが127バイト以下であれば問題は起きません。
  • SH3(CAT709)では問題は起こりません。

簡単な確認方法

SH7760, SH7780, SH7785 搭載機で、ttySC1で実験するとして
ボーレートを設定する(例:9600bpsの場合)

# stty -F /dev/ttySC1 9600

ttySC1 に何か書き込み

# echo A > /dev/ttySC1             open(),write(),close()発生

外部機器から ttySC1 に128バイト以上のデータを送る。
そのあと再び ttySC1 に何か書き込む

# echo A > /dev/ttySC1             open()した瞬間にフリーズする (?)

対策

カーネル 2008年3月6日版で修正 しましたので新しいカーネルと差し替えてください。ファイル名 (linux-2.6.15-cat_20080306.tgz) → 26環境_CDROM履歴

ユーザ様独自のカスタムカーネルを使っている場合は、以下の2行(2か所 0x7f→0xff)を修正してください。

パッチ

--- linux-2.6.15-cat/drivers/serial/sh-sci.c-old	2008-03-06 18:49:48.578617912 +0900
+++ linux-2.6.15-cat/drivers/serial/sh-sci.c	2008-03-06 18:49:30.344685381 +0900
@@ -431,7 +431,7 @@
 #if !defined(SCI_ONLY)
 	if (port->type == PORT_SCIF) {
 #if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
-		txroom = SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f);
+		txroom = SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff);
 #else
 		txroom = SCIF_TXROOM_MAX - (sci_in(port, SCFDR)>>8);
 #endif
@@ -503,7 +503,7 @@
 #if !defined(SCI_ONLY)
 		if (port->type == PORT_SCIF) {
 #if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
-			count = sci_in(port, SCRFDR) & 0x7f;
+			count = sci_in(port, SCRFDR) & 0xff;
 #else
 			count = sci_in(port, SCFDR)&SCIF_RFDC_MASK ;
 #endif

原因

知りたい人向けです。

linux-2.6.15 に含まれる SH内蔵シリアルポートドライバの SH7760, SH7780版のソフトウェアミス。誰が書いたかはわかりません。

  1. SH7760には各チャンネル受送信それぞれ128段のハードウェアFIFOが内蔵されている。
  2. デバイスがopenされるまではシリアルポートは非活性化(動かない)されている。
  3. デバイスがopenされると受送信動作を開始する。
  4. open中は割り込みがかかるので 128段の受信FIFOがオーバーフローすることはない。
  5. closeすると割り込みが停止する。
  6. close中に受信したデータは(リードするプロセスもないので)ハードウェアFIFOに溜まる→(海老原コメント:ここに問題がある。close中は受信がディセイブルになっているべき)
  7. ハードウェアFIFOに128バイト以上のデータが溜まると 受信FIFOデータ数レジスタ SCRFDR が 128 (0x80)までカウントアップする
  8. 再びデバイスがopenされると割り込みが活性化し、FIFOにデータがあるので受信割り込みが発生する
  9. ドライバ中で SCRFDR & 0x7F 処理を行っていたため、受信データ数を0としてしまう
  10. したがってデータを受信せずに割り込みを終了するので割り込みがかかりっぱなしになる

今 ftp.kernel.org に上がっている最新の 2.6.24 カーネルを見てみましたが、同じようになってます。。。
linux-2.6.24/drivers/serial/sh-sci.c

static inline int scif_rxroom(struct uart_port *port)
{
        return sci_in(port, SCRFDR) & 0x7f;
}

再現試験やりましたけど再現しますね。パッチ送らないと。
本家にパッチ送りました。2.6.25 で取り込まれるようです。

[GIT PULL] sh updates for 2.6.25-rc7

Please pull from:

	master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6.25.git

Which contains:

Franck Bui-Huu (1):
      sh: Use relative paths for mach/cpu symlinks.

Kieran Bingham (1):
      sh: Fix up the address error exception handler for SH-2.

Paul Mundt (3):
      sh: Fix up the timer IRQ definition for SH7203.
       sh: Fix uImage build error.
     sh: Fix more user header breakage from sh64 integration.

Robert P. J. Day (1):
      SH: Use newer, non-deprecated __SPIN_LOCK_UNLOCKED macro.

Yutaro Ebihara (1):
      serial: sh-sci: Fix fifo stall on SH7760/SH7780/SH7785 SCIF.

関連

関連自動リンク