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

drm/exynos: move Exynos platform drivers registration to init

Registering the Exynos DRM subdevices platform drivers in the probe
function is causing an infinite loop. Fix this by moving it to the
exynos_drm_init() function to register the drivers on module init.

Registering drivers in the probe functions causes a deadlock in the parent
device lock. See Grant Likely explanation on the topic:

"I think the problem is that exynos_drm_init() is registering a normal
(non-OF) platform device, so the parent will be /sys/devices/platform.
It immediately gets bound against exynos_drm_platform_driver which
calls the exynos drm_platform_probe() hook. The driver core obtains
device_lock() on the device *and on the device parent*.

Inside the probe hook, additional platform_drivers get registered.
Each time one does, it tries to bind against every platform device in
the system, which includes the ones created by OF. When it attempts to
bind, it obtains device_lock() on the device *and on the device
parent*.

Before the change to move of-generated platform devices into
/sys/devices/platform, the devices had different parents. Now both
devices have /sys/devices/platform as the parent, so yes they are
going to deadlock.

The real problem is registering drivers from within a probe hook. That
is completely wrong for the above deadlock reason. __driver_attach()
will deadlock. Those registrations must be pulled out of .probe().

Registering devices in .probe() is okay because __device_attach()
doesn't try to obtain device_lock() on the parent."

