|
4 | 4 | * Copyright (c) 2011-2014, Intel Corporation.
|
5 | 5 | */
|
6 | 6 |
|
| 7 | +#include <linux/acpi.h> |
7 | 8 | #include <linux/aer.h>
|
8 | 9 | #include <linux/async.h>
|
9 | 10 | #include <linux/blkdev.h>
|
@@ -94,6 +95,10 @@ static unsigned int poll_queues;
|
94 | 95 | module_param_cb(poll_queues, &io_queue_count_ops, &poll_queues, 0644);
|
95 | 96 | MODULE_PARM_DESC(poll_queues, "Number of queues to use for polled IO.");
|
96 | 97 |
|
| 98 | +static bool noacpi; |
| 99 | +module_param(noacpi, bool, 0444); |
| 100 | +MODULE_PARM_DESC(noacpi, "disable acpi bios quirks"); |
| 101 | + |
97 | 102 | struct nvme_dev;
|
98 | 103 | struct nvme_queue;
|
99 | 104 |
|
@@ -2754,6 +2759,54 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev)
|
2754 | 2759 | return 0;
|
2755 | 2760 | }
|
2756 | 2761 |
|
| 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 | + |
2757 | 2810 | static void nvme_async_probe(void *data, async_cookie_t cookie)
|
2758 | 2811 | {
|
2759 | 2812 | struct nvme_dev *dev = data;
|
@@ -2803,6 +2856,16 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
2803 | 2856 |
|
2804 | 2857 | quirks |= check_vendor_combination_bug(pdev);
|
2805 | 2858 |
|
| 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 | + |
2806 | 2869 | /*
|
2807 | 2870 | * Double check that our mempool alloc size will cover the biggest
|
2808 | 2871 | * command we support.
|
|
0 commit comments