linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH V5] drivers/nvme: Add support for ACPI StorageD3Enable property
@ 2021-05-26 17:53 Raul Rangel
  2021-05-27  2:20 ` David E. Box
  0 siblings, 1 reply; 6+ messages in thread
From: Raul Rangel @ 2021-05-26 17:53 UTC (permalink / raw)
  To: David E. Box
  Cc: Rafael J. Wysocki, Len Brown, kbusch, axboe, hch, sagi,
	dan.j.williams, shyjumon.n, linux-acpi, linux-kernel, linux-nvme

On Thu, Jul 09, 2020 at 11:43:33AM -0700, David E. Box wrote:
> +#ifdef CONFIG_ACPI
> +static bool nvme_acpi_storage_d3(struct pci_dev *dev)
> +{
> +     const struct fwnode_handle *fwnode;
> +     struct acpi_device *adev;
> +     struct pci_dev *root;
> +     acpi_handle handle;
> +     acpi_status status;
> +     u8 val;
> +
> +     /*
> +      * Look for _DSD property specifying that the storage device on
> +      * the port must use D3 to support deep platform power savings during
> +      * suspend-to-idle
> +      */
> +     root = pcie_find_root_port(dev);
> +     if (!root)
> +             return false;
> +
> +     adev = ACPI_COMPANION(&root->dev);
> +     if (!adev)
> +             return false;
> +
> +     /*
> +      * The property is defined in the PXSX device for South complex ports
> +      * and in the PEGP device for North complex ports.
> +      */
> +     status = acpi_get_handle(adev->handle, "PXSX", &handle);
So I'm curious why we need to directly look at the PXSX and PEGP
devices instead of the ACPI_COMPANION node attached to the pci device?

I've looked around and I can't find any documentation that defines
the PXSX and PEGP device names.

I've dumped some ACPI from a system that uses the PXSX name and
StorageD3Cold attribute:

    Scope (\_SB.PCI0.GP14)
    {
        Device (PXSX)
        {
            Name (_ADR, 0x0000000000000000)  // _ADR: Address
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (0x0F)
            }

            Name (_DSD, Package (0x02)  // _DSD: Device-Specific Data
            {
                ToUUID ("5025030f-842f-4ab4-a561-99a5189762d0"),
                Package (0x01)
                {
                    Package (0x02)
                    {
                        "StorageD3Enable",
                        One
                    }
                }
            })
        }
    }

It looks to me like it's just the firmware node for the NVMe device
attached to the root port. Is that the correct assumption?

I'm wondering if we can simplify the look up logic to look at the
ACPI_COMPANION of the pci device?

The reason I ask is that I'm working on enabling S0i3 on an AMD device.
This device also defines the StorageD3Enable property, but it don't use
the PXSX name:

    Scope (GPP6) {
        Device (NVME)
        {
            Name (_ADR, Zero)  // _ADR: Address

            Name (_DSD, Package (0x02)  // _DSD: Device-Specific Data
            {
                ToUUID ("5025030f-842f-4ab4-a561-99a5189762d0"),
                Package (0x01)
                {
                    Package (0x02)
                    {
                        "StorageD3Enable",
                        One
                    }
                }
            })
        }
    }

The Windows
[documentation](https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/power-management-for-storage-hardware-devices-intro#d3-support)
makes it sound like the _DSD should be defined on the PCI device.

I can send one of the following patches depending on the feedback:
1) Additionally check the pci device's ACPI_COMPANION for the _DSD.
2) Delete the PXSX and PEGP lookups and only look at the pci device's
   ACPI_COMPANION.

> +     if (ACPI_FAILURE(status)) {
> +             status = acpi_get_handle(adev->handle, "PEGP", &handle);
> +             if (ACPI_FAILURE(status))
> +                     return false;
> +     }
> +
> +     if (acpi_bus_get_device(handle, &adev))
> +             return false;
> +
> +     fwnode = acpi_fwnode_handle(adev);
> +
> +     return fwnode_property_read_u8(fwnode, "StorageD3Enable", &val) ?
> +             false : val == 1;
> +}

Thanks,
Raul

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH V5] drivers/nvme: Add support for ACPI StorageD3Enable property
  2021-05-26 17:53 [PATCH V5] drivers/nvme: Add support for ACPI StorageD3Enable property Raul Rangel
@ 2021-05-27  2:20 ` David E. Box
  0 siblings, 0 replies; 6+ messages in thread
