drm/amdgpu: disable runpm if we are the primary adapter
authorAlex Deucher <alexander.deucher@amd.com>
Thu, 23 Dec 2021 03:57:16 +0000 (22:57 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 Jan 2022 14:35:17 +0000 (15:35 +0100)
commit b95dc06af3e683d6b7ddbbae178b2b2a21ee8b2b upstream.

If we are the primary adapter (i.e., the one used by the firwmare
framebuffer), disable runtime pm.  This fixes a regression caused
by commit 55285e21f045 which results in the displays waking up
shortly after they go to sleep due to the device coming out of
runtime suspend and sending a hotplug uevent.

v2: squash in reworked fix from Evan

Fixes: 55285e21f045 ("fbdev/efifb: Release PCI device's runtime PM ref during FB destroy")
Bug: https://bugzilla.kernel.org/show_bug.cgi?id=215203
Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1840
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c

index 289c7dc05363476f490a7364038bc5801c189017..f428f94b43c0a3f87632aa4fc89b1b70016f1952 100644 (file)
@@ -1069,6 +1069,7 @@ struct amdgpu_device {
        bool                            runpm;
        bool                            in_runpm;
        bool                            has_pr3;
+       bool                            is_fw_fb;
 
        bool                            pm_sysfs_en;
        bool                            ucode_sysfs_en;
index f18240f8738789d83d6eb1a2bc22cc754b6977f2..70e8a86c3a69f58f3cb2b53aa5fdae425081531c 100644 (file)
@@ -38,6 +38,7 @@
 #include <drm/drm_probe_helper.h>
 #include <linux/mmu_notifier.h>
 #include <linux/suspend.h>
+#include <linux/fb.h>
 
 #include "amdgpu.h"
 #include "amdgpu_irq.h"
@@ -1246,6 +1247,26 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 
 static const struct drm_driver amdgpu_kms_driver;
 
+static bool amdgpu_is_fw_framebuffer(resource_size_t base,
+                                    resource_size_t size)
+{
+       bool found = false;
+#if IS_REACHABLE(CONFIG_FB)
+       struct apertures_struct *a;
+
+       a = alloc_apertures(1);
+       if (!a)
+               return false;
+
+       a->ranges[0].base = base;
+       a->ranges[0].size = size;
+
+       found = is_firmware_framebuffer(a);
+       kfree(a);
+#endif
+       return found;
+}
+
 static int amdgpu_pci_probe(struct pci_dev *pdev,
                            const struct pci_device_id *ent)
 {
@@ -1254,6 +1275,8 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
        unsigned long flags = ent->driver_data;
        int ret, retry = 0;
        bool supports_atomic = false;
+       bool is_fw_fb;
+       resource_size_t base, size;
 
        if (amdgpu_virtual_display ||
            amdgpu_device_asic_has_dc_support(flags & AMD_ASIC_MASK))
@@ -1310,6 +1333,10 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
        }
 #endif
 
+       base = pci_resource_start(pdev, 0);
+       size = pci_resource_len(pdev, 0);
+       is_fw_fb = amdgpu_is_fw_framebuffer(base, size);
+
        /* Get rid of things like offb */
        ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &amdgpu_kms_driver);
        if (ret)
@@ -1322,6 +1349,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
        adev->dev  = &pdev->dev;
        adev->pdev = pdev;
        ddev = adev_to_drm(adev);
+       adev->is_fw_fb = is_fw_fb;
 
        if (!supports_atomic)
                ddev->driver_features &= ~DRIVER_ATOMIC;
index 7e45640fbee02638fe90ac9972911eac930ce11c..09a2fe839059164c2b444a14dcc5ec41fc1987b3 100644 (file)
@@ -206,6 +206,12 @@ int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags)
                        adev->runpm = true;
                        break;
                }
+               /* XXX: disable runtime pm if we are the primary adapter
+                * to avoid displays being re-enabled after DPMS.
+                * This needs to be sorted out and fixed properly.
+                */
+               if (adev->is_fw_fb)
+                       adev->runpm = false;
                if (adev->runpm)
                        dev_info(adev->dev, "Using BACO for runtime pm\n");
        }