[PATCH] drm: rcar-du: Perform initialization/cleanup at probe/remove time
Daniel Vetter
daniel at ffwll.ch
Tue Oct 20 00:32:13 PDT 2015
On Tue, Oct 20, 2015 at 01:51:54AM +0300, Laurent Pinchart wrote:
> The drm driver .load() operation is prone to race conditions as it
> initializes the driver after registering the device nodes. Its usage is
> deprecated, inline it in the probe function and call drm_dev_alloc() and
> drm_dev_register() explicitly.
>
> For consistency inline the .unload() handler in the remove function as
> well.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas at ideasonboard.com>
> ---
> drivers/gpu/drm/rcar-du/rcar_du_drv.c | 184 ++++++++++++++++--------------
> drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c | 11 +-
> drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c | 11 +-
> drivers/gpu/drm/rcar-du/rcar_du_vgacon.c | 11 +-
> 4 files changed, 104 insertions(+), 113 deletions(-)
>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> index bebcc97db5e5..46d628752371 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> @@ -119,82 +119,6 @@ MODULE_DEVICE_TABLE(of, rcar_du_of_table);
> * DRM operations
> */
>
> -static int rcar_du_unload(struct drm_device *dev)
> -{
> - struct rcar_du_device *rcdu = dev->dev_private;
> -
> - if (rcdu->fbdev)
> - drm_fbdev_cma_fini(rcdu->fbdev);
> -
> - drm_kms_helper_poll_fini(dev);
> - drm_mode_config_cleanup(dev);
> - drm_vblank_cleanup(dev);
> -
> - dev->irq_enabled = 0;
> - dev->dev_private = NULL;
> -
> - return 0;
> -}
> -
> -static int rcar_du_load(struct drm_device *dev, unsigned long flags)
> -{
> - struct platform_device *pdev = dev->platformdev;
> - struct device_node *np = pdev->dev.of_node;
> - struct rcar_du_device *rcdu;
> - struct resource *mem;
> - int ret;
> -
> - if (np == NULL) {
> - dev_err(dev->dev, "no platform data\n");
> - return -ENODEV;
> - }
> -
> - rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL);
> - if (rcdu == NULL) {
> - dev_err(dev->dev, "failed to allocate private data\n");
> - return -ENOMEM;
> - }
> -
> - init_waitqueue_head(&rcdu->commit.wait);
> -
> - rcdu->dev = &pdev->dev;
> - rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data;
> - rcdu->ddev = dev;
> - dev->dev_private = rcdu;
> -
> - /* I/O resources */
> - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
> - if (IS_ERR(rcdu->mmio))
> - return PTR_ERR(rcdu->mmio);
> -
> - /* Initialize vertical blanking interrupts handling. Start with vblank
> - * disabled for all CRTCs.
> - */
> - ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1);
> - if (ret < 0) {
> - dev_err(&pdev->dev, "failed to initialize vblank\n");
> - goto done;
> - }
> -
> - /* DRM/KMS objects */
> - ret = rcar_du_modeset_init(rcdu);
> - if (ret < 0) {
> - dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret);
> - goto done;
> - }
> -
> - dev->irq_enabled = 1;
> -
> - platform_set_drvdata(pdev, rcdu);
> -
> -done:
> - if (ret)
> - rcar_du_unload(dev);
> -
> - return ret;
> -}
> -
> static void rcar_du_preclose(struct drm_device *dev, struct drm_file *file)
> {
> struct rcar_du_device *rcdu = dev->dev_private;
> @@ -244,8 +168,6 @@ static const struct file_operations rcar_du_fops = {
> static struct drm_driver rcar_du_driver = {
> .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
> | DRIVER_ATOMIC,
> - .load = rcar_du_load,
> - .unload = rcar_du_unload,
> .preclose = rcar_du_preclose,
> .lastclose = rcar_du_lastclose,
> .set_busid = drm_platform_set_busid,
> @@ -308,18 +230,114 @@ static const struct dev_pm_ops rcar_du_pm_ops = {
> * Platform driver
> */
>
> -static int rcar_du_probe(struct platform_device *pdev)
> +static int rcar_du_remove(struct platform_device *pdev)
> {
> - return drm_platform_init(&rcar_du_driver, pdev);
> + struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
> + struct drm_device *ddev = rcdu->ddev;
> +
> + mutex_lock(&ddev->mode_config.mutex);
> + drm_connector_unplug_all(ddev);
> + mutex_unlock(&ddev->mode_config.mutex);
> +
> + drm_dev_unregister(ddev);
> +
> + if (rcdu->fbdev)
> + drm_fbdev_cma_fini(rcdu->fbdev);
> +
> + drm_kms_helper_poll_fini(ddev);
> + drm_mode_config_cleanup(ddev);
> + drm_vblank_cleanup(ddev);
> +
> + drm_dev_unref(ddev);
> +
> + return 0;
> }
>
> -static int rcar_du_remove(struct platform_device *pdev)
> +static int rcar_du_probe(struct platform_device *pdev)
> {
> - struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
> + struct device_node *np = pdev->dev.of_node;
> + struct rcar_du_device *rcdu;
> + struct drm_connector *connector;
> + struct drm_device *ddev;
> + struct resource *mem;
> + int ret;
> +
> + if (np == NULL) {
> + dev_err(&pdev->dev, "no device tree node\n");
> + return -ENODEV;
> + }
> +
> + /* Allocate and initialize the DRM and R-Car device structures. */
> + rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL);
> + if (rcdu == NULL)
> + return -ENOMEM;
> +
> + init_waitqueue_head(&rcdu->commit.wait);
>
> - drm_put_dev(rcdu->ddev);
> + rcdu->dev = &pdev->dev;
> + rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data;
> +
> + ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev);
> + if (!ddev)
> + return -ENOMEM;
> +
> + rcdu->ddev = ddev;
> + ddev->dev_private = rcdu;
> +
> + platform_set_drvdata(pdev, rcdu);
> +
> + /* I/O resources */
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
> + if (IS_ERR(rcdu->mmio)) {
> + ret = PTR_ERR(rcdu->mmio);
> + goto error;
> + }
> +
> + /* Initialize vertical blanking interrupts handling. Start with vblank
> + * disabled for all CRTCs.
> + */
> + ret = drm_vblank_init(ddev, (1 << rcdu->info->num_crtcs) - 1);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "failed to initialize vblank\n");
> + goto error;
> + }
> +
> + /* DRM/KMS objects */
> + ret = rcar_du_modeset_init(rcdu);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret);
> + goto error;
> + }
> +
> + ddev->irq_enabled = 1;
> +
> + /* Register the DRM device with the core and the connectors with
> + * sysfs.
> + */
> + ret = drm_dev_register(ddev, 0);
> + if (ret)
> + goto error;
> +
> + mutex_lock(&ddev->mode_config.mutex);
> + drm_for_each_connector(connector, ddev) {
> + ret = drm_connector_register(connector);
> + if (ret < 0)
> + break;
> + }
> + mutex_unlock(&ddev->mode_config.mutex);
I'm wondereding whether we shouldn't just wrap this up in a helper
somehow, like drm_dev_modeset_register. Only trouble is that we might be
racing with adding MST connectors already, and that's where I stopped
thinking about it ;-) Anyway that aside aside:
Acked-by: Daniel Vetter <daniel.vetter at ffwll.ch>
-Daniel
> +
> + if (ret < 0)
> + goto error;
> +
> + DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
>
> return 0;
> +
> +error:
> + rcar_du_remove(pdev);
> +
> + return ret;
> }
>
> static struct platform_driver rcar_du_platform_driver = {
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
> index 96f2eb43713c..6038be93c58d 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
> @@ -55,12 +55,6 @@ static const struct drm_connector_helper_funcs connector_helper_funcs = {
> .best_encoder = rcar_du_connector_best_encoder,
> };
>
> -static void rcar_du_hdmi_connector_destroy(struct drm_connector *connector)
> -{
> - drm_connector_unregister(connector);
> - drm_connector_cleanup(connector);
> -}
> -
> static enum drm_connector_status
> rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force)
> {
> @@ -79,7 +73,7 @@ static const struct drm_connector_funcs connector_funcs = {
> .reset = drm_atomic_helper_connector_reset,
> .detect = rcar_du_hdmi_connector_detect,
> .fill_modes = drm_helper_probe_single_connector_modes,
> - .destroy = rcar_du_hdmi_connector_destroy,
> + .destroy = drm_connector_cleanup,
> .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> };
> @@ -108,9 +102,6 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
> return ret;
>
> drm_connector_helper_add(connector, &connector_helper_funcs);
> - ret = drm_connector_register(connector);
> - if (ret < 0)
> - return ret;
>
> connector->dpms = DRM_MODE_DPMS_OFF;
> drm_object_property_set_value(&connector->base,
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
> index 0c43032fc693..e905f5da7aaa 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
> @@ -62,12 +62,6 @@ static const struct drm_connector_helper_funcs connector_helper_funcs = {
> .best_encoder = rcar_du_connector_best_encoder,
> };
>
> -static void rcar_du_lvds_connector_destroy(struct drm_connector *connector)
> -{
> - drm_connector_unregister(connector);
> - drm_connector_cleanup(connector);
> -}
> -
> static enum drm_connector_status
> rcar_du_lvds_connector_detect(struct drm_connector *connector, bool force)
> {
> @@ -79,7 +73,7 @@ static const struct drm_connector_funcs connector_funcs = {
> .reset = drm_atomic_helper_connector_reset,
> .detect = rcar_du_lvds_connector_detect,
> .fill_modes = drm_helper_probe_single_connector_modes,
> - .destroy = rcar_du_lvds_connector_destroy,
> + .destroy = drm_connector_cleanup,
> .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> };
> @@ -117,9 +111,6 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
> return ret;
>
> drm_connector_helper_add(connector, &connector_helper_funcs);
> - ret = drm_connector_register(connector);
> - if (ret < 0)
> - return ret;
>
> connector->dpms = DRM_MODE_DPMS_OFF;
> drm_object_property_set_value(&connector->base,
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
> index e0a5d8f93963..9d7e5c99caf6 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
> @@ -31,12 +31,6 @@ static const struct drm_connector_helper_funcs connector_helper_funcs = {
> .best_encoder = rcar_du_connector_best_encoder,
> };
>
> -static void rcar_du_vga_connector_destroy(struct drm_connector *connector)
> -{
> - drm_connector_unregister(connector);
> - drm_connector_cleanup(connector);
> -}
> -
> static enum drm_connector_status
> rcar_du_vga_connector_detect(struct drm_connector *connector, bool force)
> {
> @@ -48,7 +42,7 @@ static const struct drm_connector_funcs connector_funcs = {
> .reset = drm_atomic_helper_connector_reset,
> .detect = rcar_du_vga_connector_detect,
> .fill_modes = drm_helper_probe_single_connector_modes,
> - .destroy = rcar_du_vga_connector_destroy,
> + .destroy = drm_connector_cleanup,
> .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> };
> @@ -76,9 +70,6 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
> return ret;
>
> drm_connector_helper_add(connector, &connector_helper_funcs);
> - ret = drm_connector_register(connector);
> - if (ret < 0)
> - return ret;
>
> connector->dpms = DRM_MODE_DPMS_OFF;
> drm_object_property_set_value(&connector->base,
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://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