From: David E. Box @ 2021-05-27  2:20 UTC (permalink / raw)
  To: Raul Rangel, michael.a.bottini
  Cc: Rafael J. Wysocki, Len Brown, kbusch, axboe, hch, sagi,
	dan.j.williams, shyjumon.n, linux-acpi, linux-kernel, linux-nvme

Hi Raul,

On Wed, 2021-05-26 at 11:53 -0600, Raul Rangel wrote:
> On Thu, Jul 09, 2020 at 11:43:33AM -0700, David E. Box wrote:
> > +#ifdef CONFIG_ACPI
> > +static bool nvme_acpi_storage_d3(struct pci_dev *dev)
> > +{
> > +     const struct fwnode_handle *fwnode;
> > +     struct acpi_device *adev;
> > +     struct pci_dev *root;
> > +     acpi_handle handle;
> > +     acpi_status status;
> > +     u8 val;
> > +
> > +     /*
> > +      * Look for _DSD property specifying that the storage device
> > on
> > +      * the port must use D3 to support deep platform power
> > savings during
> > +      * suspend-to-idle
> > +      */
> > +     root = pcie_find_root_port(dev);
> > +     if (!root)
> > +             return false;
> > +
> > +     adev = ACPI_COMPANION(&root->dev);
> > +     if (!adev)
> > +             return false;
> > +
> > +     /*
> > +      * The property is defined in the PXSX device for South
> > complex ports
> > +      * and in the PEGP device for North complex ports.
> > +      */
> > +     status = acpi_get_handle(adev->handle, "PXSX", &handle);
> So I'm curious why we need to directly look at the PXSX and PEGP
> devices instead of the ACPI_COMPANION node attached to the pci
> device?
> 
> I've looked around and I can't find any documentation that defines
> the PXSX and PEGP device names.
> 
> I've dumped some ACPI from a system that uses the PXSX name and
> StorageD3Cold attribute:
> 
>     Scope (\_SB.PCI0.GP14)
>     {
>         Device (PXSX)
>         {
>             Name (_ADR, 0x0000000000000000)  // _ADR: Address
>             Method (_STA, 0, NotSerialized)  // _STA: Status
>             {
>                 Return (0x0F)
>             }
> 
>             Name (_DSD, Package (0x02)  // _DSD: Device-Specific Data
>             {
>                 ToUUID ("5025030f-842f-4ab4-a561-99a5189762d0"),
>                 Package (0x01)
>                 {
>                     Package (0x02)
>                     {
>                         "StorageD3Enable",
>                         One
>                     }
>                 }
>             })
>         }
>     }
> 
> It looks to me like it's just the firmware node for the NVMe device
> attached to the root port. Is that the correct assumption?
> 
> I'm wondering if we can simplify the look up logic to look at the
> ACPI_COMPANION of the pci device?

I believe so, but I'd need to confirm on our systems that it will work.
I recall trying to use the companion device and not being able to
locate the _DSD. But that was on a preproduction platform at the time.

> 
> The reason I ask is that I'm working on enabling S0i3 on an AMD
> device.
> This device also defines the StorageD3Enable property, but it don't
> use
> the PXSX name:
> 
>     Scope (GPP6) {
>         Device (NVME)
>         {
>             Name (_ADR, Zero)  // _ADR: Address
> 
>             Name (_DSD, Package (0x02)  // _DSD: Device-Specific Data
>             {
>                 ToUUID ("5025030f-842f-4ab4-a561-99a5189762d0"),
>                 Package (0x01)
>                 {
>                     Package (0x02)
>                     {
>                         "StorageD3Enable",
>                         One
>                     }
>                 }
>             })
>         }
>     }
> 
> The Windows
> [documentation]( 
> https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/power-management-for-storage-hardware-devices-intro#d3-support
> )
> makes it sound like the _DSD should be defined on the PCI device.
> 
> I can send one of the following patches depending on the feedback:
> 1) Additionally check the pci device's ACPI_COMPANION for the _DSD.
> 2) Delete the PXSX and PEGP lookups and only look at the pci device's
>    ACPI_COMPANION.
> 
> > +     if (ACPI_FAILURE(status)) {
> > +             status = acpi_get_handle(adev->handle, "PEGP",
> > &handle);
> > +             if (ACPI_FAILURE(status))
> > +                     return false;
> > +     }
> > +
> > +     if (acpi_bus_get_device(handle, &adev))
> > +             return false;
> > +
> > +     fwnode = acpi_fwnode_handle(adev);
> > +
> > +     return fwnode_property_read_u8(fwnode, "StorageD3Enable",
> > &val) ?
> > +             false : val == 1;
> > +}

