Linuxカーネルは共有IRQをどのように処理しますか?


14

これまでに読んだことによると、「カーネルが割り込みを受け取ると、登録されているすべてのハンドラーが呼び出されます」。

各IRQの登録済みハンドラーはを介して表示できることを/proc/interrupts理解しています。また、登録済みハンドラーrequest_irqは、おおよそ次の形式のコールバックの受け渡しを呼び出したドライバーからのものであることも理解しています。

irqreturn_t (*handler)(int, void *)

私が知っていることに基づいて、特定のIRQに関連付けられたこれらの割り込みハンドラーコールバックのそれぞれを呼び出す必要があり、割り込みを実際に処理するかどうかを決定するのはハンドラー次第です。ハンドラーが特定の割り込みを処理しない場合、カーネルマクロを返す必要がありますIRQ_NONE

私が理解できない問題は、各ドライバーが割り込みを処理する必要があるかどうかをどのように判断するかです。割り込みを想定している場合、内部的に追跡できると思います。もしそうなら、同じIRQの背後にある複数のドライバーが割り込みを予期している状況にどのように対処できるかわかりません。

これらの詳細を理解しようとする理由はkexec、PCIeブリッ​​ジとダウンストリームPCIのリセットピンとさまざまなレジスタで遊んでいる間にシステム操作の途中でカーネルを再実行するメカニズムをいじっているからです。端末。そうすることで、再起動後にカーネルパニックが発生するか、他のドライバーが操作を行っていなくても割り込みを受け取っていると不平を言っています。

ハンドラーが割り込みを処理する必要があると判断した方法は謎です。

編集:関連する場合、問題のCPUアーキテクチャはx86です。


1
stackoverflow.com/questions/14371513/for-a-shared-interrupt-line-how-do-i-find-which-interrupt-handler-to-usec
Ciro Santilli新疆改造中心法轮功六四事件

回答:


14

これは、中に覆われている第10章Linuxデバイスドライバコーベットらによって、第3版。オンラインで無料で利用できます。または、 O'Reillyの方法で枯れ木や電子書籍のフォームを。質問に関連する部分は、278ページの最初のリンクから始まります。

価値のあるものとして、これらの3つのページを言い換えると、Googleで調べた他のビットを言い換える試みがあります。

  • 共有IRQハンドラを登録すると、カーネルは次のいずれかをチェックします。

    a。その割り込みに他のハンドラーが存在しない、または

    b。以前に登録したものすべて割り込み共有を要求しました

    どちらかの場合が当てはまる場合dev_id、カーネルが複数のハンドラーを区別できるように、たとえばハンドラーの削除中に、パラメーターが一意であることを確認します。

  • PCI¹ハードウェアデバイスがIRQラインを上げると、カーネルの低レベル割り込みハンドラーが呼び出され、登録されたすべての割り込みハンドラーを呼び出しdev_id、ハンドラーを登録するために使用した各ハンドラーを返します。request_irq()

    dev_id値は、マシン固有である必要があり。これを行う一般的な方法はstruct、ドライバーがそのデバイスを管理するために使用するデバイスごとにポインターを渡すことです。このポインターは、ドライバーにとって有用であるためにドライバーのメモリ空間内にある必要があるため、そのドライバーに事実上一意です。²

    特定の割り込みに対して複数のドライバが登録されている場合、デバイスのいずれかがその共有割り込みラインを発生させると、それらはすべて呼び出されます。これを行ったのがドライバーのデバイスではなかった場合、ドライバーの割り込みハンドラーには、それに属していない値が渡されます。これが発生すると、ドライバーの割り込みハンドラーはすぐに戻る必要があります。dev_id

    別のケースは、ドライバーが複数のデバイスを管理していることです。ドライバーの割り込みハンドラーはdev_id、ドライバーが認識している値の1つを取得します。コードは各デバイスをポーリングして、どのデバイスが割り込みを発生させたかを調べることになっています。

    例Corbet et al。giveは、PCパラレルポートのものです。割り込みラインをアサートすると、最初のデバイスレジスタの最上位ビットも設定します。(つまり、inb(0x378) & 0x80 == true標準のI / Oポート番号付けを想定しています。)ハンドラーがこれを検出すると、ハンドラーは処理を実行し、I / Oポートから読み取った値を先頭のポートに書き戻すことでIRQをクリアします。ビットがクリアされました。

    特定のメカニズムが特別である理由はわかりません。別のハードウェアデバイスが別のメカニズムを選択できます。唯一重要なことは、デバイスが共有割り込みを許可するには、ドライバーがデバイスの割り込みステータスを読み取るための何らかの方法と、割り込みをクリアするための何らかの方法が必要であるということです。特定のデバイスが使用するメカニズムを調べるには、デバイスのデータシートまたはプログラミングマニュアルを読む必要があります。

  • 割り込みハンドラーが割り込みを処理したことをカーネルに伝えても、カーネルが同じ割り込みに登録されている他のハンドラーの呼び出しを停止することはありません。レベルトリガー割り込みを使用するときに割り込みラインを共有する場合、これは避けられません。

    2つのデバイスが同じ割り込みラインを同時にアサートすることを想像してください。(または、少なくとも、カーネルが割り込みハンドラーを呼び出して行をクリアする時間がないため、カーネルは2番目のアサーションを個別と見なします。)カーネルは、その割り込み行のすべてのハンドラーを呼び出して、関連するハードウェアを照会して、注意が必要かどうかを確認する機会。2つの異なるドライバーが、特定の割り込みのハンドラーリストの同じパス内で割り込みを正常に処理することは可能です。

    このため、ドライバーは、割り込みハンドラーが戻る前に、割り込みアサーションをクリアすることを管理しているデバイスにデバイスに通知することが不可欠です。さもなければ何が起こるかは私には明らかではありません。連続的にアサートされた割り込みラインは、カーネルが共有割り込みハンドラーを継続的に呼び出すか、ハンドラーが呼び出されないように新しい割り込みを確認するカーネルの能力をマスクします。どちらにしても、災害。


