]> git.proxmox.com Git - pve-kernel.git/blob - patches/kernel/0010-fbdev-Hot-unplug-firmware-fb-devices-on-forced-remov.patch
backport "io_uring: fix race between timeout flush and removal"
[pve-kernel.git] / patches / kernel / 0010-fbdev-Hot-unplug-firmware-fb-devices-on-forced-remov.patch
1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Thomas Zimmermann <tzimmermann@suse.de>
3 Date: Tue, 25 Jan 2022 10:12:18 +0100
4 Subject: [PATCH] fbdev: Hot-unplug firmware fb devices on forced removal
5
6 Hot-unplug all firmware-framebuffer devices as part of removing
7 them via remove_conflicting_framebuffers() et al. Releases all
8 memory regions to be acquired by native drivers.
9
10 Firmware, such as EFI, install a framebuffer while posting the
11 computer. After removing the firmware-framebuffer device from fbdev,
12 a native driver takes over the hardware and the firmware framebuffer
13 becomes invalid.
14
15 Firmware-framebuffer drivers, specifically simplefb, don't release
16 their device from Linux' device hierarchy. It still owns the firmware
17 framebuffer and blocks the native drivers from loading. This has been
18 observed in the vmwgfx driver. [1]
19
20 Initiating a device removal (i.e., hot unplug) as part of
21 remove_conflicting_framebuffers() removes the underlying device and
22 returns the memory range to the system.
23
24 [1] https://lore.kernel.org/dri-devel/20220117180359.18114-1-zack@kde.org/
25
26 v2:
27 * rename variable 'dev' to 'device' (Javier)
28
29 Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
30 Reported-by: Zack Rusin <zackr@vmware.com>
31 Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
32 Reviewed-by: Zack Rusin <zackr@vmware.com>
33 CC: stable@vger.kernel.org # v5.11+
34 Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
35 ---
36 drivers/video/fbdev/core/fbmem.c | 29 ++++++++++++++++++++++++++---
37 include/linux/fb.h | 1 +
38 2 files changed, 27 insertions(+), 3 deletions(-)
39
40 diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
41 index 7bd5e2a4a9da..91145d93990a 100644
42 --- a/drivers/video/fbdev/core/fbmem.c
43 +++ b/drivers/video/fbdev/core/fbmem.c
44 @@ -25,6 +25,7 @@
45 #include <linux/init.h>
46 #include <linux/linux_logo.h>
47 #include <linux/proc_fs.h>
48 +#include <linux/platform_device.h>
49 #include <linux/seq_file.h>
50 #include <linux/console.h>
51 #include <linux/kmod.h>
52 @@ -1557,18 +1558,36 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
53 /* check all firmware fbs and kick off if the base addr overlaps */
54 for_each_registered_fb(i) {
55 struct apertures_struct *gen_aper;
56 + struct device *device;
57
58 if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE))
59 continue;
60
61 gen_aper = registered_fb[i]->apertures;
62 + device = registered_fb[i]->device;
63 if (fb_do_apertures_overlap(gen_aper, a) ||
64 (primary && gen_aper && gen_aper->count &&
65 gen_aper->ranges[0].base == VGA_FB_PHYS)) {
66
67 printk(KERN_INFO "fb%d: switching to %s from %s\n",
68 i, name, registered_fb[i]->fix.id);
69 - do_unregister_framebuffer(registered_fb[i]);
70 +
71 + /*
72 + * If we kick-out a firmware driver, we also want to remove
73 + * the underlying platform device, such as simple-framebuffer,
74 + * VESA, EFI, etc. A native driver will then be able to
75 + * allocate the memory range.
76 + *
77 + * If it's not a platform device, at least print a warning. A
78 + * fix would add code to remove the device from the system.
79 + */
80 + if (dev_is_platform(device)) {
81 + registered_fb[i]->forced_out = true;
82 + platform_device_unregister(to_platform_device(device));
83 + } else {
84 + pr_warn("fb%d: cannot remove device\n", i);
85 + do_unregister_framebuffer(registered_fb[i]);
86 + }
87 }
88 }
89 }
90 @@ -1895,9 +1914,13 @@ EXPORT_SYMBOL(register_framebuffer);
91 void
92 unregister_framebuffer(struct fb_info *fb_info)
93 {
94 - mutex_lock(&registration_lock);
95 + bool forced_out = fb_info->forced_out;
96 +
97 + if (!forced_out)
98 + mutex_lock(&registration_lock);
99 do_unregister_framebuffer(fb_info);
100 - mutex_unlock(&registration_lock);
101 + if (!forced_out)
102 + mutex_unlock(&registration_lock);
103 }
104 EXPORT_SYMBOL(unregister_framebuffer);
105
106 diff --git a/include/linux/fb.h b/include/linux/fb.h
107 index 02f362c661c8..3d7306c9a706 100644
108 --- a/include/linux/fb.h
109 +++ b/include/linux/fb.h
110 @@ -502,6 +502,7 @@ struct fb_info {
111 } *apertures;
112
113 bool skip_vt_switch; /* no VT switch on suspend/resume required */
114 + bool forced_out; /* set when being removed by another driver */
115 };
116
117 static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {