From 9af336e8d0ec2d2a201e27800e6b0b243c481a32 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 18 Jun 2020 17:13:23 -0400 Subject: [PATCH] Fixes for 4.14 Signed-off-by: Sasha Levin --- ...-add-acs-quirk-for-ampere-root-ports.patch | 61 ++ ...k-for-intel-root-complex-integrated-.patch | 113 ++++ .../pci-add-acs-quirk-for-iproc-paxb.patch | 59 ++ ...flr-for-amd-matisse-hd-audio-usb-3.0.patch | 62 ++ ...i-avoid-flr-for-amd-starship-usb-3.0.patch | 69 ++ ...for-freescale-layerscape-pcie-rc-mod.patch | 42 ++ ...ulti-function-power-dependency-devic.patch | 109 ++++ ...s-quirk-implementations-more-uniform.patch | 124 ++++ ...s-quirk-desired-vs-provided-checking.patch | 177 ++++++ queue-4.14/series | 11 + ...roo-deduplicate-power-state-tracking.patch | 156 +++++ ...o-use-device-link-for-hda-controller.patch | 594 ++++++++++++++++++ 12 files changed, 1577 insertions(+) create mode 100644 queue-4.14/pci-add-acs-quirk-for-ampere-root-ports.patch create mode 100644 queue-4.14/pci-add-acs-quirk-for-intel-root-complex-integrated-.patch create mode 100644 queue-4.14/pci-add-acs-quirk-for-iproc-paxb.patch create mode 100644 queue-4.14/pci-avoid-flr-for-amd-matisse-hd-audio-usb-3.0.patch create mode 100644 queue-4.14/pci-avoid-flr-for-amd-starship-usb-3.0.patch create mode 100644 queue-4.14/pci-disable-msi-for-freescale-layerscape-pcie-rc-mod.patch create mode 100644 queue-4.14/pci-generalize-multi-function-power-dependency-devic.patch create mode 100644 queue-4.14/pci-make-acs-quirk-implementations-more-uniform.patch create mode 100644 queue-4.14/pci-unify-acs-quirk-desired-vs-provided-checking.patch create mode 100644 queue-4.14/vga_switcheroo-deduplicate-power-state-tracking.patch create mode 100644 queue-4.14/vga_switcheroo-use-device-link-for-hda-controller.patch diff --git a/queue-4.14/pci-add-acs-quirk-for-ampere-root-ports.patch b/queue-4.14/pci-add-acs-quirk-for-ampere-root-ports.patch new file mode 100644 index 00000000000..40e139aa6fa --- /dev/null +++ b/queue-4.14/pci-add-acs-quirk-for-ampere-root-ports.patch @@ -0,0 +1,61 @@ +From 2d9452b07f3030faa6effe2de76436d9e8523a92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Feb 2018 19:19:27 -0800 +Subject: PCI: Add ACS quirk for Ampere root ports + +From: Feng Kan + +[ 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 +Signed-off-by: Bjorn Helgaas +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.14/pci-add-acs-quirk-for-intel-root-complex-integrated-.patch b/queue-4.14/pci-add-acs-quirk-for-intel-root-complex-integrated-.patch new file mode 100644 index 00000000000..3d6017dab65 --- /dev/null +++ b/queue-4.14/pci-add-acs-quirk-for-intel-root-complex-integrated-.patch @@ -0,0 +1,113 @@ +From 3176df575b23c89afb39c412539d2ada05dca6b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 May 2020 13:57:42 -0700 +Subject: PCI: Add ACS quirk for Intel Root Complex Integrated Endpoints + +From: Ashok Raj + +[ 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 +Signed-off-by: Ashok Raj +Signed-off-by: Bjorn Helgaas +Reviewed-by: Alex Williamson +Cc: stable@vger.kernel.org +Cc: Lu Baolu +Cc: Mark Scott , +Cc: Romil Sharma +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.14/pci-add-acs-quirk-for-iproc-paxb.patch b/queue-4.14/pci-add-acs-quirk-for-iproc-paxb.patch new file mode 100644 index 00000000000..e3c6efc3f78 --- /dev/null +++ b/queue-4.14/pci-add-acs-quirk-for-iproc-paxb.patch @@ -0,0 +1,59 @@ +From 7076f531cfb1a89d7cff3272c045c77681c8bc4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Aug 2019 10:09:45 +0530 +Subject: PCI: Add ACS quirk for iProc PAXB + +From: Abhinav Ratna + +[ 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 +Signed-off-by: Srinath Mannam +Signed-off-by: Bjorn Helgaas +Acked-by: Scott Branden +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.14/pci-avoid-flr-for-amd-matisse-hd-audio-usb-3.0.patch b/queue-4.14/pci-avoid-flr-for-amd-matisse-hd-audio-usb-3.0.patch new file mode 100644 index 00000000000..7dcc781b9c8 --- /dev/null +++ b/queue-4.14/pci-avoid-flr-for-amd-matisse-hd-audio-usb-3.0.patch @@ -0,0 +1,62 @@ +From 468337a4389057fd9735ac1746daf91738c98cbb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 May 2020 18:23:30 -0500 +Subject: PCI: Avoid FLR for AMD Matisse HD Audio & USB 3.0 + +From: Marcos Scriven + +[ 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 +Signed-off-by: Bjorn Helgaas +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.14/pci-avoid-flr-for-amd-starship-usb-3.0.patch b/queue-4.14/pci-avoid-flr-for-amd-starship-usb-3.0.patch new file mode 100644 index 00000000000..646cd8337d5 --- /dev/null +++ b/queue-4.14/pci-avoid-flr-for-amd-starship-usb-3.0.patch @@ -0,0 +1,69 @@ +From 6a5f6cec3b2fdde3e3b8d5c8072921f7a256a600 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 May 2020 00:35:29 -0700 +Subject: PCI: Avoid FLR for AMD Starship USB 3.0 + +From: Kevin Buettner + +[ 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 +Signed-off-by: Bjorn Helgaas +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.14/pci-disable-msi-for-freescale-layerscape-pcie-rc-mod.patch b/queue-4.14/pci-disable-msi-for-freescale-layerscape-pcie-rc-mod.patch new file mode 100644 index 00000000000..95c2688770f --- /dev/null +++ b/queue-4.14/pci-disable-msi-for-freescale-layerscape-pcie-rc-mod.patch @@ -0,0 +1,42 @@ +From 92ffb17260a9abdb8e6caa6c23197c0937fdfb4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Oct 2017 17:44:47 +0800 +Subject: PCI: Disable MSI for Freescale Layerscape PCIe RC mode + +From: Hou Zhiqiang + +[ 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 +Signed-off-by: Bjorn Helgaas +Acked-by: Minghuan Lian +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.14/pci-generalize-multi-function-power-dependency-devic.patch b/queue-4.14/pci-generalize-multi-function-power-dependency-devic.patch new file mode 100644 index 00000000000..eef86284ae1 --- /dev/null +++ b/queue-4.14/pci-generalize-multi-function-power-dependency-devic.patch @@ -0,0 +1,109 @@ +From a6d309cf192cec0086d13cd004cb920546638861 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Jun 2019 14:52:24 +0530 +Subject: PCI: Generalize multi-function power dependency device links + +From: Abhishek Sahu + +[ 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 +[bhelgaas: commit log, reword diagnostic] +Signed-off-by: Bjorn Helgaas +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.14/pci-make-acs-quirk-implementations-more-uniform.patch b/queue-4.14/pci-make-acs-quirk-implementations-more-uniform.patch new file mode 100644 index 00000000000..94bb13cfc5e --- /dev/null +++ b/queue-4.14/pci-make-acs-quirk-implementations-more-uniform.patch @@ -0,0 +1,124 @@ +From 9e91e02ae51bba67384b1877263f216463da4421 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Sep 2019 17:54:42 -0500 +Subject: PCI: Make ACS quirk implementations more uniform + +From: Bjorn Helgaas + +[ 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 +Reviewed-by: Logan Gunthorpe +Reviewed-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.14/pci-unify-acs-quirk-desired-vs-provided-checking.patch b/queue-4.14/pci-unify-acs-quirk-desired-vs-provided-checking.patch new file mode 100644 index 00000000000..d18f75ee721 --- /dev/null +++ b/queue-4.14/pci-unify-acs-quirk-desired-vs-provided-checking.patch @@ -0,0 +1,177 @@ +From be6b1a52e610d5e4dc15ee8d4072862465ef0bcf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Sep 2019 18:36:06 -0500 +Subject: PCI: Unify ACS quirk desired vs provided checking + +From: Bjorn Helgaas + +[ Upstream commit 7cf2cba43f15c74bac46dc5f0326805d25ef514d ] + +Most of the ACS quirks have a similar pattern of: + + acs_flags &= ~( ); + 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 +Reviewed-by: Logan Gunthorpe +Reviewed-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.14/series b/queue-4.14/series index 518fc01589f..22f2915bde8 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -145,3 +145,14 @@ evm-fix-possible-memory-leak-in-evm_calc_hmac_or_hash.patch 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 diff --git a/queue-4.14/vga_switcheroo-deduplicate-power-state-tracking.patch b/queue-4.14/vga_switcheroo-deduplicate-power-state-tracking.patch new file mode 100644 index 00000000000..ec3560a7345 --- /dev/null +++ b/queue-4.14/vga_switcheroo-deduplicate-power-state-tracking.patch @@ -0,0 +1,156 @@ +From bbfbc2e26d5c1061004ab106951d78e9d05d2e52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 3 Mar 2018 10:53:24 +0100 +Subject: vga_switcheroo: Deduplicate power state tracking + +From: Lukas Wunner + +[ 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 +Cc: Ben Skeggs +Cc: Takashi Iwai +Cc: Alex Deucher +Cc: Rafael J. Wysocki +Reviewed-by: Peter Wu +Tested-by: Kai Heng Feng # AMD PowerXpress +Tested-by: Mike Lothian # AMD PowerXpress +Tested-by: Denis Lisov # Nvidia Optimus +Tested-by: Peter Wu # Nvidia Optimus +Tested-by: Lukas Wunner # MacBook Pro +Signed-off-by: Lukas Wunner +Link: https://patchwork.freedesktop.org/patch/msgid/0aa49d735b988aa04524a8dc339582ace33f0f94.1520068884.git.lukas@wunner.de +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-4.14/vga_switcheroo-use-device-link-for-hda-controller.patch b/queue-4.14/vga_switcheroo-use-device-link-for-hda-controller.patch new file mode 100644 index 00000000000..7887762b1d4 --- /dev/null +++ b/queue-4.14/vga_switcheroo-use-device-link-for-hda-controller.patch @@ -0,0 +1,594 @@ +From 9b8dc8fe5c3d49fb91dae57651c8c08f0dac8d42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 3 Mar 2018 10:53:24 +0100 +Subject: vga_switcheroo: Use device link for HDA controller + +From: Lukas Wunner + +[ 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 +Cc: Ben Skeggs +Cc: Alex Deucher +Cc: Rafael J. Wysocki +Acked-by: Bjorn Helgaas +Reviewed-by: Takashi Iwai +Reviewed-by: Peter Wu +Tested-by: Kai Heng Feng # AMD PowerXpress +Tested-by: Mike Lothian # AMD PowerXpress +Tested-by: Denis Lisov # Nvidia Optimus +Tested-by: Peter Wu # Nvidia Optimus +Tested-by: Lukas Wunner # MacBook Pro +Signed-off-by: Lukas Wunner +Link: https://patchwork.freedesktop.org/patch/msgid/51bd38360ff502a8c42b1ebf4405ee1d3f27118d.1520068884.git.lukas@wunner.de +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include /* 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 + -- 2.47.3