* [RFC 0/7] drm: Add generic fbdev emulation
@ 2017-12-31 13:58 Noralf Trønnes
2017-12-31 13:58 ` [RFC 1/7] drm: provide management functions for drm_file Noralf Trønnes
` (6 more replies)
0 siblings, 7 replies; 10+ messages in thread
From: Noralf Trønnes @ 2017-12-31 13:58 UTC (permalink / raw)
To: dri-devel; +Cc: daniel.vetter, intel-gfx, laurent.pinchart
This patchset explores the possibility of having generic fbdev emulation
in DRM for drivers that supports dumb buffers which they can export.
I was about to polish up my 'vmalloc BO helper' series, which has fbdev
support, when this idea[1] of Laurent popped into my mind:
Ideally I'd like to remove 100% of fbdev-related code from drivers. This
includes
- initialization and cleanup of fbdev helpers
- fbdev restore in last_close()
- forwarding of hotplug events to fbdev compatibility layer
In practice we'll likely need to keep one initialization function (or a
drm_driver flag) to let drivers opt-in to fbdev compatibility, but the rest
should go away. Or maybe we could even enable fbdev compatibility in all
drivers unconditionally.
So I set out to see what it would take to accomplish that.
Noralf.
[1] https://lists.freedesktop.org/archives/dri-devel/2017-September/152612.html
David Herrmann (1):
drm: provide management functions for drm_file
Noralf Trønnes (6):
drm/fb-helper: Ensure driver module is pinned in fb_open()
drm/fb-helper: Don't restore if fbdev is not in use
drm/prime: Clear drm_gem_object->dma_buf on release
drm: Handle fbdev emulation in core
drm/fb-helper: Add generic fbdev emulation
drm/vc4: Test generic fbdev emulation
drivers/gpu/drm/drm_fb_helper.c | 344 +++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/drm_file.c | 321 ++++++++++++++++++++--------------
drivers/gpu/drm/drm_internal.h | 2 +
drivers/gpu/drm/drm_mode_config.c | 10 ++
drivers/gpu/drm/drm_prime.c | 1 +
drivers/gpu/drm/drm_probe_helper.c | 4 +
drivers/gpu/drm/vc4/vc4_drv.c | 3 -
drivers/gpu/drm/vc4/vc4_kms.c | 3 +-
include/drm/drm_fb_helper.h | 95 ++++++++++
9 files changed, 645 insertions(+), 138 deletions(-)
--
2.14.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 10+ messages in thread
* [RFC 1/7] drm: provide management functions for drm_file
2017-12-31 13:58 [RFC 0/7] drm: Add generic fbdev emulation Noralf Trønnes
@ 2017-12-31 13:58 ` Noralf Trønnes
2017-12-31 13:58 ` [RFC 2/7] drm/fb-helper: Ensure driver module is pinned in fb_open() Noralf Trønnes
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Noralf Trønnes @ 2017-12-31 13:58 UTC (permalink / raw)
To: dri-devel; +Cc: daniel.vetter, intel-gfx, laurent.pinchart
From: David Herrmann <dh.herrmann@gmail.com>
Rather than doing drm_file allocation/destruction right in the fops, lets
provide separate helpers. This decouples drm_file management from the
still-mandatory drm-fops. It prepares for use of drm_file without the
fops, both by possible separate fops implementations and APIs (not that I
am aware of any such plans), and more importantly from in-kernel use where
no real file is available.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
[rebased]
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/gpu/drm/drm_file.c | 309 +++++++++++++++++++++++------------------
drivers/gpu/drm/drm_internal.h | 2 +
2 files changed, 179 insertions(+), 132 deletions(-)
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index b3c6e997ccdb..d208faade27e 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -101,6 +101,179 @@ DEFINE_MUTEX(drm_global_mutex);
static int drm_open_helper(struct file *filp, struct drm_minor *minor);
+/**
+ * drm_file_alloc - allocate file context
+ * @minor: minor to allocate on
+ *
+ * This allocates a new DRM file context. It is not linked into any context and
+ * can be used by the caller freely. Note that the context keeps a pointer to
+ * @minor, so it must be freed before @minor is.
+ *
+ * The legacy paths might require the drm_global_mutex to be held.
+ *
+ * RETURNS:
+ * Pointer to newly allocated context, ERR_PTR on failure.
+ */
+struct drm_file *drm_file_alloc(struct drm_minor *minor)
+{
+ struct drm_device *dev = minor->dev;
+ struct drm_file *file;
+ int ret;
+
+ file = kzalloc(sizeof(*file), GFP_KERNEL);
+ if (!file)
+ return ERR_PTR(-ENOMEM);
+
+ file->pid = get_pid(task_pid(current));
+ file->minor = minor;
+
+ /* for compatibility root is always authenticated */
+ file->authenticated = capable(CAP_SYS_ADMIN);
+ file->lock_count = 0;
+
+ INIT_LIST_HEAD(&file->lhead);
+ INIT_LIST_HEAD(&file->fbs);
+ mutex_init(&file->fbs_lock);
+ INIT_LIST_HEAD(&file->blobs);
+ INIT_LIST_HEAD(&file->pending_event_list);
+ INIT_LIST_HEAD(&file->event_list);
+ init_waitqueue_head(&file->event_wait);
+ file->event_space = 4096; /* set aside 4k for event buffer */
+
+ mutex_init(&file->event_read_lock);
+
+ if (drm_core_check_feature(dev, DRIVER_GEM))
+ drm_gem_open(dev, file);
+
+ if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+ drm_syncobj_open(file);
+
+ if (drm_core_check_feature(dev, DRIVER_PRIME))
+ drm_prime_init_file_private(&file->prime);
+
+ if (dev->driver->open) {
+ ret = dev->driver->open(dev, file);
+ if (ret < 0)
+ goto out_prime_destroy;
+ }
+
+ if (drm_is_primary_client(file)) {
+ ret = drm_master_open(file);
+ if (ret)
+ goto out_close;
+ }
+
+ return file;
+
+out_close:
+ if (dev->driver->postclose)
+ dev->driver->postclose(dev, file);
+out_prime_destroy:
+ if (drm_core_check_feature(dev, DRIVER_PRIME))
+ drm_prime_destroy_file_private(&file->prime);
+ if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+ drm_syncobj_release(file);
+ if (drm_core_check_feature(dev, DRIVER_GEM))
+ drm_gem_release(dev, file);
+ put_pid(file->pid);
+ kfree(file);
+
+ return ERR_PTR(ret);
+}
+
+static void drm_events_release(struct drm_file *file_priv)
+{
+ struct drm_device *dev = file_priv->minor->dev;
+ struct drm_pending_event *e, *et;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+
+ /* Unlink pending events */
+ list_for_each_entry_safe(e, et, &file_priv->pending_event_list,
+ pending_link) {
+ list_del(&e->pending_link);
+ e->file_priv = NULL;
+ }
+
+ /* Remove unconsumed events */
+ list_for_each_entry_safe(e, et, &file_priv->event_list, link) {
+ list_del(&e->link);
+ kfree(e);
+ }
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+/**
+ * drm_file_free - free file context
+ * @file: context to free, or NULL
+ *
+ * This destroys and deallocates a DRM file context previously allocated via
+ * drm_file_alloc(). The caller must make sure to unlink it from any contexts
+ * before calling this.
+ *
+ * The legacy paths might require the drm_global_mutex to be held.
+ *
+ * If NULL is passed, this is a no-op.
+ *
+ * RETURNS:
+ * 0 on success, or error code on failure.
+ */
+void drm_file_free(struct drm_file *file)
+{
+ struct drm_device *dev;
+
+ if (!file)
+ return;
+
+ dev = file->minor->dev;
+
+ DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
+ task_pid_nr(current),
+ (long)old_encode_dev(file->minor->kdev->devt),
+ dev->open_count);
+
+ if (drm_core_check_feature(dev, DRIVER_LEGACY) &&
+ dev->driver->preclose)
+ dev->driver->preclose(dev, file);
+
+ if (drm_core_check_feature(dev, DRIVER_LEGACY))
+ drm_legacy_lock_release(dev, file->filp);
+
+ if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
+ drm_legacy_reclaim_buffers(dev, file);
+
+ drm_events_release(file);
+
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ drm_fb_release(file);
+ drm_property_destroy_user_blobs(dev, file);
+ }
+
+ if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+ drm_syncobj_release(file);
+
+ if (drm_core_check_feature(dev, DRIVER_GEM))
+ drm_gem_release(dev, file);
+
+ drm_legacy_ctxbitmap_flush(dev, file);
+
+ if (drm_is_primary_client(file))
+ drm_master_release(file);
+
+ if (dev->driver->postclose)
+ dev->driver->postclose(dev, file);
+
+ if (drm_core_check_feature(dev, DRIVER_PRIME))
+ drm_prime_destroy_file_private(&file->prime);
+
+ WARN_ON(!list_empty(&file->event_list));
+
+ put_pid(file->pid);
+ kfree(file);
+}
+
static int drm_setup(struct drm_device * dev)
{
int ret;
@@ -196,7 +369,6 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
struct drm_file *priv;
- int ret;
if (filp->f_flags & O_EXCL)
return -EBUSY; /* No exclusive opens */
@@ -207,50 +379,12 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor->index);
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
+ priv = drm_file_alloc(minor);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
filp->private_data = priv;
priv->filp = filp;
- priv->pid = get_pid(task_pid(current));
- priv->minor = minor;
-
- /* for compatibility root is always authenticated */
- priv->authenticated = capable(CAP_SYS_ADMIN);
- priv->lock_count = 0;
-
- INIT_LIST_HEAD(&priv->lhead);
- INIT_LIST_HEAD(&priv->fbs);
- mutex_init(&priv->fbs_lock);
- INIT_LIST_HEAD(&priv->blobs);
- INIT_LIST_HEAD(&priv->pending_event_list);
- INIT_LIST_HEAD(&priv->event_list);
- init_waitqueue_head(&priv->event_wait);
- priv->event_space = 4096; /* set aside 4k for event buffer */
-
- mutex_init(&priv->event_read_lock);
-
- if (drm_core_check_feature(dev, DRIVER_GEM))
- drm_gem_open(dev, priv);
-
- if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
- drm_syncobj_open(priv);
-
- if (drm_core_check_feature(dev, DRIVER_PRIME))
- drm_prime_init_file_private(&priv->prime);
-
- if (dev->driver->open) {
- ret = dev->driver->open(dev, priv);
- if (ret < 0)
- goto out_prime_destroy;
- }
-
- if (drm_is_primary_client(priv)) {
- ret = drm_master_open(priv);
- if (ret)
- goto out_close;
- }
mutex_lock(&dev->filelist_mutex);
list_add(&priv->lhead, &dev->filelist);
@@ -277,45 +411,6 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
#endif
return 0;
-
-out_close:
- if (dev->driver->postclose)
- dev->driver->postclose(dev, priv);
-out_prime_destroy:
- if (drm_core_check_feature(dev, DRIVER_PRIME))
- drm_prime_destroy_file_private(&priv->prime);
- if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
- drm_syncobj_release(priv);
- if (drm_core_check_feature(dev, DRIVER_GEM))
- drm_gem_release(dev, priv);
- put_pid(priv->pid);
- kfree(priv);
- filp->private_data = NULL;
- return ret;
-}
-
-static void drm_events_release(struct drm_file *file_priv)
-{
- struct drm_device *dev = file_priv->minor->dev;
- struct drm_pending_event *e, *et;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->event_lock, flags);
-
- /* Unlink pending events */
- list_for_each_entry_safe(e, et, &file_priv->pending_event_list,
- pending_link) {
- list_del(&e->pending_link);
- e->file_priv = NULL;
- }
-
- /* Remove unconsumed events */
- list_for_each_entry_safe(e, et, &file_priv->event_list, link) {
- list_del(&e->link);
- kfree(e);
- }
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
static void drm_legacy_dev_reinit(struct drm_device *dev)
@@ -382,57 +477,7 @@ int drm_release(struct inode *inode, struct file *filp)
list_del(&file_priv->lhead);
mutex_unlock(&dev->filelist_mutex);
- if (drm_core_check_feature(dev, DRIVER_LEGACY) &&
- dev->driver->preclose)
- dev->driver->preclose(dev, file_priv);
-
- /* ========================================================
- * Begin inline drm_release
- */
-
- DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
- task_pid_nr(current),
- (long)old_encode_dev(file_priv->minor->kdev->devt),
- dev->open_count);
-
- if (drm_core_check_feature(dev, DRIVER_LEGACY))
- drm_legacy_lock_release(dev, filp);
-
- if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
- drm_legacy_reclaim_buffers(dev, file_priv);
-
- drm_events_release(file_priv);
-
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- drm_fb_release(file_priv);
- drm_property_destroy_user_blobs(dev, file_priv);
- }
-
- if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
- drm_syncobj_release(file_priv);
-
- if (drm_core_check_feature(dev, DRIVER_GEM))
- drm_gem_release(dev, file_priv);
-
- drm_legacy_ctxbitmap_flush(dev, file_priv);
-
- if (drm_is_primary_client(file_priv))
- drm_master_release(file_priv);
-
- if (dev->driver->postclose)
- dev->driver->postclose(dev, file_priv);
-
- if (drm_core_check_feature(dev, DRIVER_PRIME))
- drm_prime_destroy_file_private(&file_priv->prime);
-
- WARN_ON(!list_empty(&file_priv->event_list));
-
- put_pid(file_priv->pid);
- kfree(file_priv);
-
- /* ========================================================
- * End inline drm_release
- */
+ drm_file_free(file_priv);
if (!--dev->open_count) {
drm_lastclose(dev);
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index b72242e93ea4..40179c5fc6b8 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -26,6 +26,8 @@
/* drm_file.c */
extern struct mutex drm_global_mutex;
+struct drm_file *drm_file_alloc(struct drm_minor *minor);
+void drm_file_free(struct drm_file *file);
void drm_lastclose(struct drm_device *dev);
/* drm_pci.c */
--
2.14.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC 2/7] drm/fb-helper: Ensure driver module is pinned in fb_open()
2017-12-31 13:58 [RFC 0/7] drm: Add generic fbdev emulation Noralf Trønnes
2017-12-31 13:58 ` [RFC 1/7] drm: provide management functions for drm_file Noralf Trønnes
@ 2017-12-31 13:58 ` Noralf Trønnes
2017-12-31 13:58 ` [RFC 3/7] drm/fb-helper: Don't restore if fbdev is not in use Noralf Trønnes
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Noralf Trønnes @ 2017-12-31 13:58 UTC (permalink / raw)
To: dri-devel
Cc: daniel.vetter, intel-gfx, Noralf Trønnes, laurent.pinchart,
dh.herrmann
If struct fb_ops is defined in a library like cma, fb_open() and fbcon
takes a ref on the library instead of the driver module. Use
fb_ops.fb_open/fb_release to ensure that the driver module is pinned.
Add drm_fb_helper_fb_open() and drm_fb_helper_fb_release() to
DRM_FB_HELPER_DEFAULT_OPS().
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/gpu/drm/drm_fb_helper.c | 40 ++++++++++++++++++++++++++++++++++++++++
include/drm/drm_fb_helper.h | 15 +++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 035784ddd133..2c6adf1d80c2 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1207,6 +1207,46 @@ void drm_fb_helper_cfb_imageblit(struct fb_info *info,
}
EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
+/**
+ * drm_fb_helper_fb_open - implementation for &fb_ops.fb_open
+ * @info: fbdev registered by the helper
+ * @user: 1=userspace, 0=fbcon
+ *
+ * If &fb_ops is wrapped in a library, pin the driver module.
+ */
+int drm_fb_helper_fb_open(struct fb_info *info, int user)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+ struct drm_device *dev = fb_helper->dev;
+
+ if (info->fbops->owner != dev->driver->fops->owner) {
+ if (!try_module_get(dev->driver->fops->owner))
+ return -ENODEV;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_fb_open);
+
+/**
+ * drm_fb_helper_fb_release - implementation for &fb_ops.fb_release
+ * @info: fbdev registered by the helper
+ * @user: 1=userspace, 0=fbcon
+ *
+ * If &fb_ops is wrapped in a library, unpin the driver module.
+ */
+int drm_fb_helper_fb_release(struct fb_info *info, int user)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+ struct drm_device *dev = fb_helper->dev;
+
+ if (info->fbops->owner != dev->driver->fops->owner)
+ module_put(dev->driver->fops->owner);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_fb_release);
+
/**
* drm_fb_helper_set_suspend - wrapper around fb_set_suspend
* @fb_helper: driver-allocated fbdev helper, can be NULL
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index b069433e7fc1..6f546ca3a6a1 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -241,6 +241,8 @@ struct drm_fb_helper {
* functions. To be used in struct fb_ops of drm drivers.
*/
#define DRM_FB_HELPER_DEFAULT_OPS \
+ .fb_open = drm_fb_helper_fb_open, \
+ .fb_release = drm_fb_helper_fb_release, \
.fb_check_var = drm_fb_helper_check_var, \
.fb_set_par = drm_fb_helper_set_par, \
.fb_setcmap = drm_fb_helper_setcmap, \
@@ -297,6 +299,9 @@ void drm_fb_helper_cfb_copyarea(struct fb_info *info,
void drm_fb_helper_cfb_imageblit(struct fb_info *info,
const struct fb_image *image);
+int drm_fb_helper_fb_open(struct fb_info *info, int user);
+int drm_fb_helper_fb_release(struct fb_info *info, int user);
+
void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend);
void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
bool suspend);
@@ -473,6 +478,16 @@ static inline void drm_fb_helper_cfb_imageblit(struct fb_info *info,
{
}
+static inline int drm_fb_helper_fb_open(struct fb_info *info, int user)
+{
+ return -ENODEV;
+}
+
+static inline int drm_fb_helper_fb_release(struct fb_info *info, int user)
+{
+ return -ENODEV;
+}
+
static inline void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper,
bool suspend)
{
--
2.14.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC 3/7] drm/fb-helper: Don't restore if fbdev is not in use
2017-12-31 13:58 [RFC 0/7] drm: Add generic fbdev emulation Noralf Trønnes
2017-12-31 13:58 ` [RFC 1/7] drm: provide management functions for drm_file Noralf Trønnes
2017-12-31 13:58 ` [RFC 2/7] drm/fb-helper: Ensure driver module is pinned in fb_open() Noralf Trønnes
@ 2017-12-31 13:58 ` Noralf Trønnes
2017-12-31 13:58 ` [RFC 4/7] drm/prime: Clear drm_gem_object->dma_buf on release Noralf Trønnes
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Noralf Trønnes @ 2017-12-31 13:58 UTC (permalink / raw)
To: dri-devel; +Cc: daniel.vetter, intel-gfx, laurent.pinchart
Keep track of fbdev users and only restore fbdev in
drm_fb_helper_restore_fbdev_mode_unlocked() when in use. This avoids
fbdev being restored in drm_driver.last_close when nothing uses it.
Additionally fbdev is turned off when the last user is closing.
fbcon is a user in this context.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/gpu/drm/drm_fb_helper.c | 15 +++++++++++++++
include/drm/drm_fb_helper.h | 14 ++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 2c6adf1d80c2..f9dcc7a5761f 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -522,6 +522,9 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
if (READ_ONCE(fb_helper->deferred_setup))
return 0;
+ if (!atomic_read(&fb_helper->open_count))
+ return 0;
+
mutex_lock(&fb_helper->lock);
ret = restore_fbdev_mode(fb_helper);
@@ -781,6 +784,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
+ atomic_set(&helper->open_count, 1);
mutex_init(&helper->lock);
helper->funcs = funcs;
helper->dev = dev;
@@ -1212,6 +1216,7 @@ EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
* @info: fbdev registered by the helper
* @user: 1=userspace, 0=fbcon
*
+ * Increase fbdev use count.
* If &fb_ops is wrapped in a library, pin the driver module.
*/
int drm_fb_helper_fb_open(struct fb_info *info, int user)
@@ -1224,6 +1229,8 @@ int drm_fb_helper_fb_open(struct fb_info *info, int user)
return -ENODEV;
}
+ atomic_inc(&fb_helper->open_count);
+
return 0;
}
EXPORT_SYMBOL(drm_fb_helper_fb_open);
@@ -1233,6 +1240,7 @@ EXPORT_SYMBOL(drm_fb_helper_fb_open);
* @info: fbdev registered by the helper
* @user: 1=userspace, 0=fbcon
*
+ * Decrease fbdev use count and turn off if there are no users left.
* If &fb_ops is wrapped in a library, unpin the driver module.
*/
int drm_fb_helper_fb_release(struct fb_info *info, int user)
@@ -1240,6 +1248,10 @@ int drm_fb_helper_fb_release(struct fb_info *info, int user)
struct drm_fb_helper *fb_helper = info->par;
struct drm_device *dev = fb_helper->dev;
+ if (atomic_dec_and_test(&fb_helper->open_count) &&
+ !drm_dev_is_unplugged(fb_helper->dev))
+ drm_fb_helper_blank(FB_BLANK_POWERDOWN, info);
+
if (info->fbops->owner != dev->driver->fops->owner)
module_put(dev->driver->fops->owner);
@@ -1936,6 +1948,9 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
if (ret < 0)
return ret;
+ if (fb_helper->fbdev->fbops->fb_open == drm_fb_helper_fb_open)
+ atomic_set(&fb_helper->open_count, 0);
+
strcpy(fb_helper->fb->comm, "[fbcon]");
return 0;
}
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 6f546ca3a6a1..5d4ccc3f28aa 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -232,6 +232,20 @@ struct drm_fb_helper {
* See also: @deferred_setup
*/
int preferred_bpp;
+
+ /**
+ * @open_count:
+ *
+ * Keeps track of fbdev use to know when to not restore fbdev.
+ *
+ * Drivers that use DRM_FB_HELPER_DEFAULT_OPS and don't override
+ * \.fb_open will get an initial value of 0 and get restore based on
+ * actual use. Others will get an initial value of 1 which means that
+ * fbdev will always be restored. Drivers that call
+ * drm_fb_helper_fb_open() in their \.fb_open, thus needs to set the
+ * initial value to 0 themselves.
+ */
+ atomic_t open_count;
};
/**
--
2.14.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC 4/7] drm/prime: Clear drm_gem_object->dma_buf on release
2017-12-31 13:58 [RFC 0/7] drm: Add generic fbdev emulation Noralf Trønnes
` (2 preceding siblings ...)
2017-12-31 13:58 ` [RFC 3/7] drm/fb-helper: Don't restore if fbdev is not in use Noralf Trønnes
@ 2017-12-31 13:58 ` Noralf Trønnes
2017-12-31 15:41 ` Chris Wilson
2017-12-31 13:58 ` [RFC 5/7] drm: Handle fbdev emulation in core Noralf Trønnes
` (2 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: Noralf Trønnes @ 2017-12-31 13:58 UTC (permalink / raw)
To: dri-devel
Cc: daniel.vetter, intel-gfx, Noralf Trønnes, laurent.pinchart,
dh.herrmann
Clear the pointer so the buffer can be re-exported. Otherwise use
after free happens in the next call to drm_gem_prime_handle_to_fd().
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/gpu/drm/drm_prime.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 9a17725b0f7a..3214c0eb7466 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -343,6 +343,7 @@ void drm_gem_dmabuf_release(struct dma_buf *dma_buf)
/* drop the reference on the export fd holds */
drm_gem_object_put_unlocked(obj);
+ obj->dma_buf = NULL;
drm_dev_put(dev);
}
--
2.14.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC 5/7] drm: Handle fbdev emulation in core
2017-12-31 13:58 [RFC 0/7] drm: Add generic fbdev emulation Noralf Trønnes
` (3 preceding siblings ...)
2017-12-31 13:58 ` [RFC 4/7] drm/prime: Clear drm_gem_object->dma_buf on release Noralf Trønnes
@ 2017-12-31 13:58 ` Noralf Trønnes
2017-12-31 13:58 ` [RFC 6/7] drm/fb-helper: Add generic fbdev emulation Noralf Trønnes
2017-12-31 13:58 ` [RFC 7/7] drm/vc4: Test " Noralf Trønnes
6 siblings, 0 replies; 10+ messages in thread
From: Noralf Trønnes @ 2017-12-31 13:58 UTC (permalink / raw)
To: dri-devel; +Cc: daniel.vetter, intel-gfx, laurent.pinchart
Prepare for generic fbdev emulation by letting DRM core work directly
with the fbdev compatibility layer. This is done by adding new fbdev
helper vtable callbacks for restore, hotplug_event, unregister and
release.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/gpu/drm/drm_file.c | 12 +++++++++++-
drivers/gpu/drm/drm_mode_config.c | 10 ++++++++++
drivers/gpu/drm/drm_probe_helper.c | 4 ++++
include/drm/drm_fb_helper.h | 33 +++++++++++++++++++++++++++++++++
4 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index d208faade27e..67f0309e22ff 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -35,6 +35,7 @@
#include <linux/slab.h>
#include <linux/module.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drmP.h>
@@ -439,10 +440,19 @@ static void drm_legacy_dev_reinit(struct drm_device *dev)
void drm_lastclose(struct drm_device * dev)
{
+ struct drm_fb_helper *fb_helper = dev->fb_helper;
+ int ret;
+
DRM_DEBUG("\n");
- if (dev->driver->lastclose)
+ if (dev->driver->lastclose) {
dev->driver->lastclose(dev);
+ } else if (fb_helper && fb_helper->funcs && fb_helper->funcs->restore) {
+ ret = fb_helper->funcs->restore(fb_helper);
+ if (ret)
+ DRM_ERROR("Failed to restore fbdev: %d\n", ret);
+ }
+
DRM_DEBUG("driver lastclose completed\n");
if (drm_core_check_feature(dev, DRIVER_LEGACY))
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index bc5c46306b3d..260eb1730244 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -21,6 +21,7 @@
*/
#include <drm/drm_encoder.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_mode_config.h>
#include <drm/drmP.h>
@@ -61,6 +62,11 @@ int drm_modeset_register_all(struct drm_device *dev)
void drm_modeset_unregister_all(struct drm_device *dev)
{
+ struct drm_fb_helper *fb_helper = dev->fb_helper;
+
+ if (fb_helper && fb_helper->funcs && fb_helper->funcs->unregister)
+ fb_helper->funcs->unregister(fb_helper);
+
drm_connector_unregister_all(dev);
drm_encoder_unregister_all(dev);
drm_crtc_unregister_all(dev);
@@ -408,6 +414,7 @@ EXPORT_SYMBOL(drm_mode_config_init);
*/
void drm_mode_config_cleanup(struct drm_device *dev)
{
+ struct drm_fb_helper *fb_helper = dev->fb_helper;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
struct drm_crtc *crtc, *ct;
@@ -417,6 +424,9 @@ void drm_mode_config_cleanup(struct drm_device *dev)
struct drm_property_blob *blob, *bt;
struct drm_plane *plane, *plt;
+ if (fb_helper && fb_helper->funcs && fb_helper->funcs->release)
+ fb_helper->funcs->release(fb_helper);
+
list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
head) {
encoder->funcs->destroy(encoder);
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 555fbe54d6e2..9d8b0ba54173 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -559,10 +559,14 @@ EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
*/
void drm_kms_helper_hotplug_event(struct drm_device *dev)
{
+ struct drm_fb_helper *fb_helper = dev->fb_helper;
+
/* send a uevent + call fbdev */
drm_sysfs_hotplug_event(dev);
if (dev->mode_config.funcs->output_poll_changed)
dev->mode_config.funcs->output_poll_changed(dev);
+ else if (fb_helper && fb_helper->funcs && fb_helper->funcs->hotplug_event)
+ fb_helper->funcs->hotplug_event(fb_helper);
}
EXPORT_SYMBOL(drm_kms_helper_hotplug_event);
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 5d4ccc3f28aa..f5ea79bbb831 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -125,6 +125,39 @@ struct drm_fb_helper_funcs {
struct drm_display_mode **modes,
struct drm_fb_offset *offsets,
bool *enabled, int width, int height);
+
+ /**
+ * @restore:
+ *
+ * Optional callback for restoring fbdev emulation.
+ * Called by drm_lastclose() if &drm_driver->lastclose is not set.
+ */
+ int (*restore)(struct drm_fb_helper *fb_helper);
+
+ /**
+ * @hotplug_event:
+ *
+ * Optional callback for hotplug events.
+ * Called by drm_kms_helper_hotplug_event() if
+ * &drm_mode_config_funcs->output_poll_changed is not set.
+ */
+ int (*hotplug_event)(struct drm_fb_helper *fb_helper);
+
+ /**
+ * @unregister:
+ *
+ * Optional callback for unregistrering fbdev emulation.
+ * Called by drm_dev_unregister().
+ */
+ void (*unregister)(struct drm_fb_helper *fb_helper);
+
+ /**
+ * @release:
+ *
+ * Optional callback for releasing fbdev emulation resources.
+ * Called by drm_mode_config_cleanup().
+ */
+ void (*release)(struct drm_fb_helper *fb_helper);
};
struct drm_fb_helper_connector {
--
2.14.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC 6/7] drm/fb-helper: Add generic fbdev emulation
2017-12-31 13:58 [RFC 0/7] drm: Add generic fbdev emulation Noralf Trønnes
` (4 preceding siblings ...)
2017-12-31 13:58 ` [RFC 5/7] drm: Handle fbdev emulation in core Noralf Trønnes
@ 2017-12-31 13:58 ` Noralf Trønnes
2017-12-31 13:58 ` [RFC 7/7] drm/vc4: Test " Noralf Trønnes
6 siblings, 0 replies; 10+ messages in thread
From: Noralf Trønnes @ 2017-12-31 13:58 UTC (permalink / raw)
To: dri-devel
Cc: daniel.vetter, intel-gfx, Noralf Trønnes, laurent.pinchart,
dh.herrmann
Add generic fbdev emulation which uses a drm_file to get a dumb_buffer
and drm_framebuffer. The buffer is exported and vmap/mmap called on
the dma-buf.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/gpu/drm/drm_fb_helper.c | 289 ++++++++++++++++++++++++++++++++++++++++
include/drm/drm_fb_helper.h | 33 +++++
2 files changed, 322 insertions(+)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index f9dcc7a5761f..d51bd5b1ecf1 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -30,6 +30,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/console.h>
+#include <linux/dma-buf.h>
#include <linux/kernel.h>
#include <linux/sysrq.h>
#include <linux/slab.h>
@@ -43,6 +44,7 @@
#include "drm_crtc_internal.h"
#include "drm_crtc_helper_internal.h"
+#include "drm_internal.h"
static bool drm_fbdev_emulation = true;
module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
@@ -2975,6 +2977,293 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_fb_helper_output_poll_changed);
+static int drm_fb_helper_generic_vmap(struct drm_fb_helper *fb_helper)
+{
+ struct drm_prime_handle prime_args = {
+ .handle = fb_helper->dumb_handle,
+ };
+ struct dma_buf *dma_buf;
+ void *vaddr;
+ int ret;
+
+ ret = drm_prime_handle_to_fd_ioctl(fb_helper->dev, &prime_args,
+ fb_helper->file);
+ if (ret)
+ return ret;
+
+ dma_buf = dma_buf_get(prime_args.fd);
+ if (WARN_ON(IS_ERR(dma_buf)))
+ return PTR_ERR(dma_buf);
+
+ /* drop the ref we picked up in handle_to_fd */
+ dma_buf_put(dma_buf);
+
+ vaddr = dma_buf_vmap(dma_buf);
+ if (!vaddr) {
+ ret = -ENOMEM;
+ goto err_remove_handle;
+ }
+
+ if (fb_helper->fbdev->fbdefio)
+ fb_deferred_io_init(fb_helper->fbdev);
+
+ fb_helper->fbdev->screen_buffer = vaddr;
+ fb_helper->dma_buf = dma_buf;
+
+ return 0;
+
+err_remove_handle:
+ drm_prime_remove_buf_handle_locked(&fb_helper->file->prime,
+ fb_helper->dma_buf);
+ dma_buf_put(dma_buf);
+
+ return ret;
+}
+
+static void drm_fb_helper_generic_vunmap(struct drm_fb_helper *fb_helper)
+{
+ if (fb_helper->fbdev->fbdefio) {
+ cancel_delayed_work_sync(&fb_helper->fbdev->deferred_work);
+ cancel_work_sync(&fb_helper->dirty_work);
+ fb_deferred_io_cleanup(fb_helper->fbdev);
+ }
+
+ dma_buf_vunmap(fb_helper->dma_buf, fb_helper->fbdev->screen_buffer);
+ fb_helper->fbdev->screen_buffer = NULL;
+
+ drm_prime_remove_buf_handle_locked(&fb_helper->file->prime,
+ fb_helper->dma_buf);
+ dma_buf_put(fb_helper->dma_buf);
+ fb_helper->dma_buf = NULL;
+}
+
+static int drm_fb_helper_generic_fb_open(struct fb_info *info, int user)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+ int ret;
+
+ ret = drm_fb_helper_fb_open(info, user);
+ if (ret)
+ return ret;
+
+ if (!fb_helper->fbdev->screen_buffer) {
+ /*
+ * Exporting a buffer to get a virtual address results in
+ * dma-buf pinning the driver module. This means that we have
+ * to vmap/vunmap in open/close to be able to unload the driver
+ * module.
+ */
+ ret = drm_fb_helper_generic_vmap(fb_helper);
+ if (ret) {
+ DRM_ERROR("fbdev: Failed to vmap buffer: %d\n", ret);
+ drm_fb_helper_fb_release(info, user);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int drm_fb_helper_generic_fb_release(struct fb_info *info, int user)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+
+ drm_fb_helper_fb_release(info, user);
+
+ if (!atomic_read(&fb_helper->open_count))
+ drm_fb_helper_generic_vunmap(fb_helper);
+
+ return 0;
+}
+
+static int drm_fb_helper_generic_fb_mmap(struct fb_info *info,
+ struct vm_area_struct *vma)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+
+ return dma_buf_mmap(fb_helper->dma_buf, vma, 0);
+}
+
+static struct fb_ops drm_fb_helper_generic_fbdev_ops = {
+ .owner = THIS_MODULE,
+ DRM_FB_HELPER_DEFAULT_OPS,
+ .fb_open = drm_fb_helper_generic_fb_open,
+ .fb_release = drm_fb_helper_generic_fb_release,
+ .fb_mmap = drm_fb_helper_generic_fb_mmap,
+ .fb_read = drm_fb_helper_sys_read,
+ .fb_write = drm_fb_helper_sys_write,
+ .fb_fillrect = drm_fb_helper_sys_fillrect,
+ .fb_copyarea = drm_fb_helper_sys_copyarea,
+ .fb_imageblit = drm_fb_helper_sys_imageblit,
+};
+
+static struct fb_deferred_io drm_fb_helper_generic_defio = {
+ .delay = HZ / 20,
+ .deferred_io = drm_fb_helper_deferred_io,
+};
+
+static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_mode_create_dumb dumb_args = { 0 };
+ struct drm_mode_fb_cmd2 fb_args = { 0 };
+ struct drm_device *dev = fb_helper->dev;
+ struct drm_framebuffer *fb;
+ struct drm_file *file;
+ struct fb_info *fbi;
+ int ret;
+
+ DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
+ sizes->surface_width, sizes->surface_height,
+ sizes->surface_bpp);
+
+ file = drm_file_alloc(dev->primary);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
+
+ drm_dropmaster_ioctl(dev, NULL, file);
+
+ dumb_args.width = sizes->surface_width;
+ dumb_args.height = sizes->surface_height;
+ dumb_args.bpp = sizes->surface_bpp;
+
+ ret = drm_mode_create_dumb_ioctl(dev, &dumb_args, file);
+ if (ret)
+ goto err_free_file;
+
+ fb_args.width = dumb_args.width;
+ fb_args.height = dumb_args.height;
+ fb_args.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+ fb_args.handles[0] = dumb_args.handle;
+ fb_args.pitches[0] = dumb_args.pitch;
+
+ ret = drm_mode_addfb2(dev, &fb_args, file);
+ if (ret)
+ goto err_free_file;
+
+ fb = drm_framebuffer_lookup(dev, file, fb_args.fb_id);
+ if (!fb) {
+ ret = -ENOENT;
+ goto err_free_file;
+ }
+
+ /* drop the reference we picked up in framebuffer lookup */
+ drm_framebuffer_put(fb);
+
+ fb_helper->dumb_handle = dumb_args.handle;
+ fb_helper->file = file;
+ fb_helper->fb = fb;
+
+ fbi = drm_fb_helper_alloc_fbi(fb_helper);
+ if (IS_ERR(fbi)) {
+ ret = PTR_ERR(fbi);
+ goto err_free_file;
+ }
+
+ fbi->par = fb_helper;
+ fbi->fbops = &drm_fb_helper_generic_fbdev_ops;
+ fbi->screen_size = fb->height * fb->pitches[0];
+ fbi->fix.smem_len = fbi->screen_size;
+ strcpy(fbi->fix.id, "generic");
+
+ drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth);
+ drm_fb_helper_fill_var(fbi, fb_helper, sizes->fb_width, sizes->fb_height);
+
+ if (fb->funcs->dirty) {
+ struct fb_ops *fbops;
+
+ /*
+ * fb_deferred_io_cleanup() clears &fbops->fb_mmap so a per
+ * instance version is necessary.
+ */
+ fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
+ if (!fbops) {
+ ret = -ENOMEM;
+ goto err_fb_info_destroy;
+ }
+
+ *fbops = *fbi->fbops;
+ fbi->fbops = fbops;
+ fbi->fbdefio = &drm_fb_helper_generic_defio;
+ }
+
+ atomic_set(&fb_helper->open_count, 0);
+
+ return 0;
+
+err_fb_info_destroy:
+ drm_fb_helper_fini(fb_helper);
+err_free_file:
+ drm_file_free(file);
+
+ return ret;
+}
+
+static void drm_fb_helper_generic_release(struct drm_fb_helper *fb_helper)
+{
+ struct fb_ops *fbops = NULL;
+
+ if (fb_helper->fbdev->fbdefio)
+ fbops = fb_helper->fbdev->fbops;
+
+ drm_fb_helper_fini(fb_helper);
+ drm_file_free(fb_helper->file);
+
+ kfree(fb_helper);
+ kfree(fbops);
+}
+
+static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = {
+ .fb_probe = drm_fb_helper_generic_probe,
+ .restore = drm_fb_helper_restore_fbdev_mode_unlocked,
+ .hotplug_event = drm_fb_helper_hotplug_event,
+ .unregister = drm_fb_helper_unregister_fbi,
+ .release = drm_fb_helper_generic_release,
+};
+
+/**
+ * drm_fb_helper_generic_fbdev_setup() - Setup generic fbdev emulation
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device.
+ * @dev->mode_config.preferred_depth is used if this is zero.
+ * @max_conn_count: Maximum number of connectors.
+ * @dev->mode_config.num_connector is used if this is zero.
+ *
+ * This function sets up generic fbdev emulation for drivers that supports
+ * dumb buffers and provides exported buffers with a virtual address.
+ * The driver doesn't have to anything else than to call this function,
+ * restore, hotplug events and teardown are all taken care of.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_fb_helper_generic_fbdev_setup(struct drm_device *dev,
+ unsigned int preferred_bpp,
+ unsigned int max_conn_count)
+{
+ struct drm_fb_helper *fb_helper;
+ int ret;
+
+ if (!drm_fbdev_emulation)
+ return 0;
+
+ fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
+ if (!fb_helper)
+ return -ENOMEM;
+
+ ret = drm_fb_helper_fbdev_setup(dev, fb_helper,
+ &drm_fb_helper_generic_funcs,
+ preferred_bpp, max_conn_count);
+ if (ret) {
+ kfree(fb_helper);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_generic_fbdev_setup);
+
/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
* but the module doesn't depend on any fb console symbols. At least
* attempt to load fbcon to avoid leaving the system without a usable console.
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index f5ea79bbb831..38738a1abad7 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -279,6 +279,28 @@ struct drm_fb_helper {
* initial value to 0 themselves.
*/
atomic_t open_count;
+
+ /**
+ * @file:
+ *
+ * Optional DRM file. Used by the generic fbdev code.
+ */
+ struct drm_file *file;
+
+ /**
+ * @dumb_handle:
+ *
+ * Optional dumb buffer handle. Used by the generic fbdev code.
+ */
+ u32 dumb_handle;
+
+ /**
+ * @dma_buf:
+ *
+ * Optional pointer to a DMA buffer object.
+ * Used by the generic fbdev code.
+ */
+ struct dma_buf *dma_buf;
};
/**
@@ -382,6 +404,10 @@ void drm_fb_helper_fbdev_teardown(struct drm_device *dev);
void drm_fb_helper_lastclose(struct drm_device *dev);
void drm_fb_helper_output_poll_changed(struct drm_device *dev);
+
+int drm_fb_helper_generic_fbdev_setup(struct drm_device *dev,
+ unsigned int preferred_bpp,
+ unsigned int max_conn_count);
#else
static inline void drm_fb_helper_prepare(struct drm_device *dev,
struct drm_fb_helper *helper,
@@ -626,6 +652,13 @@ static inline void drm_fb_helper_output_poll_changed(struct drm_device *dev)
{
}
+static inline int
+drm_fb_helper_generic_fbdev_setup(struct drm_device *dev,
+ unsigned int preferred_bpp,
+ unsigned int max_conn_count)
+{
+ return 0;
+}
#endif
static inline int
--
2.14.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC 7/7] drm/vc4: Test generic fbdev emulation
2017-12-31 13:58 [RFC 0/7] drm: Add generic fbdev emulation Noralf Trønnes
` (5 preceding siblings ...)
2017-12-31 13:58 ` [RFC 6/7] drm/fb-helper: Add generic fbdev emulation Noralf Trønnes
@ 2017-12-31 13:58 ` Noralf Trønnes
6 siblings, 0 replies; 10+ messages in thread
From: Noralf Trønnes @ 2017-12-31 13:58 UTC (permalink / raw)
To: dri-devel; +Cc: daniel.vetter, intel-gfx, laurent.pinchart
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/gpu/drm/vc4/vc4_drv.c | 3 ---
drivers/gpu/drm/vc4/vc4_kms.c | 3 +--
2 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index ceb385fd69c5..ef8a2d3a6d1f 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -152,7 +152,6 @@ static struct drm_driver vc4_drm_driver = {
DRIVER_HAVE_IRQ |
DRIVER_RENDER |
DRIVER_PRIME),
- .lastclose = drm_fb_helper_lastclose,
.irq_handler = vc4_irq,
.irq_preinstall = vc4_irq_preinstall,
.irq_postinstall = vc4_irq_postinstall,
@@ -297,8 +296,6 @@ static void vc4_drm_unbind(struct device *dev)
drm_dev_unregister(drm);
- drm_fb_cma_fbdev_fini(drm);
-
drm_mode_config_cleanup(drm);
drm_dev_unref(drm);
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 4256f294c346..671c62f1b4d3 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -188,7 +188,6 @@ static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev,
}
static const struct drm_mode_config_funcs vc4_mode_funcs = {
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = vc4_atomic_commit,
.fb_create = vc4_fb_create,
@@ -219,7 +218,7 @@ int vc4_kms_load(struct drm_device *dev)
drm_mode_config_reset(dev);
if (dev->mode_config.num_connector)
- drm_fb_cma_fbdev_init(dev, 32, 0);
+ drm_fb_helper_generic_fbdev_setup(dev, 32, 0);
drm_kms_helper_poll_init(dev);
--
2.14.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC 4/7] drm/prime: Clear drm_gem_object->dma_buf on release
2017-12-31 13:58 ` [RFC 4/7] drm/prime: Clear drm_gem_object->dma_buf on release Noralf Trønnes
@ 2017-12-31 15:41 ` Chris Wilson
2018-01-01 14:33 ` Noralf Trønnes
0 siblings, 1 reply; 10+ messages in thread
From: Chris Wilson @ 2017-12-31 15:41 UTC (permalink / raw)
To: dri-devel
Cc: daniel.vetter, intel-gfx, Noralf Trønnes, laurent.pinchart,
dh.herrmann
Quoting Noralf Trønnes (2017-12-31 13:58:40)
> Clear the pointer so the buffer can be re-exported. Otherwise use
> after free happens in the next call to drm_gem_prime_handle_to_fd().
>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
> drivers/gpu/drm/drm_prime.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> index 9a17725b0f7a..3214c0eb7466 100644
> --- a/drivers/gpu/drm/drm_prime.c
> +++ b/drivers/gpu/drm/drm_prime.c
> @@ -343,6 +343,7 @@ void drm_gem_dmabuf_release(struct dma_buf *dma_buf)
>
> /* drop the reference on the export fd holds */
> drm_gem_object_put_unlocked(obj);
> + obj->dma_buf = NULL;
obj->dma_buf holds a reference to the dma_buf, so to get to the dma_buf
release we must have already called dma_buf_put(obj->dma_buf). See
drm_gem_object_exported_dma_buf_free(). (Note you would do the
obj->dma_buf = NULL before dropping the potentially last ref to obj.)
A BUG_ON(obj->dma_buf) may help clarify the cache was already released.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC 4/7] drm/prime: Clear drm_gem_object->dma_buf on release
2017-12-31 15:41 ` Chris Wilson
@ 2018-01-01 14:33 ` Noralf Trønnes
0 siblings, 0 replies; 10+ messages in thread
From: Noralf Trønnes @ 2018-01-01 14:33 UTC (permalink / raw)
To: Chris Wilson, dri-devel
Cc: daniel.vetter, intel-gfx, laurent.pinchart, dh.herrmann
Den 31.12.2017 16.41, skrev Chris Wilson:
> Quoting Noralf Trønnes (2017-12-31 13:58:40)
>> Clear the pointer so the buffer can be re-exported. Otherwise use
>> after free happens in the next call to drm_gem_prime_handle_to_fd().
>>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>> ---
>> drivers/gpu/drm/drm_prime.c | 1 +
>> 1 file changed, 1 insertion(+)
>>
>> diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
>> index 9a17725b0f7a..3214c0eb7466 100644
>> --- a/drivers/gpu/drm/drm_prime.c
>> +++ b/drivers/gpu/drm/drm_prime.c
>> @@ -343,6 +343,7 @@ void drm_gem_dmabuf_release(struct dma_buf *dma_buf)
>>
>> /* drop the reference on the export fd holds */
>> drm_gem_object_put_unlocked(obj);
>> + obj->dma_buf = NULL;
> obj->dma_buf holds a reference to the dma_buf, so to get to the dma_buf
> release we must have already called dma_buf_put(obj->dma_buf). See
> drm_gem_object_exported_dma_buf_free(). (Note you would do the
> obj->dma_buf = NULL before dropping the potentially last ref to obj.)
> A BUG_ON(obj->dma_buf) may help clarify the cache was already released.
Hmm, okay it was a shot in the dark.
Maybe I can defer dumb_buffer and drm_framebuffer creation until fb_open
and then free it all in fb_close. That would align fbdev emulation more
with how DRM userspace operates. Let's see what assumptions the code has
about drm_fb_helper->fb being set on probe...
Noralf.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2018-01-01 14:33 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-31 13:58 [RFC 0/7] drm: Add generic fbdev emulation Noralf Trønnes
2017-12-31 13:58 ` [RFC 1/7] drm: provide management functions for drm_file Noralf Trønnes
2017-12-31 13:58 ` [RFC 2/7] drm/fb-helper: Ensure driver module is pinned in fb_open() Noralf Trønnes
2017-12-31 13:58 ` [RFC 3/7] drm/fb-helper: Don't restore if fbdev is not in use Noralf Trønnes
2017-12-31 13:58 ` [RFC 4/7] drm/prime: Clear drm_gem_object->dma_buf on release Noralf Trønnes
2017-12-31 15:41 ` Chris Wilson
2018-01-01 14:33 ` Noralf Trønnes
2017-12-31 13:58 ` [RFC 5/7] drm: Handle fbdev emulation in core Noralf Trønnes
2017-12-31 13:58 ` [RFC 6/7] drm/fb-helper: Add generic fbdev emulation Noralf Trønnes
2017-12-31 13:58 ` [RFC 7/7] drm/vc4: Test " Noralf Trønnes
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).