Go for 2 first. I will check on those systems again with our latest
BIOS to ensure it works.

David

> 
> Thanks,
> Raul



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH V5] drivers/nvme: Add support for ACPI StorageD3Enable property
  2020-07-09 18:43 ` [PATCH V5] " David E. Box
  2020-07-13 11:12   ` Rafael J. Wysocki
@ 2021-05-26 19:25   ` Raul E Rangel
  1 sibling, 0 replies; 6+ messages in thread
From: Raul E Rangel @ 2021-05-26 19:25 UTC (permalink / raw)
  To: David E. Box
  Cc: rjw, lenb, kbusch, axboe, hch, sagi, dan.j.williams, shyjumon.n,
	linux-acpi, linux-kernel, linux-nvme

On Thu, Jul 09, 2020 at 11:43:33AM -0700, David E. Box wrote:
> +#ifdef CONFIG_ACPI
> +static bool nvme_acpi_storage_d3(struct pci_dev *dev)
> +{
> +	const struct fwnode_handle *fwnode;
> +	struct acpi_device *adev;
> +	struct pci_dev *root;
> +	acpi_handle handle;
> +	acpi_status status;
> +	u8 val;
> +
> +	/*
> +	 * Look for _DSD property specifying that the storage device on
> +	 * the port must use D3 to support deep platform power savings during
> +	 * suspend-to-idle
> +	 */
> +	root = pcie_find_root_port(dev);
> +	if (!root)
> +		return false;
> +
> +	adev = ACPI_COMPANION(&root->dev);
> +	if (!adev)
> +		return false;
> +
> +	/*
> +	 * The property is defined in the PXSX device for South complex ports
> +	 * and in the PEGP device for North complex ports.
> +	 */
> +	status = acpi_get_handle(adev->handle, "PXSX", &handle);
So I'm curious why we need to directly look at the PXSX and PEGP
devices instead of the ACPI_COMPANION node attached to the pci device?

I've looked around and I can't find any documentation that defines the
the PXSX and PEGP device names.

I've dumped some ACPI from a system that uses the PXSX name and
StorageD3Cold attribute:

    Scope (\_SB.PCI0.GP14)
    {
        Device (PXSX)
        {
            Name (_ADR, 0x0000000000000000)  // _ADR: Address
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (0x0F)
            }

            Name (_DSD, Package (0x02)  // _DSD: Device-Specific Data
            {
                ToUUID ("5025030f-842f-4ab4-a561-99a5189762d0"),
                Package (0x01)
                {
                    Package (0x02)
                    {
                        "StorageD3Enable",
                        One
                    }
                }
            })
        }
    }

It looks to me like it's just the firmware node for the NVMe device
attached to the root port. Is that the correct assumption?

I'm wondering if we can simplify the look up logic to look at the
ACPI_COMPANION of the pci device?

The reason I ask is that I'm working on enabling S0i3 on an AMD device.
This device also defines the StorageD3Enable property, but it don't use
the PXSX name:

    Scope (GPP6) {
        Device (NVME)
        {
            Name (_ADR, Zero)  // _ADR: Address

            Name (_DSD, Package (0x02)  // _DSD: Device-Specific Data
            {
                ToUUID ("5025030f-842f-4ab4-a561-99a5189762d0"),
                Package (0x01)
                {
                    Package (0x02)
                    {
                        "StorageD3Enable",
                        One
                    }
                }
            })
        }
    }

The Windows
[documentation](https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/power-management-for-storage-hardware-devices-intro#d3-support)
makes it sound like the _DSD should be defined on the PCI device.

I can send one of the following patches depending on the feedback:
1) Additionally check the pci device's ACPI_COMPANION for the _DSD.
2) Delete the PXSX and PEGP lookups and only look at the pci device's
   ACPI_COMPANION.

> +	if (ACPI_FAILURE(status)) {
> +		status = acpi_get_handle(adev->handle, "PEGP", &handle);
> +		if (ACPI_FAILURE(status))
> +			return false;
> +	}
> +
> +	if (acpi_bus_get_device(handle, &adev))
> +		return false;
> +
> +	fwnode = acpi_fwnode_handle(adev);
> +
> +	return fwnode_property_read_u8(fwnode, "StorageD3Enable", &val) ?
> +		false : val == 1;
> +}

Thanks,
Raul

p.s., Sorry for the second message, I somehow mangled the headers in the
first message and dropped the Message-Id.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH V5] drivers/nvme: Add support for ACPI StorageD3Enable property
  2020-07-13 11:12   ` Rafael J. Wysocki
@ 2020-07-16 14:39     ` Christoph Hellwig
  0 siblings, 0 replies; 6+ messages in thread
From: Christoph Hellwig @ 2020-07-16 14:39 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: David E. Box, Rafael J. Wysocki, Len Brown, Keith Busch,
	Jens Axboe, Christoph Hellwig, Sagi Grimberg, Dan Williams,
	shyjumon.n, ACPI Devel Maling List, Linux Kernel Mailing List,
	linux-nvme

On Mon, Jul 13, 2020 at 01:12:26PM +0200, Rafael J. Wysocki wrote:
> I would write this as
> 
> if (fwnode_property_read_u8(acpi_fwnode_handle(adev),
>                             "StorageD3Enable", &val))
>         return false;
> 
> return val == 1;
> 
> to eliminate the redundant fwnode variable and untangle the last
> checks somewhat.
> 
> With that changed please feel free to add
> 
> Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Applied to nvme-5.9 with the above fixup.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH V5] drivers/nvme: Add support for ACPI StorageD3Enable property
  2020-07-09 18:43 ` [PATCH V5] " David E. Box
@ 2020-07-13 11:12   ` Rafael J. Wysocki
  2020-07-16 14:39     ` Christoph Hellwig
  2021-05-26 19:25   ` Raul E Rangel
  1 sibling, 1 reply; 6+ messages in thread
From: Rafael J. Wysocki @ 2020-07-13 11:12 UTC (permalink / raw)
  To: David E. Box
  Cc: Rafael J. Wysocki, Len Brown, Keith Busch, Jens Axboe,
	Christoph Hellwig, Sagi Grimberg, Dan Williams, shyjumon.n,
	ACPI Devel Maling List, Linux Kernel Mailing List, linux-nvme

On Thu, Jul 9, 2020 at 8:43 PM David E. Box <david.e.box@linux.intel.com> wrote:
>
> 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 on:
> 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 <david.e.box@linux.intel.com>
> ---
> Changes from V4:
>         - Add support for North complex PCI root ports.
>         - Use acpi_bus_get_device instead of acpi_bus_get_acpi_device.
>           Also fixes compiler error on V4 reported by lkp@intel.com.
>         - Place CONFIG_ACPI around function since acpi_bus_get_device
>           is not stubbed out.
>
> Changes from V3:
>         - Use pcie_find_root_port() instead of pci_find_pcie_root_port(),
>           changed in 5.8.
>         - Remove "Cc:" emails that ended up at top of V3 commit message.
>         - Fix changelog numbering.
>
> Changes from V2:
>         - Remove check for "not yet bound" ACPI companion device since
>           this will not be a concern at driver probe time per Rafael.
>         - Move storage_d3 function out of PCI core and into NVMe driver
>           since there's nothing the PCI core can do with this code as
>           noted by Bjorn.
>
> Changes from V1:
>         - Export the pci_acpi_storage_d3 function for use by drivers as
>           needed instead of modifying the pci header.
>         - Add missing put on acpi device handle.
>         - Add 'noacpi' module parameter to allow undoing this change.
>         - Add info message that this is a platform quirk.
>
>
>  drivers/acpi/property.c |  3 ++
>  drivers/nvme/host/pci.c | 64 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 67 insertions(+)
>
> diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
> index e601c4511a8b..c2e2ae774a19 100644
> --- a/drivers/acpi/property.c
> +++ b/drivers/acpi/property.c
> @@ -45,6 +45,9 @@ static const guid_t prp_guids[] = {
>         /* Thunderbolt GUID for WAKE_SUPPORTED: 6c501103-c189-4296-ba72-9bf5a26ebe5d */
>         GUID_INIT(0x6c501103, 0xc189, 0x4296,
>                   0xba, 0x72, 0x9b, 0xf5, 0xa2, 0x6e, 0xbe, 0x5d),
> +       /* Storage device needs D3 GUID: 5025030f-842f-4ab4-a561-99a5189762d0 */
> +       GUID_INIT(0x5025030f, 0x842f, 0x4ab4,
> +                 0xa5, 0x61, 0x99, 0xa5, 0x18, 0x97, 0x62, 0xd0),
>  };
>
>  /* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index b1d18f0633c7..7c0be363eb22 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -4,6 +4,7 @@
>   * Copyright (c) 2011-2014, Intel Corporation.
>   */
>
> +#include <linux/acpi.h>
>  #include <linux/aer.h>
>  #include <linux/async.h>
>  #include <linux/blkdev.h>
> @@ -94,6 +95,10 @@ static unsigned int poll_queues;
>  module_param_cb(poll_queues, &io_queue_count_ops, &poll_queues, 0644);
>  MODULE_PARM_DESC(poll_queues, "Number of queues to use for polled IO.");
>
> +static bool noacpi;
> +module_param(noacpi, bool, 0444);
> +MODULE_PARM_DESC(noacpi, "disable acpi bios quirks");
> +
>  struct nvme_dev;
>  struct nvme_queue;
>
> @@ -2759,6 +2764,55 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev)
>         return 0;
>  }
>
> +#ifdef CONFIG_ACPI
> +static bool nvme_acpi_storage_d3(struct pci_dev *dev)
> +{
> +       const struct fwnode_handle *fwnode;
> +       struct acpi_device *adev;
> +       struct pci_dev *root;
> +       acpi_handle handle;
> +       acpi_status status;
> +       u8 val;
> +
> +       /*
> +        * Look for _DSD property specifying that the storage device on
> +        * the port must use D3 to support deep platform power savings during
> +        * suspend-to-idle
> +        */
> +       root = pcie_find_root_port(dev);
> +       if (!root)
> +               return false;
> +
> +       adev = ACPI_COMPANION(&root->dev);
> +       if (!adev)
> +               return false;
> +
> +       /*
> +        * The property is defined in the PXSX device for South complex ports
> +        * and in the PEGP device for North complex ports.
> +        */
> +       status = acpi_get_handle(adev->handle, "PXSX", &handle);
> +       if (ACPI_FAILURE(status)) {
> +               status = acpi_get_handle(adev->handle, "PEGP", &handle);
> +               if (ACPI_FAILURE(status))
> +                       return false;
> +       }
> +
> +       if (acpi_bus_get_device(handle, &adev))
> +               return false;
> +
> +       fwnode = acpi_fwnode_handle(adev);
> +
> +       return fwnode_property_read_u8(fwnode, "StorageD3Enable", &val) ?
> +               false : val == 1;

I would write this as

if (fwnode_property_read_u8(acpi_fwnode_handle(adev),
                            "StorageD3Enable", &val))
        return false;

return val == 1;

to eliminate the redundant fwnode variable and untangle the last
checks somewhat.

With that changed please feel free to add

Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

to the patch.

Thanks!

> +}
> +#else
> +static inline bool nvme_acpi_storage_d3(struct pci_dev *dev)
> +{
> +       return false;
> +}
> +#endif
> +
>  static void nvme_async_probe(void *data, async_cookie_t cookie)
>  {
>         struct nvme_dev *dev = data;
> @@ -2808,6 +2862,16 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>
>         quirks |= check_vendor_combination_bug(pdev);
>
> +       if (!noacpi && nvme_acpi_storage_d3(pdev)) {
> +               /*
> +                * Some systems use a bios work around to ask for D3 on
> +                * platforms that support kernel managed suspend.
> +                */
> +               dev_info(&pdev->dev,
> +                        "platform quirk: setting simple suspend\n");
> +               quirks |= NVME_QUIRK_SIMPLE_SUSPEND;
> +       }
> +
>         /*
>          * Double check that our mempool alloc size will cover the biggest
>          * command we support.
> --
> 2.20.1
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH V5] drivers/nvme: Add support for ACPI StorageD3Enable property
  2020-07-02 22:50 [PATCH v4] " David E. Box
@ 2020-07-09 18:43 ` David E. Box
  2020-07-13 11:12   ` Rafael J. Wysocki
  2021-05-26 19:25   ` Raul E Rangel
  0 siblings, 2 replies; 6+ messages in thread
