On Mon, Nov 3, 2014 at 8:22 PM, Ulf Hansson <ulf.hansson@xxxxxxxxxx> wrote: > On 3 November 2014 15:54, Rafael J. Wysocki <rjw@xxxxxxxxxxxxx> 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@xxxxxxxxx> >>> Reviewed-by: Pankaj Dubey <pankaj.dubey@xxxxxxxxxxx> >>> Signed-off-by: Amit Daniel Kachhap <amit.daniel@xxxxxxxxxxx> >>> --- >>> 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@xxxxxxxxxxxxxxx >> 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@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html