[PATCH 4/5] drm/imx: drop deprecated load/unload drm_driver ops

Daniel Vetter daniel at ffwll.ch
Fri Jun 17 12:48:38 UTC 2016


On Fri, Jun 17, 2016 at 12:13:41PM +0200, Lucas Stach wrote:
> Drop the load/unload driver ops, as they are deprecated because of their
> inherent races, with devices being visible to userspace before they are
> fully initialized.
> 
> Move this code into the driver bind/unbind routines bracketed by the
> proper drm_dev_alloc/register and drm_dev_unregister/unref calls.
> 
> Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
> ---
>  drivers/gpu/drm/imx/imx-drm-core.c | 247 ++++++++++++++++++-------------------
>  1 file changed, 121 insertions(+), 126 deletions(-)
> 
> diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
> index c63378661e11..799a68976590 100644
> --- a/drivers/gpu/drm/imx/imx-drm-core.c
> +++ b/drivers/gpu/drm/imx/imx-drm-core.c
> @@ -78,25 +78,6 @@ static void imx_drm_driver_lastclose(struct drm_device *drm)
>  	}
>  }
>  
> -static int imx_drm_driver_unload(struct drm_device *drm)
> -{
> -	struct imx_drm_device *imxdrm = drm->dev_private;
> -
> -	drm_kms_helper_poll_fini(drm);
> -
> -	if (imxdrm->fbhelper)
> -		drm_fbdev_cma_fini(imxdrm->fbhelper);
> -
> -	component_unbind_all(drm->dev, drm);
> -
> -	drm_vblank_cleanup(drm);
> -	drm_mode_config_cleanup(drm);
> -
> -	platform_set_drvdata(drm->platformdev, NULL);
> -
> -	return 0;
> -}
> -
>  static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
>  {
>  	struct imx_drm_device *imxdrm = crtc->dev->dev_private;
> @@ -223,109 +204,6 @@ static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
>  };
>  
>  /*
> - * Main DRM initialisation. This binds, initialises and registers
> - * with DRM the subcomponents of the driver.
> - */
> -static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
> -{
> -	struct imx_drm_device *imxdrm;
> -	struct drm_connector *connector;
> -	int ret;
> -
> -	imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
> -	if (!imxdrm)
> -		return -ENOMEM;
> -
> -	imxdrm->drm = drm;
> -
> -	drm->dev_private = imxdrm;
> -
> -	/*
> -	 * enable drm irq mode.
> -	 * - with irq_enabled = true, we can use the vblank feature.
> -	 *
> -	 * P.S. note that we wouldn't use drm irq handler but
> -	 *      just specific driver own one instead because
> -	 *      drm framework supports only one irq handler and
> -	 *      drivers can well take care of their interrupts
> -	 */
> -	drm->irq_enabled = true;
> -
> -	/*
> -	 * set max width and height as default value(4096x4096).
> -	 * this value would be used to check framebuffer size limitation
> -	 * at drm_mode_addfb().
> -	 */
> -	drm->mode_config.min_width = 64;
> -	drm->mode_config.min_height = 64;
> -	drm->mode_config.max_width = 4096;
> -	drm->mode_config.max_height = 4096;
> -	drm->mode_config.funcs = &imx_drm_mode_config_funcs;
> -
> -	drm_mode_config_init(drm);
> -
> -	ret = drm_vblank_init(drm, MAX_CRTC);
> -	if (ret)
> -		goto err_kms;
> -
> -	platform_set_drvdata(drm->platformdev, drm);
> -
> -	/* Now try and bind all our sub-components */
> -	ret = component_bind_all(drm->dev, drm);
> -	if (ret)
> -		goto err_vblank;
> -
> -	/*
> -	 * All components are now added, we can publish the connector sysfs
> -	 * entries to userspace.  This will generate hotplug events and so
> -	 * userspace will expect to be able to access DRM at this point.
> -	 */
> -	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
> -		ret = drm_connector_register(connector);
> -		if (ret) {
> -			dev_err(drm->dev,
> -				"[CONNECTOR:%d:%s] drm_connector_register failed: %d\n",
> -				connector->base.id,
> -				connector->name, ret);
> -			goto err_unbind;
> -		}
> -	}
> -
> -	/*
> -	 * All components are now initialised, so setup the fb helper.
> -	 * The fb helper takes copies of key hardware information, so the
> -	 * crtcs/connectors/encoders must not change after this point.
> -	 */
> -#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
> -	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
> -		dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
> -		legacyfb_depth = 16;
> -	}
> -	drm_helper_disable_unused_functions(drm);
> -	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
> -				drm->mode_config.num_crtc, MAX_CRTC);
> -	if (IS_ERR(imxdrm->fbhelper)) {
> -		ret = PTR_ERR(imxdrm->fbhelper);
> -		imxdrm->fbhelper = NULL;
> -		goto err_unbind;
> -	}
> -#endif
> -
> -	drm_kms_helper_poll_init(drm);
> -
> -	return 0;
> -
> -err_unbind:
> -	component_unbind_all(drm->dev, drm);
> -err_vblank:
> -	drm_vblank_cleanup(drm);
> -err_kms:
> -	drm_mode_config_cleanup(drm);
> -
> -	return ret;
> -}
> -
> -/*
>   * imx_drm_add_crtc - add a new crtc
>   */
>  int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
> @@ -416,8 +294,6 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = {
>  
>  static struct drm_driver imx_drm_driver = {
>  	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
> -	.load			= imx_drm_driver_load,
> -	.unload			= imx_drm_driver_unload,
>  	.lastclose		= imx_drm_driver_lastclose,
>  	.set_busid		= drm_platform_set_busid,
>  	.gem_free_object_unlocked = drm_gem_cma_free_object,
> @@ -471,12 +347,131 @@ static int compare_of(struct device *dev, void *data)
>  
>  static int imx_drm_bind(struct device *dev)
>  {
> -	return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
> +	struct drm_device *drm;
> +	struct imx_drm_device *imxdrm;
> +	int ret;
> +
> +	drm = drm_dev_alloc(&imx_drm_driver, dev);
> +	if (!drm)
> +		return -ENOMEM;
> +
> +	imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL);
> +	if (!imxdrm) {
> +		ret = -ENOMEM;
> +		goto err_unref;
> +	}
> +
> +	imxdrm->drm = drm;
> +	drm->dev_private = imxdrm;
> +
> +	/*
> +	 * enable drm irq mode.
> +	 * - with irq_enabled = true, we can use the vblank feature.
> +	 *
> +	 * P.S. note that we wouldn't use drm irq handler but
> +	 *      just specific driver own one instead because
> +	 *      drm framework supports only one irq handler and
> +	 *      drivers can well take care of their interrupts
> +	 */
> +	drm->irq_enabled = true;
> +
> +	/*
> +	 * set max width and height as default value(4096x4096).
> +	 * this value would be used to check framebuffer size limitation
> +	 * at drm_mode_addfb().
> +	 */
> +	drm->mode_config.min_width = 64;
> +	drm->mode_config.min_height = 64;
> +	drm->mode_config.max_width = 4096;
> +	drm->mode_config.max_height = 4096;
> +	drm->mode_config.funcs = &imx_drm_mode_config_funcs;
> +
> +	drm_mode_config_init(drm);
> +
> +	ret = drm_vblank_init(drm, MAX_CRTC);
> +	if (ret)
> +		goto err_kms;
> +
> +	dev_set_drvdata(dev, drm);
> +
> +	/* Now try and bind all our sub-components */
> +	ret = component_bind_all(dev, drm);
> +	if (ret)
> +		goto err_vblank;
> +
> +	ret = drm_dev_register(drm, 0);

In principle this should be the last step in the init sequence, otherwise
you might have userspace fighting with your init code over the hw. Please
move down.

> +	if (ret)
> +		goto err_unbind;
> +
> +	/*
> +	 * All components are now added, we can publish the connector sysfs
> +	 * entries to userspace.  This will generate hotplug events and so
> +	 * userspace will expect to be able to access DRM at this point.
> +	 */
> +	ret = drm_connector_register_all(drm);

This (and connector_unregister_all) just became unecessary with the
patches from Chris that I merged into drm-misc today. Please remove.

> +	if (ret)
> +		goto err_unregister;
> +
> +	/*
> +	 * All components are now initialised, so setup the fb helper.
> +	 * The fb helper takes copies of key hardware information, so the
> +	 * crtcs/connectors/encoders must not change after this point.
> +	 */
> +#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
> +	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
> +		dev_warn(dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
> +		legacyfb_depth = 16;
> +	}
> +	drm_helper_disable_unused_functions(drm);

fyi, you need to nuke this when switching to atomic.

> +	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
> +				drm->mode_config.num_crtc, MAX_CRTC);
> +	if (IS_ERR(imxdrm->fbhelper)) {
> +		ret = PTR_ERR(imxdrm->fbhelper);
> +		imxdrm->fbhelper = NULL;
> +		goto err_unregister;
> +	}
> +#endif
> +
> +	drm_kms_helper_poll_init(drm);
> +
> +	return 0;
> +
> +err_unregister:
> +	drm_dev_unregister(drm);
> +err_unbind:
> +	component_unbind_all(drm->dev, drm);
> +err_vblank:
> +	drm_vblank_cleanup(drm);
> +err_kms:
> +	drm_mode_config_cleanup(drm);
> +err_unref:
> +	drm_dev_unref(drm);
> +
> +	return ret;
>  }
>  
>  static void imx_drm_unbind(struct device *dev)
>  {
> -	drm_put_dev(dev_get_drvdata(dev));
> +	struct drm_device *drm = dev_get_drvdata(dev);
> +	struct imx_drm_device *imxdrm = drm->dev_private;
> +	struct drm_fbdev_cma *fbhelper = imxdrm->fbhelper;
> +
> +	drm_kms_helper_poll_fini(drm);
> +	/* device is going down, so no need to restore fbdev modes */
> +	imxdrm->fbhelper = NULL;
> +
> +	drm_connector_unregister_all(drm);
> +	drm_dev_unregister(drm);

Same here: unregister should be first, connector_unregister_all isn't
needed any more.
-Daniel

> +
> +	if (fbhelper)
> +		drm_fbdev_cma_fini(fbhelper);
> +
> +	component_unbind_all(drm->dev, drm);
> +	dev_set_drvdata(dev, NULL);
> +
> +	drm_mode_config_cleanup(drm);
> +
> +	drm_dev_unref(drm);
>  }
>  
>  static const struct component_master_ops imx_drm_ops = {
> -- 
> 2.8.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


More information about the dri-devel mailing list