--- /dev/null
+From 112a7f9c8edbf76f7cb83856a6cb6b60a210b659 Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Tue, 20 Jun 2023 09:04:51 -0500
+Subject: PCI/ACPI: Call _REG when transitioning D-states
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+commit 112a7f9c8edbf76f7cb83856a6cb6b60a210b659 upstream.
+
+ACPI r6.5, sec 6.5.4, describes how AML is unable to access an
+OperationRegion unless _REG has been called to connect a handler:
+
+ The OS runs _REG control methods to inform AML code of a change in the
+ availability of an operation region. When an operation region handler is
+ unavailable, AML cannot access data fields in that region. (Operation
+ region writes will be ignored and reads will return indeterminate data.)
+
+The PCI core does not call _REG at any time, leading to the undefined
+behavior mentioned in the spec.
+
+The spec explains that _REG should be executed to indicate whether a
+given region can be accessed:
+
+ Once _REG has been executed for a particular operation region, indicating
+ that the operation region handler is ready, a control method can access
+ fields in the operation region. Conversely, control methods must not
+ access fields in operation regions when _REG method execution has not
+ indicated that the operation region handler is ready.
+
+An example included in the spec demonstrates calling _REG when devices are
+turned off: "when the host controller or bridge controller is turned off
+or disabled, PCI Config Space Operation Regions for child devices are
+no longer available. As such, ETH0’s _REG method will be run when it
+is turned off and will again be run when PCI1 is turned off."
+
+It is reported that ASMedia PCIe GPIO controllers fail functional tests
+after the system has returning from suspend (S3 or s2idle). This is because
+the BIOS checks whether the OSPM has called the _REG method to determine
+whether it can interact with the OperationRegion assigned to the device as
+part of the other AML called for the device.
+
+To fix this issue, call acpi_evaluate_reg() when devices are transitioning
+to D3cold or D0.
+
+[bhelgaas: split pci_power_t checking to preliminary patch]
+Link: https://uefi.org/specs/ACPI/6.5/06_Device_Configuration.html#reg-region
+Link: https://lore.kernel.org/r/20230620140451.21007-1-mario.limonciello@amd.com
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Rafael J. Wysocki <rafael@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/pci-acpi.c | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+--- a/drivers/pci/pci-acpi.c
++++ b/drivers/pci/pci-acpi.c
+@@ -1043,6 +1043,16 @@ bool acpi_pci_bridge_d3(struct pci_dev *
+ return false;
+ }
+
++static void acpi_pci_config_space_access(struct pci_dev *dev, bool enable)
++{
++ int val = enable ? ACPI_REG_CONNECT : ACPI_REG_DISCONNECT;
++ int ret = acpi_evaluate_reg(ACPI_HANDLE(&dev->dev),
++ ACPI_ADR_SPACE_PCI_CONFIG, val);
++ if (ret)
++ pci_dbg(dev, "ACPI _REG %s evaluation failed (%d)\n",
++ enable ? "connect" : "disconnect", ret);
++}
++
+ int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+ {
+ struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
+@@ -1074,6 +1084,9 @@ int acpi_pci_set_power_state(struct pci_
+ if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) ==
+ PM_QOS_FLAGS_ALL)
+ return -EBUSY;
++
++ /* Notify AML lack of PCI config space availability */
++ acpi_pci_config_space_access(dev, false);
+ }
+
+ error = acpi_device_set_power(adev, state_conv[state]);
+@@ -1083,6 +1096,15 @@ int acpi_pci_set_power_state(struct pci_
+ pci_dbg(dev, "power state changed by ACPI to %s\n",
+ acpi_power_state_string(adev->power.state));
+
++ /*
++ * Notify AML of PCI config space availability. Config space is
++ * accessible in all states except D3cold; the only transitions
++ * that change availability are transitions to D3cold and from
++ * D3cold to D0.
++ */
++ if (state == PCI_D0)
++ acpi_pci_config_space_access(dev, true);
++
+ return 0;
+ }
+
--- /dev/null
+From 5557b62634abbd55bab7b154ce4bca348ad7f96f Mon Sep 17 00:00:00 2001
+From: Bjorn Helgaas <bhelgaas@google.com>
+Date: Wed, 21 Jun 2023 16:36:12 -0500
+Subject: PCI/ACPI: Validate acpi_pci_set_power_state() parameter
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+commit 5557b62634abbd55bab7b154ce4bca348ad7f96f upstream.
+
+Previously acpi_pci_set_power_state() assumed the requested power state was
+valid (PCI_D0 ... PCI_D3cold). If a caller supplied something else, we
+could index outside the state_conv[] array and pass junk to
+acpi_device_set_power().
+
+Validate the pci_power_t parameter and return -EINVAL if it's invalid.
+
+Link: https://lore.kernel.org/r/20230621222857.GA122930@bhelgaas
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/pci-acpi.c | 31 ++++++++++++++++++-------------
+ 1 file changed, 18 insertions(+), 13 deletions(-)
+
+--- a/drivers/pci/pci-acpi.c
++++ b/drivers/pci/pci-acpi.c
+@@ -1053,32 +1053,37 @@ int acpi_pci_set_power_state(struct pci_
+ [PCI_D3hot] = ACPI_STATE_D3_HOT,
+ [PCI_D3cold] = ACPI_STATE_D3_COLD,
+ };
+- int error = -EINVAL;
++ int error;
+
+ /* If the ACPI device has _EJ0, ignore the device */
+ if (!adev || acpi_has_method(adev->handle, "_EJ0"))
+ return -ENODEV;
+
+ switch (state) {
+- case PCI_D3cold:
+- if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) ==
+- PM_QOS_FLAGS_ALL) {
+- error = -EBUSY;
+- break;
+- }
+- fallthrough;
+ case PCI_D0:
+ case PCI_D1:
+ case PCI_D2:
+ case PCI_D3hot:
+- error = acpi_device_set_power(adev, state_conv[state]);
++ case PCI_D3cold:
++ break;
++ default:
++ return -EINVAL;
+ }
+
+- if (!error)
+- pci_dbg(dev, "power state changed by ACPI to %s\n",
+- acpi_power_state_string(adev->power.state));
++ if (state == PCI_D3cold) {
++ if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) ==
++ PM_QOS_FLAGS_ALL)
++ return -EBUSY;
++ }
++
++ error = acpi_device_set_power(adev, state_conv[state]);
++ if (error)
++ return error;
++
++ pci_dbg(dev, "power state changed by ACPI to %s\n",
++ acpi_power_state_string(adev->power.state));
+
+- return error;
++ return 0;
+ }
+
+ pci_power_t acpi_pci_get_power_state(struct pci_dev *dev)