
これまで読んだことによると、「カーネルが割り込みを受け取ると、登録されたすべてのハンドラが呼び出されます」
私が知っている限り、各IRQに対して登録されたハンドラを見ることができ、登録されたハンドラはおおよそ次のような形式のコールバックを渡すドライバから来ることを/proc/interrupts
知っています。request_irq
irqreturn_t (*handler)(int, void *)
私が知っている限り、特定のIRQに関連する各割り込みハンドラコールバックは呼び出されなければならず、割り込みが実際に処理されるべきかどうかを判断するのはハンドラの役割です。ハンドラが特定の割り込みを処理しない場合は、カーネルマクロを返す必要がありますIRQ_NONE
。
私が理解できないのは、各ドライバが割り込みを処理する必要があるかどうかを判断する方法です。割り込みを待たなければならないなら、内部的に追跡できると思います。それでは、同じIRQの背後で割り込みを待っている複数のドライバの状況をどのように処理できるかわかりません。
私がこれらの詳細を理解しようとしている理由は、kexec
PCIeブリッジとダウンストリームPCIのリセットピンとさまざまなレジスタを扱い、システムの動作中にカーネルを再実行するメカニズムを台無しにしているからです。機器。これにより、再起動後にカーネルパニックが発生したり、何もしなかったとしても割り込みを受けたと文句を言う他のドライバが発生します。
ハンドラがどの割り込みを処理すべきかを決定する方法はミステリーです。
編集:関連する場合、問題のCPUアーキテクチャはx86
。
答え1
この内容は次のとおりです。第10章~のLinuxデバイスドライバ、第3版、Corbet et al。無料でオンライン、またはできますO'Reilly方式で新シェケルを投資する。死んだ木や電子ブック形式の場合。あなたの質問に関するセクションは、最初のリンクの278ページから始まります。
それに価値があるものについてGoogleが見つけた他のものと一緒に、次の3ページの私の試みは次のとおりです。
共有IRQハンドラを登録すると、カーネルは次のことを確認します。
ㅏ。この割り込みに対する他のハンドラは存在しません。
b。以前に登録されたすべて返品共有中止リクエスト
dev_id
どちらの場合も、適用される場合は、カーネルがたとえばハンドラの削除中に複数のハンドラを区別できるように、パラメータが一意であることを確認してください。
- PCI1ハードウェアデバイスがIRQラインを発行すると、カーネルの低レベル割り込みハンドラが呼び出され、順番にみんな登録された割り込みハンドラは、各リターンを
dev_id
登録されたハンドラに渡しますrequest_irq()
。
値dev_id
はシステムごとに一意でなければなりません。一般的なアプローチは、struct
ドライバがデバイスを管理するために使用する各デバイスにポインタを渡すことです。このポインタは、ドライバに役立つドライバのメモリ空間内にある必要があるためそれ自体このドライバに固有です。 ²
特定の割り込みに対して複数のドライバが登録されている場合みんな電話したときどのデバイスは共有割り込みラインを発生させます。ドライバ以外のデバイスがこれを行う場合、ドライバの割り込みハンドラはそれを検出してIRQ_NONE
すぐに返す必要があります。
別の状況は、ドライバが複数のデバイスを管理していることです。ドライバの割り込みハンドラを使用して、ポーリングするdev_id
デバイスを決定する必要があります。
コベットの例他。指定されたPCパラレルポートのポート。割り込みラインを指定すると、最初のデバイスレジスタで最も高いビットもセットされます。 (つまりinb(0x378) & 0x80 == true
、標準I / Oポート番号を想定しています。)ハンドラがそれを検出した場合は、それを実行してからI / Oポートから読み取った値を最上位ポートに書き戻してIRQを消去する必要があります。少しクリア。
特別な特別なメカニズムは見えません。さまざまなハードウェアデバイスは、さまざまなメカニズムを選択できます。唯一の重要なことは、デバイスが共有割り込みを許可するには、ドライバがこれを行う方法が必要であることです。読むデバイスの割り込み状態といくつかの方法明らか邪魔する特定のデバイスで使用されるメカニズムを理解するには、デバイスのデータシートまたはプログラミングマニュアルをお読みください。
- 割り込みハンドラがカーネルに割り込みを処理したことを知らせても、カーネルが同じ割り込みに登録されている別のハンドラを呼び出すのを防ぐことはできません。レベルトリガ割り込みを使用するときに割り込みラインを共有する場合、これは避けられません。
同時に、同じ割り込みラインをアサートする2つのデバイスを想像してください。 (または少なくとも時間が近すぎて、カーネルがラインをクリアするために割り込みハンドラを呼び出す時間がないので、2番目の主張を別々に扱います)。します。関連ハードウェアを照会して、注意が必要かどうかを確認します。特定の割り込みに対して、2つの異なるドライバが同じハンドラリストから割り込みを正常に処理する可能性が非常に高いです。
したがって、ドライバは、割り込みハンドラが返される前に割り込みアサーションをクリアしようとしていることをデバイスに知らせる必要があります。そうでなければ何が起こるのかわかりません。継続的にアサートされた割り込みラインは、カーネルが共有割り込みハンドラを引き続き呼び出すか、カーネルが新しい割り込みを表示する機能をブロックするため、ハンドラは呼び出されません。どちらにしても災いです。
脚注:
上記の内容はすべて想定しているため、上記でPCIを指定しました。レベルがトリガーされました元のPCI仕様で使用されていた割り込み。 ISAの使用エッジトリガーこれは、せいぜい共有をトリッキーにし、ハードウェアがそれをサポートしている場合にのみ可能です。 PCIeの目的メッセージ信号割り込み:割り込みメッセージには、PCI割り込み共有に必要なループ推測ゲームを回避するためにカーネルが使用できる固有の値が含まれています。 PCIe を使用すると、割り込み共有が不要になる場合があります。 (実際にはそんなことはわかりませんが、潜在力があるというだけです。)
Linuxカーネルドライバはすべて同じメモリスペースを共有しますが、関連していないドライバは他のドライバのメモリスペースを乱すべきではありません。そのポインタを渡さない限り、他のドライバが誤って自分自身で同じ値を提示しないと確信できます。
答え2
ドライバが共有IRQを要求すると、ドライバはカーネルへのポインタとドライバメモリ空間内のデバイス固有の構造への参照を渡します。
LDD3によると:
複数のドライバが割り込みラインを共有し、ハードウェアがそのライン上のプロセッサを割り込むたびに、カーネルはその割り込みに登録されている各ハンドラを呼び出し、各ハンドラに独自の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
サービスが必要な割り込みがあるかどうかを確認するためにレジスタを読み取ります。
intmask = sdhci_readl(host, SDHCI_INT_STATUS);
if (!intmask || intmask == 0xffffffff) {
result = IRQ_NONE;
goto out;
}
前の例のように、ドライバはステータスレジスタをチェックしてSDHCI_INT_STATUS
割り込みを処理する必要があるかどうかを判断します。
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;
別の例を挙げましょう。
答え3
これを確認するには訪問してください協会:
メモリマップされたレジスタでIRQステータスを確認した後にのみ、IRQハンドラの下半分または他のロジックをトリガするのが一般的な方法です。したがって、この問題は基本的に良いプログラマーによって解決されます。