INFO: task swapper/0:1 blocked for more than 120 seconds.
Not tainted 3.18.0-rc3-next-20141105 #794
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
swapper/0 D c052534c 0 1 0 0x00000000
[<c052534c>] (__schedule) from [<c0525b34>] (schedule_preempt_disabled+0x14/0x20)
[<c0525b34>] (schedule_preempt_disabled) from [<c0526d44>] (mutex_lock_nested+0x1c4/0x464

[<c0526d44>] (mutex_lock_nested) from [<c02be908>] (__driver_attach+0x48/0x98)
[<c02be908>] (__driver_attach) from [<c02bcc00>] (bus_for_each_dev+0x54/0x88)
[<c02bcc00>] (bus_for_each_dev) from [<c02bdce0>] (bus_add_driver+0xe4/0x200)
[<c02bdce0>] (bus_add_driver) from [<c02bef94>] (driver_register+0x78/0xf4)
[<c02bef94>] (driver_register) from [<c029e99c>] (exynos_drm_platform_probe+0x34/0x234)
[<c029e99c>] (exynos_drm_platform_probe) from [<c02bfcf0>] (platform_drv_probe+0x48/0xa4)
[<c02bfcf0>] (platform_drv_probe) from [<c02be680>] (driver_probe_device+0x13c/0x37c)
[<c02be680>] (driver_probe_device) from [<c02be954>] (__driver_attach+0x94/0x98)
[<c02be954>] (__driver_attach) from [<c02bcc00>] (bus_for_each_dev+0x54/0x88)
[<c02bcc00>] (bus_for_each_dev) from [<c02bdce0>] (bus_add_driver+0xe4/0x200)
[<c02bdce0>] (bus_add_driver) from [<c02bef94>] (driver_register+0x78/0xf4)
[<c02bef94>] (driver_register) from [<c029e938>] (exynos_drm_init+0x70/0xa0)
[<c029e938>] (exynos_drm_init) from [<c00089b0>] (do_one_initcall+0xac/0x1f0)
[<c00089b0>] (do_one_initcall) from [<c074bd90>] (kernel_init_freeable+0x10c/0x1d8)
[<c074bd90>] (kernel_init_freeable) from [<c051eabc>] (kernel_init+0x8/0xec)
[<c051eabc>] (kernel_init) from [<c000f268>] (ret_from_fork+0x14/0x2c)
3 locks held by swapper/0/1:
#0: (&dev->mutex){......}, at: [<c02be908>] __driver_attach+0x48/0x98
#1: (&dev->mutex){......}, at: [<c02be918>] __driver_attach+0x58/0x98
#2: (&dev->mutex){......}, at: [<c02be908>] __driver_attach+0x48/0x98

Changelog v2:
- call platform_driver_register after all kms and non kms drivers are
registered
- rebased it to exynos-drm-next

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Signed-off-by: Inki Dae <inki.dae@samsung.com>

authored by

Gustavo Padovan and committed by
Inki Dae
820687be b6713957

+48 -57
+48 -57
drivers/gpu/drm/exynos/exynos_drm_drv.c
··· 591 591 static int exynos_drm_platform_probe(struct platform_device *pdev) 592 592 { 593 593 struct component_match *match; 594 - int ret, i, j; 595 594 596 595 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 597 596 exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls); 598 597 599 - for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { 600 - ret = platform_driver_register(exynos_drm_kms_drivers[i]); 601 - if (ret < 0) 602 - goto err_unregister_kms_drivers; 603 - } 604 - 605 598 match = exynos_drm_match_add(&pdev->dev); 606 599 if (IS_ERR(match)) { 607 - ret = PTR_ERR(match); 608 - goto err_unregister_kms_drivers; 600 + return PTR_ERR(match); 609 601 } 610 602 611 - ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, 612 - match); 613 - if (ret < 0) 614 - goto err_unregister_kms_drivers; 615 - 616 - for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { 617 - ret = platform_driver_register(exynos_drm_non_kms_drivers[j]); 618 - if (ret < 0) 619 - goto err_del_component_master; 620 - } 621 - 622 - ret = exynos_platform_device_ipp_register(); 623 - if (ret < 0) 624 - goto err_unregister_non_kms_drivers; 625 - 626 - return ret; 627 - 628 - #ifdef CONFIG_DRM_EXYNOS_IPP 629 - exynos_platform_device_ipp_unregister(); 630 - #endif 631 - err_unregister_non_kms_drivers: 632 - while (--j >= 0) 633 - platform_driver_unregister(exynos_drm_non_kms_drivers[j]); 634 - 635 - err_del_component_master: 636 - component_master_del(&pdev->dev, &exynos_drm_ops); 637 - 638 - err_unregister_kms_drivers: 639 - while (--i >= 0) 640 - platform_driver_unregister(exynos_drm_kms_drivers[i]); 641 - 642 - return ret; 603 + return component_master_add_with_match(&pdev->dev, &exynos_drm_ops, 604 + match); 643 605 } 644 606 645 607 static int exynos_drm_platform_remove(struct platform_device *pdev) 646 608 { 647 - int i; 648 - 649 - #ifdef CONFIG_DRM_EXYNOS_IPP 650 - exynos_platform_device_ipp_unregister(); 651 - #endif 652 - 653 - for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i) 654 - platform_driver_unregister(exynos_drm_non_kms_drivers[i]); 655 - 656 609 component_master_del(&pdev->dev, &exynos_drm_ops); 657 - 658 - for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i) 659 - platform_driver_unregister(exynos_drm_kms_drivers[i]); 660 - 661 610 return 0; 662 611 } 663 612 ··· 622 673 623 674 static int exynos_drm_init(void) 624 675 { 625 - int ret; 676 + int ret, i, j; 626 677 627 678 /* 628 679 * Register device object only in case of Exynos SoC. ··· 645 696 if (ret < 0) 646 697 goto err_unregister_pd; 647 698 699 + for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { 700 + ret = platform_driver_register(exynos_drm_kms_drivers[i]); 701 + if (ret < 0) 702 + goto err_unregister_kms_drivers; 703 + } 704 + 705 + for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { 706 + ret = platform_driver_register(exynos_drm_non_kms_drivers[j]); 707 + if (ret < 0) 708 + goto err_unregister_non_kms_drivers; 709 + } 710 + 711 + #ifdef CONFIG_DRM_EXYNOS_IPP 712 + ret = exynos_platform_device_ipp_register(); 713 + if (ret < 0) 714 + goto err_unregister_non_kms_drivers; 715 + #endif 716 + 648 717 ret = platform_driver_register(&exynos_drm_platform_driver); 649 718 if (ret) 650 - goto err_remove_vidi; 719 + goto err_unregister_resources; 651 720 652 721 return 0; 653 722 654 - err_remove_vidi: 723 + err_unregister_resources: 724 + #ifdef CONFIG_DRM_EXYNOS_IPP 725 + exynos_platform_device_ipp_unregister(); 726 + #endif 727 + 728 + err_unregister_non_kms_drivers: 729 + while (--j >= 0) 730 + platform_driver_unregister(exynos_drm_non_kms_drivers[j]); 731 + 732 + err_unregister_kms_drivers: 733 + while (--i >= 0) 734 + platform_driver_unregister(exynos_drm_kms_drivers[i]); 735 + 655 736 exynos_drm_remove_vidi(); 656 737 657 738 err_unregister_pd: ··· 692 713 693 714 static void exynos_drm_exit(void) 694 715 { 716 + int i; 717 + 718 + #ifdef CONFIG_DRM_EXYNOS_IPP 719 + exynos_platform_device_ipp_unregister(); 720 + #endif 721 + 722 + for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i) 723 + platform_driver_unregister(exynos_drm_non_kms_drivers[i]); 724 + 725 + for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i) 726 + platform_driver_unregister(exynos_drm_kms_drivers[i]); 727 + 695 728 platform_driver_unregister(&exynos_drm_platform_driver); 696 729 697 730 exynos_drm_remove_vidi();