aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustavo Padovan <gustavo.padovan@collabora.co.uk>2014-11-24 02:37:26 -0500
committerInki Dae <inki.dae@samsung.com>2014-11-24 04:02:57 -0500
commit820687befec471aff3bb59bd69302d34a776e807 (patch)
tree0571f52ce23b128955adbaf6401514f62ab00e02
parentb67139571ec0956eb94a354572df73cf24d4521c (diff)
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>
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c105
1 files changed, 48 insertions, 57 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 2ca0c5dcf80e..c5cb8b6c85a9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -591,73 +591,22 @@ static struct platform_driver *const exynos_drm_non_kms_drivers[] = {
591static int exynos_drm_platform_probe(struct platform_device *pdev) 591static int exynos_drm_platform_probe(struct platform_device *pdev)
592{ 592{
593 struct component_match *match; 593 struct component_match *match;
594 int ret, i, j;
595 594
596 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 595 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
597 exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls); 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 match = exynos_drm_match_add(&pdev->dev); 598 match = exynos_drm_match_add(&pdev->dev);
606 if (IS_ERR(match)) { 599 if (IS_ERR(match)) {
607 ret = PTR_ERR(match); 600 return PTR_ERR(match);
608 goto err_unregister_kms_drivers;
609 } 601 }
610 602
611 ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, 603 return component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
612 match); 604 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
631err_unregister_non_kms_drivers:
632 while (--j >= 0)
633 platform_driver_unregister(exynos_drm_non_kms_drivers[j]);
634
635err_del_component_master:
636 component_master_del(&pdev->dev, &exynos_drm_ops);
637
638err_unregister_kms_drivers:
639 while (--i >= 0)
640 platform_driver_unregister(exynos_drm_kms_drivers[i]);
641
642 return ret;
643} 605}
644 606
645static int exynos_drm_platform_remove(struct platform_device *pdev) 607static 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 component_master_del(&pdev->dev, &exynos_drm_ops); 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 return 0; 610 return 0;
662} 611}
663 612
@@ -673,7 +622,7 @@ static struct platform_driver exynos_drm_platform_driver = {
673 622
674static int exynos_drm_init(void) 623static int exynos_drm_init(void)
675{ 624{
676 int ret; 625 int ret, i, j;
677 626
678 /* 627 /*
679 * Register device object only in case of Exynos SoC. 628 * Register device object only in case of Exynos SoC.
@@ -696,13 +645,43 @@ static int exynos_drm_init(void)
696 if (ret < 0) 645 if (ret < 0)
697 goto err_unregister_pd; 646 goto err_unregister_pd;
698 647
648 for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) {
649 ret = platform_driver_register(exynos_drm_kms_drivers[i]);
650 if (ret < 0)
651 goto err_unregister_kms_drivers;
652 }
653
654 for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) {
655 ret = platform_driver_register(exynos_drm_non_kms_drivers[j]);
656 if (ret < 0)
657 goto err_unregister_non_kms_drivers;
658 }
659
660#ifdef CONFIG_DRM_EXYNOS_IPP
661 ret = exynos_platform_device_ipp_register();
662 if (ret < 0)
663 goto err_unregister_non_kms_drivers;
664#endif
665
699 ret = platform_driver_register(&exynos_drm_platform_driver); 666 ret = platform_driver_register(&exynos_drm_platform_driver);
700 if (ret) 667 if (ret)
701 goto err_remove_vidi; 668 goto err_unregister_resources;
702 669
703 return 0; 670 return 0;
704 671
705err_remove_vidi: 672err_unregister_resources:
673#ifdef CONFIG_DRM_EXYNOS_IPP
674 exynos_platform_device_ipp_unregister();
675#endif
676
677err_unregister_non_kms_drivers:
678 while (--j >= 0)
679 platform_driver_unregister(exynos_drm_non_kms_drivers[j]);
680
681err_unregister_kms_drivers:
682 while (--i >= 0)
683 platform_driver_unregister(exynos_drm_kms_drivers[i]);
684
706 exynos_drm_remove_vidi(); 685 exynos_drm_remove_vidi();
707 686
708err_unregister_pd: 687err_unregister_pd:
@@ -713,6 +692,18 @@ err_unregister_pd:
713 692
714static void exynos_drm_exit(void) 693static void exynos_drm_exit(void)
715{ 694{
695 int i;
696
697#ifdef CONFIG_DRM_EXYNOS_IPP
698 exynos_platform_device_ipp_unregister();
699#endif
700
701 for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i)
702 platform_driver_unregister(exynos_drm_non_kms_drivers[i]);
703
704 for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i)
705 platform_driver_unregister(exynos_drm_kms_drivers[i]);
706
716 platform_driver_unregister(&exynos_drm_platform_driver); 707 platform_driver_unregister(&exynos_drm_platform_driver);
717 708
718 exynos_drm_remove_vidi(); 709 exynos_drm_remove_vidi();