[Suzaku:01828] Linuxの割り込みでハンドラがリソースを占有
Nobuaki Sugishima
email@hidden
2010年 7月 1日 (木) 04:21:52 JST
杉島と申します。
Linuxで割り込みに関するデバイスドライバが不調です。
Linuxドライバを深く勉強していないので解決策が見つかりません。横着ではありますがご教示いただければ幸いです。
まずEDKの段階では割り込みは正常に動作しています。割り込み源は繰り返し10Hzのタイマーです。
それから通常のIOに関してはキャラクタ型デバイスドライバは正常に動作しています。
1.割り込みハンドラはいたって簡単です
static irqreturn_t
my_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
printk("%s %x\n", "INT NO", int_count);
int_count++;
return IRQ_HANDLED;
}
2.メイン側プログラム
while(1)
{
スイッチセンスと処理
printf("%s %x\n", "INP_Loop", inp);
}
3.不具合の現象 : 割り込みはかかるがハンドラがリソースを占有、メインプログラム側にコントロールが戻らない
動作開始
INP_Loop ****
ここで割り込みタイマ開始のスイッチをON
INT NO 0 # 最初の割り込みが入った
INT NO 1 # 2番目の割り込み
INT NO 2
INT NO 3
INT NO 4
INT NO 5
INT NO 6
・・・・・・・・
・・・・・・・・
が無限に繰り返され、スイッチセンスのプログラムは動作しません。ただし割り込みが毎回かかっているのは間違いなさそうです。
結局割り込みドライバ(ハンドラ)がリソースを占有してしまったとみなしました。
printk();の実行が極端に遅いことも考えられ、省くつまり
return IRQ_HANDLED;
だけでも確認したのですが現象は同じです。
4.割り込みハンドラの宣言。
通常IOデバイスドライバと同居し、Initialize時にハンドラを宣言しています:
static int __init my_init_module(void)
{
int ret;
int_count = 0; // Debug用
pr_info(DEV_NAME" ("DEV_VER") : MY Driver of MY I/O Board\n");
sema_init(&sem, 1);
my_addr = (u32 *)ioremap_nocache(XPAR_MY_CNTLR_BASEADDR,
XPAR_MY_CNTLR_REMAP_SIZE);
if (my_addr == NULL) {
printk(KERN_ERR "ioremap failed\n");
return -EIO;
}
ret = register_chrdev(DEV_MAJOR, DEV_NAME, &my_fops); // Driver
info.registered to kurnel table
if (ret < 0) {
iounmap(my_addr);
return ret;
}
// 割り込み要求の登録 my_interrupt : 割り込みハンドラ IRQF_DISABLED: 多重割り込み禁止?
ret = request_irq(irq, my_interrupt, IRQF_DISABLED, DEV_NAME, dev_id);
if (ret)
printk(KERN_ERR "my_interrupt failed\n");
return ret;
}
5. interrupt_init(); の実行
割り込みEnable、マスクセット、例外処理に関する事前の設定が必要ですが、上記ルーティンをLinuxに組み込むには複雑な手続きが必要なので、Bootプログラムに含めて実行するようにしてしまいました。
つまりLinux起動時は割り込みEnableになっています。割り込みのコントロールは割り込み源のON/OFFで行っています。
interrupt_init(); のなかにはtimer割り込みに関する指定があり、EDKの段階ではこの中のslot();にあたる部分を書き換えて実行、これで動作していました。今回はslot();にあたる部分は省いています。つまり同じ種類の割り込み指定が行われてしまっています。しかし、
Linuxのなかでドライバ初期化時にrequest_irqによりベクトルテーブルは上書きされるはずなのでこれで問題ないと判断しました。事実割り込みはかかっています。
6.『占有』を回避する試み
ハンドラがリソースを独占、という解釈は正しいのか分かりませんが、上記のような現象なので回避の検討をしました。
調査した範囲では、ハンドラはReturnする前にSleep状態にしないとリソースを解放しないらしいです。
そこでWakeUpのため
if (waitqueue_active(&my_wait))
wake_up(&my_wait);
を処理に先立って入れました。
my_waitはコンパイル段階で
static DECLARE_WAIT_QUEUE_HEAD(my_wait);
により取得しています。
処理
printk("%s %x\n", "INT NO", int_count);
int_count++;
の後、何を記述すればいいのか分かりません。
Sleep_onというCommandがあるようですが、これはハンドラ中に記述してはいけないそうです。
wait_event_interruptible(my_wait, 0);
というCommandも試みたのですがStackに関するエラーが出ます。
過去LOGには本件に関するものはないようです。私だけに生じた現象あるいは単純ミスなのかご指摘いただければ幸いです。
suzaku メーリングリストの案内