--- /dev/null
+From 2d9452b07f3030faa6effe2de76436d9e8523a92 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Feb 2018 19:19:27 -0800
+Subject: PCI: Add ACS quirk for Ampere root ports
+
+From: Feng Kan <fkan@apm.com>
+
+[ Upstream commit 4ef76ad0462cf25ce948541c8724eaa8a8365e1d ]
+
+The Ampere Computing PCIe root port does not support ACS at this point.
+However, the hardware provides isolation and source validation through the
+SMMU. The stream ID generated by the PCIe ports contain both the
+bus/device/function number as well as the port ID in its 3 most significant
+bits. Turn on ACS but disable all the peer-to-peer features.
+
+APM is being rebranded to Ampere. The Vendor and Device IDs change, but
+the functionality stays the same.
+
+Signed-off-by: Feng Kan <fkan@apm.com>
+Signed-off-by: Bjorn Helgaas <helgaas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 9 +++++++++
+ include/linux/pci_ids.h | 1 +
+ 2 files changed, 10 insertions(+)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index f6e88d5b1c4f..81d76e34b0db 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -4610,6 +4610,15 @@ static const struct pci_dev_acs_enabled {
+ { PCI_VENDOR_ID_CAVIUM, PCI_ANY_ID, pci_quirk_cavium_acs },
+ /* APM X-Gene */
+ { PCI_VENDOR_ID_AMCC, 0xE004, pci_quirk_xgene_acs },
++ /* Ampere Computing */
++ { PCI_VENDOR_ID_AMPERE, 0xE005, pci_quirk_xgene_acs },
++ { PCI_VENDOR_ID_AMPERE, 0xE006, pci_quirk_xgene_acs },
++ { PCI_VENDOR_ID_AMPERE, 0xE007, pci_quirk_xgene_acs },
++ { PCI_VENDOR_ID_AMPERE, 0xE008, pci_quirk_xgene_acs },
++ { PCI_VENDOR_ID_AMPERE, 0xE009, pci_quirk_xgene_acs },
++ { PCI_VENDOR_ID_AMPERE, 0xE00A, pci_quirk_xgene_acs },
++ { PCI_VENDOR_ID_AMPERE, 0xE00B, pci_quirk_xgene_acs },
++ { PCI_VENDOR_ID_AMPERE, 0xE00C, pci_quirk_xgene_acs },
+ { PCI_VENDOR_ID_BROADCOM, 0xD714, pci_quirk_brcm_acs },
+ { 0 }
+ };
+diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
+index 7fa3f1498b34..bd882f51fb5f 100644
+--- a/include/linux/pci_ids.h
++++ b/include/linux/pci_ids.h
+@@ -1331,6 +1331,7 @@
+ #define PCI_DEVICE_ID_IMS_TT3D 0x9135
+
+ #define PCI_VENDOR_ID_AMCC 0x10e8
++#define PCI_VENDOR_ID_AMPERE 0x1def
+
+ #define PCI_VENDOR_ID_INTERG 0x10ea
+ #define PCI_DEVICE_ID_INTERG_1682 0x1682
+--
+2.25.1
+
--- /dev/null
+From 3176df575b23c89afb39c412539d2ada05dca6b4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 May 2020 13:57:42 -0700
+Subject: PCI: Add ACS quirk for Intel Root Complex Integrated Endpoints
+
+From: Ashok Raj <ashok.raj@intel.com>
+
+[ Upstream commit 3247bd10a4502a3075ce8e1c3c7d31ef76f193ce ]
+
+All Intel platforms guarantee that all root complex implementations must
+send transactions up to IOMMU for address translations. Hence for Intel
+RCiEP devices, we can assume some ACS-type isolation even without an ACS
+capability.
+
+From the Intel VT-d spec, r3.1, sec 3.16 ("Root-Complex Peer to Peer
+Considerations"):
+
+ When DMA remapping is enabled, peer-to-peer requests through the
+ Root-Complex must be handled as follows:
+
+ - The input address in the request is translated (through first-level,
+ second-level or nested translation) to a host physical address (HPA).
+ The address decoding for peer addresses must be done only on the
+ translated HPA. Hardware implementations are free to further limit
+ peer-to-peer accesses to specific host physical address regions (or
+ to completely disallow peer-forwarding of translated requests).
+
+ - Since address translation changes the contents (address field) of
+ the PCI Express Transaction Layer Packet (TLP), for PCI Express
+ peer-to-peer requests with ECRC, the Root-Complex hardware must use
+ the new ECRC (re-computed with the translated address) if it
+ decides to forward the TLP as a peer request.
+
+ - Root-ports, and multi-function root-complex integrated endpoints, may
+ support additional peer-to-peer control features by supporting PCI
+ Express Access Control Services (ACS) capability. Refer to ACS
+ capability in PCI Express specifications for details.
+
+Since Linux didn't give special treatment to allow this exception, certain
+RCiEP MFD devices were grouped in a single IOMMU group. This doesn't permit
+a single device to be assigned to a guest for instance.
+
+In one vendor system: Device 14.x were grouped in a single IOMMU group.
+
+ /sys/kernel/iommu_groups/5/devices/0000:00:14.0
+ /sys/kernel/iommu_groups/5/devices/0000:00:14.2
+ /sys/kernel/iommu_groups/5/devices/0000:00:14.3
+
+After this patch:
+
+ /sys/kernel/iommu_groups/5/devices/0000:00:14.0
+ /sys/kernel/iommu_groups/5/devices/0000:00:14.2
+ /sys/kernel/iommu_groups/6/devices/0000:00:14.3 <<< new group
+
+14.0 and 14.2 are integrated devices, but legacy end points, whereas 14.3
+was a PCIe-compliant RCiEP.
+
+ 00:14.3 Network controller: Intel Corporation Device 9df0 (rev 30)
+ Capabilities: [40] Express (v2) Root Complex Integrated Endpoint, MSI 00
+
+This permits assigning this device to a guest VM.
+
+[bhelgaas: drop "Fixes" tag since this doesn't fix a bug in that commit]
+Link: https://lore.kernel.org/r/1590699462-7131-1-git-send-email-ashok.raj@intel.com
+Tested-by: Darrel Goeddel <dgoeddel@forcepoint.com>
+Signed-off-by: Ashok Raj <ashok.raj@intel.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
+Cc: stable@vger.kernel.org
+Cc: Lu Baolu <baolu.lu@linux.intel.com>
+Cc: Mark Scott <mscott@forcepoint.com>,
+Cc: Romil Sharma <rsharma@forcepoint.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 3e1a0a207734..0472e69833c8 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -4513,6 +4513,20 @@ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
+ return acs_flags ? 0 : 1;
+ }
+
++static int pci_quirk_rciep_acs(struct pci_dev *dev, u16 acs_flags)
++{
++ /*
++ * Intel RCiEP's are required to allow p2p only on translated
++ * addresses. Refer to Intel VT-d specification, r3.1, sec 3.16,
++ * "Root-Complex Peer to Peer Considerations".
++ */
++ if (pci_pcie_type(dev) != PCI_EXP_TYPE_RC_END)
++ return -ENOTTY;
++
++ return pci_acs_ctrl_enabled(acs_flags,
++ PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
++}
++
+ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)
+ {
+ /*
+@@ -4596,6 +4610,7 @@ static const struct pci_dev_acs_enabled {
+ /* I219 */
+ { PCI_VENDOR_ID_INTEL, 0x15b7, pci_quirk_mf_endpoint_acs },
+ { PCI_VENDOR_ID_INTEL, 0x15b8, pci_quirk_mf_endpoint_acs },
++ { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_rciep_acs },
+ /* QCOM QDF2xxx root ports */
+ { 0x17cb, 0x400, pci_quirk_qcom_rp_acs },
+ { 0x17cb, 0x401, pci_quirk_qcom_rp_acs },
+--
+2.25.1
+
--- /dev/null
+From 7076f531cfb1a89d7cff3272c045c77681c8bc4c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Aug 2019 10:09:45 +0530
+Subject: PCI: Add ACS quirk for iProc PAXB
+
+From: Abhinav Ratna <abhinav.ratna@broadcom.com>
+
+[ Upstream commit 46b2c32df7a462d0e64b68c513e5c4c1b2a399a7 ]
+
+iProc PAXB Root Ports don't advertise an ACS capability, but they do not
+allow peer-to-peer transactions between Root Ports. Add an ACS quirk so
+each Root Port can be in a separate IOMMU group.
+
+[bhelgaas: commit log, comment, use common implementation style]
+Link: https://lore.kernel.org/r/1566275985-25670-1-git-send-email-srinath.mannam@broadcom.com
+Signed-off-by: Abhinav Ratna <abhinav.ratna@broadcom.com>
+Signed-off-by: Srinath Mannam <srinath.mannam@broadcom.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Acked-by: Scott Branden <scott.branden@broadcom.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 1bc7d4bcfea4..f6e88d5b1c4f 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -4515,6 +4515,19 @@ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
+ return acs_flags ? 0 : 1;
+ }
+
++static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)
++{
++ /*
++ * iProc PAXB Root Ports don't advertise an ACS capability, but
++ * they do not allow peer-to-peer transactions between Root Ports.
++ * Allow each Root Port to be in a separate IOMMU group by masking
++ * SV/RR/CR/UF bits.
++ */
++ acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
++
++ return acs_flags ? 0 : 1;
++}
++
+ static const struct pci_dev_acs_enabled {
+ u16 vendor;
+ u16 device;
+@@ -4597,6 +4610,7 @@ static const struct pci_dev_acs_enabled {
+ { PCI_VENDOR_ID_CAVIUM, PCI_ANY_ID, pci_quirk_cavium_acs },
+ /* APM X-Gene */
+ { PCI_VENDOR_ID_AMCC, 0xE004, pci_quirk_xgene_acs },
++ { PCI_VENDOR_ID_BROADCOM, 0xD714, pci_quirk_brcm_acs },
+ { 0 }
+ };
+
+--
+2.25.1
+
--- /dev/null
+From 468337a4389057fd9735ac1746daf91738c98cbb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2020 18:23:30 -0500
+Subject: PCI: Avoid FLR for AMD Matisse HD Audio & USB 3.0
+
+From: Marcos Scriven <marcos@scriven.org>
+
+[ Upstream commit 0d14f06cd6657ba3446a5eb780672da487b068e7 ]
+
+The AMD Matisse HD Audio & USB 3.0 devices advertise Function Level Reset
+support, but hang when an FLR is triggered.
+
+To reproduce the problem, attach the device to a VM, then detach and try to
+attach again.
+
+Rename the existing quirk_intel_no_flr(), which was not Intel-specific, to
+quirk_no_flr(), and apply it to prevent the use of FLR on these AMD
+devices.
+
+Link: https://lore.kernel.org/r/CAAri2DpkcuQZYbT6XsALhx2e6vRqPHwtbjHYeiH7MNp4zmt1RA@mail.gmail.com
+Signed-off-by: Marcos Scriven <marcos@scriven.org>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index c751f2f81142..8d01c6d372fe 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -4869,13 +4869,23 @@ static void quirk_intel_qat_vf_cap(struct pci_dev *pdev)
+ }
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap);
+
+-/* FLR may cause some 82579 devices to hang. */
+-static void quirk_intel_no_flr(struct pci_dev *dev)
++/*
++ * FLR may cause the following to devices to hang:
++ *
++ * AMD Starship/Matisse HD Audio Controller 0x1487
++ * AMD Matisse USB 3.0 Host Controller 0x149c
++ * Intel 82579LM Gigabit Ethernet Controller 0x1502
++ * Intel 82579V Gigabit Ethernet Controller 0x1503
++ *
++ */
++static void quirk_no_flr(struct pci_dev *dev)
+ {
+ dev->dev_flags |= PCI_DEV_FLAGS_NO_FLR_RESET;
+ }
+-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_intel_no_flr);
+-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_intel_no_flr);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr);
+
+ static void quirk_no_ext_tags(struct pci_dev *pdev)
+ {
+--
+2.25.1
+
--- /dev/null
+From 6a5f6cec3b2fdde3e3b8d5c8072921f7a256a600 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2020 00:35:29 -0700
+Subject: PCI: Avoid FLR for AMD Starship USB 3.0
+
+From: Kevin Buettner <kevinb@redhat.com>
+
+[ Upstream commit 5727043c73fdfe04597971b5f3f4850d879c1f4f ]
+
+The AMD Starship USB 3.0 host controller advertises Function Level Reset
+support, but it apparently doesn't work. Add a quirk to prevent use of FLR
+on this device.
+
+Without this quirk, when attempting to assign (pass through) an AMD
+Starship USB 3.0 host controller to a guest OS, the system becomes
+increasingly unresponsive over the course of several minutes, eventually
+requiring a hard reset. Shortly after attempting to start the guest, I see
+these messages:
+
+ vfio-pci 0000:05:00.3: not ready 1023ms after FLR; waiting
+ vfio-pci 0000:05:00.3: not ready 2047ms after FLR; waiting
+ vfio-pci 0000:05:00.3: not ready 4095ms after FLR; waiting
+ vfio-pci 0000:05:00.3: not ready 8191ms after FLR; waiting
+
+And then eventually:
+
+ vfio-pci 0000:05:00.3: not ready 65535ms after FLR; giving up
+ INFO: NMI handler (perf_event_nmi_handler) took too long to run: 0.000 msecs
+ perf: interrupt took too long (642744 > 2500), lowering kernel.perf_event_max_sample_rate to 1000
+ INFO: NMI handler (perf_event_nmi_handler) took too long to run: 82.270 msecs
+ INFO: NMI handler (perf_event_nmi_handler) took too long to run: 680.608 msecs
+ INFO: NMI handler (perf_event_nmi_handler) took too long to run: 100.952 msecs
+ ...
+ watchdog: BUG: soft lockup - CPU#3 stuck for 22s! [qemu-system-x86:7487]
+
+Tested on a Micro-Star International Co., Ltd. MS-7C59/Creator TRX40
+motherboard with an AMD Ryzen Threadripper 3970X.
+
+Link: https://lore.kernel.org/r/20200524003529.598434ff@f31-4.lan
+Signed-off-by: Kevin Buettner <kevinb@redhat.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 8d01c6d372fe..1bc7d4bcfea4 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -4873,6 +4873,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap);
+ * FLR may cause the following to devices to hang:
+ *
+ * AMD Starship/Matisse HD Audio Controller 0x1487
++ * AMD Starship USB 3.0 Host Controller 0x148c
+ * AMD Matisse USB 3.0 Host Controller 0x149c
+ * Intel 82579LM Gigabit Ethernet Controller 0x1502
+ * Intel 82579V Gigabit Ethernet Controller 0x1503
+@@ -4883,6 +4884,7 @@ static void quirk_no_flr(struct pci_dev *dev)
+ dev->dev_flags |= PCI_DEV_FLAGS_NO_FLR_RESET;
+ }
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x148c, quirk_no_flr);
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr);
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr);
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr);
+--
+2.25.1
+
--- /dev/null
+From 92ffb17260a9abdb8e6caa6c23197c0937fdfb4e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Oct 2017 17:44:47 +0800
+Subject: PCI: Disable MSI for Freescale Layerscape PCIe RC mode
+
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+
+[ Upstream commit 06dc4ee54e306eff61cbdac3593b42b09f618103 ]
+
+The Freescale PCIe controller advertises the MSI/MSI-X capability in both
+RC and Endpoint mode, but in RC mode it doesn't support MSI/MSI-X by
+itself; it can only transfer MSI/MSI-X from downstream devices.
+
+Add a quirk to prevent use of MSI/MSI-X in RC mode.
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Acked-by: Minghuan Lian <minghuan.Lian@nxp.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index e7ed051ec125..c751f2f81142 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -4912,3 +4912,11 @@ static void quirk_no_ats(struct pci_dev *pdev)
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x98e4, quirk_no_ats);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6900, quirk_no_ats);
+ #endif /* CONFIG_PCI_ATS */
++
++/* Freescale PCIe doesn't support MSI in RC mode */
++static void quirk_fsl_no_msi(struct pci_dev *pdev)
++{
++ if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT)
++ pdev->no_msi = 1;
++}
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi);
+--
+2.25.1
+
--- /dev/null
+From a6d309cf192cec0086d13cd004cb920546638861 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Jun 2019 14:52:24 +0530
+Subject: PCI: Generalize multi-function power dependency device links
+
+From: Abhishek Sahu <abhsahu@nvidia.com>
+
+[ Upstream commit a17beb1a0882a544523dcb5d0da4801272dfd43a ]
+
+Although not allowed by the PCI specs, some multi-function devices have
+power dependencies between the functions. For example, function 1 may not
+work unless function 0 is in the D0 power state.
+
+The existing quirk_gpu_hda() adds a device link to express this dependency
+for GPU and HDA devices, but it really is not specific to those device
+types.
+
+Generalize it and rename it to pci_create_device_link() so we can create
+dependencies between any "consumer" and "producer" functions of a
+multi-function device, where the consumer is only functional if the
+producer is in D0. This reorganization should not affect any
+functionality.
+
+Link: https://lore.kernel.org/lkml/20190606092225.17960-2-abhsahu@nvidia.com
+Signed-off-by: Abhishek Sahu <abhsahu@nvidia.com>
+[bhelgaas: commit log, reword diagnostic]
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 54 ++++++++++++++++++++++++++++----------------
+ 1 file changed, 34 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 6af7fc0be21d..3e1a0a207734 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -4955,35 +4955,49 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev)
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi);
+
+ /*
+- * GPUs with integrated HDA controller for streaming audio to attached displays
+- * need a device link from the HDA controller (consumer) to the GPU (supplier)
+- * so that the GPU is powered up whenever the HDA controller is accessed.
+- * The GPU and HDA controller are functions 0 and 1 of the same PCI device.
+- * The device link stays in place until shutdown (or removal of the PCI device
+- * if it's hotplugged). Runtime PM is allowed by default on the HDA controller
+- * to prevent it from permanently keeping the GPU awake.
++ * Although not allowed by the spec, some multi-function devices have
++ * dependencies of one function (consumer) on another (supplier). For the
++ * consumer to work in D0, the supplier must also be in D0. Create a
++ * device link from the consumer to the supplier to enforce this
++ * dependency. Runtime PM is allowed by default on the consumer to prevent
++ * it from permanently keeping the supplier awake.
+ */
+-static void quirk_gpu_hda(struct pci_dev *hda)
++static void pci_create_device_link(struct pci_dev *pdev, unsigned int consumer,
++ unsigned int supplier, unsigned int class,
++ unsigned int class_shift)
+ {
+- struct pci_dev *gpu;
++ struct pci_dev *supplier_pdev;
+
+- if (PCI_FUNC(hda->devfn) != 1)
++ if (PCI_FUNC(pdev->devfn) != consumer)
+ return;
+
+- gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus),
+- hda->bus->number,
+- PCI_DEVFN(PCI_SLOT(hda->devfn), 0));
+- if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) {
+- pci_dev_put(gpu);
++ supplier_pdev = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus),
++ pdev->bus->number,
++ PCI_DEVFN(PCI_SLOT(pdev->devfn), supplier));
++ if (!supplier_pdev || (supplier_pdev->class >> class_shift) != class) {
++ pci_dev_put(supplier_pdev);
+ return;
+ }
+
+- if (!device_link_add(&hda->dev, &gpu->dev,
+- DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
+- pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu));
++ if (device_link_add(&pdev->dev, &supplier_pdev->dev,
++ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
++ pci_info(pdev, "D0 power state depends on %s\n",
++ pci_name(supplier_pdev));
++ else
++ pci_err(pdev, "Cannot enforce power dependency on %s\n",
++ pci_name(supplier_pdev));
++
++ pm_runtime_allow(&pdev->dev);
++ pci_dev_put(supplier_pdev);
++}
+
+- pm_runtime_allow(&hda->dev);
+- pci_dev_put(gpu);
++/*
++ * Create device link for GPUs with integrated HDA controller for streaming
++ * audio to attached displays.
++ */
++static void quirk_gpu_hda(struct pci_dev *hda)
++{
++ pci_create_device_link(hda, 1, 0, PCI_BASE_CLASS_DISPLAY, 16);
+ }
+ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+ PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
+--
+2.25.1
+
--- /dev/null
+From 9e91e02ae51bba67384b1877263f216463da4421 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Sep 2019 17:54:42 -0500
+Subject: PCI: Make ACS quirk implementations more uniform
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit c8de8ed2dcaac82e5d76d467dc0b02e0ee79809b ]
+
+The ACS quirks differ in needless ways, which makes them look more
+different than they really are.
+
+Reorder the ACS flags in order of definitions in the spec:
+
+ PCI_ACS_SV Source Validation
+ PCI_ACS_TB Translation Blocking
+ PCI_ACS_RR P2P Request Redirect
+ PCI_ACS_CR P2P Completion Redirect
+ PCI_ACS_UF Upstream Forwarding
+ PCI_ACS_EC P2P Egress Control
+ PCI_ACS_DT Direct Translated P2P
+
+(PCIe r5.0, sec 7.7.8.2) and use similar code structure in all. No
+functional change intended.
+
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
+Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 41 +++++++++++++++++++----------------------
+ 1 file changed, 19 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 81d76e34b0db..44be840dac0d 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -4305,18 +4305,18 @@ static bool pci_quirk_cavium_acs_match(struct pci_dev *dev)
+
+ static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags)
+ {
++ if (!pci_quirk_cavium_acs_match(dev))
++ return -ENOTTY;
++
+ /*
+- * Cavium root ports don't advertise an ACS capability. However,
++ * Cavium Root Ports don't advertise an ACS capability. However,
+ * the RTL internally implements similar protection as if ACS had
+- * Request Redirection, Completion Redirection, Source Validation,
++ * Source Validation, Request Redirection, Completion Redirection,
+ * and Upstream Forwarding features enabled. Assert that the
+ * hardware implements and enables equivalent ACS functionality for
+ * these flags.
+ */
+- acs_flags &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_SV | PCI_ACS_UF);
+-
+- if (!pci_quirk_cavium_acs_match(dev))
+- return -ENOTTY;
++ acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+
+ return acs_flags ? 0 : 1;
+ }
+@@ -4334,7 +4334,7 @@ static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags)
+ }
+
+ /*
+- * Many Intel PCH root ports do provide ACS-like features to disable peer
++ * Many Intel PCH Root Ports do provide ACS-like features to disable peer
+ * transactions and validate bus numbers in requests, but do not provide an
+ * actual PCIe ACS capability. This is the list of device IDs known to fall
+ * into that category as provided by Intel in Red Hat bugzilla 1037684.
+@@ -4382,37 +4382,34 @@ static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
+ return false;
+ }
+
+-#define INTEL_PCH_ACS_FLAGS (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV)
++#define INTEL_PCH_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
+
+ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
+ {
+- u16 flags = dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK ?
+- INTEL_PCH_ACS_FLAGS : 0;
+-
+ if (!pci_quirk_intel_pch_acs_match(dev))
+ return -ENOTTY;
+
+- return acs_flags & ~flags ? 0 : 1;
++ if (dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK)
++ acs_flags &= ~(INTEL_PCH_ACS_FLAGS);
++
++ return acs_flags ? 0 : 1;
+ }
+
+ /*
+- * These QCOM root ports do provide ACS-like features to disable peer
++ * These QCOM Root Ports do provide ACS-like features to disable peer
+ * transactions and validate bus numbers in requests, but do not provide an
+ * actual PCIe ACS capability. Hardware supports source validation but it
+ * will report the issue as Completer Abort instead of ACS Violation.
+- * Hardware doesn't support peer-to-peer and each root port is a root
+- * complex with unique segment numbers. It is not possible for one root
+- * port to pass traffic to another root port. All PCIe transactions are
+- * terminated inside the root port.
++ * Hardware doesn't support peer-to-peer and each Root Port is a Root
++ * Complex with unique segment numbers. It is not possible for one Root
++ * Port to pass traffic to another Root Port. All PCIe transactions are
++ * terminated inside the Root Port.
+ */
+ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags)
+ {
+- u16 flags = (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV);
+- int ret = acs_flags & ~flags ? 0 : 1;
+-
+- dev_info(&dev->dev, "Using QCOM ACS Quirk (%d)\n", ret);
++ acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+
+- return ret;
++ return acs_flags ? 0 : 1;
+ }
+
+ /*
+--
+2.25.1
+
--- /dev/null
+From be6b1a52e610d5e4dc15ee8d4072862465ef0bcf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2019 18:36:06 -0500
+Subject: PCI: Unify ACS quirk desired vs provided checking
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit 7cf2cba43f15c74bac46dc5f0326805d25ef514d ]
+
+Most of the ACS quirks have a similar pattern of:
+
+ acs_flags &= ~( <controls provided by this device> );
+ return acs_flags ? 0 : 1;
+
+Pull this out into a helper function to simplify the quirks slightly. The
+helper function is also a convenient place for comments about what the list
+of ACS controls means. No functional change intended.
+
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
+Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 67 +++++++++++++++++++++++++++++---------------
+ 1 file changed, 45 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 0472e69833c8..5f26c170315c 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -4236,6 +4236,24 @@ static void quirk_chelsio_T5_disable_root_port_attributes(struct pci_dev *pdev)
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
+ quirk_chelsio_T5_disable_root_port_attributes);
+
++/*
++ * pci_acs_ctrl_enabled - compare desired ACS controls with those provided
++ * by a device
++ * @acs_ctrl_req: Bitmask of desired ACS controls
++ * @acs_ctrl_ena: Bitmask of ACS controls enabled or provided implicitly by
++ * the hardware design
++ *
++ * Return 1 if all ACS controls in the @acs_ctrl_req bitmask are included
++ * in @acs_ctrl_ena, i.e., the device provides all the access controls the
++ * caller desires. Return 0 otherwise.
++ */
++static int pci_acs_ctrl_enabled(u16 acs_ctrl_req, u16 acs_ctrl_ena)
++{
++ if ((acs_ctrl_req & acs_ctrl_ena) == acs_ctrl_req)
++ return 1;
++ return 0;
++}
++
+ /*
+ * AMD has indicated that the devices below do not support peer-to-peer
+ * in any system where they are found in the southbridge with an AMD
+@@ -4279,7 +4297,7 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
+ /* Filter out flags not applicable to multifunction */
+ acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC | PCI_ACS_DT);
+
+- return acs_flags & ~(PCI_ACS_RR | PCI_ACS_CR) ? 0 : 1;
++ return pci_acs_ctrl_enabled(acs_flags, PCI_ACS_RR | PCI_ACS_CR);
+ #else
+ return -ENODEV;
+ #endif
+@@ -4317,9 +4335,8 @@ static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags)
+ * hardware implements and enables equivalent ACS functionality for
+ * these flags.
+ */
+- acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+-
+- return acs_flags ? 0 : 1;
++ return pci_acs_ctrl_enabled(acs_flags,
++ PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+ }
+
+ static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags)
+@@ -4329,9 +4346,8 @@ static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags)
+ * transactions with others, allowing masking out these bits as if they
+ * were unimplemented in the ACS capability.
+ */
+- acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+-
+- return acs_flags ? 0 : 1;
++ return pci_acs_ctrl_enabled(acs_flags,
++ PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+ }
+
+ /*
+@@ -4383,17 +4399,16 @@ static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
+ return false;
+ }
+
+-#define INTEL_PCH_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
+-
+ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
+ {
+ if (!pci_quirk_intel_pch_acs_match(dev))
+ return -ENOTTY;
+
+ if (dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK)
+- acs_flags &= ~(INTEL_PCH_ACS_FLAGS);
++ return pci_acs_ctrl_enabled(acs_flags,
++ PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+
+- return acs_flags ? 0 : 1;
++ return pci_acs_ctrl_enabled(acs_flags, 0);
+ }
+
+ /*
+@@ -4408,9 +4423,8 @@ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
+ */
+ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags)
+ {
+- acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+-
+- return acs_flags ? 0 : 1;
++ return pci_acs_ctrl_enabled(acs_flags,
++ PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+ }
+
+ /*
+@@ -4493,7 +4507,7 @@ static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u16 acs_flags)
+
+ pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);
+
+- return acs_flags & ~ctrl ? 0 : 1;
++ return pci_acs_ctrl_enabled(acs_flags, ctrl);
+ }
+
+ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
+@@ -4507,10 +4521,9 @@ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
+ * perform peer-to-peer with other functions, allowing us to mask out
+ * these bits as if they were unimplemented in the ACS capability.
+ */
+- acs_flags &= ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
+- PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);
+-
+- return acs_flags ? 0 : 1;
++ return pci_acs_ctrl_enabled(acs_flags,
++ PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
++ PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);
+ }
+
+ static int pci_quirk_rciep_acs(struct pci_dev *dev, u16 acs_flags)
+@@ -4535,9 +4548,8 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)
+ * Allow each Root Port to be in a separate IOMMU group by masking
+ * SV/RR/CR/UF bits.
+ */
+- acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+-
+- return acs_flags ? 0 : 1;
++ return pci_acs_ctrl_enabled(acs_flags,
++ PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+ }
+
+ static const struct pci_dev_acs_enabled {
+@@ -4636,6 +4648,17 @@ static const struct pci_dev_acs_enabled {
+ { 0 }
+ };
+
++/*
++ * pci_dev_specific_acs_enabled - check whether device provides ACS controls
++ * @dev: PCI device
++ * @acs_flags: Bitmask of desired ACS controls
++ *
++ * Returns:
++ * -ENOTTY: No quirk applies to this device; we can't tell whether the
++ * device provides the desired controls
++ * 0: Device does not provide all the desired controls
++ * >0: Device provides all the controls in @acs_flags
++ */
+ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
+ {
+ const struct pci_dev_acs_enabled *i;
+--
+2.25.1
+
ext4-fix-ext_max_extent-index-to-check-for-zeroed-eh_max.patch
ext4-fix-error-pointer-dereference.patch
ext4-fix-race-between-ext4_sync_parent-and-rename.patch
+pci-disable-msi-for-freescale-layerscape-pcie-rc-mod.patch
+pci-avoid-flr-for-amd-matisse-hd-audio-usb-3.0.patch
+pci-avoid-flr-for-amd-starship-usb-3.0.patch
+pci-add-acs-quirk-for-iproc-paxb.patch
+pci-add-acs-quirk-for-ampere-root-ports.patch
+pci-make-acs-quirk-implementations-more-uniform.patch
+vga_switcheroo-deduplicate-power-state-tracking.patch
+vga_switcheroo-use-device-link-for-hda-controller.patch
+pci-generalize-multi-function-power-dependency-devic.patch
+pci-add-acs-quirk-for-intel-root-complex-integrated-.patch
+pci-unify-acs-quirk-desired-vs-provided-checking.patch
--- /dev/null
+From bbfbc2e26d5c1061004ab106951d78e9d05d2e52 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 3 Mar 2018 10:53:24 +0100
+Subject: vga_switcheroo: Deduplicate power state tracking
+
+From: Lukas Wunner <lukas@wunner.de>
+
+[ Upstream commit 8948ca1a12c9a039361bbc3e4627064153971d57 ]
+
+If DRM drivers use runtime PM, they currently notify vga_switcheroo
+whenever they ->runtime_suspend or ->runtime_resume to update
+vga_switcheroo's internal power state tracking.
+
+That's essentially a duplication of a functionality performed by the
+PM core as it already tracks the GPU's power state and vga_switcheroo
+can always query it.
+
+Introduce a new internal helper vga_switcheroo_pwr_state() which does
+just that if runtime PM is used, or falls back to vga_switcheroo's
+internal power state tracking if manual power control is used.
+Drop a redundant power state check in set_audio_state() while at it.
+
+This removes one of the two purposes of the notification mechanism
+implemented by vga_switcheroo_set_dynamic_switch(). The other one is
+power management of the audio device and we'll remove that next.
+
+Cc: Dave Airlie <airlied@redhat.com>
+Cc: Ben Skeggs <bskeggs@redhat.com>
+Cc: Takashi Iwai <tiwai@suse.de>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reviewed-by: Peter Wu <peter@lekensteyn.nl>
+Tested-by: Kai Heng Feng <kai.heng.feng@canonical.com> # AMD PowerXpress
+Tested-by: Mike Lothian <mike@fireburn.co.uk> # AMD PowerXpress
+Tested-by: Denis Lisov <dennis.lissov@gmail.com> # Nvidia Optimus
+Tested-by: Peter Wu <peter@lekensteyn.nl> # Nvidia Optimus
+Tested-by: Lukas Wunner <lukas@wunner.de> # MacBook Pro
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Link: https://patchwork.freedesktop.org/patch/msgid/0aa49d735b988aa04524a8dc339582ace33f0f94.1520068884.git.lukas@wunner.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/vga/vga_switcheroo.c | 35 +++++++++++++++++++++-----------
+ 1 file changed, 23 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
+index 3cd153c6d271..5da45325621c 100644
+--- a/drivers/gpu/vga/vga_switcheroo.c
++++ b/drivers/gpu/vga/vga_switcheroo.c
+@@ -92,7 +92,8 @@
+ * struct vga_switcheroo_client - registered client
+ * @pdev: client pci device
+ * @fb_info: framebuffer to which console is remapped on switching
+- * @pwr_state: current power state
++ * @pwr_state: current power state if manual power control is used.
++ * For driver power control, call vga_switcheroo_pwr_state().
+ * @ops: client callbacks
+ * @id: client identifier. Determining the id requires the handler,
+ * so gpus are initially assigned VGA_SWITCHEROO_UNKNOWN_ID
+@@ -406,6 +407,19 @@ bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev)
+ }
+ EXPORT_SYMBOL(vga_switcheroo_client_probe_defer);
+
++static enum vga_switcheroo_state
++vga_switcheroo_pwr_state(struct vga_switcheroo_client *client)
++{
++ if (client->driver_power_control)
++ if (pm_runtime_enabled(&client->pdev->dev) &&
++ pm_runtime_active(&client->pdev->dev))
++ return VGA_SWITCHEROO_ON;
++ else
++ return VGA_SWITCHEROO_OFF;
++ else
++ return client->pwr_state;
++}
++
+ /**
+ * vga_switcheroo_get_client_state() - obtain power state of a given client
+ * @pdev: client pci device
+@@ -425,7 +439,7 @@ enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *pdev)
+ if (!client)
+ ret = VGA_SWITCHEROO_NOT_FOUND;
+ else
+- ret = client->pwr_state;
++ ret = vga_switcheroo_pwr_state(client);
+ mutex_unlock(&vgasr_mutex);
+ return ret;
+ }
+@@ -598,7 +612,7 @@ static int vga_switcheroo_show(struct seq_file *m, void *v)
+ client_is_vga(client) ? "" : "-Audio",
+ client->active ? '+' : ' ',
+ client->driver_power_control ? "Dyn" : "",
+- client->pwr_state ? "Pwr" : "Off",
++ vga_switcheroo_pwr_state(client) ? "Pwr" : "Off",
+ pci_name(client->pdev));
+ i++;
+ }
+@@ -641,7 +655,7 @@ static void set_audio_state(enum vga_switcheroo_client_id id,
+ struct vga_switcheroo_client *client;
+
+ client = find_client_from_id(&vgasr_priv.clients, id | ID_BIT_AUDIO);
+- if (client && client->pwr_state != state) {
++ if (client) {
+ client->ops->set_gpu_state(client->pdev, state);
+ client->pwr_state = state;
+ }
+@@ -656,7 +670,7 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
+ if (!active)
+ return 0;
+
+- if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
++ if (vga_switcheroo_pwr_state(new_client) == VGA_SWITCHEROO_OFF)
+ vga_switchon(new_client);
+
+ vga_set_default_device(new_client->pdev);
+@@ -695,7 +709,7 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
+ if (new_client->ops->reprobe)
+ new_client->ops->reprobe(new_client->pdev);
+
+- if (active->pwr_state == VGA_SWITCHEROO_ON)
++ if (vga_switcheroo_pwr_state(active) == VGA_SWITCHEROO_ON)
+ vga_switchoff(active);
+
+ set_audio_state(new_client->id, VGA_SWITCHEROO_ON);
+@@ -940,8 +954,7 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
+ * command line disables it.
+ *
+ * When the driver decides to power up or down, it notifies vga_switcheroo
+- * thereof so that it can (a) power the audio device on the GPU up or down,
+- * and (b) update its internal power state representation for the device.
++ * thereof so that it can power the audio device on the GPU up or down.
+ * This is achieved by vga_switcheroo_set_dynamic_switch().
+ *
+ * After the GPU has been suspended, the handler needs to be called to cut
+@@ -985,9 +998,8 @@ static void vga_switcheroo_power_switch(struct pci_dev *pdev,
+ *
+ * Helper for GPUs whose power state is controlled by the driver's runtime pm.
+ * When the driver decides to power up or down, it notifies vga_switcheroo
+- * thereof using this helper so that it can (a) power the audio device on
+- * the GPU up or down, and (b) update its internal power state representation
+- * for the device.
++ * thereof using this helper so that it can power the audio device on the GPU
++ * up or down.
+ */
+ void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev,
+ enum vga_switcheroo_state dynamic)
+@@ -1001,7 +1013,6 @@ void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev,
+ return;
+ }
+
+- client->pwr_state = dynamic;
+ set_audio_state(client->id, dynamic);
+ mutex_unlock(&vgasr_mutex);
+ }
+--
+2.25.1
+
--- /dev/null
+From 9b8dc8fe5c3d49fb91dae57651c8c08f0dac8d42 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 3 Mar 2018 10:53:24 +0100
+Subject: vga_switcheroo: Use device link for HDA controller
+
+From: Lukas Wunner <lukas@wunner.de>
+
+[ Upstream commit 07f4f97d7b4bf325d9f558c5b58230387e4e57e0 ]
+
+Back in 2013, runtime PM for GPUs with integrated HDA controller was
+introduced with commits 0d69704ae348 ("gpu/vga_switcheroo: add driver
+control power feature. (v3)") and 246efa4a072f ("snd/hda: add runtime
+suspend/resume on optimus support (v4)").
+
+Briefly, the idea was that the HDA controller is forced on and off in
+unison with the GPU.
+
+The original code is mostly still in place even though it was never a
+100% perfect solution: E.g. on access to the HDA controller, the GPU
+is powered up via vga_switcheroo_runtime_resume_hdmi_audio() but there
+are no provisions to keep it resumed until access to the HDA controller
+has ceased: The GPU autosuspends after 5 seconds, rendering the HDA
+controller inaccessible.
+
+Additionally, a kludge is required when hda_intel.c probes: It has to
+check whether the GPU is powered down (check_hdmi_disabled()) and defer
+probing if so.
+
+However in the meantime (in v4.10) the driver core has gained a feature
+called device links which promises to solve such issues in a clean way:
+It allows us to declare a dependency from the HDA controller (consumer)
+to the GPU (supplier). The PM core then automagically ensures that the
+GPU is runtime resumed as long as the HDA controller's ->probe hook is
+executed and whenever the HDA controller is accessed.
+
+By default, the HDA controller has a dependency on its parent, a PCIe
+Root Port. Adding a device link creates another dependency on its
+sibling:
+
+ PCIe Root Port
+ ^ ^
+ | |
+ | |
+ HDA ===> GPU
+
+The device link is not only used for runtime PM, it also guarantees that
+on system sleep, the HDA controller suspends before the GPU and resumes
+after the GPU, and on system shutdown the HDA controller's ->shutdown
+hook is executed before the one of the GPU. It is a complete solution.
+
+Using this functionality is as simple as calling device_link_add(),
+which results in a dmesg entry like this:
+
+ pci 0000:01:00.1: Linked as a consumer to 0000:01:00.0
+
+The code for the GPU-governed audio power management can thus be removed
+(except where it's still needed for legacy manual power control).
+
+The device link is added in a PCI quirk rather than in hda_intel.c.
+It is therefore legal for the GPU to runtime suspend to D3cold even if
+the HDA controller is not bound to a driver or if CONFIG_SND_HDA_INTEL
+is not enabled, for accesses to the HDA controller will cause the GPU to
+wake up regardless if they're occurring outside of hda_intel.c (think
+config space readout via sysfs).
+
+Contrary to the previous implementation, the HDA controller's power
+state is now self-governed, rather than GPU-governed, whereas the GPU's
+power state is no longer fully self-governed. (The HDA controller needs
+to runtime suspend before the GPU can.)
+
+It is thus crucial that runtime PM is always activated on the HDA
+controller even if CONFIG_SND_HDA_POWER_SAVE_DEFAULT is set to 0 (which
+is the default), lest the GPU stays awake. This is achieved by setting
+the auto_runtime_pm flag on every codec and the AZX_DCAPS_PM_RUNTIME
+flag on the HDA controller.
+
+A side effect is that power consumption might be reduced if the GPU is
+in use but the HDA controller is not, because the HDA controller is now
+allowed to go to D3hot. Before, it was forced to stay in D0 as long as
+the GPU was in use. (There is no reduction in power consumption on my
+Nvidia GK107, but there might be on other chips.)
+
+The code paths for legacy manual power control are adjusted such that
+runtime PM is disabled during power off, thereby preventing the PM core
+from resuming the HDA controller.
+
+Note that the device link is not only added on vga_switcheroo capable
+systems, but for *any* GPU with integrated HDA controller. The idea is
+that the HDA controller streams audio via connectors located on the GPU,
+so the GPU needs to be on for the HDA controller to do anything useful.
+
+This commit implicitly fixes an unbalanced runtime PM ref upon unbind of
+hda_intel.c: On ->probe, a runtime PM ref was previously released under
+the condition "azx_has_pm_runtime(chip) || hda->use_vga_switcheroo", but
+on ->remove a runtime PM ref was only acquired under the first of those
+conditions. Thus, binding and unbinding the driver twice on a
+vga_switcheroo capable system caused the runtime PM refcount to drop
+below zero. The issue is resolved because the AZX_DCAPS_PM_RUNTIME flag
+is now always set if use_vga_switcheroo is true.
+
+For more information on device links please refer to:
+https://www.kernel.org/doc/html/latest/driver-api/device_link.html
+Documentation/driver-api/device_link.rst
+
+Cc: Dave Airlie <airlied@redhat.com>
+Cc: Ben Skeggs <bskeggs@redhat.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Takashi Iwai <tiwai@suse.de>
+Reviewed-by: Peter Wu <peter@lekensteyn.nl>
+Tested-by: Kai Heng Feng <kai.heng.feng@canonical.com> # AMD PowerXpress
+Tested-by: Mike Lothian <mike@fireburn.co.uk> # AMD PowerXpress
+Tested-by: Denis Lisov <dennis.lissov@gmail.com> # Nvidia Optimus
+Tested-by: Peter Wu <peter@lekensteyn.nl> # Nvidia Optimus
+Tested-by: Lukas Wunner <lukas@wunner.de> # MacBook Pro
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Link: https://patchwork.freedesktop.org/patch/msgid/51bd38360ff502a8c42b1ebf4405ee1d3f27118d.1520068884.git.lukas@wunner.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 -
+ drivers/gpu/drm/nouveau/nouveau_drm.c | 2 -
+ drivers/gpu/drm/radeon/radeon_drv.c | 2 -
+ drivers/gpu/vga/vga_switcheroo.c | 115 ++----------------------
+ drivers/pci/quirks.c | 39 ++++++++
+ include/linux/pci_ids.h | 1 +
+ include/linux/vga_switcheroo.h | 6 --
+ include/sound/hdaudio.h | 3 -
+ sound/pci/hda/hda_intel.c | 35 +++++---
+ sound/pci/hda/hda_intel.h | 3 -
+ 10 files changed, 72 insertions(+), 136 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+index 4894d8a87c04..ae23f7e0290c 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+@@ -728,7 +728,6 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
+
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+ drm_kms_helper_poll_disable(drm_dev);
+- vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
+
+ ret = amdgpu_device_suspend(drm_dev, false, false);
+ pci_save_state(pdev);
+@@ -765,7 +764,6 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
+
+ ret = amdgpu_device_resume(drm_dev, false, false);
+ drm_kms_helper_poll_enable(drm_dev);
+- vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
+ return 0;
+ }
+diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
+index 70a8d0b0c4f1..d00524a5d7f0 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
+@@ -754,7 +754,6 @@ nouveau_pmops_runtime_suspend(struct device *dev)
+ }
+
+ drm_kms_helper_poll_disable(drm_dev);
+- vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
+ nouveau_switcheroo_optimus_dsm();
+ ret = nouveau_do_suspend(drm_dev, true);
+ pci_save_state(pdev);
+@@ -789,7 +788,6 @@ nouveau_pmops_runtime_resume(struct device *dev)
+
+ /* do magic */
+ nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25));
+- vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
+
+ /* Monitors may have been connected / disconnected during suspend */
+diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
+index f4becad0a78c..f6908e2f9e55 100644
+--- a/drivers/gpu/drm/radeon/radeon_drv.c
++++ b/drivers/gpu/drm/radeon/radeon_drv.c
+@@ -424,7 +424,6 @@ static int radeon_pmops_runtime_suspend(struct device *dev)
+
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+ drm_kms_helper_poll_disable(drm_dev);
+- vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
+
+ ret = radeon_suspend_kms(drm_dev, false, false, false);
+ pci_save_state(pdev);
+@@ -461,7 +460,6 @@ static int radeon_pmops_runtime_resume(struct device *dev)
+
+ ret = radeon_resume_kms(drm_dev, false, false);
+ drm_kms_helper_poll_enable(drm_dev);
+- vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
+ return 0;
+ }
+diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
+index 5da45325621c..f188c85b3b7a 100644
+--- a/drivers/gpu/vga/vga_switcheroo.c
++++ b/drivers/gpu/vga/vga_switcheroo.c
+@@ -105,8 +105,7 @@
+ * @list: client list
+ *
+ * Registered client. A client can be either a GPU or an audio device on a GPU.
+- * For audio clients, the @fb_info, @active and @driver_power_control members
+- * are bogus.
++ * For audio clients, the @fb_info and @active members are bogus.
+ */
+ struct vga_switcheroo_client {
+ struct pci_dev *pdev;
+@@ -332,8 +331,8 @@ EXPORT_SYMBOL(vga_switcheroo_register_client);
+ * @ops: client callbacks
+ * @id: client identifier
+ *
+- * Register audio client (audio device on a GPU). The power state of the
+- * client is assumed to be ON. Beforehand, vga_switcheroo_client_probe_defer()
++ * Register audio client (audio device on a GPU). The client is assumed
++ * to use runtime PM. Beforehand, vga_switcheroo_client_probe_defer()
+ * shall be called to ensure that all prerequisites are met.
+ *
+ * Return: 0 on success, -ENOMEM on memory allocation error.
+@@ -342,7 +341,7 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
+ const struct vga_switcheroo_client_ops *ops,
+ enum vga_switcheroo_client_id id)
+ {
+- return register_client(pdev, ops, id | ID_BIT_AUDIO, false, false);
++ return register_client(pdev, ops, id | ID_BIT_AUDIO, false, true);
+ }
+ EXPORT_SYMBOL(vga_switcheroo_register_audio_client);
+
+@@ -655,10 +654,8 @@ static void set_audio_state(enum vga_switcheroo_client_id id,
+ struct vga_switcheroo_client *client;
+
+ client = find_client_from_id(&vgasr_priv.clients, id | ID_BIT_AUDIO);
+- if (client) {
++ if (client)
+ client->ops->set_gpu_state(client->pdev, state);
+- client->pwr_state = state;
+- }
+ }
+
+ /* stage one happens before delay */
+@@ -953,10 +950,6 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
+ * Specifying nouveau.runpm=0, radeon.runpm=0 or amdgpu.runpm=0 on the kernel
+ * command line disables it.
+ *
+- * When the driver decides to power up or down, it notifies vga_switcheroo
+- * thereof so that it can power the audio device on the GPU up or down.
+- * This is achieved by vga_switcheroo_set_dynamic_switch().
+- *
+ * After the GPU has been suspended, the handler needs to be called to cut
+ * power to the GPU. Likewise it needs to reinstate power before the GPU
+ * can resume. This is achieved by vga_switcheroo_init_domain_pm_ops(),
+@@ -964,8 +957,9 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
+ * calls to the handler.
+ *
+ * When the audio device resumes, the GPU needs to be woken. This is achieved
+- * by vga_switcheroo_init_domain_pm_optimus_hdmi_audio(), which augments the
+- * audio device's resume function.
++ * by a PCI quirk which calls device_link_add() to declare a dependency on the
++ * GPU. That way, the GPU is kept awake whenever and as long as the audio
++ * device is in use.
+ *
+ * On muxed machines, if the mux is initially switched to the discrete GPU,
+ * the user ends up with a black screen when the GPU powers down after boot.
+@@ -991,33 +985,6 @@ static void vga_switcheroo_power_switch(struct pci_dev *pdev,
+ vgasr_priv.handler->power_state(client->id, state);
+ }
+
+-/**
+- * vga_switcheroo_set_dynamic_switch() - helper for driver power control
+- * @pdev: client pci device
+- * @dynamic: new power state
+- *
+- * Helper for GPUs whose power state is controlled by the driver's runtime pm.
+- * When the driver decides to power up or down, it notifies vga_switcheroo
+- * thereof using this helper so that it can power the audio device on the GPU
+- * up or down.
+- */
+-void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev,
+- enum vga_switcheroo_state dynamic)
+-{
+- struct vga_switcheroo_client *client;
+-
+- mutex_lock(&vgasr_mutex);
+- client = find_client_from_pci(&vgasr_priv.clients, pdev);
+- if (!client || !client->driver_power_control) {
+- mutex_unlock(&vgasr_mutex);
+- return;
+- }
+-
+- set_audio_state(client->id, dynamic);
+- mutex_unlock(&vgasr_mutex);
+-}
+-EXPORT_SYMBOL(vga_switcheroo_set_dynamic_switch);
+-
+ /* switcheroo power domain */
+ static int vga_switcheroo_runtime_suspend(struct device *dev)
+ {
+@@ -1087,69 +1054,3 @@ void vga_switcheroo_fini_domain_pm_ops(struct device *dev)
+ dev_pm_domain_set(dev, NULL);
+ }
+ EXPORT_SYMBOL(vga_switcheroo_fini_domain_pm_ops);
+-
+-static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev)
+-{
+- struct pci_dev *pdev = to_pci_dev(dev);
+- struct vga_switcheroo_client *client;
+- struct device *video_dev = NULL;
+- int ret;
+-
+- /* we need to check if we have to switch back on the video
+- * device so the audio device can come back
+- */
+- mutex_lock(&vgasr_mutex);
+- list_for_each_entry(client, &vgasr_priv.clients, list) {
+- if (PCI_SLOT(client->pdev->devfn) == PCI_SLOT(pdev->devfn) &&
+- client_is_vga(client)) {
+- video_dev = &client->pdev->dev;
+- break;
+- }
+- }
+- mutex_unlock(&vgasr_mutex);
+-
+- if (video_dev) {
+- ret = pm_runtime_get_sync(video_dev);
+- if (ret && ret != 1)
+- return ret;
+- }
+- ret = dev->bus->pm->runtime_resume(dev);
+-
+- /* put the reference for the gpu */
+- if (video_dev) {
+- pm_runtime_mark_last_busy(video_dev);
+- pm_runtime_put_autosuspend(video_dev);
+- }
+- return ret;
+-}
+-
+-/**
+- * vga_switcheroo_init_domain_pm_optimus_hdmi_audio() - helper for driver
+- * power control
+- * @dev: audio client device
+- * @domain: power domain
+- *
+- * Helper for GPUs whose power state is controlled by the driver's runtime pm.
+- * When the audio device resumes, the GPU needs to be woken. This helper
+- * augments the audio device's resume function to do that.
+- *
+- * Return: 0 on success, -EINVAL if no power management operations are
+- * defined for this device.
+- */
+-int
+-vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev,
+- struct dev_pm_domain *domain)
+-{
+- /* copy over all the bus versions */
+- if (dev->bus && dev->bus->pm) {
+- domain->ops = *dev->bus->pm;
+- domain->ops.runtime_resume =
+- vga_switcheroo_runtime_resume_hdmi_audio;
+-
+- dev_pm_domain_set(dev, domain);
+- return 0;
+- }
+- dev_pm_domain_set(dev, NULL);
+- return -EINVAL;
+-}
+-EXPORT_SYMBOL(vga_switcheroo_init_domain_pm_optimus_hdmi_audio);
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 44be840dac0d..6af7fc0be21d 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -27,6 +27,7 @@
+ #include <linux/ktime.h>
+ #include <linux/mm.h>
+ #include <linux/platform_data/x86/apple.h>
++#include <linux/pm_runtime.h>
+ #include <asm/dma.h> /* isa_dma_bridge_buggy */
+ #include "pci.h"
+
+@@ -4952,3 +4953,41 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev)
+ pdev->no_msi = 1;
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi);
++
++/*
++ * GPUs with integrated HDA controller for streaming audio to attached displays
++ * need a device link from the HDA controller (consumer) to the GPU (supplier)
++ * so that the GPU is powered up whenever the HDA controller is accessed.
++ * The GPU and HDA controller are functions 0 and 1 of the same PCI device.
++ * The device link stays in place until shutdown (or removal of the PCI device
++ * if it's hotplugged). Runtime PM is allowed by default on the HDA controller
++ * to prevent it from permanently keeping the GPU awake.
++ */
++static void quirk_gpu_hda(struct pci_dev *hda)
++{
++ struct pci_dev *gpu;
++
++ if (PCI_FUNC(hda->devfn) != 1)
++ return;
++
++ gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus),
++ hda->bus->number,
++ PCI_DEVFN(PCI_SLOT(hda->devfn), 0));
++ if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) {
++ pci_dev_put(gpu);
++ return;
++ }
++
++ if (!device_link_add(&hda->dev, &gpu->dev,
++ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
++ pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu));
++
++ pm_runtime_allow(&hda->dev);
++ pci_dev_put(gpu);
++}
++DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
++ PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
++DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMD, PCI_ANY_ID,
++ PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
++DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
++ PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
+diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
+index bd882f51fb5f..2d036930a3cd 100644
+--- a/include/linux/pci_ids.h
++++ b/include/linux/pci_ids.h
+@@ -45,6 +45,7 @@
+ #define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400
+ #define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
+ #define PCI_CLASS_MULTIMEDIA_PHONE 0x0402
++#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
+ #define PCI_CLASS_MULTIMEDIA_OTHER 0x0480
+
+ #define PCI_BASE_CLASS_MEMORY 0x05
+diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
+index 960bedbdec87..77f0f0af3a71 100644
+--- a/include/linux/vga_switcheroo.h
++++ b/include/linux/vga_switcheroo.h
+@@ -168,11 +168,8 @@ int vga_switcheroo_process_delayed_switch(void);
+ bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev);
+ enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev);
+
+-void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic);
+-
+ int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain);
+ void vga_switcheroo_fini_domain_pm_ops(struct device *dev);
+-int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain);
+ #else
+
+ static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
+@@ -192,11 +189,8 @@ static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
+ static inline bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) { return false; }
+ static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; }
+
+-static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic) {}
+-
+ static inline int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; }
+ static inline void vga_switcheroo_fini_domain_pm_ops(struct device *dev) {}
+-static inline int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; }
+
+ #endif
+ #endif /* _LINUX_VGA_SWITCHEROO_H_ */
+diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
+index 926ea701cdc4..5d0bf1688eba 100644
+--- a/include/sound/hdaudio.h
++++ b/include/sound/hdaudio.h
+@@ -228,9 +228,6 @@ struct hdac_io_ops {
+ #define HDA_UNSOL_QUEUE_SIZE 64
+ #define HDA_MAX_CODECS 8 /* limit by controller side */
+
+-/* HD Audio class code */
+-#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
+-
+ /*
+ * CORB/RIRB
+ *
+diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
+index 7779f5460715..e399c5718ee6 100644
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -1282,6 +1282,7 @@ static void azx_vs_set_state(struct pci_dev *pci,
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct azx *chip = card->private_data;
+ struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
++ struct hda_codec *codec;
+ bool disabled;
+
+ wait_for_completion(&hda->probe_wait);
+@@ -1306,8 +1307,12 @@ static void azx_vs_set_state(struct pci_dev *pci,
+ dev_info(chip->card->dev, "%s via vga_switcheroo\n",
+ disabled ? "Disabling" : "Enabling");
+ if (disabled) {
+- pm_runtime_put_sync_suspend(card->dev);
+- azx_suspend(card->dev);
++ list_for_each_codec(codec, &chip->bus) {
++ pm_runtime_suspend(hda_codec_dev(codec));
++ pm_runtime_disable(hda_codec_dev(codec));
++ }
++ pm_runtime_suspend(card->dev);
++ pm_runtime_disable(card->dev);
+ /* when we get suspended by vga_switcheroo we end up in D3cold,
+ * however we have no ACPI handle, so pci/acpi can't put us there,
+ * put ourselves there */
+@@ -1318,9 +1323,12 @@ static void azx_vs_set_state(struct pci_dev *pci,
+ "Cannot lock devices!\n");
+ } else {
+ snd_hda_unlock_devices(&chip->bus);
+- pm_runtime_get_noresume(card->dev);
+ chip->disabled = false;
+- azx_resume(card->dev);
++ pm_runtime_enable(card->dev);
++ list_for_each_codec(codec, &chip->bus) {
++ pm_runtime_enable(hda_codec_dev(codec));
++ pm_runtime_resume(hda_codec_dev(codec));
++ }
+ }
+ }
+ }
+@@ -1350,6 +1358,7 @@ static void init_vga_switcheroo(struct azx *chip)
+ dev_info(chip->card->dev,
+ "Handle vga_switcheroo audio client\n");
+ hda->use_vga_switcheroo = 1;
++ chip->driver_caps |= AZX_DCAPS_PM_RUNTIME;
+ pci_dev_put(p);
+ }
+ }
+@@ -1375,9 +1384,6 @@ static int register_vga_switcheroo(struct azx *chip)
+ return err;
+ hda->vga_switcheroo_registered = 1;
+
+- /* register as an optimus hdmi audio power domain */
+- vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev,
+- &hda->hdmi_pm_domain);
+ return 0;
+ }
+ #else
+@@ -1406,10 +1412,8 @@ static int azx_free(struct azx *chip)
+ if (use_vga_switcheroo(hda)) {
+ if (chip->disabled && hda->probe_continued)
+ snd_hda_unlock_devices(&chip->bus);
+- if (hda->vga_switcheroo_registered) {
++ if (hda->vga_switcheroo_registered)
+ vga_switcheroo_unregister_client(chip->pci);
+- vga_switcheroo_fini_domain_pm_ops(chip->card->dev);
+- }
+ }
+
+ if (bus->chip_init) {
+@@ -2301,6 +2305,7 @@ static int azx_probe_continue(struct azx *chip)
+ struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct hdac_bus *bus = azx_bus(chip);
+ struct pci_dev *pci = chip->pci;
++ struct hda_codec *codec;
+ int dev = chip->dev_index;
+ int val;
+ int err;
+@@ -2385,6 +2390,14 @@ static int azx_probe_continue(struct azx *chip)
+ chip->running = 1;
+ azx_add_card_list(chip);
+
++ /*
++ * The discrete GPU cannot power down unless the HDA controller runtime
++ * suspends, so activate runtime PM on codecs even if power_save == 0.
++ */
++ if (use_vga_switcheroo(hda))
++ list_for_each_codec(codec, &chip->bus)
++ codec->auto_runtime_pm = 1;
++
+ val = power_save;
+ #ifdef CONFIG_PM
+ if (pm_blacklist) {
+@@ -2399,7 +2412,7 @@ static int azx_probe_continue(struct azx *chip)
+ }
+ #endif /* CONFIG_PM */
+ snd_hda_set_power_save(&chip->bus, val * 1000);
+- if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
++ if (azx_has_pm_runtime(chip))
+ pm_runtime_put_autosuspend(&pci->dev);
+
+ out_free:
+diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h
+index ff0c4d617bc1..e3a3d318d2e5 100644
+--- a/sound/pci/hda/hda_intel.h
++++ b/sound/pci/hda/hda_intel.h
+@@ -40,9 +40,6 @@ struct hda_intel {
+ unsigned int vga_switcheroo_registered:1;
+ unsigned int init_failed:1; /* delayed init failed */
+
+- /* secondary power domain for hdmi audio under vga device */
+- struct dev_pm_domain hdmi_pm_domain;
+-
+ bool need_i915_power:1; /* the hda controller needs i915 power */
+ };
+
+--
+2.25.1
+