Message ID | 20210113110320.13149-1-m.szyprowski@samsung.com |
---|---|
State | New |
Headers | show |
Series | soc: samsung: pm_domains: Convert to regular platform driver | expand |
On Wed, Jan 13, 2021 at 3:03 AM Marek Szyprowski <m.szyprowski@samsung.com> wrote: > > When Exynos power domain driver was introduced, the only way to ensure > that power domains will be instantiated before the devices which belongs > to them was to initialize them early enough, before the devices are > instantiated in the system. This in turn required not to use any platform > device infrastructure at all, as there have been no way to ensure proper > probe order between devices. > > This has been finally changed and patch e590474768f1 ("driver core: Set > fw_devlink=on by default") ensures that each device will be probbed only > when its resource providers are ready. This allows to convert Exynos > power domain driver to regular platform driver. > > This is also required by the mentioned commit to enable probing any > device which belongs to the Exynos power domains, as otherwise the core > won't notice that the power domains are in fact available. > > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > --- > Some more comments are in the following thread: > https://lore.kernel.org/lkml/2556a69b-5da5-bf80-e051-df2d02fbc40f@samsung.com/ > --- > drivers/soc/samsung/pm_domains.c | 97 ++++++++++++++++---------------- > 1 file changed, 48 insertions(+), 49 deletions(-) > > diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c > index ab8582971bfc..5ec0c13f0aaf 100644 > --- a/drivers/soc/samsung/pm_domains.c > +++ b/drivers/soc/samsung/pm_domains.c > @@ -16,7 +16,7 @@ > #include <linux/delay.h> > #include <linux/of_address.h> > #include <linux/of_platform.h> > -#include <linux/sched.h> > +#include <linux/pm_runtime.h> > > struct exynos_pm_domain_config { > /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */ > @@ -73,15 +73,15 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain) > return exynos_pd_power(domain, false); > } > > -static const struct exynos_pm_domain_config exynos4210_cfg __initconst = { > +static const struct exynos_pm_domain_config exynos4210_cfg = { > .local_pwr_cfg = 0x7, > }; > > -static const struct exynos_pm_domain_config exynos5433_cfg __initconst = { > +static const struct exynos_pm_domain_config exynos5433_cfg = { > .local_pwr_cfg = 0xf, > }; > > -static const struct of_device_id exynos_pm_domain_of_match[] __initconst = { > +static const struct of_device_id exynos_pm_domain_of_match[] = { > { > .compatible = "samsung,exynos4210-pd", > .data = &exynos4210_cfg, > @@ -92,7 +92,7 @@ static const struct of_device_id exynos_pm_domain_of_match[] __initconst = { > { }, > }; > > -static __init const char *exynos_get_domain_name(struct device_node *node) > +static const char *exynos_get_domain_name(struct device_node *node) > { > const char *name; > > @@ -101,60 +101,44 @@ static __init const char *exynos_get_domain_name(struct device_node *node) > return kstrdup_const(name, GFP_KERNEL); > } > > -static __init int exynos4_pm_init_power_domain(void) > +static int exynos_pd_probe(struct platform_device *pdev) > { > - struct device_node *np; > - const struct of_device_id *match; > - > - for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) { > - const struct exynos_pm_domain_config *pm_domain_cfg; > - struct exynos_pm_domain *pd; > - int on; > + const struct exynos_pm_domain_config *pm_domain_cfg; > + struct device *dev = &pdev->dev; > + struct device_node *np = dev->of_node; > + struct of_phandle_args child, parent; > + struct exynos_pm_domain *pd; > + int on, ret; > > - pm_domain_cfg = match->data; > + pm_domain_cfg = of_device_get_match_data(dev); > + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); > + if (!pd) > + return -ENOMEM; > > - pd = kzalloc(sizeof(*pd), GFP_KERNEL); > - if (!pd) { > - of_node_put(np); > - return -ENOMEM; > - } > - pd->pd.name = exynos_get_domain_name(np); > - if (!pd->pd.name) { > - kfree(pd); > - of_node_put(np); > - return -ENOMEM; > - } > + pd->pd.name = exynos_get_domain_name(np); > + if (!pd->pd.name) > + return -ENOMEM; > > - pd->base = of_iomap(np, 0); > - if (!pd->base) { > - pr_warn("%s: failed to map memory\n", __func__); > - kfree_const(pd->pd.name); > - kfree(pd); > - continue; > - } > - > - pd->pd.power_off = exynos_pd_power_off; > - pd->pd.power_on = exynos_pd_power_on; > - pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; > + pd->base = of_iomap(np, 0); > + if (!pd->base) { > + kfree_const(pd->pd.name); > + return -ENODEV; > + } > > - on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg; > + pd->pd.power_off = exynos_pd_power_off; > + pd->pd.power_on = exynos_pd_power_on; > + pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; > > - pm_genpd_init(&pd->pd, NULL, !on); > - of_genpd_add_provider_simple(np, &pd->pd); > - } > + on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg; > > - /* Assign the child power domains to their parents */ > - for_each_matching_node(np, exynos_pm_domain_of_match) { > - struct of_phandle_args child, parent; > + pm_genpd_init(&pd->pd, NULL, !on); > + ret = of_genpd_add_provider_simple(np, &pd->pd); > > + if (ret == 0 && of_parse_phandle_with_args(np, "power-domains", > + "#power-domain-cells", 0, &parent) == 0) { > child.np = np; > child.args_count = 0; > > - if (of_parse_phandle_with_args(np, "power-domains", > - "#power-domain-cells", 0, > - &parent) != 0) > - continue; > - > if (of_genpd_add_subdomain(&parent, &child)) > pr_warn("%pOF failed to add subdomain: %pOF\n", > parent.np, child.np); > @@ -163,6 +147,21 @@ static __init int exynos4_pm_init_power_domain(void) > parent.np, child.np); > } > > - return 0; > + pm_runtime_enable(dev); > + return ret; > +} > + > +static struct platform_driver exynos_pd_driver = { > + .probe = exynos_pd_probe, > + .driver = { > + .name = "exynos-pd", > + .of_match_table = exynos_pm_domain_of_match, > + .suppress_bind_attrs = true, > + } > +}; > + > +static __init int exynos4_pm_init_power_domain(void) > +{ > + return platform_driver_register(&exynos_pd_driver); > } > core_initcall(exynos4_pm_init_power_domain); > -- > 2.17.1 > Skimmed through this patch and at a high level, it looks good for what it's trying to do. Thanks for doing this! Btw, I assume that this won't work with fw_devlink=off/permissive (default since 5.10 or earlier)? My concern is that we might temporarily set fw_devlink=permissive by default if the other breakages aren't fixed in time for 5.12? How do you want to handle that? -Saravana
Hi Saravana, On 13.01.2021 21:27, Saravana Kannan wrote: > On Wed, Jan 13, 2021 at 3:03 AM Marek Szyprowski > <m.szyprowski@samsung.com> wrote: >> When Exynos power domain driver was introduced, the only way to ensure >> that power domains will be instantiated before the devices which belongs >> to them was to initialize them early enough, before the devices are >> instantiated in the system. This in turn required not to use any platform >> device infrastructure at all, as there have been no way to ensure proper >> probe order between devices. >> >> This has been finally changed and patch e590474768f1 ("driver core: Set >> fw_devlink=on by default") ensures that each device will be probbed only >> when its resource providers are ready. This allows to convert Exynos >> power domain driver to regular platform driver. >> >> This is also required by the mentioned commit to enable probing any >> device which belongs to the Exynos power domains, as otherwise the core >> won't notice that the power domains are in fact available. >> >> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> >> --- >> Some more comments are in the following thread: >> https://protect2.fireeye.com/v1/url?k=8ac052ac-d55b6ba4-8ac1d9e3-0cc47a31c8b4-9068b559b0fd155d&q=1&e=b393c3ff-16ba-48a4-9d72-6805d02971d5&u=https%3A%2F%2Flore.kernel.org%2Flkml%2F2556a69b-5da5-bf80-e051-df2d02fbc40f%40samsung.com%2F >> --- >> ... > Skimmed through this patch and at a high level, it looks good for what > it's trying to do. Thanks for doing this! > > Btw, I assume that this won't work with fw_devlink=off/permissive > (default since 5.10 or earlier)? My concern is that we might > temporarily set fw_devlink=permissive by default if the other > breakages aren't fixed in time for 5.12? How do you want to handle that? I've applied my patch on top of vanilla v5.10 and checked on my test boards. Surprisingly everything works fine, so something must have been changed during the last few years as the power domain driver in the current form has been written long time ago. I remember that the moment when platform devices are created from the of nodes has been change at some point, so maybe this is somehow related. Anyway, the platform driver for Exynos power domains registered from core_initcall works fine with v5.10 kernel. I have no strong opinion on the way of merging this fix. It can go via Samsung tree, so in the end the v5.12-rc1 will have both my fix and your change, but won't be fully bisectable in-between. Krzysztof, what's your opinion? Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
On Thu, Jan 14, 2021 at 11:03 AM Marek Szyprowski <m.szyprowski@samsung.com> wrote: > > Hi Saravana, > > On 13.01.2021 21:27, Saravana Kannan wrote: > > On Wed, Jan 13, 2021 at 3:03 AM Marek Szyprowski > > <m.szyprowski@samsung.com> wrote: > >> When Exynos power domain driver was introduced, the only way to ensure > >> that power domains will be instantiated before the devices which belongs > >> to them was to initialize them early enough, before the devices are > >> instantiated in the system. This in turn required not to use any platform > >> device infrastructure at all, as there have been no way to ensure proper > >> probe order between devices. > >> > >> This has been finally changed and patch e590474768f1 ("driver core: Set > >> fw_devlink=on by default") ensures that each device will be probbed only > >> when its resource providers are ready. This allows to convert Exynos > >> power domain driver to regular platform driver. > >> > >> This is also required by the mentioned commit to enable probing any > >> device which belongs to the Exynos power domains, as otherwise the core > >> won't notice that the power domains are in fact available. > >> > >> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > >> --- > >> Some more comments are in the following thread: > >> https://protect2.fireeye.com/v1/url?k=8ac052ac-d55b6ba4-8ac1d9e3-0cc47a31c8b4-9068b559b0fd155d&q=1&e=b393c3ff-16ba-48a4-9d72-6805d02971d5&u=https%3A%2F%2Flore.kernel.org%2Flkml%2F2556a69b-5da5-bf80-e051-df2d02fbc40f%40samsung.com%2F > >> --- > >> ... > > Skimmed through this patch and at a high level, it looks good for what > > it's trying to do. Thanks for doing this! > > > > Btw, I assume that this won't work with fw_devlink=off/permissive > > (default since 5.10 or earlier)? My concern is that we might > > temporarily set fw_devlink=permissive by default if the other > > breakages aren't fixed in time for 5.12? How do you want to handle that? > > I've applied my patch on top of vanilla v5.10 and checked on my test > boards. Surprisingly everything works fine, so something must have been > changed during the last few years as the power domain driver in the > current form has been written long time ago. I remember that the moment > when platform devices are created from the of nodes has been change at > some point, so maybe this is somehow related. Anyway, the platform > driver for Exynos power domains registered from core_initcall works fine > with v5.10 kernel. > > I have no strong opinion on the way of merging this fix. It can go via > Samsung tree, so in the end the v5.12-rc1 will have both my fix and your > change, but won't be fully bisectable in-between. Krzysztof, what's your > opinion? If it doesn't break anything without my changes, then let's try to get it merged independent of my series. This is a good change even without my changes. -Saravana
On Thu, Jan 14, 2021 at 11:07:30AM -0800, Saravana Kannan wrote: > On Thu, Jan 14, 2021 at 11:03 AM Marek Szyprowski > <m.szyprowski@samsung.com> wrote: > > > > Hi Saravana, > > > > On 13.01.2021 21:27, Saravana Kannan wrote: > > > On Wed, Jan 13, 2021 at 3:03 AM Marek Szyprowski > > > <m.szyprowski@samsung.com> wrote: > > >> When Exynos power domain driver was introduced, the only way to ensure > > >> that power domains will be instantiated before the devices which belongs > > >> to them was to initialize them early enough, before the devices are > > >> instantiated in the system. This in turn required not to use any platform > > >> device infrastructure at all, as there have been no way to ensure proper > > >> probe order between devices. > > >> > > >> This has been finally changed and patch e590474768f1 ("driver core: Set > > >> fw_devlink=on by default") ensures that each device will be probbed only > > >> when its resource providers are ready. This allows to convert Exynos > > >> power domain driver to regular platform driver. > > >> > > >> This is also required by the mentioned commit to enable probing any > > >> device which belongs to the Exynos power domains, as otherwise the core > > >> won't notice that the power domains are in fact available. > > >> > > >> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > > >> --- > > >> Some more comments are in the following thread: > > >> https://protect2.fireeye.com/v1/url?k=8ac052ac-d55b6ba4-8ac1d9e3-0cc47a31c8b4-9068b559b0fd155d&q=1&e=b393c3ff-16ba-48a4-9d72-6805d02971d5&u=https%3A%2F%2Flore.kernel.org%2Flkml%2F2556a69b-5da5-bf80-e051-df2d02fbc40f%40samsung.com%2F > > >> --- > > >> ... > > > Skimmed through this patch and at a high level, it looks good for what > > > it's trying to do. Thanks for doing this! > > > > > > Btw, I assume that this won't work with fw_devlink=off/permissive > > > (default since 5.10 or earlier)? My concern is that we might > > > temporarily set fw_devlink=permissive by default if the other > > > breakages aren't fixed in time for 5.12? How do you want to handle that? > > > > I've applied my patch on top of vanilla v5.10 and checked on my test > > boards. Surprisingly everything works fine, so something must have been > > changed during the last few years as the power domain driver in the > > current form has been written long time ago. I remember that the moment > > when platform devices are created from the of nodes has been change at > > some point, so maybe this is somehow related. Anyway, the platform > > driver for Exynos power domains registered from core_initcall works fine > > with v5.10 kernel. > > > > I have no strong opinion on the way of merging this fix. It can go via > > Samsung tree, so in the end the v5.12-rc1 will have both my fix and your > > change, but won't be fully bisectable in-between. Krzysztof, what's your > > opinion? > > If it doesn't break anything without my changes, then let's try to get > it merged independent of my series. This is a good change even without > my changes. I agree, I'll take it via Samsung SoC. It's not the perfect solution - as Marek said, the tree won't be bisectable. Have in mind that some other boards/architectures might be broken where no one reported it yet, so fw_devlink=off/permissive might still be good choice for v5.12. Best regards, Krzysztof
On Wed, 13 Jan 2021 12:03:20 +0100, Marek Szyprowski wrote: > When Exynos power domain driver was introduced, the only way to ensure > that power domains will be instantiated before the devices which belongs > to them was to initialize them early enough, before the devices are > instantiated in the system. This in turn required not to use any platform > device infrastructure at all, as there have been no way to ensure proper > probe order between devices. > > [...] Applied, thanks! [1/1] soc: samsung: pm_domains: Convert to regular platform driver commit: 9fcdb21857cf42c0da7b9a929e6781eca557a2f5 Best regards, -- Krzysztof Kozlowski <krzk@kernel.org>
On Fri, Jan 15, 2021 at 01:11:36PM -0800, Saravana Kannan wrote: > Hi Krzysztof, > > When you pull this in, can you please add this tag too for completeness? > > Fixes: e590474768f1 ("driver core: Set fw_devlink=on by default") I actually removed that commit SHA from the message because it's still only in next. It might not be valid and I don't have a control whether it will be changed or not. Best regards, Krzysztof
diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c index ab8582971bfc..5ec0c13f0aaf 100644 --- a/drivers/soc/samsung/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -16,7 +16,7 @@ #include <linux/delay.h> #include <linux/of_address.h> #include <linux/of_platform.h> -#include <linux/sched.h> +#include <linux/pm_runtime.h> struct exynos_pm_domain_config { /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */ @@ -73,15 +73,15 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain) return exynos_pd_power(domain, false); } -static const struct exynos_pm_domain_config exynos4210_cfg __initconst = { +static const struct exynos_pm_domain_config exynos4210_cfg = { .local_pwr_cfg = 0x7, }; -static const struct exynos_pm_domain_config exynos5433_cfg __initconst = { +static const struct exynos_pm_domain_config exynos5433_cfg = { .local_pwr_cfg = 0xf, }; -static const struct of_device_id exynos_pm_domain_of_match[] __initconst = { +static const struct of_device_id exynos_pm_domain_of_match[] = { { .compatible = "samsung,exynos4210-pd", .data = &exynos4210_cfg, @@ -92,7 +92,7 @@ static const struct of_device_id exynos_pm_domain_of_match[] __initconst = { { }, }; -static __init const char *exynos_get_domain_name(struct device_node *node) +static const char *exynos_get_domain_name(struct device_node *node) { const char *name; @@ -101,60 +101,44 @@ static __init const char *exynos_get_domain_name(struct device_node *node) return kstrdup_const(name, GFP_KERNEL); } -static __init int exynos4_pm_init_power_domain(void) +static int exynos_pd_probe(struct platform_device *pdev) { - struct device_node *np; - const struct of_device_id *match; - - for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) { - const struct exynos_pm_domain_config *pm_domain_cfg; - struct exynos_pm_domain *pd; - int on; + const struct exynos_pm_domain_config *pm_domain_cfg; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct of_phandle_args child, parent; + struct exynos_pm_domain *pd; + int on, ret; - pm_domain_cfg = match->data; + pm_domain_cfg = of_device_get_match_data(dev); + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - of_node_put(np); - return -ENOMEM; - } - pd->pd.name = exynos_get_domain_name(np); - if (!pd->pd.name) { - kfree(pd); - of_node_put(np); - return -ENOMEM; - } + pd->pd.name = exynos_get_domain_name(np); + if (!pd->pd.name) + return -ENOMEM; - pd->base = of_iomap(np, 0); - if (!pd->base) { - pr_warn("%s: failed to map memory\n", __func__); - kfree_const(pd->pd.name); - kfree(pd); - continue; - } - - pd->pd.power_off = exynos_pd_power_off; - pd->pd.power_on = exynos_pd_power_on; - pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; + pd->base = of_iomap(np, 0); + if (!pd->base) { + kfree_const(pd->pd.name); + return -ENODEV; + } - on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg; + pd->pd.power_off = exynos_pd_power_off; + pd->pd.power_on = exynos_pd_power_on; + pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; - pm_genpd_init(&pd->pd, NULL, !on); - of_genpd_add_provider_simple(np, &pd->pd); - } + on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg; - /* Assign the child power domains to their parents */ - for_each_matching_node(np, exynos_pm_domain_of_match) { - struct of_phandle_args child, parent; + pm_genpd_init(&pd->pd, NULL, !on); + ret = of_genpd_add_provider_simple(np, &pd->pd); + if (ret == 0 && of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", 0, &parent) == 0) { child.np = np; child.args_count = 0; - if (of_parse_phandle_with_args(np, "power-domains", - "#power-domain-cells", 0, - &parent) != 0) - continue; - if (of_genpd_add_subdomain(&parent, &child)) pr_warn("%pOF failed to add subdomain: %pOF\n", parent.np, child.np); @@ -163,6 +147,21 @@ static __init int exynos4_pm_init_power_domain(void) parent.np, child.np); } - return 0; + pm_runtime_enable(dev); + return ret; +} + +static struct platform_driver exynos_pd_driver = { + .probe = exynos_pd_probe, + .driver = { + .name = "exynos-pd", + .of_match_table = exynos_pm_domain_of_match, + .suppress_bind_attrs = true, + } +}; + +static __init int exynos4_pm_init_power_domain(void) +{ + return platform_driver_register(&exynos_pd_driver); } core_initcall(exynos4_pm_init_power_domain);
When Exynos power domain driver was introduced, the only way to ensure that power domains will be instantiated before the devices which belongs to them was to initialize them early enough, before the devices are instantiated in the system. This in turn required not to use any platform device infrastructure at all, as there have been no way to ensure proper probe order between devices. This has been finally changed and patch e590474768f1 ("driver core: Set fw_devlink=on by default") ensures that each device will be probbed only when its resource providers are ready. This allows to convert Exynos power domain driver to regular platform driver. This is also required by the mentioned commit to enable probing any device which belongs to the Exynos power domains, as otherwise the core won't notice that the power domains are in fact available. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> --- Some more comments are in the following thread: https://lore.kernel.org/lkml/2556a69b-5da5-bf80-e051-df2d02fbc40f@samsung.com/ --- drivers/soc/samsung/pm_domains.c | 97 ++++++++++++++++---------------- 1 file changed, 48 insertions(+), 49 deletions(-) -- 2.17.1