脚注:

  1. 上記のすべてのPCIは、元のPCI仕様で使用されているレベルトリガー割り込みを想定しているため、上記のPCIを指定しました。ISAはエッジトリガー割り込みを使用しました。これにより、ハードウェアでサポートされている場合にのみ共有が困難になります。PCIeはメッセージ信号割り込みを使用します。割り込みメッセージには、PCI割り込み共有に必要なラウンドロビン推測ゲームを回避するためにカーネルが使用できる一意の値が含まれています。PCIeは、割り込み共有の必要性を完全に排除する可能性があります。(実際に機能するかどうかはわかりませんが、可能性があるというだけです。)

  2. Linuxカーネルドライバーはすべて同じメモリスペースを共有しますが、無関係なドライバーが他のドライバーのメモリスペースをいじっていることは想定されていません。そのポインターを渡さない限り、別のドライバーが同じ値を偶然に偶然思いつかないことを確信できます。


1
あなたが述べたように、割り込みハンドラはdev_idそれが所有していないものを渡されるかもしれません。私には、dev_id構造を所有していないドライバーが、内容を解釈する方法に基づいて、構造を自分のものと間違える可能性がゼロではないようです。そうでない場合、どのメカニズムがこれを防止しますか?
bsirang

dev_idドライバーのメモリ空間内の何かへのポインターを作成することにより、それを防ぎます。別のドライバは、可能性が作るdev_id価値が起こったドライバが所有しているメモリへのポインタと混同しやすいようにし、それは誰もがルールで再生されているために起こることはないだろう。これはカーネル空間です。覚えておいてください。禁止されていないものはすべて許可されていると思い込んでいるユーザー空間コードとは異なり、自己規律は当然のこととして想定されています。
ウォーレンヤング

LDD3の章の10によると:「2つの以上のドライバが割り込みラインとハードウェア割り込み、そのライン上のプロセッサを共有しているときはいつでも、カーネルはそれぞれ独自のなdev_idを渡して、その割り込みのために登録されているすべてのハンドラを呼び出す」それは、以前の理解のように思えます割り込みハンドラーがdev_id、それが所有していないものに渡される可能性があるかどうかに関して間違っていました。
bsirang

それは私の側の誤読でした。それを書いたとき、私は2つの概念を混同していました。回答を編集しました。割り込みハンドラーをすばやく返す必要がある条件は、管理していないデバイスによる割り込みのアサートによって呼び出されることです。の値は、dev_idこれが発生したかどうかを判断するのに役立ちません。ハードウェアに「鳴った?」と尋ねる必要があります。
ウォーレンヤング

はい、今、私がいじっていることは、カーネルを再起動した後、他のドライバーが実際にどのようにデバイスを「鳴った」と信じているかを理解する必要がありますkexec
bsirang

4

ドライバーは共有IRQを要求すると、カーネルのポインターをドライバーのメモリ空間内のデバイス固有の構造への参照に渡します。

LDD3によると:

2つ以上のドライバーが割り込みラインを共有し、ハードウェアがそのラインのプロセッサーに割り込みを行うたびに、カーネルはその割り込みに登録されているすべてのハンドラーを呼び出し、それぞれ独自のdev_idを渡します。

いくつかのドライバーのIRQハンドラーをチェックすると、割り込みまたはリターンを処理する必要があるかどうかを判断するために、ハードウェア自体をプローブしているようIRQ_NONEです。

UHCI-HCDドライバー
  status = inw(uhci->io_addr + USBSTS);
  if (!(status & ~USBSTS_HCH))  /* shared interrupt, not mine */
    return IRQ_NONE;

上記のコードでは、ドライバーは USBSTSレジスタをサービスへの割り込みがあるかどうかを判断しています。

SDHCIドライバー
  intmask = sdhci_readl(host, SDHCI_INT_STATUS);

  if (!intmask || intmask == 0xffffffff) {
    result = IRQ_NONE;
    goto out;
  }

前の例と同様に、ドライバーはステータスレジスタをチェックしています。 SDHCI_INT_STATUS割り込みを処理する必要があるかどうかを判断するために。

Ath5kドライバー
  struct ath5k_softc *sc = dev_id;
  struct ath5k_hw *ah = sc->ah;
  enum ath5k_int status;
  unsigned int counter = 1000;

  if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) ||
        !ath5k_hw_is_intr_pending(ah)))
    return IRQ_NONE;

もう1つの例です。


0

このリンクをチェックしてください

メモリマップされたレジスタからIRQステータスをチェックした後にのみ、IRQハンドラで下半分またはその他のロジックをトリガーする通常の方法です。したがって、問題はデフォルトで優秀なプログラマーによって解決されます。


リンクのコンテンツは利用できません
-user3405291
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.