LinuxでのNVME APST問題の明確化

LinuxでのNVME APST問題の明確化

ほぼ同じ問題が発生しました。に記載されているもののいずれかアクベントコミュニティ

この質問を投稿したユーザーと同様に、私のシステムにはKingston NVMEディスクが装備されており、そのユーザーと同様に、grubメニューに次のカーネルオプションを追加して問題を解決しましたnvme_core.default_ps_max_latency_us=0

ユーザーが指定した解決策は次のとおりです。

問題は、SSD機能であるAPST(Autonomous Power State Transition)によって動作が停止することです。この問題を軽減するには、修正がリリースされるまでオプションnvme_core.default_ps_max_latency_us=0 にこの行を含めますGRUB_CMDLINE_LINUX_DEFAULT

このレビューは役に立ちますが、次のようないくつかの答えがない質問を残します。

  1. 問題を引き起こす具体的な欠陥は何であり、どこにありますか?
  2. 欠陥を防ぐために、回避策にどのような変更が加えられましたか?
  3. この回避策は、どのような機能やその他の望ましい効果が失われますか?
  4. 特に適切なソリューションを提供するには、カーネル、ストレージメディアファームウェア、システムファームウェア(UEFI / BIOSなど)、またはその他のコンポーネントのどれを変更する必要がありますか?

どんな意見でも、この混乱の全部または一部を解決するのに役立ちます。

答え1

内部のコードコメントdrivers/nvme/host/core.cLinuxカーネルのソースコードで最もよく説明されているようです。

/*
 * APST (Autonomous Power State Transition) lets us program a table of power
 * state transitions that the controller will perform automatically.
 *
 * Depending on module params, one of the two supported techniques will be used:
 *
 * - If the parameters provide explicit timeouts and tolerances, they will be
 *   used to build a table with up to 2 non-operational states to transition to.
 *   The default parameter values were selected based on the values used by
 *   Microsoft's and Intel's NVMe drivers. Yet, since we don't implement dynamic
 *   regeneration of the APST table in the event of switching between external
 *   and battery power, the timeouts and tolerances reflect a compromise
 *   between values used by Microsoft for AC and battery scenarios.
 * - If not, we'll configure the table with a simple heuristic: we are willing
 *   to spend at most 2% of the time transitioning between power states.
 *   Therefore, when running in any given state, we will enter the next
 *   lower-power non-operational state after waiting 50 * (enlat + exlat)
 *   microseconds, as long as that state's exit latency is under the requested
 *   maximum latency.
 *
 * We will not autonomously enter any non-operational state for which the total
 * latency exceeds ps_max_latency_us.
 *
 * Users can set ps_max_latency_us to zero to turn off APST.
 */
static int nvme_configure_apst(struct nvme_ctrl *ctrl)

したがって、APSTは、NVMeコントローラ(NVMe SSD内)が設定可能な規則に従って電源管理状態を自動的に切り替えることを可能にする機能です。 NVMeコントローラは、各省電力状態を開始および終了するのにかかる時間をマイクロ秒単位で指定します。カーネルはこの情報を使用して、NVMeコントローラ内で状態遷移ルール​​を設定します。

  1. 問題を引き起こす具体的な欠陥は何であり、どこにありますか?

この特定のKingston NVMe SSDは、スリープモード解除時間の予測に対して楽観的であるか、十分に深いスリープ状態に入った後(コントローラを完全にリセットせず)、スリープモードから解除されないようです。 APST 権限が付与されると、ある種の省電力状態に入り、指定された時間内に動作状態に戻ることができず、カーネルが不幸になります。

  1. 欠陥を防ぐために、回避策にどのような変更が加えられましたか?

APST電源管理状態で目覚めるのに許容される最大時間は正確に0マイクロ秒であるため、APST機能は無効になります。

  1. この回避策は、どのような機能やその他の望ましい効果が失われますか?

NVMeコントローラの自律電源管理機能が利用できない場合、コントローラはカーネルから明示的に要求されたときにのみスリープ状態に入ることができます。これは、省エネがAPSTを使用する場合ほど大きくはないことを意味します。

  1. 具体的には、ユーザーが正しいソリューションを体験できるように、カーネル、ストレージメディアファームウェア、システムファームウェア(UEFI / BIOSなど)、またはその他のコンポーネントのどれを変更する必要がありますか?

最善の解決策は、KingstonがAPST電源管理を正しく機能させるNVMeディスクファームウェアアップデートを提供すること、または少なくともドライブが提供できないことを約束しないようにすることです。つまり、APSTモードへの過度に楽観的な移行時間を発表しないようにすること、および/または使用中にコントローラの誤動作を引き起こすAPSTモードについてはまったく発表しません。

