Skip to content

Commit b8f0009

Browse files
committed
Merge tag 'drm-misc-fixes-2022-06-30' of git://anongit.freedesktop.org/drm/drm-misc into drm-fixes
A NULL pointer dereference fix for vc4, and 3 patches to improve the sysfb device behaviour when removing conflicting framebuffers Signed-off-by: Dave Airlie <[email protected]> From: Maxime Ripard <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/20220630072404.2fa4z3nk5h5q34ci@houat
2 parents 078a3be + ee7a69a commit b8f0009

File tree

6 files changed

+99
-24
lines changed

6 files changed

+99
-24
lines changed

Documentation/driver-api/firmware/other_interfaces.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ EDD Interfaces
1313
.. kernel-doc:: drivers/firmware/edd.c
1414
:internal:
1515

16+
Generic System Framebuffers Interface
17+
-------------------------------------
18+
19+
.. kernel-doc:: drivers/firmware/sysfb.c
20+
:export:
21+
1622
Intel Stratix10 SoC Service Layer
1723
---------------------------------
1824
Some features of the Intel Stratix10 SoC require a level of privilege

drivers/firmware/sysfb.c

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,59 @@
3434
#include <linux/screen_info.h>
3535
#include <linux/sysfb.h>
3636

37+
static struct platform_device *pd;
38+
static DEFINE_MUTEX(disable_lock);
39+
static bool disabled;
40+
41+
static bool sysfb_unregister(void)
42+
{
43+
if (IS_ERR_OR_NULL(pd))
44+
return false;
45+
46+
platform_device_unregister(pd);
47+
pd = NULL;
48+
49+
return true;
50+
}
51+
52+
/**
53+
* sysfb_disable() - disable the Generic System Framebuffers support
54+
*
55+
* This disables the registration of system framebuffer devices that match the
56+
* generic drivers that make use of the system framebuffer set up by firmware.
57+
*
58+
* It also unregisters a device if this was already registered by sysfb_init().
59+
*
60+
* Context: The function can sleep. A @disable_lock mutex is acquired to serialize
61+
* against sysfb_init(), that registers a system framebuffer device.
62+
*/
63+
void sysfb_disable(void)
64+
{
65+
mutex_lock(&disable_lock);
66+
sysfb_unregister();
67+
disabled = true;
68+
mutex_unlock(&disable_lock);
69+
}
70+
EXPORT_SYMBOL_GPL(sysfb_disable);
71+
3772
static __init int sysfb_init(void)
3873
{
3974
struct screen_info *si = &screen_info;
4075
struct simplefb_platform_data mode;
41-
struct platform_device *pd;
4276
const char *name;
4377
bool compatible;
44-
int ret;
78+
int ret = 0;
79+
80+
mutex_lock(&disable_lock);
81+
if (disabled)
82+
goto unlock_mutex;
4583

4684
/* try to create a simple-framebuffer device */
4785
compatible = sysfb_parse_mode(si, &mode);
4886
if (compatible) {
49-
ret = sysfb_create_simplefb(si, &mode);
50-
if (!ret)
51-
return 0;
87+
pd = sysfb_create_simplefb(si, &mode);
88+
if (!IS_ERR(pd))
89+
goto unlock_mutex;
5290
}
5391

5492
/* if the FB is incompatible, create a legacy framebuffer device */
@@ -60,8 +98,10 @@ static __init int sysfb_init(void)
6098
name = "platform-framebuffer";
6199

62100
pd = platform_device_alloc(name, 0);
63-
if (!pd)
64-
return -ENOMEM;
101+
if (!pd) {
102+
ret = -ENOMEM;
103+
goto unlock_mutex;
104+
}
65105

66106
sysfb_apply_efi_quirks(pd);
67107

@@ -73,9 +113,11 @@ static __init int sysfb_init(void)
73113
if (ret)
74114
goto err;
75115

76-
return 0;
116+
goto unlock_mutex;
77117
err:
78118
platform_device_put(pd);
119+
unlock_mutex:
120+
mutex_unlock(&disable_lock);
79121
return ret;
80122
}
81123

drivers/firmware/sysfb_simplefb.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ __init bool sysfb_parse_mode(const struct screen_info *si,
5757
return false;
5858
}
5959

