Re: [PATCH 01/11] drm: Add devm_drm_dev_init/register

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxx>
> 
> devm_ considered harmful unfortunately. You cannot allocate any structures
> which might outlive the lifetime of your device using devm_ on the device.
> Since drm_device has it's own lifetime, that structure and _everything_ we
> allocate tied to it (i.e. drm_encoder/plane/connector/crtc/whatever)
> cannot be allocated using devm_ infrastructure tied to the underlying
> parent device.
> 
> Yes this means almost all the devm usage in drm drivers is fundamentally
> broken. You also generally don't unplug gpus, so no one cares :-/
> 
> What could instead is add a struct device to drm_device somehow, use that
> struct device to manage the lifetime of the drm_device (would still need
> our special open counter maybe), and then use devm to allocate all the drm
> bits tied to the drm_device.
> 
> This here unfortunataly doesn't work, even if it looks like a really neat
> idea.

Strike all that, because I wasn't awak yet. Sorry for the confusion.

> > ---
> >  Documentation/driver-model/devres.txt |   4 +
> >  drivers/gpu/drm/drm_drv.c             | 106 ++++++++++++++++++++++++++
> >  include/drm/drm_drv.h                 |   6 ++
> >  3 files changed, 116 insertions(+)
> > 
> > diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
> > index b277cafce71e..6eebc28d4c21 100644
> > --- a/Documentation/driver-model/devres.txt
> > +++ b/Documentation/driver-model/devres.txt
> > @@ -254,6 +254,10 @@ DMA
> >    dmam_pool_create()
> >    dmam_pool_destroy()
> >  
> > +DRM
> > +  devm_drm_dev_init()
> > +  devm_drm_dev_register_with_fbdev()
> > +
> >  GPIO
> >    devm_gpiod_get()
> >    devm_gpiod_get_index()
> > 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.

> > +}
> > +
> > +/**
> > + * 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.
-Daniel

> > + *
> > + * 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@xxxxxxxxxxxxxxxxxxxxx
> > 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@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/dri-devel




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux