Call drm_client_dev_acquire_outputs() from vga_switcheroo's pre_switch
callback. Pushes fbcon updates from vga_switcheroo into DRM's fbdev
emulation. This affects amdgpu, i915, nouveau and radeon. No other
drivers implement vga_switcheroo.

Also remove the calls to vga_switcheroo_client_fb_set() from fbcon. It
is called from the DRM client's hotplug and sets the fbcon's framebuffer
at vga_switcheroo. Running pre_switch and hotplug concurrently could
result in a deadlock between clientlist_mutex and vgasr_mutex. Hence
clean up fbcon here as well.

Signed-off-by: Thomas Zimmermann <[email protected]>
Reviewed-by: Lyude Paul <[email protected]> # nouveau
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c |  8 ++++++++
 drivers/gpu/drm/i915/i915_switcheroo.c     | 10 ++++++++++
 drivers/gpu/drm/nouveau/nouveau_vga.c      |  9 +++++++++
 drivers/gpu/drm/radeon/radeon_device.c     |  8 ++++++++
 drivers/video/fbdev/core/fbcon.c           |  8 --------
 5 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 78c96c7102e4..87a59a79a019 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1699,10 +1699,18 @@ static bool amdgpu_switcheroo_can_switch(struct pci_dev 
*pdev)
        return atomic_read(&dev->open_count) == 0;
 }
 
+static void amdgpu_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       drm_client_dev_acquire_outputs(dev);
+}
+
 static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = {
        .set_gpu_state = amdgpu_switcheroo_set_state,
        .reprobe = NULL,
        .can_switch = amdgpu_switcheroo_can_switch,
+       .pre_switch = amdgpu_switcheroo_pre_switch,
 };
 
 /**
diff --git a/drivers/gpu/drm/i915/i915_switcheroo.c 
b/drivers/gpu/drm/i915/i915_switcheroo.c
index 7e0791024282..6b306ece0556 100644
--- a/drivers/gpu/drm/i915/i915_switcheroo.c
+++ b/drivers/gpu/drm/i915/i915_switcheroo.c
@@ -5,6 +5,7 @@
 
 #include <linux/vga_switcheroo.h>
 
+#include <drm/drm_client_event.h>
 #include <drm/drm_print.h>
 
 #include "display/intel_display_device.h"
@@ -58,10 +59,19 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
                atomic_read(&i915->drm.open_count) == 0;
 }
 
+static void i915_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+       struct drm_i915_private *i915 = pdev_to_i915(pdev);
+
+       if (i915 && intel_display_device_present(i915->display))
+               drm_client_dev_acquire_outputs(&i915->drm);
+}
+
 static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
        .set_gpu_state = i915_switcheroo_set_state,
        .reprobe = NULL,
        .can_switch = i915_switcheroo_can_switch,
+       .pre_switch = i915_switcheroo_pre_switch,
 };
 
 int i915_switcheroo_register(struct drm_i915_private *i915)
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c 
b/drivers/gpu/drm/nouveau/nouveau_vga.c
index a6c375a24154..2d2d08be8fbe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -76,11 +76,20 @@ nouveau_switcheroo_can_switch(struct pci_dev *pdev)
        return atomic_read(&drm->dev->open_count) == 0;
 }
 
+static void
+nouveau_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+       struct nouveau_drm *drm = pci_get_drvdata(pdev);
+
+       drm_client_dev_acquire_outputs(drm->dev);
+}
+
 static const struct vga_switcheroo_client_ops
 nouveau_switcheroo_ops = {
        .set_gpu_state = nouveau_switcheroo_set_state,
        .reprobe = nouveau_switcheroo_reprobe,
        .can_switch = nouveau_switcheroo_can_switch,
+       .pre_switch = nouveau_switcheroo_pre_switch,
 };
 
 void
diff --git a/drivers/gpu/drm/radeon/radeon_device.c 
b/drivers/gpu/drm/radeon/radeon_device.c
index 705c012fcf9e..8697a9eb5d13 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1258,10 +1258,18 @@ static bool radeon_switcheroo_can_switch(struct pci_dev 
*pdev)
        return atomic_read(&dev->open_count) == 0;
 }
 
+static void radeon_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       drm_client_dev_acquire_outputs(dev);
+}
+
 static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = {
        .set_gpu_state = radeon_switcheroo_set_state,
        .reprobe = NULL,
        .can_switch = radeon_switcheroo_can_switch,
+       .pre_switch = radeon_switcheroo_pre_switch,
 };
 
 /**
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 9f5c4c101581..974c7dcf5251 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -78,7 +78,6 @@
 #include <linux/interrupt.h>
 #include <linux/crc32.h> /* For counting font checksums */
 #include <linux/uaccess.h>
-#include <linux/vga_switcheroo.h>
 #include <asm/irq.h>
 
 #include "fbcon.h"
@@ -2851,9 +2850,6 @@ void fbcon_fb_unregistered(struct fb_info *info)
 
        console_lock();
 
-       if (info->device && dev_is_pci(info->device))
-               vga_switcheroo_client_fb_set(to_pci_dev(info->device), NULL);
-
        fbcon_registered_fb[info->node] = NULL;
        fbcon_num_registered_fb--;
 
@@ -2987,10 +2983,6 @@ static int do_fb_registered(struct fb_info *info)
                }
        }
 
-       /* Set the fb info for vga_switcheroo clients. Does nothing otherwise. 
*/
-       if (info->device && dev_is_pci(info->device))
-               vga_switcheroo_client_fb_set(to_pci_dev(info->device), info);
-
        return ret;
 }
 
-- 
2.54.0

Reply via email to