[PATCH 03/12] PM / Domains: Add notifier support for power domain transitions

amit daniel kachhap amit.daniel at samsung.com
Mon Nov 3 22:18:28 PST 2014


On Mon, Nov 3, 2014 at 8:22 PM, Ulf Hansson <ulf.hansson at linaro.org> wrote:
> On 3 November 2014 15:54, Rafael J. Wysocki <rjw at rjwysocki.net> wrote:
>> CC: Kevin, Ulf, Geert.
>>
>> On Monday, November 03, 2014 09:23:01 AM Amit Daniel Kachhap wrote:
>>> These power domain transition notifiers will assist in carrying
>>> out some activity associated with domain power on/off such as
>>> some registers which may lose its contents and need save/restore
>>> across domain power off/on.
>
> Hi Amit,
>
> This mechanism seems to be needed - somehow.
> A similar approach has been posted earlier, I am not sure that
> discussion was fully settled though.
>
> http://marc.info/?l=linux-pm&m=136448756308203&w=2
Missed looking into it. Thanks for the pointer.
>
> Anyway, I plan to review this shortly.
Sure.
>
> Kind regards
> Uffe
>
>>>
>>> 4 type of notifications are added,
>>> GPD_OFF_PRE     - GPD state before power off
>>> GPD_OFF_POST    - GPD state after power off
>>> GPD_ON_PRE      - GPD state before power off
>>> GPD_ON_POST     - GPD state after power off
>>>
>>> 3 notfication API's are exported.
>>> 1) int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
>>> 2) int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
>>> 3) void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
>>>                       enum gpd_on_off_state state);
>>>
>>> In this approach the notifiers are registered/unregistered with pd name.
>>> The actual invoking of the notfiers will be done by the platform implementing
>>> power domain enable/disable low level handlers according to the above
>>> defined notification types. This approach will considerably reduce the
>>> number of call to notifiers as compared to calling always from core
>>> powerdomain subsystem.
>>>
>>> Also the registered domain's will be managed inside a cache list and not
>>> part of the genpd structure. This will help in registration of notifiers from
>>> subsystems (such as clock) even when the PD subsystem is still not initialised.
>>> This list also filters out the unregistered pd's requesting notification.
>>>
>>> Cc: Rafael J. Wysocki <rafael.j.wysocki at intel.com>
>>> Reviewed-by: Pankaj Dubey <pankaj.dubey at samsung.com>
>>> Signed-off-by: Amit Daniel Kachhap <amit.daniel at samsung.com>
>>> ---
>>>  drivers/base/power/domain.c |  112 ++++++++++++++++++++++++++++++++++++++++++-
>>>  include/linux/pm_domain.h   |   31 ++++++++++++
>>>  2 files changed, 142 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>>> index 40bc2f4..e05045e 100644
>>> --- a/drivers/base/power/domain.c
>>> +++ b/drivers/base/power/domain.c
>>> @@ -46,10 +46,19 @@
>>>       __retval;                                                               \
>>>  })
>>>
>>> +struct cache_notify_domains {
>>> +     char *name;
>>> +     /* Node in the cache pm domain name list */
>>> +     struct list_head cache_list_node;
>>> +};
>>> +
>>>  static LIST_HEAD(gpd_list);
>>>  static DEFINE_MUTEX(gpd_list_lock);
>>> +static LIST_HEAD(domain_notify_list);
>>> +static DEFINE_MUTEX(domain_notify_list_lock);
>>> +static BLOCKING_NOTIFIER_HEAD(genpd_transition_notifier_list);
>>>
>>> -static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
>>> +struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
>>>  {
>>>       struct generic_pm_domain *genpd = NULL, *gpd;
>>>
>>> @@ -66,6 +75,7 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
>>>       mutex_unlock(&gpd_list_lock);
>>>       return genpd;
>>>  }
>>> +EXPORT_SYMBOL_GPL(pm_genpd_lookup_name);
>>>
>>>  struct generic_pm_domain *dev_to_genpd(struct device *dev)
>>>  {
>>> @@ -1908,6 +1918,106 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
>>>       mutex_unlock(&gpd_list_lock);
>>>  }
>>>
>>> +/**
>>> + * genpd_register_notifier - Register a PM domain for future notification.
>>> + * @nb: notification block containing notification handle.
>>> + * @pd_name: PM domain name.
>>> + */
>>> +int genpd_register_notifier(struct notifier_block *nb, char *pd_name)
>>> +{
>>> +     int ret;
>>> +     struct cache_notify_domains *entry;
>>> +
>>> +     if (!pd_name)
>>> +             return -EINVAL;
>>> +
>>> +     /* Search if the pd is already registered */
>>> +     mutex_lock(&domain_notify_list_lock);
>>> +     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
>>> +             if (!strcmp(entry->name, pd_name))
>>> +                     break;
>>> +     }
>>> +     mutex_unlock(&domain_notify_list_lock);
>>> +
>>> +     if (entry) {
>>> +             pr_err("%s: pd already exists\n", __func__);
>>> +             return -EINVAL;
>>> +     }
>>> +
>>> +     entry = kzalloc(sizeof(*entry), GFP_KERNEL);
>>> +     if (!entry)
>>> +             return -ENOMEM;
>>> +
>>> +     entry->name = pd_name;
>>> +
>>> +     mutex_lock(&domain_notify_list_lock);
>>> +     list_add(&entry->cache_list_node, &domain_notify_list);
>>> +     mutex_unlock(&domain_notify_list_lock);
>>> +     ret = blocking_notifier_chain_register(
>>> +                             &genpd_transition_notifier_list, nb);
>>> +     return ret;
>>> +}
>>> +
>>> +/**
>>> + * genpd_unregister_notifier - Un-register a PM domain for future notification.
>>> + * @nb: notification block containing notification handle.
>>> + * @pd_name: PM domain name.
>>> + */
>>> +int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
>>> +{
>>> +     int ret;
>>> +     struct cache_notify_domains *entry;
>>> +
>>> +     mutex_lock(&domain_notify_list_lock);
>>> +     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
>>> +             if (!strcmp(entry->name, pd_name))
>>> +                     break;
>>> +     }
>>> +     if (!entry) {
>>> +             mutex_unlock(&domain_notify_list_lock);
>>> +             pr_err("%s: Invalid pd name\n", __func__);
>>> +             return -EINVAL;
>>> +     }
>>> +     list_del(&entry->cache_list_node);
>>> +     mutex_unlock(&domain_notify_list_lock);
>>> +     ret = blocking_notifier_chain_unregister(
>>> +                             &genpd_transition_notifier_list, nb);
>>> +     return ret;
>>> +}
>>> +
>>> +/**
>>> + * genpd_invoke_transition_notifier - Calls the matching notification handler.
>>> + * @genpd: generic power domain structure.
>>> + * @state: can be of type - GPD_OFF_PRE/GPD_OFF_POST/GPD_ON_PRE/GPD_ON_POST.
>>> + */
>>> +void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
>>> +                     enum gpd_on_off_state state)
>>> +{
>>> +     struct cache_notify_domains *entry;
>>> +
>>> +     if (!genpd) {
>>> +             pr_err("Invalid genpd parameter\n");
>>> +             return;
>>> +     }
>>> +
>>> +     if (state != GPD_OFF_PRE || state != GPD_OFF_POST
>>> +                     || state != GPD_ON_PRE || state != GPD_ON_POST) {
>>> +             pr_err("Invalid state parameter\n");
>>> +             return;
>>> +     }
>>> +
>>> +     mutex_lock(&domain_notify_list_lock);
>>> +     list_for_each_entry(entry, &domain_notify_list, cache_list_node) {
>>> +             if (!strcmp(entry->name, genpd->name))
>>> +                     break;
>>> +     }
>>> +     mutex_unlock(&domain_notify_list_lock);
>>> +     if (!entry) /* Simply ignore */
>>> +             return;
>>> +
>>> +     blocking_notifier_call_chain(&genpd_transition_notifier_list, state,
>>> +                             genpd);
>>> +}
>>>  #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
>>>  /*
>>>   * Device Tree based PM domain providers.
>>> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
>>> index 73e938b..659997f 100644
>>> --- a/include/linux/pm_domain.h
>>> +++ b/include/linux/pm_domain.h
>>> @@ -25,6 +25,13 @@ enum gpd_status {
>>>       GPD_STATE_POWER_OFF,    /* PM domain is off */
>>>  };
>>>
>>> +enum gpd_on_off_state {
>>> +     GPD_OFF_PRE = 0,        /* GPD state before power off */
>>> +     GPD_OFF_POST,           /* GPD state after power off */
>>> +     GPD_ON_PRE,             /* GPD state before power on */
>>> +     GPD_ON_POST,            /* GPD state after power on */
>>> +};
>>> +
>>>  struct dev_power_governor {
>>>       bool (*power_down_ok)(struct dev_pm_domain *domain);
>>>       bool (*stop_ok)(struct device *dev);
>>> @@ -148,6 +155,12 @@ extern int pm_genpd_name_poweron(const char *domain_name);
>>>
>>>  extern struct dev_power_governor simple_qos_governor;
>>>  extern struct dev_power_governor pm_domain_always_on_gov;
>>> +
>>> +struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name);
>>> +int genpd_register_notifier(struct notifier_block *nb, char *pd_name);
>>> +int genpd_unregister_notifier(struct notifier_block *nb, char *pd_name);
>>> +void genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
>>> +                     enum gpd_on_off_state state);
>>>  #else
>>>
>>>  static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
>>> @@ -219,6 +232,24 @@ static inline int pm_genpd_name_poweron(const char *domain_name)
>>>  {
>>>       return -ENOSYS;
>>>  }
>>> +static inline struct
>>> +generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
>>> +{
>>> +     return NULL;
>>> +}
>>> +static inline int
>>> +genpd_register_notifier(struct notifier_block *nb, char *pd_name)
>>> +{
>>> +     return 0;
>>> +}
>>> +static inline int
>>> +genpd_unregister_notifier(struct notifier_block *nb, char *pd_name)
>>> +{
>>> +     return 0;
>>> +}
>>> +static inline void
>>> +genpd_invoke_transition_notifier(struct generic_pm_domain *genpd,
>>> +                     enum gpd_on_off_state state) { }
>>>  #define simple_qos_governor NULL
>>>  #define pm_domain_always_on_gov NULL
>>>  #endif
>>>
>>
>> --
>> I speak only for myself.
>> Rafael J. Wysocki, Intel Open Source Technology Center.
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the linux-arm-kernel mailing list