прояснение проблем nvme apst для Linux

Sep 30 2020

У меня возникла проблема, почти идентичная той, что описана в сообществе askubuntu .

Как у пользователя , который разместил этот вопрос, моя система имеет диск Kingston NVME, и как с этим пользователем, моя проблема решена, добавив следующий параметр ядра в меню потайного: nvme_core.default_ps_max_latency_us=0.

Заявленное пользователем разрешение начинается со следующего:

Проблема заключалась в функциях SSD, автономные переходы между состояниями питания (APST) вызывали зависания. Чтобы смягчить его, включите строку nvme_core.default_ps_max_latency_us=0в GRUB_CMDLINE_LINUX_DEFAULTпараметрах , пока они не выпустят исправление .

Хотя этот комментарий полезен, он оставляет открытыми несколько вопросов, в том числе следующие:

  1. Что и где конкретный недостаток вызывает проблему?
  2. Что нужно изменить в обходном пути, чтобы предотвратить проявление недостатка?
  3. Какие функции или другой желаемый эффект теряются из-за такого обходного пути?
  4. И особенно, что требуется исправить: ядро, прошивка носителя, прошивка системы (например, UEFI / BIOS) или какой-либо другой компонент, чтобы обеспечить правильное разрешение?

Любые комментарии полезны в попытке разрешить всю или часть этой путаницы.

Ответы

5 telcoM Sep 30 2020 at 13:26

Код комментарий внутри drivers/nvme/host/core.cв Linux Kernel источник , кажется, объясняет это лучше всего:

static int nvme_configure_apst(struct nvme_ctrl *ctrl)
{
    /*
     * APST (Autonomous Power State Transition) lets us program a
     * table of power state transitions that the controller will
     * perform automatically.  We configure it 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.
     */

Итак, APST - это функция, которая позволяет контроллеру NVMe (на твердотельном накопителе NVMe) автономно переключаться между состояниями управления питанием в соответствии с настраиваемыми правилами. Контроллер NVMe определяет, сколько микросекунд ему нужно для входа и выхода в каждое состояние энергосбережения; ядро использует эту информацию для настройки правил перехода между состояниями в контроллере NVMe.

  1. Что и где конкретный недостаток вызывает проблему?

Похоже, что этот конкретный твердотельный накопитель Kingston NVMe либо слишком оптимистичен в оценках времени пробуждения, либо вообще не просыпается (без полного сброса контроллера) после перехода в достаточно глубокое состояние энергосбережения. Получив разрешение на использование APST, он явно переходит в состояние энергосбережения, а затем не может вернуться в рабочее состояние в течение указанного времени, что делает ядро ​​недовольным.

  1. Что нужно изменить в обходном пути, чтобы предотвратить проявление недостатка?

Он сообщает, что максимально допустимое время для пробуждения из состояний управления питанием APST составляет ровно 0 микросекунд, что приводит к отключению функции APST.

  1. Какие функции или другой желаемый эффект теряются из-за такого обходного пути?

Если функция автономного управления питанием контроллера NVMe не может быть использована, контроллеру будет разрешено переходить в режим энергосбережения только по специальному запросу ядра. Это означает, что экономия энергии, скорее всего, будет не такой большой, как при использовании APST.

  1. И особенно, что требуется исправить: ядро, прошивка носителя, прошивка системы (например, UEFI / BIOS) или какой-то другой компонент, чтобы пользователи могли правильно решить проблему?

Оптимальным решением для Kingston было бы предоставление обновления микропрограммы диска NVMe, которое либо обеспечивает правильную работу управления питанием APST, либо, как минимум, заставляет диск не обещать то, что он не может предоставить, т.е. не объявлять режимы APST с чрезмерно оптимистичным временем перехода, и / или вообще не объявлять какие-либо режимы APST, которые приведут к отказу контроллера при использовании.

Если выяснится, что проблемы можно избежать, например, запрограммировав APST, чтобы полностью исключить состояние самого глубокого энергосбережения, возможно, можно будет создать более конкретный обходной путь на уровне ядра. Многие драйверы устройств в ядре Linux имеют «таблицы особенностей», в которых указаны обходные пути для конкретных моделей оборудования. В случае с NVMe вы можете найти его в drivers/nvme/host/pci.cисходном коде ядра Linux:

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, },
    { 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, },
[...]

Здесь различные NVME_QUIRK_настройки запускают различные фрагменты кода обходного решения в драйвере.

Обратите внимание, что уже существует параметр причуды с именем, NVME_QUIRK_NO_DEEPEST_PSкоторый предотвращает переходы между состояниями в самое глубокое состояние управления питанием. Если для проблемы APST вашего Kingston NVMe обнаруживается тот же обходной путь, который уже реализован для 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 оптимального способа реализации.