From: David E. Box @ 2020-07-09 18:43 UTC (permalink / raw)
  To: rjw, lenb, kbusch, axboe, hch, sagi, dan.j.williams, shyjumon.n
  Cc: David E. Box, linux-acpi, linux-kernel, linux-nvme

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 on:
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 <david.e.box@linux.intel.com>
---
Changes from V4:
 	- Add support for North complex PCI root ports.
	- Use acpi_bus_get_device instead of acpi_bus_get_acpi_device.
	  Also fixes compiler error on V4 reported by lkp@intel.com.
	- Place CONFIG_ACPI around function since acpi_bus_get_device
	  is not stubbed out.

Changes from V3:
 	- Use pcie_find_root_port() instead of pci_find_pcie_root_port(),
 	  changed in 5.8.
 	- Remove "Cc:" emails that ended up at top of V3 commit message.
 	- Fix changelog numbering.
 
Changes from V2:
	- Remove check for "not yet bound" ACPI companion device since
	  this will not be a concern at driver probe time per Rafael.
	- Move storage_d3 function out of PCI core and into NVMe driver
	  since there's nothing the PCI core can do with this code as
	  noted by Bjorn.
 
Changes from V1:
	- Export the pci_acpi_storage_d3 function for use by drivers as
	  needed instead of modifying the pci header.
	- Add missing put on acpi device handle.
	- Add 'noacpi' module parameter to allow undoing this change.
	- Add info message that this is a platform quirk.


 drivers/acpi/property.c |  3 ++
 drivers/nvme/host/pci.c | 64 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index e601c4511a8b..c2e2ae774a19 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -45,6 +45,9 @@ static const guid_t prp_guids[] = {
 	/* Thunderbolt GUID for WAKE_SUPPORTED: 6c501103-c189-4296-ba72-9bf5a26ebe5d */
 	GUID_INIT(0x6c501103, 0xc189, 0x4296,
 		  0xba, 0x72, 0x9b, 0xf5, 0xa2, 0x6e, 0xbe, 0x5d),
+	/* Storage device needs D3 GUID: 5025030f-842f-4ab4-a561-99a5189762d0 */
+	GUID_INIT(0x5025030f, 0x842f, 0x4ab4,
+		  0xa5, 0x61, 0x99, 0xa5, 0x18, 0x97, 0x62, 0xd0),
 };
 
 /* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index b1d18f0633c7..7c0be363eb22 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -4,6 +4,7 @@
  * Copyright (c) 2011-2014, Intel Corporation.
  */
 
