soc: imx: gpcv2: removing and probing fails
Stefan Agner
stefan at agner.ch
Tue Jan 9 13:08:31 PST 2018
On 2018-01-09 15:55, Lucas Stach wrote:
> Am Dienstag, den 09.01.2018, 15:44 +0100 schrieb Stefan Agner:
>> On 2018-01-09 15:24, Lucas Stach wrote:
>> > Am Sonntag, den 07.01.2018, 11:48 +0100 schrieb Stefan Agner:
>> > > Hi Andrew,
>> > >
>> > > I noticed that the driver fails when removing and probing again.
>> > > As far
>> > > as I can see due to duplicate add of the platform devices.
>> > >
>> > > As far as I can tell the driver should register the remove
>> > > callback and
>> > > do a platform_device_unregister on the newly created platform
>> > > devices.
>> > > However, as far as I can tell we don't hold on to a reference to
>> > > them...
>> > > I guess we could keep references in imx_gpcv2_probe, but maybe
>> > > there is
>> > > an easier way?
>> >
>> > The GPC v1 driver adds the necessary device dependency between the
>> > power domain devices and the GPC parent device. See the
>> > device_link_add() in imx_pgc_power_domain_probe().
>>
>> Note that despite device_link_add, GPC v1 seems to cause issue with
>> CONFIG_DEBUG_TEST_DRIVER_REMOVE=y:
>> https://marc.info/?l=linux-arm-kernel&m=151544599904423&w=4
>>
>> (sorry, I made it confusing, by adding a stack trace when using GPC
>> v1
>> in the gpcv2 thread...)
>
> IMHO this is an issue with the CONFIG_DEBUG_TEST_DRIVER_REMOVE option,
> as it just blindly calls the remove callback instead of doing a proper
> __device_release_driver(). All the regular driver/device unbind paths
> will properly unbind the consumer devices before removing the driver.
They do unbind the consumer device, but do not unregister the platform
device.
I tried to fix it by calling platform_device_unregister, e.g. with this
changes unbind seems to work:
--- a/drivers/soc/imx/gpc.c
+++ b/drivers/soc/imx/gpc.c
@@ -40,6 +40,7 @@
struct imx_pm_domain {
struct generic_pm_domain base;
+ struct platform_device *pdev;
struct regmap *regmap;
struct regulator *supply;
struct clk *clk[GPC_CLK_MAX];
@@ -462,6 +465,8 @@ static int imx_gpc_probe(struct platform_device
*pdev)
of_node_put(np);
return ret;
}
+
+ domain->pdev = pd_pdev;
}
}
@@ -470,7 +475,7 @@ static int imx_gpc_probe(struct platform_device
*pdev)
static int imx_gpc_remove(struct platform_device *pdev)
{
- int ret;
+ int i, ret;
/*
* If the old DT binding is used the toplevel driver needs to
@@ -489,6 +494,21 @@ static int imx_gpc_remove(struct platform_device
*pdev)
return ret;
}
+
+ for (i = 0; i < ARRAY_SIZE(imx_gpc_domains); i++) {
+ struct imx_pm_domain *domain = &imx_gpc_domains[i];
+
+ if (domain->pdev) {
+ /*
+ * Unlink platform_data to prevent
+ * platform_device_unregister to kfree it.
+ */
+ domain->pdev->dev.platform_data = NULL;
+ platform_device_unregister(domain->pdev);
+ domain->pdev = NULL;
+ }
+ }
+
return 0;
}
However, it still leads to a stacktrace on next bind:
root at colibri-imx6:~# echo 20dc000.gpc >
/sys/bus/platform/drivers/imx-gpc/bind
[ 24.741624] imx-pgc-pd imx-pgc-power-domain.0: Linked as a consumer
to 20dc000.gpc
[ 24.749219] ------------[ cut here ]------------
[ 24.753934] WARNING: CPU: 0 PID: 430 at drivers/base/core.c:417
device_links_driver_bound+0xd8/0xe0
...
--
Stefan
More information about the linux-arm-kernel
mailing list