Skip to content

Commit b49420d

Browse files
committed
video/aperture: optionally match the device in sysfb_disable()
In aperture_remove_conflicting_pci_devices(), we currently only call sysfb_disable() on vga class devices. This leads to the following problem when the pimary device is not VGA compatible: 1. A PCI device with a non-VGA class is the boot display 2. That device is probed first and it is not a VGA device so sysfb_disable() is not called, but the device resources are freed by aperture_detach_platform_device() 3. Non-primary GPU has a VGA class and it ends up calling sysfb_disable() 4. NULL pointer dereference via sysfb_disable() since the resources have already been freed by aperture_detach_platform_device() when it was called by the other device. Fix this by passing a device pointer to sysfb_disable() and checking the device to determine if we should execute it or not. v2: Fix build when CONFIG_SCREEN_INFO is not set v3: Move device check into the mutex Drop primary variable in aperture_remove_conflicting_pci_devices() Drop __init on pci sysfb_pci_dev_is_enabled() Fixes: 5ae3716 ("video/aperture: Only remove sysfb on the default vga pci device") Cc: Javier Martinez Canillas <[email protected]> Cc: Thomas Zimmermann <[email protected]> Cc: Helge Deller <[email protected]> Cc: Sam Ravnborg <[email protected]> Cc: Daniel Vetter <[email protected]> Signed-off-by: Alex Deucher <[email protected]> Cc: [email protected] Reviewed-by: Javier Martinez Canillas <[email protected]> Reviewed-by: Thomas Zimmermann <[email protected]> Signed-off-by: Alex Deucher <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent e9fd436 commit b49420d

File tree

4 files changed

+19
-17
lines changed

4 files changed

+19
-17
lines changed

drivers/firmware/sysfb.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ static struct platform_device *pd;
3939
static DEFINE_MUTEX(disable_lock);
4040
static bool disabled;
4141

42+
static struct device *sysfb_parent_dev(const struct screen_info *si);
43+
4244
static bool sysfb_unregister(void)
4345
{
4446
if (IS_ERR_OR_NULL(pd))
@@ -52,6 +54,7 @@ static bool sysfb_unregister(void)
5254

5355
/**
5456
* sysfb_disable() - disable the Generic System Framebuffers support
57+
* @dev: the device to check if non-NULL
5558
*
5659
* This disables the registration of system framebuffer devices that match the
5760
* generic drivers that make use of the system framebuffer set up by firmware.
@@ -61,17 +64,21 @@ static bool sysfb_unregister(void)
6164
* Context: The function can sleep. A @disable_lock mutex is acquired to serialize
6265
* against sysfb_init(), that registers a system framebuffer device.
6366
*/
64-
void sysfb_disable(void)
67+
void sysfb_disable(struct device *dev)
6568
{
69+
struct screen_info *si = &screen_info;
70+
6671
mutex_lock(&disable_lock);
67-
sysfb_unregister();
68-
disabled = true;
72+
if (!dev || dev == sysfb_parent_dev(si)) {
73+
sysfb_unregister();
74+
disabled = true;
75+
}
6976
mutex_unlock(&disable_lock);
7077
}
7178
EXPORT_SYMBOL_GPL(sysfb_disable);
7279

7380
#if defined(CONFIG_PCI)
74-
static __init bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
81+
static bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
7582
{
7683
/*
7784
* TODO: Try to integrate this code into the PCI subsystem
@@ -87,13 +94,13 @@ static __init bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
8794
return true;
8895
}
8996
#else
90-
static __init bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
97+
static bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
9198
{
9299
return false;
93100
}
94101
#endif
95102

96-
static __init struct device *sysfb_parent_dev(const struct screen_info *si)
103+
static struct device *sysfb_parent_dev(const struct screen_info *si)
97104
{
98105
struct pci_dev *pdev;
99106

drivers/of/platform.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ static int __init of_platform_default_populate_init(void)
592592
* This can happen for example on DT systems that do EFI
593593
* booting and may provide a GOP handle to the EFI stub.
594594
*/
595-
sysfb_disable();
595+
sysfb_disable(NULL);
596596
of_platform_device_create(node, NULL, NULL);
597597
of_node_put(node);
598598
}

drivers/video/aperture.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t si
293293
* ask for this, so let's assume that a real driver for the display
294294
* was already probed and prevent sysfb to register devices later.
295295
*/
296-
sysfb_disable();
296+
sysfb_disable(NULL);
297297

298298
aperture_detach_devices(base, size);
299299

@@ -346,15 +346,10 @@ EXPORT_SYMBOL(__aperture_remove_legacy_vga_devices);
346346
*/
347347
int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, const char *name)
348348
{
349-
bool primary = false;
350349
resource_size_t base, size;
351350
int bar, ret = 0;
352351

353-
if (pdev == vga_default_device())
354-
primary = true;
355-
356-
if (primary)
357-
sysfb_disable();
352+
sysfb_disable(&pdev->dev);
358353

359354
for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) {
360355
if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
@@ -370,7 +365,7 @@ int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, const char *na
370365
* that consumes the VGA framebuffer I/O range. Remove this
371366
* device as well.
372367
*/
373-
if (primary)
368+
if (pdev == vga_default_device())
374369
ret = __aperture_remove_legacy_vga_devices(pdev);
375370

376371
return ret;

include/linux/sysfb.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ struct efifb_dmi_info {
5858

5959
#ifdef CONFIG_SYSFB
6060

61-
void sysfb_disable(void);
61+
void sysfb_disable(struct device *dev);
6262

6363
#else /* CONFIG_SYSFB */
6464

65-
static inline void sysfb_disable(void)
65+
static inline void sysfb_disable(struct device *dev)
6666
{
6767
}
6868

0 commit comments

Comments
 (0)