Commit b8f0009b authored by Dave Airlie's avatar Dave Airlie

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: default avatarDave Airlie <airlied@redhat.com>

From: Maxime Ripard <maxime@cerno.tech>
Link: https://patchwork.freedesktop.org/patch/msgid/20220630072404.2fa4z3nk5h5q34ci@houat
parents 078a3be7 ee7a69aa
...@@ -13,6 +13,12 @@ EDD Interfaces ...@@ -13,6 +13,12 @@ EDD Interfaces
.. kernel-doc:: drivers/firmware/edd.c .. kernel-doc:: drivers/firmware/edd.c
:internal: :internal:
Generic System Framebuffers Interface
-------------------------------------
.. kernel-doc:: drivers/firmware/sysfb.c
:export:
Intel Stratix10 SoC Service Layer Intel Stratix10 SoC Service Layer
--------------------------------- ---------------------------------
Some features of the Intel Stratix10 SoC require a level of privilege Some features of the Intel Stratix10 SoC require a level of privilege
......
...@@ -34,21 +34,59 @@ ...@@ -34,21 +34,59 @@
#include <linux/screen_info.h> #include <linux/screen_info.h>
#include <linux/sysfb.h> #include <linux/sysfb.h>
static struct platform_device *pd;
static DEFINE_MUTEX(disable_lock);
static bool disabled;
static bool sysfb_unregister(void)
{
if (IS_ERR_OR_NULL(pd))
return false;
platform_device_unregister(pd);
pd = NULL;
return true;
}
/**
* sysfb_disable() - disable the Generic System Framebuffers support
*
* This disables the registration of system framebuffer devices that match the
* generic drivers that make use of the system framebuffer set up by firmware.
*
* It also unregisters a device if this was already registered by sysfb_init().
*
* Context: The function can sleep. A @disable_lock mutex is acquired to serialize
* against sysfb_init(), that registers a system framebuffer device.
*/
void sysfb_disable(void)
{
mutex_lock(&disable_lock);
sysfb_unregister();
disabled = true;
mutex_unlock(&disable_lock);
}
EXPORT_SYMBOL_GPL(sysfb_disable);
static __init int sysfb_init(void) static __init int sysfb_init(void)
{ {
struct screen_info *si = &screen_info; struct screen_info *si = &screen_info;
struct simplefb_platform_data mode; struct simplefb_platform_data mode;
struct platform_device *pd;
const char *name; const char *name;
bool compatible; bool compatible;
int ret; int ret = 0;
mutex_lock(&disable_lock);
if (disabled)
goto unlock_mutex;
/* try to create a simple-framebuffer device */ /* try to create a simple-framebuffer device */
compatible = sysfb_parse_mode(si, &mode); compatible = sysfb_parse_mode(si, &mode);
if (compatible) { if (compatible) {
ret = sysfb_create_simplefb(si, &mode); pd = sysfb_create_simplefb(si, &mode);
if (!ret) if (!IS_ERR(pd))
return 0; goto unlock_mutex;
} }
/* if the FB is incompatible, create a legacy framebuffer device */ /* if the FB is incompatible, create a legacy framebuffer device */
...@@ -60,8 +98,10 @@ static __init int sysfb_init(void) ...@@ -60,8 +98,10 @@ static __init int sysfb_init(void)
name = "platform-framebuffer"; name = "platform-framebuffer";
pd = platform_device_alloc(name, 0); pd = platform_device_alloc(name, 0);
if (!pd) if (!pd) {
return -ENOMEM; ret = -ENOMEM;
goto unlock_mutex;
}
sysfb_apply_efi_quirks(pd); sysfb_apply_efi_quirks(pd);
...@@ -73,9 +113,11 @@ static __init int sysfb_init(void) ...@@ -73,9 +113,11 @@ static __init int sysfb_init(void)
if (ret) if (ret)
goto err; goto err;
return 0; goto unlock_mutex;
err: err:
platform_device_put(pd); platform_device_put(pd);
unlock_mutex:
mutex_unlock(&disable_lock);
return ret; return ret;
} }
......
...@@ -57,8 +57,8 @@ __init bool sysfb_parse_mode(const struct screen_info *si, ...@@ -57,8 +57,8 @@ __init bool sysfb_parse_mode(const struct screen_info *si,
return false; return false;
} }
__init int sysfb_create_simplefb(const struct screen_info *si, __init struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
const struct simplefb_platform_data *mode) const struct simplefb_platform_data *mode)
{ {
struct platform_device *pd; struct platform_device *pd;
struct resource res; struct resource res;
...@@ -76,7 +76,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si, ...@@ -76,7 +76,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
base |= (u64)si->ext_lfb_base << 32; base |= (u64)si->ext_lfb_base << 32;
if (!base || (u64)(resource_size_t)base != base) { if (!base || (u64)(resource_size_t)base != base) {
printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n"); printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n");
return -EINVAL; return ERR_PTR(-EINVAL);
} }
/* /*
...@@ -93,7 +93,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si, ...@@ -93,7 +93,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
length = mode->height * mode->stride; length = mode->height * mode->stride;
if (length > size) { if (length > size) {
printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n"); printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
return -EINVAL; return ERR_PTR(-EINVAL);
} }
length = PAGE_ALIGN(length); length = PAGE_ALIGN(length);
...@@ -104,11 +104,11 @@ __init int sysfb_create_simplefb(const struct screen_info *si, ...@@ -104,11 +104,11 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
res.start = base; res.start = base;
res.end = res.start + length - 1; res.end = res.start + length - 1;
if (res.end <= res.start) if (res.end <= res.start)
return -EINVAL; return ERR_PTR(-EINVAL);
pd = platform_device_alloc("simple-framebuffer", 0); pd = platform_device_alloc("simple-framebuffer", 0);
if (!pd) if (!pd)
return -ENOMEM; return ERR_PTR(-ENOMEM);
sysfb_apply_efi_quirks(pd); sysfb_apply_efi_quirks(pd);
...@@ -124,10 +124,10 @@ __init int sysfb_create_simplefb(const struct screen_info *si, ...@@ -124,10 +124,10 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
if (ret) if (ret)
goto err_put_device; goto err_put_device;
return 0; return pd;
err_put_device: err_put_device:
platform_device_put(pd); platform_device_put(pd);
return ret; return ERR_PTR(ret);
} }
...@@ -17,13 +17,16 @@ ...@@ -17,13 +17,16 @@
void vc4_perfmon_get(struct vc4_perfmon *perfmon) void vc4_perfmon_get(struct vc4_perfmon *perfmon)
{ {
struct vc4_dev *vc4 = perfmon->dev; struct vc4_dev *vc4;
if (!perfmon)
return;
vc4 = perfmon->dev;
if (WARN_ON_ONCE(vc4->is_vc5)) if (WARN_ON_ONCE(vc4->is_vc5))
return; return;
if (perfmon) refcount_inc(&perfmon->refcnt);
refcount_inc(&perfmon->refcnt);
} }
void vc4_perfmon_put(struct vc4_perfmon *perfmon) void vc4_perfmon_put(struct vc4_perfmon *perfmon)
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/major.h> #include <linux/major.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sysfb.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/vt.h> #include <linux/vt.h>
...@@ -1752,6 +1753,17 @@ int remove_conflicting_framebuffers(struct apertures_struct *a, ...@@ -1752,6 +1753,17 @@ int remove_conflicting_framebuffers(struct apertures_struct *a,
do_free = true; do_free = true;
} }
/*
* If a driver asked to unregister a platform device registered by
* sysfb, then can be assumed that this is a driver for a display
* that is set up by the system firmware and has a generic driver.
*
* Drivers for devices that don't have a generic driver will never
* ask for this, so let's assume that a real driver for the display
* was already probed and prevent sysfb to register devices later.
*/
sysfb_disable();
mutex_lock(&registration_lock); mutex_lock(&registration_lock);
do_remove_conflicting_framebuffers(a, name, primary); do_remove_conflicting_framebuffers(a, name, primary);
mutex_unlock(&registration_lock); mutex_unlock(&registration_lock);
......
...@@ -55,6 +55,18 @@ struct efifb_dmi_info { ...@@ -55,6 +55,18 @@ struct efifb_dmi_info {
int flags; int flags;
}; };
#ifdef CONFIG_SYSFB
void sysfb_disable(void);
#else /* CONFIG_SYSFB */
static inline void sysfb_disable(void)
{
}
#endif /* CONFIG_SYSFB */
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
extern struct efifb_dmi_info efifb_dmi_list[]; extern struct efifb_dmi_info efifb_dmi_list[];
...@@ -72,8 +84,8 @@ static inline void sysfb_apply_efi_quirks(struct platform_device *pd) ...@@ -72,8 +84,8 @@ static inline void sysfb_apply_efi_quirks(struct platform_device *pd)
bool sysfb_parse_mode(const struct screen_info *si, bool sysfb_parse_mode(const struct screen_info *si,
struct simplefb_platform_data *mode); struct simplefb_platform_data *mode);
int sysfb_create_simplefb(const struct screen_info *si, struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
const struct simplefb_platform_data *mode); const struct simplefb_platform_data *mode);
#else /* CONFIG_SYSFB_SIMPLE */ #else /* CONFIG_SYSFB_SIMPLE */
...@@ -83,10 +95,10 @@ static inline bool sysfb_parse_mode(const struct screen_info *si, ...@@ -83,10 +95,10 @@ static inline bool sysfb_parse_mode(const struct screen_info *si,
return false; return false;
} }
static inline int sysfb_create_simplefb(const struct screen_info *si, static inline struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
const struct simplefb_platform_data *mode) const struct simplefb_platform_data *mode)
{ {
return -EINVAL; return ERR_PTR(-EINVAL);
} }
#endif /* CONFIG_SYSFB_SIMPLE */ #endif /* CONFIG_SYSFB_SIMPLE */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment