From: Daniel Vetter <daniel@ffwll.ch>
To: "Noralf Trønnes" <noralf@tronnes.org>
Cc: dri-devel@lists.freedesktop.org, david@lechnology.com
Subject: Re: [PATCH 01/11] drm: Add devm_drm_dev_init/register
Date: Tue, 22 Jan 2019 10:32:13 +0100 [thread overview]
Message-ID: <20190122093213.GU3271@phenom.ffwll.local> (raw)
In-Reply-To: <eee7b04d-956f-5bc5-e4bd-4030be67f5cb@tronnes.org>
On Mon, Jan 21, 2019 at 01:21:46PM +0100, Noralf Trønnes wrote:
>
>
> Den 21.01.2019 10.55, skrev Daniel Vetter:
> > On Mon, Jan 21, 2019 at 10:10:14AM +0100, Daniel Vetter wrote:
> >> On Sun, Jan 20, 2019 at 12:43:08PM +0100, Noralf Trønnes wrote:
> >>> This adds resource managed (devres) versions of drm_dev_init() and
> >>> drm_dev_register().
> >>>
> >>> Also added is devm_drm_dev_register_with_fbdev() which sets up generic
> >>> fbdev emulation as well.
> >>>
> >>> devm_drm_dev_register() isn't exported since there are no users.
> >>>
> >>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> >>
>
> <snip>
>
> >>> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> >>> index 381581b01d48..12129772be45 100644
> >>> --- a/drivers/gpu/drm/drm_drv.c
> >>> +++ b/drivers/gpu/drm/drm_drv.c
> >>> @@ -36,6 +36,7 @@
> >>>
> >>> #include <drm/drm_client.h>
> >>> #include <drm/drm_drv.h>
> >>> +#include <drm/drm_fb_helper.h>
> >>> #include <drm/drmP.h>
> >>>
> >>> #include "drm_crtc_internal.h"
> >>> @@ -871,6 +872,111 @@ void drm_dev_unregister(struct drm_device *dev)
> >>> }
> >>> EXPORT_SYMBOL(drm_dev_unregister);
> >>>
> >>> +static void devm_drm_dev_init_release(void *data)
> >>> +{
> >>> + drm_dev_put(data);
> >
> > We need drm_dev_unplug() here, or this isn't safe.
>
> This function is only used to cover the error path if probe fails before
> devm_drm_dev_register() is called. devm_drm_dev_register_release() is
> the one that calls unplug. There are comments about this in the functions.
I think I get a prize for being ignorant and blind :-/
>
> >
> >>> +}
> >>> +
> >>> +/**
> >>> + * devm_drm_dev_init - Resource managed drm_dev_init()
> >>> + * @parent: Parent device object
> >>> + * @dev: DRM device
> >>> + * @driver: DRM driver
> >>> + *
> >>> + * Managed drm_dev_init(). The DRM device initialized with this function is
> >>> + * automatically released on driver detach. You must supply a
> >
> > I think a bit more clarity here would be good:
> >
> > "... automatically released on driver unbind by callind drm_dev_unplug()."
> >
> >>> + * &drm_driver.release callback to control the finalization explicitly.
> >
> > I think a loud warning for these is in order:
> >
> > "WARNING:
> >
> > "In generally it is unsafe to use devm functions for drm structures
> > because the lifetimes of &drm_device and the underlying &device do not
> > match. This here works because it doesn't immediately free anything, but
> > only calls drm_dev_unplug(), which internally decrements the &drm_device
> > refcount through drm_dev_put().
> >
> > "All other drm structures must still be explicitly released in the
> > &drm_driver.release callback."
> >
> > While thinking about this I just realized that with this design we have no
> > good place to call drm_atomic_helper_shutdown(). Which we need to, or all
> > kinds of things will leak badly (connectors, fb, ...), but there's no
> > place to call it:
> > - unbind is too early, since we haven't yet called drm_dev_unplug, and the
> > drm_dev_unregister in there must be called _before_ we start to shut
> > down anything.
> > - drm_driver.release is way too late.
> >
> > Ofc for a real hotunplug there's no point in shutting down the hw (it's
> > already gone), but for a driver unload/unbind it would be nice if this
> > happens automatically and in the right order.
> >
> > So not sure what to do here really.
>
> How about this change: (it breaks the rule of pulling helpers into the
> core, so maybe we should put the devm_ functions into the simple KMS
> helper instead?)
Yeah smells a bit much like midlayer ... What would work is having a pile
more devm_ helper functions, so that we onion-unwrap everything correctly,
and in the right order. So:
- devm_drm_dev_init (always does a drm_dev_put())
- devm_drm_poll_enable (shuts down the poll helper with a devm action)
- devm_drm_mode_config_reset (does an atomic_helper_shutdown() as it's cleanup action)
- devm_drm_dev_register (grabs an additional drm_dev_get() reference so it
can call drm_dev_unplug() unconditionally).
We'd need to make sure some of the cleanup actions dtrt when the device is
gone, but I think we can achieve that by liberally sprinkling
drm_dev_enter/exit over them, e.g. the the cleanup action for
drm_mode_config_reset would be:
{
if (drm_dev_enter())
return;
drm_atomic_helper_shutdown();
drm_dev_exit();
}
This would be analog to your shutdown parameter below.
Essentially I think we can only do the drm_dev_unplug autocleanup in a
given driver from devm_drm_dev_register iff all the cleanup actions have
been devm-ified, and there's nothing left in it's unbind callback. Because
if anything is left in its unbind callback that's a bug, since
drm_dev_unregister() (called through drm_dev_unplug) is the very first (or
at least one of the very first, before we start cleanup up) functions that
need to be called.
-Daniel
>
> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> index 12129772be45..7ed9550baff6 100644
> --- a/drivers/gpu/drm/drm_drv.c
> +++ b/drivers/gpu/drm/drm_drv.c
> @@ -34,7 +34,9 @@
> #include <linux/slab.h>
> #include <linux/srcu.h>
>
> +#include <drm/drm_atomic_helper.h>
> #include <drm/drm_client.h>
> +#include <drm/drm_crtc_helper.h>
> #include <drm/drm_drv.h>
> #include <drm/drm_fb_helper.h>
> #include <drm/drmP.h>
> @@ -355,17 +357,7 @@ void drm_dev_exit(int idx)
> }
> EXPORT_SYMBOL(drm_dev_exit);
>
> -/**
> - * drm_dev_unplug - unplug a DRM device
> - * @dev: DRM device
> - *
> - * This unplugs a hotpluggable DRM device, which makes it inaccessible to
> - * userspace operations. Entry-points can use drm_dev_enter() and
> - * drm_dev_exit() to protect device resources in a race free manner. This
> - * essentially unregisters the device like drm_dev_unregister(), but can be
> - * called while there are still open users of @dev.
> - */
> -void drm_dev_unplug(struct drm_device *dev)
> +static void __drm_dev_unplug(struct drm_device *dev, bool shutdown)
> {
> /*
> * After synchronizing any critical read section is guaranteed
> to see
> @@ -378,11 +370,32 @@ void drm_dev_unplug(struct drm_device *dev)
>
> drm_dev_unregister(dev);
>
> + if (shutdown)
> + drm_kms_helper_poll_fini(dev);
> +
> mutex_lock(&drm_global_mutex);
> - if (dev->open_count == 0)
> + if (dev->open_count == 0) {
> + if (shutdown)
> + drm_atomic_helper_shutdown(dev);
> drm_dev_put(dev);
> + }
> mutex_unlock(&drm_global_mutex);
> }
> +
> +/**
> + * drm_dev_unplug - unplug a DRM device
> + * @dev: DRM device
> + *
> + * This unplugs a hotpluggable DRM device, which makes it inaccessible to
> + * userspace operations. Entry-points can use drm_dev_enter() and
> + * drm_dev_exit() to protect device resources in a race free manner. This
> + * essentially unregisters the device like drm_dev_unregister(), but can be
> + * called while there are still open users of @dev.
> + */
> +void drm_dev_unplug(struct drm_device *dev)
> +{
> + __drm_dev_unplug(dev, false);
> +}
> EXPORT_SYMBOL(drm_dev_unplug);
>
> /*
> @@ -920,7 +933,7 @@ EXPORT_SYMBOL(devm_drm_dev_init);
>
> static void devm_drm_dev_register_release(void *data)
> {
> - drm_dev_unplug(data);
> + __drm_dev_unplug(data, true);
> }
>
> static int devm_drm_dev_register(struct drm_device *dev)
>
>
> I realised that we should take a ref on the parent device so it can be
> accessed by the DRM_DEV_ functions after unplug.
>
>
> Noralf.
>
>
> >
> >>> + *
> >>> + * Note: This function must be used together with
> >>> + * devm_drm_dev_register_with_fbdev().
> >>> + *
> >>> + * RETURNS:
> >>> + * 0 on success, or error code on failure.
> >>> + */
> >>> +int devm_drm_dev_init(struct device *parent,
> >>> + struct drm_device *dev,
> >>> + struct drm_driver *driver)
> >>> +{
> >>> + int ret;
> >>> +
> >>> + if (WARN_ON(!parent || !driver->release))
> >>> + return -EINVAL;
> >>> +
> >>> + ret = drm_dev_init(dev, driver, parent);
> >>> + if (ret)
> >>> + return ret;
> >>> +
> >>> + /*
> >>> + * This is a temporary release action that is used if probing fails
> >>> + * before devm_drm_dev_register() is called.
> >>> + */
> >>> + ret = devm_add_action(parent, devm_drm_dev_init_release, dev);
> >>> + if (ret)
> >>> + devm_drm_dev_init_release(dev);
> >>> +
> >>> + return ret;
> >>> +}
> >>> +EXPORT_SYMBOL(devm_drm_dev_init);
> >>> +
> >>> +static void devm_drm_dev_register_release(void *data)
> >>> +{
> >>> + drm_dev_unplug(data);
> >>> +}
> >>> +
> >>> +static int devm_drm_dev_register(struct drm_device *dev)
> >>> +{
> >>> + int ret;
> >>> +
> >>> + ret = drm_dev_register(dev, 0);
> >>> + if (ret)
> >>> + return ret;
> >>> +
> >>> + /*
> >>> + * This has now served it's purpose, remove it to not mess up ref
> >>> + * counting.
> >>> + */
> >>> + devm_remove_action(dev->dev, devm_drm_dev_init_release, dev);
> >>> +
> >>> + ret = devm_add_action(dev->dev, devm_drm_dev_register_release, dev);
> >>> + if (ret)
> >>> + devm_drm_dev_register_release(dev);
> >>> +
> >>> + return ret;
> >>> +}
> >>> +
> >>> +/**
> >>> + * devm_drm_dev_register_with_fbdev - Resource managed drm_dev_register()
> >>> + * including generic fbdev emulation
> >>> + * @dev: DRM device to register
> >>> + * @fbdev_bpp: Preferred bits per pixel for fbdev (optional)
> >>> + *
> >>> + * Managed drm_dev_register() that also calls drm_fbdev_generic_setup().
> >>> + * The DRM device registered with this function is automatically unregistered on
> >>> + * driver detach using drm_dev_unplug().
> >>> + *
> >>> + * Note: This function must be used together with devm_drm_dev_init().
> >>> + *
> >>> + * For testing driver detach can be triggered manually by writing to the driver
> >>> + * 'unbind' file.
> >>> + *
> >>> + * RETURNS:
> >>> + * 0 on success, negative error code on failure.
> >>> + */
> >>> +int devm_drm_dev_register_with_fbdev(struct drm_device *dev,
> >>> + unsigned int fbdev_bpp)
> >>> +{
> >>> + int ret;
> >>> +
> >>> + ret = devm_drm_dev_register(dev);
> >>> + if (ret)
> >>> + return ret;
> >>> +
> >>> + drm_fbdev_generic_setup(dev, fbdev_bpp);
> >>> +
> >>> + return 0;
> >>> +}
> >>> +EXPORT_SYMBOL(devm_drm_dev_register_with_fbdev);
> >>> +
> >>> /**
> >>> * drm_dev_set_unique - Set the unique name of a DRM device
> >>> * @dev: device of which to set the unique name
> >>> diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
> >>> index 35af23f5fa0d..c3f0477f2e7f 100644
> >>> --- a/include/drm/drm_drv.h
> >>> +++ b/include/drm/drm_drv.h
> >>> @@ -628,6 +628,12 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
> >>> int drm_dev_register(struct drm_device *dev, unsigned long flags);
> >>> void drm_dev_unregister(struct drm_device *dev);
> >>>
> >>> +int devm_drm_dev_init(struct device *parent,
> >>> + struct drm_device *dev,
> >>> + struct drm_driver *driver);
> >>> +int devm_drm_dev_register_with_fbdev(struct drm_device *dev,
> >>> + unsigned int fbdev_bpp);
> >>> +
> >>> void drm_dev_get(struct drm_device *dev);
> >>> void drm_dev_put(struct drm_device *dev);
> >>> void drm_put_dev(struct drm_device *dev);
> >>> --
> >>> 2.20.1
> >>>
> >>> _______________________________________________
> >>> dri-devel mailing list
> >>> dri-devel@lists.freedesktop.org
> >>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> >>
> >> --
> >> Daniel Vetter
> >> Software Engineer, Intel Corporation
> >> http://blog.ffwll.ch
> >
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2019-01-22 9:32 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-20 11:43 [PATCH 00/11] drm/tinydrm: Remove tinydrm_device Noralf Trønnes
2019-01-20 11:43 ` [PATCH 01/11] drm: Add devm_drm_dev_init/register Noralf Trønnes
2019-01-21 6:11 ` Sam Ravnborg
2019-01-21 13:09 ` Noralf Trønnes
2019-01-21 9:10 ` Daniel Vetter
2019-01-21 9:55 ` Daniel Vetter
2019-01-21 12:21 ` Noralf Trønnes
2019-01-22 9:32 ` Daniel Vetter [this message]
2019-01-22 19:07 ` Noralf Trønnes
2019-01-22 19:30 ` Daniel Vetter
2019-01-23 10:54 ` Noralf Trønnes
2019-01-24 10:43 ` devm actions and hw clenaup (was Re: [PATCH 01/11] drm: Add devm_drm_dev_init/register) Daniel Vetter
2019-01-24 17:46 ` Greg KH
2019-01-24 17:57 ` Daniel Vetter
2019-01-29 14:34 ` Noralf Trønnes
2019-01-29 15:16 ` Greg KH
2019-01-29 16:50 ` Daniel Vetter
2019-01-29 17:26 ` Noralf Trønnes
2019-01-29 17:36 ` Greg KH
2019-01-29 18:10 ` Daniel Vetter
2019-01-29 19:27 ` Greg KH
2019-01-29 23:14 ` Daniel Vetter
2019-01-30 7:14 ` Greg KH
2019-01-22 9:35 ` [PATCH 01/11] drm: Add devm_drm_dev_init/register Daniel Vetter
2019-01-20 11:43 ` [PATCH 02/11] drm/modes: Add DRM_SIMPLE_MODE() Noralf Trønnes
2019-01-20 16:37 ` Ilia Mirkin
2019-01-20 17:27 ` Noralf Trønnes
2019-01-20 11:43 ` [PATCH 03/11] drm/simple-kms-helper: Add drm_simple_connector_create() Noralf Trønnes
2019-01-20 22:14 ` Sam Ravnborg
2019-01-21 9:22 ` Daniel Vetter
2019-01-24 14:38 ` Noralf Trønnes
2019-01-24 14:53 ` Hans de Goede
2019-01-25 12:05 ` Noralf Trønnes
2019-01-20 11:43 ` [PATCH 04/11] drm/tinydrm: Remove tinydrm_display_pipe_init() Noralf Trønnes
2019-01-21 6:30 ` Sam Ravnborg
2019-01-21 9:15 ` Daniel Vetter
2019-01-28 14:46 ` Noralf Trønnes
2019-01-20 11:43 ` [PATCH 05/11] drm/tinydrm/mipi-dbi: Add drm_to_mipi_dbi() Noralf Trønnes
2019-01-21 6:34 ` Sam Ravnborg
2019-01-20 11:43 ` [PATCH 06/11] drm/tinydrm: Remove tinydrm_shutdown() Noralf Trønnes
2019-01-21 7:12 ` Sam Ravnborg
2019-01-20 11:43 ` [PATCH 07/11] drm/tinydrm/repaper: Use devm_drm_dev_*() Noralf Trønnes
2019-01-20 22:22 ` Sam Ravnborg
2019-01-20 22:25 ` Sam Ravnborg
2019-01-21 13:15 ` Noralf Trønnes
2019-01-20 11:43 ` [PATCH 08/11] drm/tinydrm: " Noralf Trønnes
2019-01-20 11:43 ` [PATCH 09/11] drm/tinydrm: Remove tinydrm_device Noralf Trønnes
2019-01-21 8:13 ` Sam Ravnborg
2019-01-21 9:29 ` Daniel Vetter
2019-01-21 13:30 ` Noralf Trønnes
2019-01-20 11:43 ` [PATCH 10/11] drm/tinydrm: Use drm_dev_enter/exit() Noralf Trønnes
2019-01-20 11:43 ` [PATCH 11/11] drm/fb-helper: generic: Don't take module ref for fbcon Noralf Trønnes
2019-01-21 9:05 ` Daniel Vetter
2019-01-28 14:40 ` Noralf Trønnes
2019-01-29 8:45 ` Daniel Vetter
2019-01-21 8:34 ` [PATCH 00/11] drm/tinydrm: Remove tinydrm_device Sam Ravnborg
2019-01-21 13:20 ` Noralf Trønnes
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190122093213.GU3271@phenom.ffwll.local \
--to=daniel@ffwll.ch \
--cc=david@lechnology.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=noralf@tronnes.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.