* Re: [PATCH] of: provide of_platform_unpopulate()
@ 2013-07-20 5:43 NAVEEN KRISHNA CHATRADHI
2013-07-22 8:25 ` Sebastian Andrzej Siewior
0 siblings, 1 reply; 14+ messages in thread
From: NAVEEN KRISHNA CHATRADHI @ 2013-07-20 5:43 UTC (permalink / raw)
To: Sebastian Andrzej Siewior, Rob Herring, Grant Likely
Cc: Kishon Vijay Abraham I, George Cherian,
linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Felipe Balbi, Kukjin Kim, Vivek Gautam,
linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Roger Quadros
Hello Sebastian,
I just did one more testing.
In case of iio/adc/exynos_adc.c there is a bug in the remove path.
If I fix the bug in the driver, with below patch
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -375,14 +375,14 @@ static int exynos_adc_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
- device_for_each_child(&pdev->dev, NULL,
- exynos_adc_remove_devices);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
writel(0, info->enable_reg);
iio_device_unregister(indio_dev);
free_irq(info->irq, info);
iio_device_free(indio_dev);
+ device_for_each_child(&pdev->dev, NULL,
+ exynos_adc_remove_devices);
Even without your fix, I could configure it as a module and the rmmod, insmod are working fine. (no crash)
Regards,
Naveen
------- Original Message -------
Sender : Sebastian Andrzej Siewior<bigeasy-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
Date : Jul 19, 2013 23:44 (GMT+05:30)
Title : [PATCH] of: provide of_platform_unpopulate()
So I called of_platform_populate() on a device to get each child device
probed and on rmmod and I need to reverse its doing. After a quick grep
I did what others did as well and rmmod ended in:
| Unable to handle kernel NULL pointer dereference at virtual address 00000018
| PC is at release_resource+0x18/0x80
| Process rmmod (pid: 2005, stack limit = 0xedc30238)
| [<c003add0>] (release_resource+0x18/0x80) from [<c0300e08>] (platform_device_del+0x78/0xac)
| [<c0300e08>] (platform_device_del+0x78/0xac) from [<c0301358>] (platform_device_unregister+0xc/0x18)
The problem is that platform_device_del() "releases" each ressource in its
tree. This does not work on platform_devices created by OF becuase they
were never added via insert_resource(). As a consequence old->parent in
__release_resource() is NULL and we explode while accessing ->child.
So I either I do something completly wrong _or_ nobody here tested the
rmmod path of their driver.
This patch provides a common function to unregister / remove devices
which added to the system via of_platform_populate(). While this works
now on my test case I have not tested any of the driver I modify here so
feedback is greatly appreciated.
Cc: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
Cc: Doug Anderson <dianders-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Cc: Vivek Gautam <gautam.vivek-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Cc: Naveen Krishna Chatradhi <ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Cc: Kukjin Kim <kgene.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Cc: Kishon Vijay Abraham I <kishon-l0cyMroinI0@public.gmane.org>
Cc: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
Cc: George Cherian <george.cherian-l0cyMroinI0@public.gmane.org>
Cc: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
---
drivers/bus/omap-ocp2scp.c | 13 ++-----------
drivers/iio/adc/exynos_adc.c | 15 ++-------------
drivers/mfd/omap-usb-host.c | 9 +--------
drivers/of/platform.c | 22 ++++++++++++++++++++++
drivers/usb/dwc3/dwc3-exynos.c | 11 +----------
drivers/usb/dwc3/dwc3-omap.c | 12 +-----------
include/linux/of_platform.h | 4 ++++
7 files changed, 33 insertions(+), 53 deletions(-)
diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c
index 5511f98..510bb9e 100644
--- a/drivers/bus/omap-ocp2scp.c
+++ b/drivers/bus/omap-ocp2scp.c
@@ -23,15 +23,6 @@
#include <linux/of.h>
#include <linux/of_platform.h>
-static int ocp2scp_remove_devices(struct device *dev, void *c)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static int omap_ocp2scp_probe(struct platform_device *pdev)
{
int ret;
@@ -51,7 +42,7 @@ static int omap_ocp2scp_probe(struct platform_device *pdev)
return 0;
err0:
- device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
return ret;
}
@@ -59,7 +50,7 @@ static int omap_ocp2scp_probe(struct platform_device *pdev)
static int omap_ocp2scp_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
- device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
return 0;
}
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 9809fc9..10248e1 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -216,15 +216,6 @@ static const struct iio_chan_spec exynos_adc_iio_channels[] = {
ADC_CHANNEL(9, "adc9"),
};
-static int exynos_adc_remove_devices(struct device *dev, void *c)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static void exynos_adc_hw_init(struct exynos_adc *info)
{
u32 con1, con2;
@@ -357,8 +348,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
return 0;
err_of_populate:
- device_for_each_child(&pdev->dev, NULL,
- exynos_adc_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
err_iio_dev:
@@ -375,8 +365,7 @@ static int exynos_adc_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
- device_for_each_child(&pdev->dev, NULL,
- exynos_adc_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
writel(0, info->enable_reg);
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 759fae3..bb26cea 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -832,13 +832,6 @@ static int usbhs_omap_probe(struct platform_device *pdev)
return ret;
}
-static int usbhs_omap_remove_child(struct device *dev, void *data)
-{
- dev_info(dev, "unregistering
");
- platform_device_unregister(to_platform_device(dev));
- return 0;
-}
-
/**
* usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
* @pdev: USB Host Controller being removed
@@ -871,7 +864,7 @@ static int usbhs_omap_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
/* remove children */
- device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child);
+ of_platform_unpopulate(&pdev->dev);
return 0;
}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index e0a6514..9cbb0c3 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -473,4 +473,26 @@ int of_platform_populate(struct device_node *root,
return rc;
}
EXPORT_SYMBOL_GPL(of_platform_populate);
+
+static int of_remove_populated_child(struct device *dev, void *d)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ of_device_unregister(pdev);
+ return 0;
+}
+/**
+ * of_platform_unpopulate() - Remove populated devices.
+ * @parent: parent of the populated devices.
+ *
+ * The reverse of of_platform_populate() and can only be used a parent was
+ * specified while invoking the former.
+ */
+void of_platform_unpopulate(struct device *parent)
+{
+ if (WARN_ON(!parent))
+ return;
+ device_for_each_child(parent, NULL, of_remove_populated_child);
+}
+EXPORT_SYMBOL_GPL(of_platform_unpopulate);
#endif /* CONFIG_OF_ADDRESS */
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index 8ce9d7f..2bf5664 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -86,15 +86,6 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
return ret;
}
-static int dwc3_exynos_remove_child(struct device *dev, void *unused)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static int dwc3_exynos_probe(struct platform_device *pdev)
{
struct dwc3_exynos *exynos;
@@ -164,7 +155,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
{
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
- device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
+ of_platform_unpopulate(&pdev->dev);
platform_device_unregister(exynos->usb2_phy);
platform_device_unregister(exynos->usb3_phy);
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 077f110..8688613 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -327,15 +327,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
return IRQ_HANDLED;
}
-static int dwc3_omap_remove_core(struct device *dev, void *c)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
{
u32 reg;
@@ -529,8 +520,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
dwc3_omap_disable_irqs(omap);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
-
+ of_platform_unpopulate(&pdev->dev);
return 0;
}
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 05cb4a9..e354f9c 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -72,6 +72,7 @@ extern int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent);
+extern void of_platform_unpopulate(struct device *parent);
#else
static inline int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
@@ -80,6 +81,9 @@ static inline int of_platform_populate(struct device_node *root,
{
return -ENODEV;
}
+static inline void of_platform_unpopulate(struct device *parent)
+{
+}
#endif
#endif /* _LINUX_OF_PLATFORM_H */
--
1.8.3.2
<p> </p><p> </p>Thanks & Best Regards,
Naveen Krishna Ch
SE @ Samsung-B.LAB
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH] of: provide of_platform_unpopulate()
2013-07-20 5:43 [PATCH] of: provide of_platform_unpopulate() NAVEEN KRISHNA CHATRADHI
@ 2013-07-22 8:25 ` Sebastian Andrzej Siewior
0 siblings, 0 replies; 14+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 8:25 UTC (permalink / raw)
To: ch.naveen
Cc: Rob Herring, Grant Likely, linux-omap@vger.kernel.org,
linux-samsung-soc@vger.kernel.org,
devicetree-discuss@lists.ozlabs.org, linux-kernel@vger.kernel.org,
Tony Lindgren, Doug Anderson, Vivek Gautam, Kukjin Kim,
Kishon Vijay Abraham I, Roger Quadros, George Cherian,
Felipe Balbi
On 07/20/2013 07:42 AM, NAVEEN KRISHNA CHATRADHI wrote:
> Hello Sebastian,
Hello Naveen,
>
> I just did one more testing.
>
> In case of iio/adc/exynos_adc.c there is a bug in the remove path.
> If I fix the bug in the driver, with below patch
>
> --- a/drivers/iio/adc/exynos_adc.c
> +++ b/drivers/iio/adc/exynos_adc.c
> @@ -375,14 +375,14 @@ static int exynos_adc_remove(struct platform_device *pdev)
> struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> struct exynos_adc *info = iio_priv(indio_dev);
>
> - device_for_each_child(&pdev->dev, NULL,
> - exynos_adc_remove_devices);
> regulator_disable(info->vdd);
> clk_disable_unprepare(info->clk);
> writel(0, info->enable_reg);
> iio_device_unregister(indio_dev);
> free_irq(info->irq, info);
> iio_device_free(indio_dev);
> + device_for_each_child(&pdev->dev, NULL,
> + exynos_adc_remove_devices);
>
> Even without your fix, I could configure it as a module and the rmmod, insmod are working fine. (no crash)
I have no idea why you moved it. I haven't found any .dts with this
binding but from the binding document I would assume that you do not
have any memory resources and therefore you don't see that crash.
> Regards,
> Naveen
Sebastian
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] of: provide of_platform_unpopulate()
@ 2013-07-20 5:03 NAVEEN KRISHNA CHATRADHI
0 siblings, 0 replies; 14+ messages in thread
From: NAVEEN KRISHNA CHATRADHI @ 2013-07-20 5:03 UTC (permalink / raw)
To: Sebastian Andrzej Siewior, Rob Herring, Grant Likely
Cc: linux-omap@vger.kernel.org, linux-samsung-soc@vger.kernel.org,
devicetree-discuss@lists.ozlabs.org, linux-kernel@vger.kernel.org,
Tony Lindgren, Doug Anderson, Vivek Gautam, Kukjin Kim,
Kishon Vijay Abraham I, Roger Quadros, George Cherian,
Felipe Balbi
Hello Sebastian,
------- Original Message -------
Sender : Sebastian Andrzej Siewior<bigeasy@linutronix.de>
Date : Jul 19, 2013 23:44 (GMT+05:30)
Title : [PATCH] of: provide of_platform_unpopulate()
So I called of_platform_populate() on a device to get each child device
probed and on rmmod and I need to reverse its doing. After a quick grep
I did what others did as well and rmmod ended in:
| Unable to handle kernel NULL pointer dereference at virtual address 00000018
| PC is at release_resource+0x18/0x80
| Process rmmod (pid: 2005, stack limit = 0xedc30238)
| [<c003add0>] (release_resource+0x18/0x80) from [<c0300e08>] (platform_device_del+0x78/0xac)
| [<c0300e08>] (platform_device_del+0x78/0xac) from [<c0301358>] (platform_device_unregister+0xc/0x18)
The problem is that platform_device_del() "releases" each ressource in its
tree. This does not work on platform_devices created by OF becuase they
were never added via insert_resource(). As a consequence old->parent in
__release_resource() is NULL and we explode while accessing ->child.
So I either I do something completly wrong _or_ nobody here tested the
rmmod path of their driver.
This patch provides a common function to unregister / remove devices
which added to the system via of_platform_populate(). While this works
now on my test case I have not tested any of the driver I modify here so
feedback is greatly appreciated.
I've tested this on the exynos_adc driver under iio/adc/
and found a bug in the driver. When I fix the bug, your change happily rmmods the module.
Will send the patch separately.
Thanks for pointing out the bug for me.
Cc: Tony Lindgren <tony@atomide.com>
Cc: Doug Anderson <dianders@chromium.org>
Cc: Vivek Gautam <gautam.vivek@samsung.com>
Cc: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Kishon Vijay Abraham I <kishon@ti.com>
Cc: Roger Quadros <rogerq@ti.com>
Cc: George Cherian <george.cherian@ti.com>
Cc: Felipe Balbi <balbi@ti.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
drivers/bus/omap-ocp2scp.c | 13 ++-----------
drivers/iio/adc/exynos_adc.c | 15 ++-------------
drivers/mfd/omap-usb-host.c | 9 +--------
drivers/of/platform.c | 22 ++++++++++++++++++++++
drivers/usb/dwc3/dwc3-exynos.c | 11 +----------
drivers/usb/dwc3/dwc3-omap.c | 12 +-----------
include/linux/of_platform.h | 4 ++++
7 files changed, 33 insertions(+), 53 deletions(-)
diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c
index 5511f98..510bb9e 100644
--- a/drivers/bus/omap-ocp2scp.c
+++ b/drivers/bus/omap-ocp2scp.c
@@ -23,15 +23,6 @@
#include <linux/of.h>
#include <linux/of_platform.h>
-static int ocp2scp_remove_devices(struct device *dev, void *c)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static int omap_ocp2scp_probe(struct platform_device *pdev)
{
int ret;
@@ -51,7 +42,7 @@ static int omap_ocp2scp_probe(struct platform_device *pdev)
return 0;
err0:
- device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
return ret;
}
@@ -59,7 +50,7 @@ static int omap_ocp2scp_probe(struct platform_device *pdev)
static int omap_ocp2scp_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
- device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
return 0;
}
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 9809fc9..10248e1 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -216,15 +216,6 @@ static const struct iio_chan_spec exynos_adc_iio_channels[] = {
ADC_CHANNEL(9, "adc9"),
};
-static int exynos_adc_remove_devices(struct device *dev, void *c)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static void exynos_adc_hw_init(struct exynos_adc *info)
{
u32 con1, con2;
@@ -357,8 +348,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
return 0;
err_of_populate:
- device_for_each_child(&pdev->dev, NULL,
- exynos_adc_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
err_iio_dev:
@@ -375,8 +365,7 @@ static int exynos_adc_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
- device_for_each_child(&pdev->dev, NULL,
- exynos_adc_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
writel(0, info->enable_reg);
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 759fae3..bb26cea 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -832,13 +832,6 @@ static int usbhs_omap_probe(struct platform_device *pdev)
return ret;
}
-static int usbhs_omap_remove_child(struct device *dev, void *data)
-{
- dev_info(dev, "unregistering
");
- platform_device_unregister(to_platform_device(dev));
- return 0;
-}
-
/**
* usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
* @pdev: USB Host Controller being removed
@@ -871,7 +864,7 @@ static int usbhs_omap_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
/* remove children */
- device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child);
+ of_platform_unpopulate(&pdev->dev);
return 0;
}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index e0a6514..9cbb0c3 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -473,4 +473,26 @@ int of_platform_populate(struct device_node *root,
return rc;
}
EXPORT_SYMBOL_GPL(of_platform_populate);
+
+static int of_remove_populated_child(struct device *dev, void *d)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ of_device_unregister(pdev);
+ return 0;
+}
+/**
+ * of_platform_unpopulate() - Remove populated devices.
+ * @parent: parent of the populated devices.
+ *
+ * The reverse of of_platform_populate() and can only be used a parent was
+ * specified while invoking the former.
+ */
+void of_platform_unpopulate(struct device *parent)
+{
+ if (WARN_ON(!parent))
+ return;
+ device_for_each_child(parent, NULL, of_remove_populated_child);
+}
+EXPORT_SYMBOL_GPL(of_platform_unpopulate);
#endif /* CONFIG_OF_ADDRESS */
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index 8ce9d7f..2bf5664 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -86,15 +86,6 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
return ret;
}
-static int dwc3_exynos_remove_child(struct device *dev, void *unused)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static int dwc3_exynos_probe(struct platform_device *pdev)
{
struct dwc3_exynos *exynos;
@@ -164,7 +155,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
{
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
- device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
+ of_platform_unpopulate(&pdev->dev);
platform_device_unregister(exynos->usb2_phy);
platform_device_unregister(exynos->usb3_phy);
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 077f110..8688613 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -327,15 +327,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
return IRQ_HANDLED;
}
-static int dwc3_omap_remove_core(struct device *dev, void *c)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
{
u32 reg;
@@ -529,8 +520,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
dwc3_omap_disable_irqs(omap);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
-
+ of_platform_unpopulate(&pdev->dev);
return 0;
}
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 05cb4a9..e354f9c 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -72,6 +72,7 @@ extern int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent);
+extern void of_platform_unpopulate(struct device *parent);
#else
static inline int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
@@ -80,6 +81,9 @@ static inline int of_platform_populate(struct device_node *root,
{
return -ENODEV;
}
+static inline void of_platform_unpopulate(struct device *parent)
+{
+}
#endif
#endif /* _LINUX_OF_PLATFORM_H */
--
1.8.3.2
<p> </p><p> </p>Thanks & Best Regards,
Naveen Krishna Ch
SE @ Samsung-B.LAB
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH] of: provide of_platform_unpopulate()
@ 2013-07-19 18:14 Sebastian Andrzej Siewior
[not found] ` <1374257691-31981-1-git-send-email-bigeasy-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
2013-07-29 9:31 ` Benjamin Herrenschmidt
0 siblings, 2 replies; 14+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-19 18:14 UTC (permalink / raw)
To: Rob Herring, Grant Likely
Cc: linux-omap, linux-samsung-soc, devicetree-discuss, linux-kernel,
Sebastian Andrzej Siewior, Tony Lindgren, Doug Anderson,
Vivek Gautam, Naveen Krishna Chatradhi, Kukjin Kim,
Kishon Vijay Abraham I, Roger Quadros, George Cherian,
Felipe Balbi
So I called of_platform_populate() on a device to get each child device
probed and on rmmod and I need to reverse its doing. After a quick grep
I did what others did as well and rmmod ended in:
| Unable to handle kernel NULL pointer dereference at virtual address 00000018
| PC is at release_resource+0x18/0x80
| Process rmmod (pid: 2005, stack limit = 0xedc30238)
| [<c003add0>] (release_resource+0x18/0x80) from [<c0300e08>] (platform_device_del+0x78/0xac)
| [<c0300e08>] (platform_device_del+0x78/0xac) from [<c0301358>] (platform_device_unregister+0xc/0x18)
The problem is that platform_device_del() "releases" each ressource in its
tree. This does not work on platform_devices created by OF becuase they
were never added via insert_resource(). As a consequence old->parent in
__release_resource() is NULL and we explode while accessing ->child.
So I either I do something completly wrong _or_ nobody here tested the
rmmod path of their driver.
This patch provides a common function to unregister / remove devices
which added to the system via of_platform_populate(). While this works
now on my test case I have not tested any of the driver I modify here so
feedback is greatly appreciated.
Cc: Tony Lindgren <tony@atomide.com>
Cc: Doug Anderson <dianders@chromium.org>
Cc: Vivek Gautam <gautam.vivek@samsung.com>
Cc: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Kishon Vijay Abraham I <kishon@ti.com>
Cc: Roger Quadros <rogerq@ti.com>
Cc: George Cherian <george.cherian@ti.com>
Cc: Felipe Balbi <balbi@ti.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
drivers/bus/omap-ocp2scp.c | 13 ++-----------
drivers/iio/adc/exynos_adc.c | 15 ++-------------
drivers/mfd/omap-usb-host.c | 9 +--------
drivers/of/platform.c | 22 ++++++++++++++++++++++
drivers/usb/dwc3/dwc3-exynos.c | 11 +----------
drivers/usb/dwc3/dwc3-omap.c | 12 +-----------
include/linux/of_platform.h | 4 ++++
7 files changed, 33 insertions(+), 53 deletions(-)
diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c
index 5511f98..510bb9e 100644
--- a/drivers/bus/omap-ocp2scp.c
+++ b/drivers/bus/omap-ocp2scp.c
@@ -23,15 +23,6 @@
#include <linux/of.h>
#include <linux/of_platform.h>
-static int ocp2scp_remove_devices(struct device *dev, void *c)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static int omap_ocp2scp_probe(struct platform_device *pdev)
{
int ret;
@@ -51,7 +42,7 @@ static int omap_ocp2scp_probe(struct platform_device *pdev)
return 0;
err0:
- device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
return ret;
}
@@ -59,7 +50,7 @@ static int omap_ocp2scp_probe(struct platform_device *pdev)
static int omap_ocp2scp_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
- device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
return 0;
}
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 9809fc9..10248e1 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -216,15 +216,6 @@ static const struct iio_chan_spec exynos_adc_iio_channels[] = {
ADC_CHANNEL(9, "adc9"),
};
-static int exynos_adc_remove_devices(struct device *dev, void *c)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static void exynos_adc_hw_init(struct exynos_adc *info)
{
u32 con1, con2;
@@ -357,8 +348,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
return 0;
err_of_populate:
- device_for_each_child(&pdev->dev, NULL,
- exynos_adc_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
err_iio_dev:
@@ -375,8 +365,7 @@ static int exynos_adc_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
- device_for_each_child(&pdev->dev, NULL,
- exynos_adc_remove_devices);
+ of_platform_unpopulate(&pdev->dev);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
writel(0, info->enable_reg);
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 759fae3..bb26cea 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -832,13 +832,6 @@ static int usbhs_omap_probe(struct platform_device *pdev)
return ret;
}
-static int usbhs_omap_remove_child(struct device *dev, void *data)
-{
- dev_info(dev, "unregistering\n");
- platform_device_unregister(to_platform_device(dev));
- return 0;
-}
-
/**
* usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
* @pdev: USB Host Controller being removed
@@ -871,7 +864,7 @@ static int usbhs_omap_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
/* remove children */
- device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child);
+ of_platform_unpopulate(&pdev->dev);
return 0;
}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index e0a6514..9cbb0c3 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -473,4 +473,26 @@ int of_platform_populate(struct device_node *root,
return rc;
}
EXPORT_SYMBOL_GPL(of_platform_populate);
+
+static int of_remove_populated_child(struct device *dev, void *d)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ of_device_unregister(pdev);
+ return 0;
+}
+/**
+ * of_platform_unpopulate() - Remove populated devices.
+ * @parent: parent of the populated devices.
+ *
+ * The reverse of of_platform_populate() and can only be used a parent was
+ * specified while invoking the former.
+ */
+void of_platform_unpopulate(struct device *parent)
+{
+ if (WARN_ON(!parent))
+ return;
+ device_for_each_child(parent, NULL, of_remove_populated_child);
+}
+EXPORT_SYMBOL_GPL(of_platform_unpopulate);
#endif /* CONFIG_OF_ADDRESS */
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index 8ce9d7f..2bf5664 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -86,15 +86,6 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
return ret;
}
-static int dwc3_exynos_remove_child(struct device *dev, void *unused)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static int dwc3_exynos_probe(struct platform_device *pdev)
{
struct dwc3_exynos *exynos;
@@ -164,7 +155,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
{
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
- device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
+ of_platform_unpopulate(&pdev->dev);
platform_device_unregister(exynos->usb2_phy);
platform_device_unregister(exynos->usb3_phy);
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 077f110..8688613 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -327,15 +327,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
return IRQ_HANDLED;
}
-static int dwc3_omap_remove_core(struct device *dev, void *c)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
{
u32 reg;
@@ -529,8 +520,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
dwc3_omap_disable_irqs(omap);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
-
+ of_platform_unpopulate(&pdev->dev);
return 0;
}
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 05cb4a9..e354f9c 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -72,6 +72,7 @@ extern int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent);
+extern void of_platform_unpopulate(struct device *parent);
#else
static inline int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
@@ -80,6 +81,9 @@ static inline int of_platform_populate(struct device_node *root,
{
return -ENODEV;
}
+static inline void of_platform_unpopulate(struct device *parent)
+{
+}
#endif
#endif /* _LINUX_OF_PLATFORM_H */
--
1.8.3.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <1374257691-31981-1-git-send-email-bigeasy-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>]
* Re: [PATCH] of: provide of_platform_unpopulate()
[not found] ` <1374257691-31981-1-git-send-email-bigeasy-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
@ 2013-07-21 14:42 ` Rob Herring
[not found] ` <51EBF33A.4050207-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2013-07-21 20:48 ` Rob Herring
0 siblings, 2 replies; 14+ messages in thread
From: Rob Herring @ 2013-07-21 14:42 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: George Cherian, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
Roger Quadros, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
Kishon Vijay Abraham I, Kukjin Kim, Felipe Balbi, Grant Likely,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Naveen Krishna Chatradhi,
Vivek Gautam
On 07/19/2013 01:14 PM, Sebastian Andrzej Siewior wrote:
> So I called of_platform_populate() on a device to get each child device
> probed and on rmmod and I need to reverse its doing. After a quick grep
> I did what others did as well and rmmod ended in:
>
> | Unable to handle kernel NULL pointer dereference at virtual address 00000018
> | PC is at release_resource+0x18/0x80
> | Process rmmod (pid: 2005, stack limit = 0xedc30238)
> | [<c003add0>] (release_resource+0x18/0x80) from [<c0300e08>] (platform_device_del+0x78/0xac)
> | [<c0300e08>] (platform_device_del+0x78/0xac) from [<c0301358>] (platform_device_unregister+0xc/0x18)
>
> The problem is that platform_device_del() "releases" each ressource in its
> tree. This does not work on platform_devices created by OF becuase they
> were never added via insert_resource(). As a consequence old->parent in
> __release_resource() is NULL and we explode while accessing ->child.
> So I either I do something completly wrong _or_ nobody here tested the
> rmmod path of their driver.
Wouldn't the correct fix be to call insert_resource somehow? The problem
I have is that while of_platform_populate is all about parsing the DT
and creating devices, the removal side has nothing to do with DT. So
this should not be in the DT code. I think the core device code should
be able to handle removal if the device creation side is done correctly.
It looks to me like of_device_add either needs to call
platform_device_add rather than device_add. I think the device name
setting in platform_device_add should be a nop. If not, a check that the
name is already set could be added.
Rob
>
> This patch provides a common function to unregister / remove devices
> which added to the system via of_platform_populate(). While this works
> now on my test case I have not tested any of the driver I modify here so
> feedback is greatly appreciated.
>
> Cc: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
> Cc: Doug Anderson <dianders-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> Cc: Vivek Gautam <gautam.vivek-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Naveen Krishna Chatradhi <ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Kukjin Kim <kgene.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Kishon Vijay Abraham I <kishon-l0cyMroinI0@public.gmane.org>
> Cc: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
> Cc: George Cherian <george.cherian-l0cyMroinI0@public.gmane.org>
> Cc: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
> ---
> drivers/bus/omap-ocp2scp.c | 13 ++-----------
> drivers/iio/adc/exynos_adc.c | 15 ++-------------
> drivers/mfd/omap-usb-host.c | 9 +--------
> drivers/of/platform.c | 22 ++++++++++++++++++++++
> drivers/usb/dwc3/dwc3-exynos.c | 11 +----------
> drivers/usb/dwc3/dwc3-omap.c | 12 +-----------
> include/linux/of_platform.h | 4 ++++
> 7 files changed, 33 insertions(+), 53 deletions(-)
>
> diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c
> index 5511f98..510bb9e 100644
> --- a/drivers/bus/omap-ocp2scp.c
> +++ b/drivers/bus/omap-ocp2scp.c
> @@ -23,15 +23,6 @@
> #include <linux/of.h>
> #include <linux/of_platform.h>
>
> -static int ocp2scp_remove_devices(struct device *dev, void *c)
> -{
> - struct platform_device *pdev = to_platform_device(dev);
> -
> - platform_device_unregister(pdev);
> -
> - return 0;
> -}
> -
> static int omap_ocp2scp_probe(struct platform_device *pdev)
> {
> int ret;
> @@ -51,7 +42,7 @@ static int omap_ocp2scp_probe(struct platform_device *pdev)
> return 0;
>
> err0:
> - device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
> + of_platform_unpopulate(&pdev->dev);
>
> return ret;
> }
> @@ -59,7 +50,7 @@ static int omap_ocp2scp_probe(struct platform_device *pdev)
> static int omap_ocp2scp_remove(struct platform_device *pdev)
> {
> pm_runtime_disable(&pdev->dev);
> - device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
> + of_platform_unpopulate(&pdev->dev);
>
> return 0;
> }
> diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
> index 9809fc9..10248e1 100644
> --- a/drivers/iio/adc/exynos_adc.c
> +++ b/drivers/iio/adc/exynos_adc.c
> @@ -216,15 +216,6 @@ static const struct iio_chan_spec exynos_adc_iio_channels[] = {
> ADC_CHANNEL(9, "adc9"),
> };
>
> -static int exynos_adc_remove_devices(struct device *dev, void *c)
> -{
> - struct platform_device *pdev = to_platform_device(dev);
> -
> - platform_device_unregister(pdev);
> -
> - return 0;
> -}
> -
> static void exynos_adc_hw_init(struct exynos_adc *info)
> {
> u32 con1, con2;
> @@ -357,8 +348,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
> return 0;
>
> err_of_populate:
> - device_for_each_child(&pdev->dev, NULL,
> - exynos_adc_remove_devices);
> + of_platform_unpopulate(&pdev->dev);
> regulator_disable(info->vdd);
> clk_disable_unprepare(info->clk);
> err_iio_dev:
> @@ -375,8 +365,7 @@ static int exynos_adc_remove(struct platform_device *pdev)
> struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> struct exynos_adc *info = iio_priv(indio_dev);
>
> - device_for_each_child(&pdev->dev, NULL,
> - exynos_adc_remove_devices);
> + of_platform_unpopulate(&pdev->dev);
> regulator_disable(info->vdd);
> clk_disable_unprepare(info->clk);
> writel(0, info->enable_reg);
> diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
> index 759fae3..bb26cea 100644
> --- a/drivers/mfd/omap-usb-host.c
> +++ b/drivers/mfd/omap-usb-host.c
> @@ -832,13 +832,6 @@ static int usbhs_omap_probe(struct platform_device *pdev)
> return ret;
> }
>
> -static int usbhs_omap_remove_child(struct device *dev, void *data)
> -{
> - dev_info(dev, "unregistering\n");
> - platform_device_unregister(to_platform_device(dev));
> - return 0;
> -}
> -
> /**
> * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
> * @pdev: USB Host Controller being removed
> @@ -871,7 +864,7 @@ static int usbhs_omap_remove(struct platform_device *pdev)
> pm_runtime_disable(&pdev->dev);
>
> /* remove children */
> - device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child);
> + of_platform_unpopulate(&pdev->dev);
> return 0;
> }
>
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index e0a6514..9cbb0c3 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -473,4 +473,26 @@ int of_platform_populate(struct device_node *root,
> return rc;
> }
> EXPORT_SYMBOL_GPL(of_platform_populate);
> +
> +static int of_remove_populated_child(struct device *dev, void *d)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> +
> + of_device_unregister(pdev);
> + return 0;
> +}
> +/**
> + * of_platform_unpopulate() - Remove populated devices.
> + * @parent: parent of the populated devices.
> + *
> + * The reverse of of_platform_populate() and can only be used a parent was
> + * specified while invoking the former.
> + */
> +void of_platform_unpopulate(struct device *parent)
> +{
> + if (WARN_ON(!parent))
> + return;
> + device_for_each_child(parent, NULL, of_remove_populated_child);
> +}
> +EXPORT_SYMBOL_GPL(of_platform_unpopulate);
> #endif /* CONFIG_OF_ADDRESS */
> diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
> index 8ce9d7f..2bf5664 100644
> --- a/drivers/usb/dwc3/dwc3-exynos.c
> +++ b/drivers/usb/dwc3/dwc3-exynos.c
> @@ -86,15 +86,6 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
> return ret;
> }
>
> -static int dwc3_exynos_remove_child(struct device *dev, void *unused)
> -{
> - struct platform_device *pdev = to_platform_device(dev);
> -
> - platform_device_unregister(pdev);
> -
> - return 0;
> -}
> -
> static int dwc3_exynos_probe(struct platform_device *pdev)
> {
> struct dwc3_exynos *exynos;
> @@ -164,7 +155,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
> {
> struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
>
> - device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
> + of_platform_unpopulate(&pdev->dev);
> platform_device_unregister(exynos->usb2_phy);
> platform_device_unregister(exynos->usb3_phy);
>
> diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
> index 077f110..8688613 100644
> --- a/drivers/usb/dwc3/dwc3-omap.c
> +++ b/drivers/usb/dwc3/dwc3-omap.c
> @@ -327,15 +327,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
> return IRQ_HANDLED;
> }
>
> -static int dwc3_omap_remove_core(struct device *dev, void *c)
> -{
> - struct platform_device *pdev = to_platform_device(dev);
> -
> - platform_device_unregister(pdev);
> -
> - return 0;
> -}
> -
> static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
> {
> u32 reg;
> @@ -529,8 +520,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
> dwc3_omap_disable_irqs(omap);
> pm_runtime_put_sync(&pdev->dev);
> pm_runtime_disable(&pdev->dev);
> - device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
> -
> + of_platform_unpopulate(&pdev->dev);
> return 0;
> }
>
> diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
> index 05cb4a9..e354f9c 100644
> --- a/include/linux/of_platform.h
> +++ b/include/linux/of_platform.h
> @@ -72,6 +72,7 @@ extern int of_platform_populate(struct device_node *root,
> const struct of_device_id *matches,
> const struct of_dev_auxdata *lookup,
> struct device *parent);
> +extern void of_platform_unpopulate(struct device *parent);
> #else
> static inline int of_platform_populate(struct device_node *root,
> const struct of_device_id *matches,
> @@ -80,6 +81,9 @@ static inline int of_platform_populate(struct device_node *root,
> {
> return -ENODEV;
> }
> +static inline void of_platform_unpopulate(struct device *parent)
> +{
> +}
> #endif
>
> #endif /* _LINUX_OF_PLATFORM_H */
>
^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <51EBF33A.4050207-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH] of: provide of_platform_unpopulate()
[not found] ` <51EBF33A.4050207-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2013-07-21 19:47 ` Sebastian Andrzej Siewior
0 siblings, 0 replies; 14+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-21 19:47 UTC (permalink / raw)
To: Rob Herring
Cc: George Cherian, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
Roger Quadros, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
Kishon Vijay Abraham I, Kukjin Kim, Felipe Balbi, Grant Likely,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Naveen Krishna Chatradhi,
Vivek Gautam
On 07/21/2013 04:42 PM, Rob Herring wrote:
> Wouldn't the correct fix be to call insert_resource somehow?
Yes unless there was a reason this wasn't done in the first place.
> The problem
> I have is that while of_platform_populate is all about parsing the DT
> and creating devices, the removal side has nothing to do with DT. So
> this should not be in the DT code. I think the core device code should
> be able to handle removal if the device creation side is done correctly.
If there is no need to use the special removal function (in case we add
insert_ressource) then yes. What about a pointer in
of_platform_populate()'s comment referring to the removal function?
>
> It looks to me like of_device_add either needs to call
> platform_device_add rather than device_add. I think the device name
> setting in platform_device_add should be a nop. If not, a check that the
> name is already set could be added.
It does actually the same thing as platform_device_add except the
"dynamic device id" and the resource insert if I remember correctly. If
you guys prefer the platdorm_device_add() path including
insert_ressource() I can try this.
>
> Rob
Sebastian
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] of: provide of_platform_unpopulate()
2013-07-21 14:42 ` Rob Herring
[not found] ` <51EBF33A.4050207-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2013-07-21 20:48 ` Rob Herring
[not found] ` <51EC4908.4040504-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
1 sibling, 1 reply; 14+ messages in thread
From: Rob Herring @ 2013-07-21 20:48 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Rob Herring, Grant Likely, Kishon Vijay Abraham I, George Cherian,
linux-samsung-soc, devicetree-discuss, linux-kernel, Felipe Balbi,
Kukjin Kim, Vivek Gautam, linux-omap, Naveen Krishna Chatradhi,
Roger Quadros
On 07/21/2013 09:42 AM, Rob Herring wrote:
> On 07/19/2013 01:14 PM, Sebastian Andrzej Siewior wrote:
>> So I called of_platform_populate() on a device to get each child device
>> probed and on rmmod and I need to reverse its doing. After a quick grep
>> I did what others did as well and rmmod ended in:
>>
>> | Unable to handle kernel NULL pointer dereference at virtual address 00000018
>> | PC is at release_resource+0x18/0x80
>> | Process rmmod (pid: 2005, stack limit = 0xedc30238)
>> | [<c003add0>] (release_resource+0x18/0x80) from [<c0300e08>] (platform_device_del+0x78/0xac)
>> | [<c0300e08>] (platform_device_del+0x78/0xac) from [<c0301358>] (platform_device_unregister+0xc/0x18)
>>
>> The problem is that platform_device_del() "releases" each ressource in its
>> tree. This does not work on platform_devices created by OF becuase they
>> were never added via insert_resource(). As a consequence old->parent in
>> __release_resource() is NULL and we explode while accessing ->child.
>> So I either I do something completly wrong _or_ nobody here tested the
>> rmmod path of their driver.
>
> Wouldn't the correct fix be to call insert_resource somehow? The problem
> I have is that while of_platform_populate is all about parsing the DT
> and creating devices, the removal side has nothing to do with DT. So
> this should not be in the DT code. I think the core device code should
> be able to handle removal if the device creation side is done correctly.
>
> It looks to me like of_device_add either needs to call
> platform_device_add rather than device_add. I think the device name
> setting in platform_device_add should be a nop. If not, a check that the
> name is already set could be added.
>
BTW, it looks like Grant has attempted this already:
commit 02bbde7849e68e193cefaa1885fe0df0f03c9fcd
Author: Grant Likely <grant.likely@secretlab.ca>
Date: Sun Feb 17 20:03:27 2013 +0000
Revert "of: use platform_device_add"
This reverts commit aac73f34542bc7ae4317928d2eabfeb21d247323. That
commit causes two kinds of breakage; it breaks registration of AMBA
devices when one of the parent nodes already contains overlapping
resource regions, and it breaks calls to request_region() by device
drivers in certain conditions where there are overlapping memory
regions. Both of these problems can probably be fixed, but it is better
to back out the commit and get a proper fix designed before trying
again.
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Rob
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] of: provide of_platform_unpopulate()
2013-07-19 18:14 Sebastian Andrzej Siewior
[not found] ` <1374257691-31981-1-git-send-email-bigeasy-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
@ 2013-07-29 9:31 ` Benjamin Herrenschmidt
1 sibling, 0 replies; 14+ messages in thread
From: Benjamin Herrenschmidt @ 2013-07-29 9:31 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Rob Herring, Grant Likely, Kishon Vijay Abraham I, George Cherian,
linux-samsung-soc, devicetree-discuss, linux-kernel, Felipe Balbi,
Kukjin Kim, Vivek Gautam, linux-omap, Naveen Krishna Chatradhi,
Roger Quadros
On Fri, 2013-07-19 at 20:14 +0200, Sebastian Andrzej Siewior wrote:
> The problem is that platform_device_del() "releases" each ressource in its
> tree. This does not work on platform_devices created by OF becuase they
> were never added via insert_resource(). As a consequence old->parent in
> __release_resource() is NULL and we explode while accessing ->child.
> So I either I do something completly wrong _or_ nobody here tested the
> rmmod path of their driver.
But that's wrong. I am not familar with all that new code, but from step
up, not having the resources in the resource tree is a bad idea to begin
with....
> This patch provides a common function to unregister / remove devices
> which added to the system via of_platform_populate(). While this works
> now on my test case I have not tested any of the driver I modify here so
> feedback is greatly appreciated.
Ben.
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2013-07-31 16:28 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-20 5:43 [PATCH] of: provide of_platform_unpopulate() NAVEEN KRISHNA CHATRADHI
2013-07-22 8:25 ` Sebastian Andrzej Siewior
-- strict thread matches above, loose matches on Subject: below --
2013-07-20 5:03 NAVEEN KRISHNA CHATRADHI
2013-07-19 18:14 Sebastian Andrzej Siewior
[not found] ` <1374257691-31981-1-git-send-email-bigeasy-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
2013-07-21 14:42 ` Rob Herring
[not found] ` <51EBF33A.4050207-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2013-07-21 19:47 ` Sebastian Andrzej Siewior
2013-07-21 20:48 ` Rob Herring
[not found] ` <51EC4908.4040504-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2013-07-21 23:44 ` Grant Likely
2013-07-22 21:16 ` Rob Herring
2013-07-24 14:19 ` Grant Likely
2013-07-31 15:21 ` Sebastian Andrzej Siewior
2013-07-29 9:33 ` Benjamin Herrenschmidt
2013-07-31 16:28 ` Rob Herring
2013-07-29 9:31 ` Benjamin Herrenschmidt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).