Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: rcar-du: Perform initialization/cleanup at probe/remove time

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@ideasonboard.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

+107 -115
+104 -85
drivers/gpu/drm/rcar-du/rcar_du_drv.c
··· 144 144 * DRM operations 145 145 */ 146 146 147 - static int rcar_du_unload(struct drm_device *dev) 148 - { 149 - struct rcar_du_device *rcdu = dev->dev_private; 150 - 151 - if (rcdu->fbdev) 152 - drm_fbdev_cma_fini(rcdu->fbdev); 153 - 154 - drm_kms_helper_poll_fini(dev); 155 - drm_mode_config_cleanup(dev); 156 - drm_vblank_cleanup(dev); 157 - 158 - dev->irq_enabled = 0; 159 - dev->dev_private = NULL; 160 - 161 - return 0; 162 - } 163 - 164 - static int rcar_du_load(struct drm_device *dev, unsigned long flags) 165 - { 166 - struct platform_device *pdev = dev->platformdev; 167 - struct device_node *np = pdev->dev.of_node; 168 - struct rcar_du_device *rcdu; 169 - struct resource *mem; 170 - int ret; 171 - 172 - if (np == NULL) { 173 - dev_err(dev->dev, "no platform data\n"); 174 - return -ENODEV; 175 - } 176 - 177 - rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL); 178 - if (rcdu == NULL) { 179 - dev_err(dev->dev, "failed to allocate private data\n"); 180 - return -ENOMEM; 181 - } 182 - 183 - init_waitqueue_head(&rcdu->commit.wait); 184 - 185 - rcdu->dev = &pdev->dev; 186 - rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data; 187 - rcdu->ddev = dev; 188 - dev->dev_private = rcdu; 189 - 190 - /* I/O resources */ 191 - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 192 - rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem); 193 - if (IS_ERR(rcdu->mmio)) 194 - return PTR_ERR(rcdu->mmio); 195 - 196 - /* Initialize vertical blanking interrupts handling. Start with vblank 197 - * disabled for all CRTCs. 198 - */ 199 - ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1); 200 - if (ret < 0) { 201 - dev_err(&pdev->dev, "failed to initialize vblank\n"); 202 - goto done; 203 - } 204 - 205 - /* DRM/KMS objects */ 206 - ret = rcar_du_modeset_init(rcdu); 207 - if (ret < 0) { 208 - dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret); 209 - goto done; 210 - } 211 - 212 - dev->irq_enabled = 1; 213 - 214 - platform_set_drvdata(pdev, rcdu); 215 - 216 - done: 217 - if (ret) 218 - rcar_du_unload(dev); 219 - 220 - return ret; 221 - } 222 - 223 147 static void rcar_du_lastclose(struct drm_device *dev) 224 148 { 225 149 struct rcar_du_device *rcdu = dev->dev_private; ··· 184 260 static struct drm_driver rcar_du_driver = { 185 261 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME 186 262 | DRIVER_ATOMIC, 187 - .load = rcar_du_load, 188 - .unload = rcar_du_unload, 189 263 .lastclose = rcar_du_lastclose, 190 - .set_busid = drm_platform_set_busid, 191 264 .get_vblank_counter = drm_vblank_no_hw_counter, 192 265 .enable_vblank = rcar_du_enable_vblank, 193 266 .disable_vblank = rcar_du_disable_vblank, ··· 244 323 * Platform driver 245 324 */ 246 325 247 - static int rcar_du_probe(struct platform_device *pdev) 248 - { 249 - return drm_platform_init(&rcar_du_driver, pdev); 250 - } 251 - 252 326 static int rcar_du_remove(struct platform_device *pdev) 253 327 { 254 328 struct rcar_du_device *rcdu = platform_get_drvdata(pdev); 329 + struct drm_device *ddev = rcdu->ddev; 255 330 256 - drm_put_dev(rcdu->ddev); 331 + mutex_lock(&ddev->mode_config.mutex); 332 + drm_connector_unplug_all(ddev); 333 + mutex_unlock(&ddev->mode_config.mutex); 334 + 335 + drm_dev_unregister(ddev); 336 + 337 + if (rcdu->fbdev) 338 + drm_fbdev_cma_fini(rcdu->fbdev); 339 + 340 + drm_kms_helper_poll_fini(ddev); 341 + drm_mode_config_cleanup(ddev); 342 + drm_vblank_cleanup(ddev); 343 + 344 + drm_dev_unref(ddev); 257 345 258 346 return 0; 347 + } 348 + 349 + static int rcar_du_probe(struct platform_device *pdev) 350 + { 351 + struct device_node *np = pdev->dev.of_node; 352 + struct rcar_du_device *rcdu; 353 + struct drm_connector *connector; 354 + struct drm_device *ddev; 355 + struct resource *mem; 356 + int ret; 357 + 358 + if (np == NULL) { 359 + dev_err(&pdev->dev, "no device tree node\n"); 360 + return -ENODEV; 361 + } 362 + 363 + /* Allocate and initialize the DRM and R-Car device structures. */ 364 + rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL); 365 + if (rcdu == NULL) 366 + return -ENOMEM; 367 + 368 + init_waitqueue_head(&rcdu->commit.wait); 369 + 370 + rcdu->dev = &pdev->dev; 371 + rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data; 372 + 373 + ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev); 374 + if (!ddev) 375 + return -ENOMEM; 376 + 377 + drm_dev_set_unique(ddev, dev_name(&pdev->dev)); 378 + 379 + rcdu->ddev = ddev; 380 + ddev->dev_private = rcdu; 381 + 382 + platform_set_drvdata(pdev, rcdu); 383 + 384 + /* I/O resources */ 385 + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 386 + rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem); 387 + if (IS_ERR(rcdu->mmio)) { 388 + ret = PTR_ERR(rcdu->mmio); 389 + goto error; 390 + } 391 + 392 + /* Initialize vertical blanking interrupts handling. Start with vblank 393 + * disabled for all CRTCs. 394 + */ 395 + ret = drm_vblank_init(ddev, (1 << rcdu->info->num_crtcs) - 1); 396 + if (ret < 0) { 397 + dev_err(&pdev->dev, "failed to initialize vblank\n"); 398 + goto error; 399 + } 400 + 401 + /* DRM/KMS objects */ 402 + ret = rcar_du_modeset_init(rcdu); 403 + if (ret < 0) { 404 + dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret); 405 + goto error; 406 + } 407 + 408 + ddev->irq_enabled = 1; 409 + 410 + /* Register the DRM device with the core and the connectors with 411 + * sysfs. 412 + */ 413 + ret = drm_dev_register(ddev, 0); 414 + if (ret) 415 + goto error; 416 + 417 + mutex_lock(&ddev->mode_config.mutex); 418 + drm_for_each_connector(connector, ddev) { 419 + ret = drm_connector_register(connector); 420 + if (ret < 0) 421 + break; 422 + } 423 + mutex_unlock(&ddev->mode_config.mutex); 424 + 425 + if (ret < 0) 426 + goto error; 427 + 428 + DRM_INFO("Device %s probed\n", dev_name(&pdev->dev)); 429 + 430 + return 0; 431 + 432 + error: 433 + rcar_du_remove(pdev); 434 + 435 + return ret; 259 436 } 260 437 261 438 static struct platform_driver rcar_du_platform_driver = {
+1 -10
drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
··· 55 55 .best_encoder = rcar_du_connector_best_encoder, 56 56 }; 57 57 58 - static void rcar_du_hdmi_connector_destroy(struct drm_connector *connector) 59 - { 60 - drm_connector_unregister(connector); 61 - drm_connector_cleanup(connector); 62 - } 63 - 64 58 static enum drm_connector_status 65 59 rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force) 66 60 { ··· 73 79 .reset = drm_atomic_helper_connector_reset, 74 80 .detect = rcar_du_hdmi_connector_detect, 75 81 .fill_modes = drm_helper_probe_single_connector_modes, 76 - .destroy = rcar_du_hdmi_connector_destroy, 82 + .destroy = drm_connector_cleanup, 77 83 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 78 84 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 79 85 }; ··· 102 108 return ret; 103 109 104 110 drm_connector_helper_add(connector, &connector_helper_funcs); 105 - ret = drm_connector_register(connector); 106 - if (ret < 0) 107 - return ret; 108 111 109 112 connector->dpms = DRM_MODE_DPMS_OFF; 110 113 drm_object_property_set_value(&connector->base,
+1 -10
drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
··· 62 62 .best_encoder = rcar_du_connector_best_encoder, 63 63 }; 64 64 65 - static void rcar_du_lvds_connector_destroy(struct drm_connector *connector) 66 - { 67 - drm_connector_unregister(connector); 68 - drm_connector_cleanup(connector); 69 - } 70 - 71 65 static enum drm_connector_status 72 66 rcar_du_lvds_connector_detect(struct drm_connector *connector, bool force) 73 67 { ··· 73 79 .reset = drm_atomic_helper_connector_reset, 74 80 .detect = rcar_du_lvds_connector_detect, 75 81 .fill_modes = drm_helper_probe_single_connector_modes, 76 - .destroy = rcar_du_lvds_connector_destroy, 82 + .destroy = drm_connector_cleanup, 77 83 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 78 84 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 79 85 }; ··· 111 117 return ret; 112 118 113 119 drm_connector_helper_add(connector, &connector_helper_funcs); 114 - ret = drm_connector_register(connector); 115 - if (ret < 0) 116 - return ret; 117 120 118 121 connector->dpms = DRM_MODE_DPMS_OFF; 119 122 drm_object_property_set_value(&connector->base,
+1 -10
drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
··· 31 31 .best_encoder = rcar_du_connector_best_encoder, 32 32 }; 33 33 34 - static void rcar_du_vga_connector_destroy(struct drm_connector *connector) 35 - { 36 - drm_connector_unregister(connector); 37 - drm_connector_cleanup(connector); 38 - } 39 - 40 34 static enum drm_connector_status 41 35 rcar_du_vga_connector_detect(struct drm_connector *connector, bool force) 42 36 { ··· 42 48 .reset = drm_atomic_helper_connector_reset, 43 49 .detect = rcar_du_vga_connector_detect, 44 50 .fill_modes = drm_helper_probe_single_connector_modes, 45 - .destroy = rcar_du_vga_connector_destroy, 51 + .destroy = drm_connector_cleanup, 46 52 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 47 53 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 48 54 }; ··· 70 76 return ret; 71 77 72 78 drm_connector_helper_add(connector, &connector_helper_funcs); 73 - ret = drm_connector_register(connector); 74 - if (ret < 0) 75 - return ret; 76 79 77 80 connector->dpms = DRM_MODE_DPMS_OFF; 78 81 drm_object_property_set_value(&connector->base,