lkml.org 
[lkml]   [2018]   [Jul]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC] soc: imx: gpc: Unregister pgc children on remove
    Date
    If the gpc device is removed the platform_devices for its
    imx-pgc-power-domains are still registered and trying to probe gpc again
    results in an error.

    Fix this by iterating children inside imx_gpc_remove and calling
    platfrom_device_unregister.

    Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
    ---
    drivers/soc/imx/gpc.c | 15 +++++++++++++++
    1 file changed, 15 insertions(+)

    This was prompted by the rejection of the following series:
    https://lkml.org/lkml/2018/7/2/534

    Tested glxgears after rebinding gpc and etnaviv by echo to
    /sys/bus/platform/drivers/{imx-gpc,etnaviv-gpu}/{unbind,bind}

    When doing probe again it triggers a warning inside
    driver_links_drivers_bound:

    WARN_ON(link->status != DL_STATE_CONSUMER_PROBE);

    This seems to be because devicelink code does not expect consumers to
    bind before suppliers but GPC code adds PGC children during its
    probe function and they register a device-link to their still-probing
    parent.

    The warning doesn't trigger on normal boot because the pgc driver is
    registered after gpc and probing is not nested. The warning can be made
    to reproduce in a normal boot by making imx_gpc_probe return
    -EPROBE_DEFER once (no other changes required).

    This does not seem to be a valid scenario for device links so fix this
    by adding a check in imx_pgc_power_domain_probe to defer if parent is not
    probed.

    This check is not very nice, device_is_bound seems like something that
    should be internal to the driver core.

    diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c
    index 32f0748fd067..b4acdfd3cffd 100644
    --- a/drivers/soc/imx/gpc.c
    +++ b/drivers/soc/imx/gpc.c
    @@ -182,10 +182,13 @@ static int imx_pgc_power_domain_probe(struct platform_device *pdev)
    {
    struct imx_pm_domain *domain = pdev->dev.platform_data;
    struct device *dev = &pdev->dev;
    int ret;

    + if (!device_is_bound(dev->parent))
    + return -EPROBE_DEFER;
    +
    /* if this PD is associated with a DT node try to parse it */
    if (dev->of_node) {
    ret = imx_pgc_parse_dt(dev, domain);
    if (ret)
    return ret;
    @@ -475,10 +478,19 @@ static int imx_gpc_probe(struct platform_device *pdev)
    }

    return 0;
    }

    +static int __imx_gpc_unregister_child(struct device *dev, void *data)
    +{
    + struct platform_device *pdev = to_platform_device(dev);
    +
    + platform_device_unregister(pdev);
    +
    + return 0;
    +}
    +
    static int imx_gpc_remove(struct platform_device *pdev)
    {
    struct device_node *pgc_node;
    int ret;

    @@ -502,10 +514,13 @@ static int imx_gpc_remove(struct platform_device *pdev)
    imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]);

    ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base);
    if (ret)
    return ret;
    + } else {
    + device_for_each_child(&pdev->dev, NULL,
    + __imx_gpc_unregister_child);
    }

    return 0;
    }

    --
    2.17.1
    \
     
     \ /
      Last update: 2018-07-03 21:40    [W:3.109 / U:2.264 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site