+#include <linux/acpi.h>
 #include <linux/aer.h>
 #include <linux/async.h>
 #include <linux/blkdev.h>
@@ -94,6 +95,10 @@ static unsigned int poll_queues;
 module_param_cb(poll_queues, &io_queue_count_ops, &poll_queues, 0644);
 MODULE_PARM_DESC(poll_queues, "Number of queues to use for polled IO.");
 
+static bool noacpi;
+module_param(noacpi, bool, 0444);
+MODULE_PARM_DESC(noacpi, "disable acpi bios quirks");
+
 struct nvme_dev;
 struct nvme_queue;
 
@@ -2759,6 +2764,55 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_ACPI
+static bool nvme_acpi_storage_d3(struct pci_dev *dev)
+{
+	const struct fwnode_handle *fwnode;
+	struct acpi_device *adev;
+	struct pci_dev *root;
+	acpi_handle handle;
+	acpi_status status;
+	u8 val;
+
+	/*
+	 * Look for _DSD property specifying that the storage device on
+	 * the port must use D3 to support deep platform power savings during
+	 * suspend-to-idle
+	 */
+	root = pcie_find_root_port(dev);
+	if (!root)
+		return false;
+
+	adev = ACPI_COMPANION(&root->dev);
+	if (!adev)
+		return false;
+
+	/*
+	 * The property is defined in the PXSX device for South complex ports
+	 * and in the PEGP device for North complex ports.
+	 */
+	status = acpi_get_handle(adev->handle, "PXSX", &handle);
+	if (ACPI_FAILURE(status)) {
+		status = acpi_get_handle(adev->handle, "PEGP", &handle);
+		if (ACPI_FAILURE(status))
+			return false;
+	}
+
+	if (acpi_bus_get_device(handle, &adev))
+		return false;
+
+	fwnode = acpi_fwnode_handle(adev);
+
+	return fwnode_property_read_u8(fwnode, "StorageD3Enable", &val) ?
+		false : val == 1;
+}
+#else
+static inline bool nvme_acpi_storage_d3(struct pci_dev *dev)
+{
+	return false;
+}
+#endif
+
 static void nvme_async_probe(void *data, async_cookie_t cookie)
 {
 	struct nvme_dev *dev = data;
@@ -2808,6 +2862,16 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	quirks |= check_vendor_combination_bug(pdev);
 
+	if (!noacpi && nvme_acpi_storage_d3(pdev)) {
+		/*
+		 * Some systems use a bios work around to ask for D3 on
+		 * platforms that support kernel managed suspend.
+		 */
+		dev_info(&pdev->dev,
+			 "platform quirk: setting simple suspend\n");
+		quirks |= NVME_QUIRK_SIMPLE_SUSPEND;
+	}
+
 	/*
 	 * Double check that our mempool alloc size will cover the biggest
 	 * command we support.
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-05-27  2:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-26 17:53 [PATCH V5] drivers/nvme: Add support for ACPI StorageD3Enable property Raul Rangel
2021-05-27  2:20 ` David E. Box
  -- strict thread matches above, loose matches on Subject: below --
2020-07-02 22:50 [PATCH v4] " David E. Box
2020-07-09 18:43 ` [PATCH V5] " David E. Box
2020-07-13 11:12   ` Rafael J. Wysocki
2020-07-16 14:39     ` Christoph Hellwig
2021-05-26 19:25   ` Raul E Rangel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).