このセクションでは主に次の問題を解決します: システムがスリープ状態に入ったときにデバイス割り込み (IRQ) を一時停止するにはどうすればよいですか?システムをウェイクアップするときにデバイスの IRQ を復元するにはどうすればよいですか?
通常、システムがスリープ状態に入ると、すべてのデバイスの IRQ (割り込み要求ライン) が無効になります。特定の時点は、デバイスの後期サスペンド フェーズの後です。以下に該当するコードを示します(関連しないコードは省略)。
#「」
static int stop_enter(suspend_state_t state, bool *wakeup){……
error = dpm_suspend_late(PMSG_SUSPEND);-----後期サスペンドフェーズ
error = platform_suspend_prepare_late(状態);
次のコードは各デバイスの IRQ を無効にします
error = dpm_suspend_noirq(PMSG_SUSPEND);——noirq 段階に入ります
error = platform_suspend_prepare_noirq(state);
……
}
」
#dpm_suspend_noirq 関数では、デバイスの noirq の場合にサスペンド コールバック関数を実行するために、システム内の各デバイスに対して device_suspend_noirq が順番に呼び出されます。もちろん、この前に、suspend_device_irqs 関数が呼び出され、デバイスの irq が無効になります。すべてのデバイス。
これを行う理由は次のとおりです。各デバイス ドライバーがレイト サスペンドを完了した後は、当然のことながら、サスペンドされたこれらのデバイスは割り込みをトリガーしないはずです。正しくサスペンドされていないデバイスがまだある場合、最善の戦略は、デバイスの IRQ をマスクして、割り込みが送信されないようにすることです。また、これまでのコード(割り込みハンドラ参照)では、IRQを共有するデバイスがうまく処理できず、IRQを共有するデバイスがサスペンドを完了した後、割り込みが発生するとデバイスが停止してしまうという問題がありました。ドライバは割り込みハンドラの準備ができていません。一部のシナリオでは、割り込みハンドラーが一時停止されたデバイスの IO アドレス空間にアクセスし、予期しない問題が発生します。これらの問題はデバッグが難しいため、suspend_device_irqs() とデバイス noirq ステージのコールバック関数を導入しました。
システム再開プロセス中、各デバイスの早期再開プロセスの前に、各デバイスの IRQ が再度オープンされます。具体的なコードは次のとおりです (一部の無関係なコードは削除されています):
#「」 static int stop_enter(suspend_state_t state, bool *wakeup)
{……platform_resume_noirq(state);---最初に noirq ステージの再開を実行します
dpm_resume_noirq(PMSG_RESUME);------ここで irq が復元され、初期再開段階に入ります
platform_resume_early(状態);
dpm_resume_early(PMSG_RESUME);
……}
」
#dpm_resume_noirq 関数では、各デバイス ドライバーの noirq コールバックが呼び出され、その後、resume_device_irqs 関数が呼び出され、各デバイス irq の有効化が完了します。
2. IRQF_NO_SUSPEND フラグについて
もちろん、一部の割り込みは、システム全体のサスペンド/レジューム プロセス中にトリガー可能にしておく必要があります (noirq ステージ、非ブート CPU をオフライン状態にプッシュし、システムの再開後にオンラインにリセットするステージを含む) . .簡単な例としては、IPI および一部の専用デバイス割り込みに加えて、タイマー割り込みがあります。
割り込みを要求する場合、IRQF_NO_SUSPEND フラグを使用して、この割り込みが前の段落で説明した種類の割り込みであること、つまりシステムのサスペンド/再開プロセス中に有効にしておく必要があることを IRQ サブシステムに通知できます。このフラグを使用すると、suspend_device_irqs は IRQ を無効にせず、後続のサスペンドおよび再開プロセス中に割り込みを有効のままにすることができます。もちろん、これは割り込みによってシステムがウェイクアップできることを保証するものではありません。ウェイクアップの目的を達成したい場合は、enable_irq_wake を呼び出してください。
IRQF_NO_SUSPEND フラグは、この IRQ を使用するすべてのペリフェラルに影響することに注意してください (IRQ は複数のペリフェラルで共有できますが、これは ARM では使用されません)。 IRQ が複数のペリフェラルによって共有され、各ペリフェラルが対応する割り込みハンドラを登録しており、そのうちの 1 つが割り込みを申請するときに IRQF_NO_SUSPEND フラグを使用する場合、システムがサスペンドされると (suspend_device_irqs 以降を参照)、次のようになります。各 IRQ が無効になっている理由)、request_irq (または他の割り込み登録関数) を呼び出すときに一部のデバイスが IRQF_NO_SUSPEND フラグを設定していない場合でも、IRQ 上のすべてのデバイスの割り込みハンドラーは正常にトリガーされ、実行できます。このため、2 つのフラグ IRQF_NO_SUSPEND と IRQF_SHARED を同時に使用することはできる限り避ける必要があります。
3. システム割り込みウェイクアップ インターフェイス:enable_irq_wake() および disable_irq_wake()
一部の割り込みは、システムをスリープ状態からウェイクアップできます。これを「システムをウェイクアップできる割り込み」と呼びます。もちろん、「システムをウェイクアップできる割り込み」は、システムをウェイクアップする機能を開始するように構成する必要があります。システム。このような割り込みは通常、動作状態では通常の I/O 割り込みとして表示されますが、ウェイクアップ システム機能を有効にする準備をしている場合にのみ、いくつかの特別な構成と設定が開始されます。
このような構成と設定は、ハードウェア システム (SOC など) の信号処理ロジックに関連している可能性があります。次のハードウェア ブロック図を考慮できます:
周辺割り込み信号は、「汎用割り込み信号処理モジュール」と「特定割り込み信号受信モジュール」に送信されます。通常動作時は「汎用割り込み信号処理モジュール」の処理ロジックをオンにし、「特定割り込み信号受信モジュール」の処理ロジックをオフにします。ただし、システムがスリープ状態に移行する際には、「汎用割り込み信号処理モジュール」がオフになっている可能性があり、このとき割り込み信号を受信するために「特定割り込み信号受信モジュール」を起動する必要があります。システムのサスペンド/レジューム モジュール (多くの場合、これはサスペンド状態で動作できる唯一の HW ブロックです) であり、通常は割り込み信号によってウェイクアップできます。ウェイクアップしたら、「特定の割り込み信号受信モジュール」をオフにして、ペリフェラルの割り込み処理を通常の動作モードに戻すことができると同時に、システムのサスペンド/レジューム モジュールへの不要な干渉も回避する必要があります。
IRQ サブシステムは、この機能を完了するために 2 つのインターフェイス関数を提供します:enable_irq_wake() 関数は、システム電源管理モジュール (つまり、上記のサスペンド/レジューム モジュール) につながるペリフェラル割り込みラインを開くために使用されます。インターフェイスは disable_irq_wake() で、ペリフェラル割り込みラインからシステム電源管理モジュールまでのパス上のさまざまな HW ブロックを閉じるために使用されます。
enable_irq_wake を呼び出すと、システムのサスペンド プロセスのサスペンド_device_irqs 処理に影響します。コードは次のとおりです:
#「」
静的ブールsuspend_device_irq(struct irq_desc *desc){
……
if (irqd_is_wakeup_set(&desc->irq_data)) {
irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED);
trueを返す;
}
無効割り込みコードを省略
}
」
#言い換えると、enable_irq_wake を呼び出してデバイスの割り込みをシステム サスペンドのウェイクアップ ソースとして設定すると、ペリフェラルの割り込みは無効になりませんが、IRQD_WAKEUP_ARMED マークが付けられます。ウェイクアップ ソースではない割り込みの場合、suspend_device_irq 関数で IRQS_SUSPENDED がマークされ、デバイスの IRQ が無効になります。システムウェイクアッププロセス (resume_device_irqs) 中に、無効になっていた割り込みが再び有効になります。
もちろん、サスペンド プロセス中に特定のイベントが発生し (たとえば、ウェイクアップ ソースが有効な信号を生成する)、このサスペンド アボートが発生した場合、このアボート イベントは PM コア モジュールにも通知されます。イベントは PM コア モジュールにすぐに通知する必要はありませんが、一般的に、サスペンド スレッドはある時点で保留中のウェイクアップ イベントを確認します。
システムのサスペンド プロセス中、ウェイクアップ ソースからの各割り込みにより、サスペンド プロセスが終了するか、システムがウェイクアップされます (システムがサスペンド状態に入っている場合)。ただし、suspend_device_irqs 実行後は通常の割り込みがブロックされるため、HW が割り込み信号をトリガしても、HW の割り込みハンドラは実行できません。ウェイクアップ ソースとしての IRQ はどうなりますか?その割り込みはマスクされていませんが、その割り込みハンドラーは実行されません (この時点の HW 信号はシステムをウェイクアップするためにのみ使用されます)。実行できる割り込みハンドラは、IRQF_NO_SUSPEND フラグが付いている IRQ だけです。これは、割り込みが常に有効になっているためです。もちろん、これらの割り込みは、ウェイクアップ ソースを設定するためにenable_irq_wakeを呼び出してはなりません。
4. 割り込みとアイドル状態へのサスペンド
サスペンドからアイドル状態 (「フリーズ」状態とも呼ばれます) は、比較的新しいシステム電源管理状態です。関連するコードは次のとおりです:
#「」
static int stop_enter(suspend_state_t state, bool *wakeup){
……
各デバイスの後期サスペンドフェーズ
各デバイスのnoirqサスペンドフェーズ
if (状態 == PM_SUSPEND_FREEZE) {
freeze_enter();
プラットフォームウェイクに移動;
}
……
}
」
#以前のフリーズとサスペンドの操作は基本的に同じです: 最初にシステム内のプロセスをフリーズし、次にシステム内のさまざまなデバイスをサスペンドします。違いは、noirq サスペンドが完了した後、フリーズは非プロセッサーを無効にしないことです。 BSP プロセッサと syscore の一時停止フェーズですが、freeze_enter 関数を呼び出してすべてのプロセッサをアイドル状態にプッシュします。現時点では、有効な割り込みによってシステムがウェイクアップされる可能性があります。これは、これらのフラグ IRQF_NO_SUSPEND (その IRQ は、suspend_device_irqs プロセス中にマスクされない) がプロセッサをアイドル状態からウェイクアップできることを意味します (ただし、この信号はシステム ウェイクアップ信号をトリガーしないことに注意してください)。通常の割り込みは、IRQ が無効になっているため、アイドル状態のプロセッサをウェイクアップできません。
システムをウェイクアップできるウェイクアップ割り込みについてはどうですか?割り込みはマスクされないため、システムはサスペンドからアイドル状態からウェイクアップすることもできます。システムをサスペンド状態からウェイクアップするプロセス全体は同じですが、唯一の違いは、システムをフリーズ状態からウェイクアップするための割り込み処理パスと、システムをサスペンド状態からウェイクアップするためのウェイクアップ処理パスです。特殊な電源管理 HW ブロックが必要 割り込み処理ロジックへの参加。
5. IRQF_NO_SUSPEND フラグとenable_irq_wake 関数は同時に使用できません
デバイスの場合、割り込み申請時に IRQF_NO_SUSPEND フラグを使用し、同時に Enable_irq_wake を呼び出してウェイクアップ要因を設定することは不合理であり、その主な理由は次のとおりです。
1. IRQ が共有されていない場合は、IRQF_NO_SUSPEND フラグを使用して、システム全体のサスペンド/再開プロセス (suspend_device_irqs 後のステージを含む) 中に割り込みを開いたままにすることを示し、その割り込みハンドラーが普通に呼ばれた。 Enable_irq_wake 関数の呼び出しは、デバイスの IRQ 信号を割り込みソースとして設定することを示しているため、その割り込みハンドラーを呼び出す必要はありません。これら 2 つの要件は明らかに相互に排他的です。2. IRQF_NO_SUSPEND フラグもenable_irq_wake 関数も、1 つの割り込みハンドラーに対するものではなく、IRQ に登録されているすべてのハンドラーに対するものです。同じ IRQ 上でウェイクアップ ソースとノーサスペンド割り込みソースを共有するのはばかげています。
ただし、非常に特殊な状況では、IRQ がウェイクアップ ソースとして設定され、IRQF_NO_SUSPEND フラグも設定されることがあります。コード ロジックが正しくなるためには、デバイスのドライバー コードがいくつかの特別な要件を満たす必要があります。
以上がLinux システムのスリープ (システム サスペンド) とデバイスの割り込み処理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。