最も深いスリープ状態を完全に防止するためにAPSTをプログラムして問題を回避できることがわかったら、より具体的なカーネルレベルの解決策を作成することが可能です。 Linuxカーネルの多くのデバイスドライバには、特定のハードウェアモデルの回避策を指定する「奇妙なテーブル」があります。 NVMeの場合、次のことができます。drivers/nvme/host/pci.cLinuxカーネルのソースコードでは:

static const struct pci_device_id nvme_id_table[] = {
    { PCI_VDEVICE(INTEL, 0x0953),   /* Intel 750/P3500/P3600/P3700 */
        .driver_data = NVME_QUIRK_STRIPE_SIZE |
                NVME_QUIRK_DEALLOCATE_ZEROES, },
    { PCI_VDEVICE(INTEL, 0x0a53),   /* Intel P3520 */
        .driver_data = NVME_QUIRK_STRIPE_SIZE |
                NVME_QUIRK_DEALLOCATE_ZEROES, },
    { PCI_VDEVICE(INTEL, 0x0a54),   /* Intel P4500/P4600 */
        .driver_data = NVME_QUIRK_STRIPE_SIZE |
                NVME_QUIRK_DEALLOCATE_ZEROES |
                NVME_QUIRK_IGNORE_DEV_SUBNQN, },
    { PCI_VDEVICE(INTEL, 0x0a55),   /* Dell Express Flash P4600 */
        .driver_data = NVME_QUIRK_STRIPE_SIZE |
                NVME_QUIRK_DEALLOCATE_ZEROES, },
    { PCI_VDEVICE(INTEL, 0xf1a5),   /* Intel 600P/P3100 */
        .driver_data = NVME_QUIRK_NO_DEEPEST_PS |
                NVME_QUIRK_MEDIUM_PRIO_SQ |
                NVME_QUIRK_NO_TEMP_THRESH_CHANGE |
                NVME_QUIRK_DISABLE_WRITE_ZEROES, },
    { PCI_VDEVICE(INTEL, 0xf1a6),   /* Intel 760p/Pro 7600p */
        .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, },
    { PCI_VDEVICE(INTEL, 0x5845),   /* Qemu emulated controller */
        .driver_data = NVME_QUIRK_IDENTIFY_CNS |
                NVME_QUIRK_DISABLE_WRITE_ZEROES |
                NVME_QUIRK_BOGUS_NID, },
    { PCI_VDEVICE(REDHAT, 0x0010),  /* Qemu emulated controller */
        .driver_data = NVME_QUIRK_BOGUS_NID, },
[...]

ここのさまざまな設定は、NVME_QUIRK_ドライバ内のさまざまな解決コードをトリガします。

NVME_QUIRK_NO_DEEPEST_PS状態が最も深い電源管理状態に移行するのを防ぐための奇妙な設定があります。 Kingston NVMeのAPST問題がIntel 600P / P3100およびADATA SX8200PNPに実装されている解決策と同じ場合は、次のように新しい奇妙なテーブルエントリを作成します(<angle brackets>内容を適切な値に置き換えると次のことができます)。lspci -nn):

    { PCI_DEVICE(<PCI vendor ID>, <PCI product ID of the SSD>),   /* <specify make/model of SSD here> */
        .driver_data = NVME_QUIRK_NO_DEEPEST_PS, },

そして、この修正を適用してカーネルを再コンパイルします。

明らかに、このSSDモデルを実際に所有している人はこれをテストする必要があります。 Cプログラミングの基本とカスタムカーネルのコンパイル方法に精通しているなら、今回はLinuxカーネルの貢献者の長いリストにあなたの名前を追加する機会になるでしょう!興味があれば読んでもいいと思います。kernelnewbies.org詳細については。

カーネルプログラミングが常に複雑である必要はありません。適切なハードウェアと基本的なプログラミング知識を持っている人だけができる簡単な部分がたくさんあります。私はこのようないくつかの小さなパッチを提出しました。

設定でNVME_QUIRK_NO_DEEPEST_PS問題が解決しないことが判明した場合は、新しい問題を実装する必要があります。これはより複雑になる可能性があり、この問題を回避するために正確に実行する必要があることを理解するためにKingstonのいくつかの実験または情報が必要になる可能性があり、これを達成するための最善の方法についてLinux NVMeドライバのメンテナンス担当者と話し合う必要があるかもしれません。

関連情報