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