60-
__init int sysfb_create_simplefb(const struct screen_info *si,
61-
const struct simplefb_platform_data *mode)
60+
__init struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
61+
const struct simplefb_platform_data *mode)
6262
{
6363
struct platform_device *pd;
6464
struct resource res;
@@ -76,7 +76,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
7676
base |= (u64)si->ext_lfb_base << 32;
7777
if (!base || (u64)(resource_size_t)base != base) {
7878
printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n");
79-
return -EINVAL;
79+
return ERR_PTR(-EINVAL);
8080
}
8181

8282
/*
@@ -93,7 +93,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
9393
length = mode->height * mode->stride;
9494
if (length > size) {
9595
printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
96-
return -EINVAL;
96+
return ERR_PTR(-EINVAL);
9797
}
9898
length = PAGE_ALIGN(length);
9999

@@ -104,11 +104,11 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
104104
res.start = base;
105105
res.end = res.start + length - 1;
106106
if (res.end <= res.start)
107-
return -EINVAL;
107+
return ERR_PTR(-EINVAL);
108108

109109
pd = platform_device_alloc("simple-framebuffer", 0);
110110
if (!pd)
111-
return -ENOMEM;
111+
return ERR_PTR(-ENOMEM);
112112

113113
sysfb_apply_efi_quirks(pd);
114114

@@ -124,10 +124,10 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
124124
if (ret)
125125
goto err_put_device;
126126

127-
return 0;
127+
return pd;
128128

129129
err_put_device:
130130
platform_device_put(pd);
131131

132-
return ret;
132+
return ERR_PTR(ret);
133133
}

drivers/gpu/drm/vc4/vc4_perfmon.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717

1818
void vc4_perfmon_get(struct vc4_perfmon *perfmon)
1919
{
20-
struct vc4_dev *vc4 = perfmon->dev;
20+
struct vc4_dev *vc4;
2121

22+
if (!perfmon)
23+
return;
24+
25+
vc4 = perfmon->dev;
2226
if (WARN_ON_ONCE(vc4->is_vc5))
2327
return;
2428

25-
if (perfmon)
26-
refcount_inc(&perfmon->refcnt);
29+
refcount_inc(&perfmon->refcnt);
2730
}
2831

2932
void vc4_perfmon_put(struct vc4_perfmon *perfmon)

drivers/video/fbdev/core/fbmem.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/kernel.h>
2020
#include <linux/major.h>
2121
#include <linux/slab.h>
22+
#include <linux/sysfb.h>
2223
#include <linux/mm.h>
2324
#include <linux/mman.h>
2425
#include <linux/vt.h>
@@ -1752,6 +1753,17 @@ int remove_conflicting_framebuffers(struct apertures_struct *a,
17521753
do_free = true;
17531754
}
17541755

1756+
/*
1757+
* If a driver asked to unregister a platform device registered by
1758+
* sysfb, then can be assumed that this is a driver for a display
1759+
* that is set up by the system firmware and has a generic driver.
1760+
*
1761+
* Drivers for devices that don't have a generic driver will never
1762+
* ask for this, so let's assume that a real driver for the display
1763+
* was already probed and prevent sysfb to register devices later.
1764+
*/
1765+
sysfb_disable();
1766+
17551767
mutex_lock(&registration_lock);
17561768
do_remove_conflicting_framebuffers(a, name, primary);
17571769
mutex_unlock(&registration_lock);

include/linux/sysfb.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ struct efifb_dmi_info {
5555
int flags;
5656
};
5757

58+
#ifdef CONFIG_SYSFB
59+
60+
void sysfb_disable(void);
61+
62+
#else /* CONFIG_SYSFB */
63+
64+
static inline void sysfb_disable(void)
65+
{
66+
}
67+
68+
#endif /* CONFIG_SYSFB */
69+
5870
#ifdef CONFIG_EFI
5971

6072
extern struct efifb_dmi_info efifb_dmi_list[];
@@ -72,8 +84,8 @@ static inline void sysfb_apply_efi_quirks(struct platform_device *pd)
7284

7385
bool sysfb_parse_mode(const struct screen_info *si,
7486
struct simplefb_platform_data *mode);
75-
int sysfb_create_simplefb(const struct screen_info *si,
76-
const struct simplefb_platform_data *mode);
87+
struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
88+
const struct simplefb_platform_data *mode);
7789

7890
#else /* CONFIG_SYSFB_SIMPLE */
7991

@@ -83,10 +95,10 @@ static inline bool sysfb_parse_mode(const struct screen_info *si,
8395
return false;
8496
}
8597

86-
static inline int sysfb_create_simplefb(const struct screen_info *si,
87-
const struct simplefb_platform_data *mode)
98+
static inline struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
99+
const struct simplefb_platform_data *mode)
88100
{
89-
return -EINVAL;
101+
return ERR_PTR(-EINVAL);
90102
}
91103

92104
#endif /* CONFIG_SYSFB_SIMPLE */

0 commit comments

Comments
 (0)