2015-02-09 10:58:08

by amit daniel kachhap

[permalink] [raw]
Subject: [PATCH RFC v4 0/3] PM / Runtime: Feature to power manage slave devices

This patch is somewhat similar to V3 version but uses pm runtime framework to
register/fetch the information about the device which may be slave or master.
Since the power domain has the necessary information about devices so it invokes
the save/restore runtime callbacks for the slave devices.

There was objection raised by Kevin and others that V3 is hacky in nature so this
revision fixes it by keeping the slave device information in pm runtime framework.

The model works like,
DEV1 (Attaches itself with PD but no support of pm_runtime_get and
/ pm_runtime_put. Registers itself as pm runtime slave device.
/ Its local runtime_suspend/resume is invoked by PD.
/
/
PD -- DEV2 (Implements complete PM runtime and calls pm_runtime_get and
\ pm_runtime_put. This in turn invokes PD On/Off)
\
DEV3 (Similar to DEV1)

This work is continuation of earlier work,

In V3: Used the existing API pm_genpd_dev_need_restore to add a feature to force
devices to perform restore/save during every power domain on/off
operation. This API is now removed.
Link (https://lkml.org/lkml/2014/12/13/74

In V2: Completely removed notfiers and add support for huge clock list to be
suspended and restored. There was some issue in this as some clocks are
not exposed and are just initialised by bootloaders. This approach
required all of them to be exposed which is cumbersome. Also some
clock API's set_parent are disabling the original parent clocks
which is not required.
Link (https://lkml.org/lkml/2014/11/24/290)

In V1: Implemented PM Domain notfier such as PD_ON_PRE, PD_ON_POST
PD_OFF_PRE and PD_OFF_POST. This was not supported and other
options suggested. link (http://www.spinics.net/lists/linux-samsung-soc/msg38442.html)

This work may also assist exynos iommu pm runtime posted earlier by Marek
http://lists.linaro.org/pipermail/linaro-mm-sig/2014-August/004099.html

Amit Daniel Kachhap (3):
PM / Runtime: Add an API pm_runtime_set_slave
PM / Domains: Save restore slave pm runtime devices
clk: samsung: Add PM runtime support for clocks.

drivers/base/power/domain.c | 28 +++++++++++++
drivers/base/power/runtime.c | 18 +++++++++
drivers/clk/samsung/clk.c | 93 ++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/samsung/clk.h | 11 ++++++
include/linux/pm.h | 1 +
include/linux/pm_runtime.h | 2 +
6 files changed, 153 insertions(+)

--
2.2.0


2015-02-09 10:58:59

by amit daniel kachhap

[permalink] [raw]
Subject: [PATCH RFC v4 1/3] PM / Runtime: Add an API pm_runtime_set_slave

This API creates a pm runtime slave type device which does not itself
participates in pm runtime but depends on the master devices to power
manage them. These devices should have pm runtime callbacks.

These devices (like clock) may not implement complete pm_runtime calls
such as pm_runtime_get/pm_runtime_put due to subsystems interaction
behaviour or any other reason.

Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/base/power/runtime.c | 18 ++++++++++++++++++
include/linux/pm.h | 1 +
include/linux/pm_runtime.h | 2 ++
3 files changed, 21 insertions(+)

diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 5070c4f..e247f08 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1252,6 +1252,24 @@ void pm_runtime_no_callbacks(struct device *dev)
EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);

/**
+ * pm_runtime_set_slave - Set these devices as slave.
+ * @dev: Device to handle.
+ *
+ * Set the power.slave flag, which tells the PM core that this device is
+ * power-managed by the master device through the runtime callbacks. Since it
+ * will not manage runtime callbacks on its own, so runtime sysfs attributes is
+ * removed.
+ */
+void pm_runtime_set_slave(struct device *dev)
+{
+ spin_lock_irq(&dev->power.lock);
+ dev->power.slave = true;
+ spin_unlock_irq(&dev->power.lock);
+ if (device_is_registered(dev))
+ rpm_sysfs_remove(dev);
+}
+
+/**
* pm_runtime_irq_safe - Leave interrupts disabled during callbacks.
* @dev: Device to handle
*
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 8b59763..a4090ef 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -581,6 +581,7 @@ struct dev_pm_info {
unsigned int use_autosuspend:1;
unsigned int timer_autosuspends:1;
unsigned int memalloc_noio:1;
+ unsigned int slave:1;
enum rpm_request request;
enum rpm_status runtime_status;
int runtime_error;
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 30e84d4..0707a4b 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -47,6 +47,7 @@ extern void __pm_runtime_disable(struct device *dev, bool check_resume);
extern void pm_runtime_allow(struct device *dev);
extern void pm_runtime_forbid(struct device *dev);
extern void pm_runtime_no_callbacks(struct device *dev);
+extern void pm_runtime_set_slave(struct device *dev);
extern void pm_runtime_irq_safe(struct device *dev);
extern void __pm_runtime_use_autosuspend(struct device *dev, bool use);
extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
@@ -168,6 +169,7 @@ static inline bool pm_runtime_suspended_if_enabled(struct device *dev) { return
static inline bool pm_runtime_enabled(struct device *dev) { return false; }

static inline void pm_runtime_no_callbacks(struct device *dev) {}
+static inline void pm_runtime_set_slave(struct device *dev) {}
static inline void pm_runtime_irq_safe(struct device *dev) {}
static inline bool pm_runtime_is_irq_safe(struct device *dev) { return false; }

--
2.2.0

2015-02-09 10:59:39

by amit daniel kachhap

[permalink] [raw]
Subject: [PATCH RFC v4 2/3] PM / Domains: Save restore slave pm runtime devices

Based on the runtime request of the active device, the callbacks of
the passive pm runtime devices will be invoked.

Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/base/power/domain.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index c5280f2..160e74a 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -49,6 +49,7 @@

static LIST_HEAD(gpd_list);
static DEFINE_MUTEX(gpd_list_lock);
+static void __pm_genpd_restore_devices(struct generic_pm_domain *genpd);

static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
{
@@ -176,6 +177,8 @@ static int genpd_power_on(struct generic_pm_domain *genpd)
pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
genpd->name, "on", elapsed_ns);

+ __pm_genpd_restore_devices(genpd);
+
return ret;
}

@@ -397,6 +400,9 @@ static int __pm_genpd_save_device(struct pm_domain_data *pdd,
struct device *dev = pdd->dev;
int ret = 0;

+ if (dev->power.slave == true)
+ gpd_data->need_restore = 0;
+
if (gpd_data->need_restore > 0)
return 0;

@@ -453,6 +459,28 @@ static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
}

/**
+ * __pm_genpd_restore_devices- Restore the pre-suspend state of all device
+ * according to the restore flag.
+ * @genpd: PM domain the device belongs to.
+ */
+static void __pm_genpd_restore_devices(struct generic_pm_domain *genpd)
+{
+ struct pm_domain_data *pdd;
+ struct generic_pm_domain_data *gpd_data;
+ struct device *dev;
+
+ /* Force restore the devices according to the restore flag */
+ list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+ dev = pdd->dev;
+ gpd_data = to_gpd_data(pdd);
+ if (dev->power.slave == true) {
+ gpd_data->need_restore = 1;
+ __pm_genpd_restore_device(pdd, genpd);
+ }
+ }
+}
+
+/**
* genpd_abort_poweroff - Check if a PM domain power off should be aborted.
* @genpd: PM domain to check.
*
--
2.2.0

2015-02-09 11:00:26

by amit daniel kachhap

[permalink] [raw]
Subject: [PATCH RFC v4 3/3] clk: samsung: Add PM runtime support for clocks.

This patch adds PM runtime support for clocks associated with Power
Domain. The PM runtime suspend/resume handlers will be called when the
power domain associated with it, is turned on/off.

The registration of clocks happen in early initailisation. The probe
is later called to register the clock device with the power domain.

Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/clk/samsung/clk.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/samsung/clk.h | 11 ++++++
2 files changed, 104 insertions(+)

diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 4bda540..0b5c82a 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -12,6 +12,9 @@
*/

#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/syscore_ops.h>

#include "clk.h"
@@ -370,6 +373,92 @@ static void samsung_clk_sleep_init(void __iomem *reg_base,
unsigned long nr_rdump) {}
#endif

+static int samsung_cmu_runtime_suspend(struct device *dev)
+{
+ struct samsung_clock_pd_reg_cache *reg_cache;
+
+ reg_cache = dev_get_drvdata(dev);
+ samsung_clk_save(reg_cache->reg_base, reg_cache->rdump,
+ reg_cache->rd_num);
+ return 0;
+}
+
+static int samsung_cmu_runtime_resume(struct device *dev)
+{
+ struct samsung_clock_pd_reg_cache *reg_cache;
+
+ reg_cache = dev_get_drvdata(dev);
+ samsung_clk_restore(reg_cache->reg_base, reg_cache->rdump,
+ reg_cache->rd_num);
+ return 0;
+}
+
+#define MAX_CMU_DEVICE_MATCH 50
+static int samsung_cmu_count;
+static struct of_device_id samsung_cmu_match[MAX_CMU_DEVICE_MATCH];
+MODULE_DEVICE_TABLE(of, samsung_cmu_match);
+
+static void samsung_clk_pd_init(struct device_node *np, void __iomem *reg_base,
+ struct samsung_cmu_info *cmu)
+{
+ struct samsung_clock_pd_reg_cache *pd_reg_cache;
+ const char *name;
+
+ if (samsung_cmu_count == MAX_CMU_DEVICE_MATCH)
+ panic("Maximum clock device limit reached.\n");
+
+ if (of_property_read_string_index(np, "compatible", 0, &name))
+ panic("Invalid DT node.\n");
+
+ pd_reg_cache = kzalloc(sizeof(struct samsung_clock_pd_reg_cache),
+ GFP_KERNEL);
+ if (!pd_reg_cache)
+ panic("Could not allocate register reg_cache.\n");
+
+ pd_reg_cache->rdump = samsung_clk_alloc_reg_dump(cmu->pd_clk_regs,
+ cmu->nr_pd_clk_regs);
+ if (!pd_reg_cache->rdump)
+ panic("Could not allocate register dump storage.\n");
+
+ pd_reg_cache->reg_base = reg_base;
+ pd_reg_cache->rd_num = cmu->nr_pd_clk_regs;
+
+ /* Fill up the compatible string and data */
+ samsung_cmu_match[samsung_cmu_count].data = pd_reg_cache;
+ strcpy(samsung_cmu_match[samsung_cmu_count].compatible, name);
+ samsung_cmu_count++;
+}
+
+static int __init samsung_cmu_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct of_device_id *match;
+
+ /* get the platform data */
+ match = (struct of_device_id *)of_match_node(samsung_cmu_match,
+ pdev->dev.of_node);
+ if (!match)
+ return 0;
+ platform_set_drvdata(pdev, (void *)match->data);
+ pm_runtime_enable(dev);
+ pm_runtime_set_slave(dev);
+ return 0;
+}
+
+static const struct dev_pm_ops samsung_cmu_pm_ops = {
+ SET_RUNTIME_PM_OPS(samsung_cmu_runtime_suspend,
+ samsung_cmu_runtime_resume, NULL)
+};
+
+static struct platform_driver samsung_cmu_driver = {
+ .driver = {
+ .name = "exynos-clk",
+ .of_match_table = samsung_cmu_match,
+ .pm = &samsung_cmu_pm_ops,
+ },
+ .probe = samsung_cmu_probe,
+};
+
/*
* Common function which registers plls, muxes, dividers and gates
* for each CMU. It also add CMU register list to register cache.
@@ -409,5 +498,9 @@ void __init samsung_cmu_register_one(struct device_node *np,
samsung_clk_sleep_init(reg_base, cmu->clk_regs,
cmu->nr_clk_regs);

+ if (cmu->pd_clk_regs)
+ samsung_clk_pd_init(np, reg_base, cmu);
+
samsung_clk_of_add_provider(np, ctx);
}
+module_platform_driver(samsung_cmu_driver);
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 8acabe1..7565be8 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -327,6 +327,12 @@ struct samsung_clock_reg_cache {
unsigned int rd_num;
};

+struct samsung_clock_pd_reg_cache {
+ void __iomem *reg_base;
+ struct samsung_clk_reg_dump *rdump;
+ unsigned int rd_num;
+};
+
struct samsung_cmu_info {
/* list of pll clocks and respective count */
struct samsung_pll_clock *pll_clks;
@@ -352,6 +358,11 @@ struct samsung_cmu_info {
/* list and number of clocks registers */
unsigned long *clk_regs;
unsigned int nr_clk_regs;
+
+ /* list and number of clocks to be saved/restored during
+ * power domain shutdown */
+ unsigned long *pd_clk_regs;
+ unsigned int nr_pd_clk_regs;
};

extern struct samsung_clk_provider *__init samsung_clk_init(
--
2.2.0

2015-02-09 15:58:44

by Alan Stern

[permalink] [raw]
Subject: Re: [PATCH RFC v4 1/3] PM / Runtime: Add an API pm_runtime_set_slave

On Mon, 9 Feb 2015, Amit Daniel Kachhap wrote:

> This API creates a pm runtime slave type device which does not itself
> participates in pm runtime but depends on the master devices to power
> manage them.

This makes no sense. How can a master device manage a slave device?
Devices are managed by drivers, not by other devices.

> These devices should have pm runtime callbacks.
>
> These devices (like clock) may not implement complete pm_runtime calls
> such as pm_runtime_get/pm_runtime_put due to subsystems interaction
> behaviour or any other reason.
>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/base/power/runtime.c | 18 ++++++++++++++++++
> include/linux/pm.h | 1 +
> include/linux/pm_runtime.h | 2 ++
> 3 files changed, 21 insertions(+)

This patch is unacceptable because it does not update the runtime PM
documentation file.

Besides, doesn't the no_callbacks flag already do more or less what you
want?

Alan Stern

2015-02-12 09:42:59

by amit daniel kachhap

[permalink] [raw]
Subject: Re: [PATCH RFC v4 1/3] PM / Runtime: Add an API pm_runtime_set_slave

Hi Alan,

On Mon, Feb 9, 2015 at 9:28 PM, Alan Stern <[email protected]> wrote:
> On Mon, 9 Feb 2015, Amit Daniel Kachhap wrote:
>
>> This API creates a pm runtime slave type device which does not itself
>> participates in pm runtime but depends on the master devices to power
>> manage them.
>
> This makes no sense. How can a master device manage a slave device?
> Devices are managed by drivers, not by other devices.
May be my commit is not explaining the requirements completely and the
API name may not reflect the relevance. But If you see the 3rd patch
it has one clock use-case where this new feature is used and the
current pm runtime feature is not sufficient enough to handle it. I
have one more IOMMU use case also which is not part of this patch
series.
I am not sure if this approach is final but I looked at runtime.c file
and it has couple of API's like pm_runtime_forbid/allow which
blocks/unblocks the runtime callbacks according to driver requirement.
In the similar line I added this new API.
>
>> These devices should have pm runtime callbacks.
>>
>> These devices (like clock) may not implement complete pm_runtime calls
>> such as pm_runtime_get/pm_runtime_put due to subsystems interaction
>> behaviour or any other reason.
>>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/base/power/runtime.c | 18 ++++++++++++++++++
>> include/linux/pm.h | 1 +
>> include/linux/pm_runtime.h | 2 ++
>> 3 files changed, 21 insertions(+)
>
> This patch is unacceptable because it does not update the runtime PM
> documentation file.
my fault. Will update in next version.
>
> Besides, doesn't the no_callbacks flag already do more or less what you
> want?
yes to some extent. But I thought its purpose is different so I added 1 more.

Regards,
Amit D
>
> Alan Stern
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2015-02-12 15:13:39

by Alan Stern

[permalink] [raw]
Subject: Re: [PATCH RFC v4 1/3] PM / Runtime: Add an API pm_runtime_set_slave

On Thu, 12 Feb 2015, amit daniel kachhap wrote:

> Hi Alan,
>
> On Mon, Feb 9, 2015 at 9:28 PM, Alan Stern <[email protected]> wrote:
> > On Mon, 9 Feb 2015, Amit Daniel Kachhap wrote:
> >
> >> This API creates a pm runtime slave type device which does not itself
> >> participates in pm runtime but depends on the master devices to power
> >> manage them.
> >
> > This makes no sense. How can a master device manage a slave device?
> > Devices are managed by drivers, not by other devices.
> May be my commit is not explaining the requirements completely and the
> API name may not reflect the relevance. But If you see the 3rd patch
> it has one clock use-case where this new feature is used and the
> current pm runtime feature is not sufficient enough to handle it. I
> have one more IOMMU use case also which is not part of this patch
> series.

Regardless, your description should say what is really happening. The
master device doesn't power-manage the clock; some driver power-manages
it.

> I am not sure if this approach is final but I looked at runtime.c file
> and it has couple of API's like pm_runtime_forbid/allow which
> blocks/unblocks the runtime callbacks according to driver requirement.
> In the similar line I added this new API.

forbid/allow blocks/unblocks runtime PM according to the user's
requirements, not the driver's requirements.

> > Besides, doesn't the no_callbacks flag already do more or less what you
> > want?
> yes to some extent. But I thought its purpose is different so I added 1 more.

The purpose doesn't matter. If no_callbacks does what you want then
you should use it instead of adding another API.

Alan Stern