From: Gustavo Padovan gustavo.padovan@collabora.co.uk
These patches were tested both in drm-exynos-next and linux-next (with drm-exynos-next merged in) and it solves the infinite loop and parent device lock deadlock. It was tested with Ajay's DP patches applied. A tree based on drm-exynos-next can be found here:
https://git.kernel.org/cgit/linux/kernel/git/padovan/drm-exynos.git/log/?h=d...
The first patch reverts the other tries to fix this problem.
The second patch is a revert and fixes a regression with the subdriver probe function getting a NULL drvdata and thus failing drm_exynos_init()
The third patch is a port to drm-exynos-next of Javier patches that moves the platform driver registration to init.
Gustavo Padovan (3): drm/exynos: revert fixes for the infinite loop issue Revert "drm/exynos: fix null pointer dereference issue" drm/exynos: move Exynos platform drivers registration to init
drivers/gpu/drm/exynos/exynos_drm_drv.c | 159 ++++++++++++++------------------ 1 file changed, 68 insertions(+), 91 deletions(-)
From: Gustavo Padovan gustavo.padovan@collabora.co.uk
This reverts commit 06a2f5c2c4e0cb4ff38ca3769ae1f81cc2d030cf and f7c2f36f4395f12d8ecb25c28ee88ec87b457089.
These two patches were trying to fix an issue that was causing an infinite loop at the load of the exynos-drm but they were not tackling the source of the problem.
A new patch that move the platform driver registration exynos_drm_init() follows this revert and fix the issue properly.
Signed-off-by: Gustavo Padovan gustavo.padovan@collabora.co.uk --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 18 ------------------ 1 file changed, 18 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index eab12f0..b94c9d1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -484,12 +484,6 @@ static struct component_match *exynos_drm_match_add(struct device *dev)
mutex_lock(&drm_component_lock);
- /* Do not retry to probe if there is no any kms driver regitered. */ - if (list_empty(&drm_component_list)) { - mutex_unlock(&drm_component_lock); - return ERR_PTR(-ENODEV); - } - list_for_each_entry(cdev, &drm_component_list, list) { /* * Add components to master only in case that crtc and @@ -674,18 +668,6 @@ static int exynos_drm_init(void) { int ret;
- /* - * Register device object only in case of Exynos SoC. - * - * Below codes resolves temporarily infinite loop issue incurred - * by Exynos drm driver when using multi-platform kernel. - * So these codes will be replaced with more generic way later. - */ - if (!of_machine_is_compatible("samsung,exynos3") && - !of_machine_is_compatible("samsung,exynos4") && - !of_machine_is_compatible("samsung,exynos5")) - return -ENODEV; - exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, NULL, 0); if (IS_ERR(exynos_drm_pdev))
From: Gustavo Padovan gustavo.padovan@collabora.co.uk
This reverts commit cea24824ab432f8acabb254d6805e9aa756de6af.
Moving subdriver probe to exynos_drm_platform_probe() was making exynos_drm_device_subdrv_probe() fail because the platform data wasn't set yet. It only gets set in exynos_drm_load.
We need to find a smarter way to fix this issue.
Signed-off-by: Gustavo Padovan gustavo.padovan@collabora.co.uk --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index b94c9d1..91891cf 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -108,6 +108,11 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto err_unbind_all;
+ /* Probe non kms sub drivers and virtual display driver. */ + ret = exynos_drm_device_subdrv_probe(dev); + if (ret) + goto err_cleanup_vblank; + /* * enable drm irq mode. * - with irq_enabled = true, we can use the vblank feature. @@ -133,6 +138,8 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
return 0;
+err_cleanup_vblank: + drm_vblank_cleanup(dev); err_unbind_all: component_unbind_all(dev->dev, dev); err_mode_config_cleanup: @@ -146,6 +153,8 @@ err_free_private:
static int exynos_drm_unload(struct drm_device *dev) { + exynos_drm_device_subdrv_remove(dev); + exynos_drm_fbdev_fini(dev); drm_kms_helper_poll_fini(dev);
@@ -608,14 +617,8 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) if (ret < 0) goto err_unregister_non_kms_drivers;
- /* Probe non kms sub drivers and virtual display driver. */ - ret = exynos_drm_device_subdrv_probe(platform_get_drvdata(pdev)); - if (ret) - goto err_unregister_resources; - return ret;
-err_unregister_resources: #ifdef CONFIG_DRM_EXYNOS_IPP exynos_platform_device_ipp_unregister(); #endif @@ -637,8 +640,6 @@ static int exynos_drm_platform_remove(struct platform_device *pdev) { int i;
- exynos_drm_device_subdrv_remove(platform_get_drvdata(pdev)); - #ifdef CONFIG_DRM_EXYNOS_IPP exynos_platform_device_ipp_unregister(); #endif
From: Gustavo Padovan gustavo.padovan@collabora.co.uk
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
Signed-off-by: Javier Martinez Canillas javier.martinez@collabora.co.uk Signed-off-by: Gustavo Padovan gustavo.padovan@collabora.co.uk --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 124 +++++++++++++++----------------- 1 file changed, 59 insertions(+), 65 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 91891cf..cb3ed9b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -548,6 +548,38 @@ static const struct component_master_ops exynos_drm_ops = { .unbind = exynos_drm_unbind, };
+static int exynos_drm_platform_probe(struct platform_device *pdev) +{ + struct component_match *match; + + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls); + + match = exynos_drm_match_add(&pdev->dev); + if (IS_ERR(match)) { + return PTR_ERR(match); + } + + return component_master_add_with_match(&pdev->dev, &exynos_drm_ops, + match); +} + +static int exynos_drm_platform_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &exynos_drm_ops); + return 0; +} + +static struct platform_driver exynos_drm_platform_driver = { + .probe = exynos_drm_platform_probe, + .remove = exynos_drm_platform_remove, + .driver = { + .owner = THIS_MODULE, + .name = "exynos-drm", + .pm = &exynos_drm_pm_ops, + }, +}; + static struct platform_driver *const exynos_drm_kms_drivers[] = { #ifdef CONFIG_DRM_EXYNOS_FIMD &fimd_driver, @@ -582,13 +614,24 @@ static struct platform_driver *const exynos_drm_non_kms_drivers[] = { #endif };
-static int exynos_drm_platform_probe(struct platform_device *pdev) +static int exynos_drm_init(void) { - struct component_match *match; int ret, i, j;
- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls); + exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, + NULL, 0); + if (IS_ERR(exynos_drm_pdev)) + return PTR_ERR(exynos_drm_pdev); + +#ifdef CONFIG_DRM_EXYNOS_VIDI + ret = exynos_drm_probe_vidi(); + if (ret < 0) + goto err_unregister_pd; +#endif + + ret = platform_driver_register(&exynos_drm_platform_driver); + if (ret) + goto err_remove_vidi;
for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { ret = platform_driver_register(exynos_drm_kms_drivers[i]); @@ -596,26 +639,17 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) goto err_unregister_kms_drivers; }
- match = exynos_drm_match_add(&pdev->dev); - if (IS_ERR(match)) { - ret = PTR_ERR(match); - goto err_unregister_kms_drivers; - } - - ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops, - match); - if (ret < 0) - goto err_unregister_kms_drivers; - for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { ret = platform_driver_register(exynos_drm_non_kms_drivers[j]); if (ret < 0) - goto err_del_component_master; + goto err_unregister_non_kms_drivers; }
+#ifdef CONFIG_DRM_EXYNOS_IPP ret = exynos_platform_device_ipp_register(); if (ret < 0) goto err_unregister_non_kms_drivers; +#endif
return ret;
@@ -626,17 +660,22 @@ err_unregister_non_kms_drivers: while (--j >= 0) platform_driver_unregister(exynos_drm_non_kms_drivers[j]);
-err_del_component_master: - component_master_del(&pdev->dev, &exynos_drm_ops); - err_unregister_kms_drivers: while (--i >= 0) platform_driver_unregister(exynos_drm_kms_drivers[i]);
+err_remove_vidi: +#ifdef CONFIG_DRM_EXYNOS_VIDI + exynos_drm_remove_vidi(); + +err_unregister_pd: +#endif + platform_device_unregister(exynos_drm_pdev); + return ret; }
-static int exynos_drm_platform_remove(struct platform_device *pdev) +static void exynos_drm_exit(void) { int i;
@@ -647,54 +686,9 @@ static int exynos_drm_platform_remove(struct platform_device *pdev) for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i) platform_driver_unregister(exynos_drm_non_kms_drivers[i]);
- component_master_del(&pdev->dev, &exynos_drm_ops); - for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i) platform_driver_unregister(exynos_drm_kms_drivers[i]);
- return 0; -} - -static struct platform_driver exynos_drm_platform_driver = { - .probe = exynos_drm_platform_probe, - .remove = exynos_drm_platform_remove, - .driver = { - .owner = THIS_MODULE, - .name = "exynos-drm", - .pm = &exynos_drm_pm_ops, - }, -}; - -static int exynos_drm_init(void) -{ - int ret; - - exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, - NULL, 0); - if (IS_ERR(exynos_drm_pdev)) - return PTR_ERR(exynos_drm_pdev); - - ret = exynos_drm_probe_vidi(); - if (ret < 0) - goto err_unregister_pd; - - ret = platform_driver_register(&exynos_drm_platform_driver); - if (ret) - goto err_remove_vidi; - - return 0; - -err_remove_vidi: - exynos_drm_remove_vidi(); - -err_unregister_pd: - platform_device_unregister(exynos_drm_pdev); - - return ret; -} - -static void exynos_drm_exit(void) -{ platform_driver_unregister(&exynos_drm_platform_driver);
exynos_drm_remove_vidi();
On 2014년 11월 21일 08:42, Gustavo Padovan wrote:
From: Gustavo Padovan gustavo.padovan@collabora.co.uk
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
Signed-off-by: Javier Martinez Canillas javier.martinez@collabora.co.uk Signed-off-by: Gustavo Padovan gustavo.padovan@collabora.co.uk
drivers/gpu/drm/exynos/exynos_drm_drv.c | 124 +++++++++++++++----------------- 1 file changed, 59 insertions(+), 65 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 91891cf..cb3ed9b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -548,6 +548,38 @@ static const struct component_master_ops exynos_drm_ops = { .unbind = exynos_drm_unbind, };
+static int exynos_drm_platform_probe(struct platform_device *pdev) +{
- struct component_match *match;
- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
- match = exynos_drm_match_add(&pdev->dev);
- if (IS_ERR(match)) {
return PTR_ERR(match);
- }
- return component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
match);
+}
+static int exynos_drm_platform_remove(struct platform_device *pdev) +{
- component_master_del(&pdev->dev, &exynos_drm_ops);
- return 0;
+}
+static struct platform_driver exynos_drm_platform_driver = {
- .probe = exynos_drm_platform_probe,
- .remove = exynos_drm_platform_remove,
- .driver = {
.owner = THIS_MODULE,
.name = "exynos-drm",
.pm = &exynos_drm_pm_ops,
- },
+};
static struct platform_driver *const exynos_drm_kms_drivers[] = { #ifdef CONFIG_DRM_EXYNOS_FIMD &fimd_driver, @@ -582,13 +614,24 @@ static struct platform_driver *const exynos_drm_non_kms_drivers[] = { #endif };
-static int exynos_drm_platform_probe(struct platform_device *pdev) +static int exynos_drm_init(void) {
struct component_match *match; int ret, i, j;
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
- exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
NULL, 0);
- if (IS_ERR(exynos_drm_pdev))
return PTR_ERR(exynos_drm_pdev);
+#ifdef CONFIG_DRM_EXYNOS_VIDI
- ret = exynos_drm_probe_vidi();
- if (ret < 0)
goto err_unregister_pd;
+#endif
If vidi driver is enabled then Exynos drm driver doesn't work.
- ret = platform_driver_register(&exynos_drm_platform_driver);
- if (ret)
goto err_remove_vidi;
Above platform_driver_register should be called after all kms and non-kms drivers are registered. And your patch should be re-based on top of exynos-drm-next.
I just re-based it on top of exynos-drm-next and changed the platform_driver_register to be called at the end.
Thanks, Inki Dae
for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { ret = platform_driver_register(exynos_drm_kms_drivers[i]); @@ -596,26 +639,17 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) goto err_unregister_kms_drivers; }
- match = exynos_drm_match_add(&pdev->dev);
- if (IS_ERR(match)) {
ret = PTR_ERR(match);
goto err_unregister_kms_drivers;
- }
- ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
match);
- if (ret < 0)
goto err_unregister_kms_drivers;
- for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { ret = platform_driver_register(exynos_drm_non_kms_drivers[j]); if (ret < 0)
goto err_del_component_master;
}goto err_unregister_non_kms_drivers;
+#ifdef CONFIG_DRM_EXYNOS_IPP ret = exynos_platform_device_ipp_register(); if (ret < 0) goto err_unregister_non_kms_drivers; +#endif
return ret;
@@ -626,17 +660,22 @@ err_unregister_non_kms_drivers: while (--j >= 0) platform_driver_unregister(exynos_drm_non_kms_drivers[j]);
-err_del_component_master:
- component_master_del(&pdev->dev, &exynos_drm_ops);
err_unregister_kms_drivers: while (--i >= 0) platform_driver_unregister(exynos_drm_kms_drivers[i]);
+err_remove_vidi: +#ifdef CONFIG_DRM_EXYNOS_VIDI
- exynos_drm_remove_vidi();
+err_unregister_pd: +#endif
- platform_device_unregister(exynos_drm_pdev);
- return ret;
}
-static int exynos_drm_platform_remove(struct platform_device *pdev) +static void exynos_drm_exit(void) { int i;
@@ -647,54 +686,9 @@ static int exynos_drm_platform_remove(struct platform_device *pdev) for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i) platform_driver_unregister(exynos_drm_non_kms_drivers[i]);
component_master_del(&pdev->dev, &exynos_drm_ops);
for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i) platform_driver_unregister(exynos_drm_kms_drivers[i]);
return 0;
-}
-static struct platform_driver exynos_drm_platform_driver = {
- .probe = exynos_drm_platform_probe,
- .remove = exynos_drm_platform_remove,
- .driver = {
.owner = THIS_MODULE,
.name = "exynos-drm",
.pm = &exynos_drm_pm_ops,
- },
-};
-static int exynos_drm_init(void) -{
- int ret;
- exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
NULL, 0);
- if (IS_ERR(exynos_drm_pdev))
return PTR_ERR(exynos_drm_pdev);
- ret = exynos_drm_probe_vidi();
- if (ret < 0)
goto err_unregister_pd;
- ret = platform_driver_register(&exynos_drm_platform_driver);
- if (ret)
goto err_remove_vidi;
- return 0;
-err_remove_vidi:
- exynos_drm_remove_vidi();
-err_unregister_pd:
- platform_device_unregister(exynos_drm_pdev);
- return ret;
-}
-static void exynos_drm_exit(void) -{ platform_driver_unregister(&exynos_drm_platform_driver);
exynos_drm_remove_vidi();
dri-devel@lists.freedesktop.org