我经历过一个与中描述的askubuntu社区几乎相同的问题。
和发布此问题的用户一样,我的系统具有一个Kingston NVME磁盘,与该用户一样,我的问题通过在grub菜单中添加以下内核选项来解决:nvme_core.default_ps_max_latency_us=0
。
用户声明的解析开始于以下步骤:
问题是SSD的特点,自主电力国家过渡(APST)是造成结冰。为了减轻这种情况,在他们发布修复之前,在
nvme_core.default_ps_max_latency_us=0
选项中包括行GRUB_CMDLINE_LINUX_DEFAULT
。
尽管这一评论很有帮助,但仍有几个问题有待解决,包括以下几点:
任何评论都有助于解决这种混乱的全部或部分问题。
发布于 2020-09-30 06:26:38
代码注释drivers/nvme/host/core.c
在Linux内核源代码中似乎最好地解释了这一点:
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 SSD内)自主地在电源管理状态之间切换,遵循可配置规则的特性。NVMe控制器指定输入和退出每个省电状态需要多少微秒;内核使用这些信息来配置NVMe控制器内的状态转换规则。
看起来这个特定的金斯敦NVMe SSD在其清醒时间估计中要么过于乐观,要么在进入足够深的省电状态后根本没有醒来(没有完全重置控制器)。当获得使用APST的权限时,它显然会进入某种省电状态,然后无法在指定的时间内返回到操作状态,这使内核感到不快。
它告诉从APST电源管理状态中醒来的最大允许时间是0微秒,这将导致APST功能被禁用。
如果不能使用NVMe控制器的自主电源管理功能,则只能在内核特别要求时才允许控制器进入节电状态。这意味着电力节约很可能不会像在使用中的APST那样大。
最佳的修复方法是金斯敦提供一个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
的奇怪设置,它防止状态转换到最深的电源管理状态。如果您的金斯敦NVMe的APST问题与已经为Intel 600p/P 3100和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
最终无法解决问题,那么可能需要实现一个新的怪癖。这可能更复杂,可能需要金斯敦提供一些实验或理想的信息,以确定需要做些什么才能避免这个问题,也许还需要与Linux NVMe驱动程序维护人员讨论实现该问题的最佳方法。
https://unix.stackexchange.com/questions/612096
复制相似问题