Skip to content

Commit df4f9bc

Browse files
debox1Christoph Hellwig
authored andcommitted
nvme-pci: add support for ACPI StorageD3Enable property
This patch implements a solution for a BIOS hack used on some currently shipping Intel systems to change driver power management policy for PCIe NVMe drives. Some newer Intel platforms, like some Comet Lake systems, require that PCIe devices use D3 when doing suspend-to-idle in order to allow the platform to realize maximum power savings. This is particularly needed to support ATX power supply shutdown on desktop systems. In order to ensure this happens for root ports with storage devices, Microsoft apparently created this ACPI _DSD property as a way to influence their driver policy. To my knowledge this property has not been discussed with the NVME specification body. Though the solution is not ideal, it addresses a problem that also affects Linux since the NVMe driver's default policy of using NVMe APST during suspend-to-idle prevents the PCI root port from going to D3 and leads to higher power consumption for these platforms. The power consumption difference may be negligible on laptop systems, but many watts on desktop systems when the ATX power supply is blocked from powering down. The patch creates a new nvme_acpi_storage_d3 function to check for the StorageD3Enable property during probe and enables D3 as a quirk if set. It also provides a 'noacpi' module parameter to allow skipping the quirk if needed. Tested with: - PM961 NVMe SED Samsung 512GB - INTEL SSDPEKKF512G8 Link: https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/power-management-for-storage-hardware-devices-intro Signed-off-by: David E. Box <[email protected]> Reviewed-by: Rafael J. Wysocki <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent b13c639 commit df4f9bc

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

drivers/acpi/property.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ static const guid_t prp_guids[] = {
4545
/* Thunderbolt GUID for WAKE_SUPPORTED: 6c501103-c189-4296-ba72-9bf5a26ebe5d */
4646
GUID_INIT(0x6c501103, 0xc189, 0x4296,
4747
0xba, 0x72, 0x9b, 0xf5, 0xa2, 0x6e, 0xbe, 0x5d),
48+
/* Storage device needs D3 GUID: 5025030f-842f-4ab4-a561-99a5189762d0 */
49+
GUID_INIT(0x5025030f, 0x842f, 0x4ab4,
50+
0xa5, 0x61, 0x99, 0xa5, 0x18, 0x97, 0x62, 0xd0),
4851
};
4952

5053
/* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */

drivers/nvme/host/pci.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Copyright (c) 2011-2014, Intel Corporation.
55
*/
66

7+
#include <linux/acpi.h>
78
#include <linux/aer.h>
89
#include <linux/async.h>
910
#include <linux/blkdev.h>
@@ -94,6 +95,10 @@ static unsigned int poll_queues;
9495
module_param_cb(poll_queues, &io_queue_count_ops, &poll_queues, 0644);
9596
MODULE_PARM_DESC(poll_queues, "Number of queues to use for polled IO.");
9697

98+
static bool noacpi;
99+
module_param(noacpi, bool, 0444);
100+
MODULE_PARM_DESC(noacpi, "disable acpi bios quirks");
101+
97102
struct nvme_dev;
98103
struct nvme_queue;
99104

@@ -2754,6 +2759,54 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev)
27542759
return 0;
27552760
}
27562761

2762+
#ifdef CONFIG_ACPI
2763+
static bool nvme_acpi_storage_d3(struct pci_dev *dev)
2764+
{
2765+
struct acpi_device *adev;
2766+
struct pci_dev *root;
2767+
acpi_handle handle;
2768+
acpi_status status;
2769+
u8 val;
2770+
2771+
/*
2772+
* Look for _DSD property specifying that the storage device on the port
2773+
* must use D3 to support deep platform power savings during
2774+
* suspend-to-idle.
2775+
*/
2776+
root = pcie_find_root_port(dev);
2777+
if (!root)
2778+
return false;
2779+
2780+
adev = ACPI_COMPANION(&root->dev);
2781+
if (!adev)
2782+
return false;
2783+
2784+
/*
2785+
* The property is defined in the PXSX device for South complex ports
2786+
* and in the PEGP device for North complex ports.
2787+
*/
2788+
status = acpi_get_handle(adev->handle, "PXSX", &handle);
2789+
if (ACPI_FAILURE(status)) {
2790+
status = acpi_get_handle(adev->handle, "PEGP", &handle);
2791+
if (ACPI_FAILURE(status))
2792+
return false;
2793+
}
2794+
2795+
if (acpi_bus_get_device(handle, &adev))
2796+
return false;
2797+
2798+
if (fwnode_property_read_u8(acpi_fwnode_handle(adev), "StorageD3Enable",
2799+
&val))
2800+
return false;
2801+
return val == 1;
2802+
}
2803+
#else
2804+
static inline bool nvme_acpi_storage_d3(struct pci_dev *dev)
2805+
{
2806+
return false;
2807+
}
2808+
#endif /* CONFIG_ACPI */
2809+
27572810
static void nvme_async_probe(void *data, async_cookie_t cookie)
27582811
{
27592812
struct nvme_dev *dev = data;
@@ -2803,6 +2856,16 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
28032856

28042857
quirks |= check_vendor_combination_bug(pdev);
28052858

2859+
if (!noacpi && nvme_acpi_storage_d3(pdev)) {
2860+
/*
2861+
* Some systems use a bios work around to ask for D3 on
2862+
* platforms that support kernel managed suspend.
2863+
*/
2864+
dev_info(&pdev->dev,
2865+
"platform quirk: setting simple suspend\n");
2866+
quirks |= NVME_QUIRK_SIMPLE_SUSPEND;
2867+
}
2868+
28062869
/*
28072870
* Double check that our mempool alloc size will cover the biggest
28082871
* command we support.

0 commit comments

Comments
 (0)