pm: remove pm global, make per domain isolated

After change, when CONFIG_PM_NDOMAINS > 1,
the pm_register will not able to get notificaion
from not PM_IDLE_DOMAIN.
Should use pm_domain_register as a replacement.

Isolate domains from global callbacks can decrease
not necessary execution, and reduce the
lock instruction requirements.

Signed-off-by: buxiasen <buxiasen@xiaomi.com>
This commit is contained in:
buxiasen 2024-05-31 17:18:53 +08:00 committed by Xiang Xiao
parent 6f50847278
commit 1933f9648d
15 changed files with 100 additions and 119 deletions

View file

@ -317,7 +317,7 @@ static void governor_update(int domain, int16_t accum)
DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS);
pdomstate = &g_pm_activity_governor.domain_states[domain];
state = g_pmglobals.domain[domain].state;
state = g_pmdomains[domain].state;
#if CONFIG_PM_GOVERNOR_MEMORY > 1
/* We won't bother to do anything until we have accumulated
@ -469,7 +469,7 @@ static enum pm_state_e governor_checkstate(int domain)
/* Get a convenience pointer to minimize all of the indexing */
pdomstate = &g_pm_activity_governor.domain_states[domain];
pdom = &g_pmglobals.domain[domain];
pdom = &g_pmdomains[domain];
/* Check for the end of the current time slice. This must be performed
* with interrupts disabled so that it does not conflict with the similar
@ -563,7 +563,7 @@ static void governor_timer(int domain, enum pm_state_e newstate)
TIME_SLICE_TICKS * CONFIG_PM_GOVERNOR_SLEEPENTER_COUNT
};
pdom = &g_pmglobals.domain[domain];
pdom = &g_pmdomains[domain];
pdomstate = &g_pm_activity_governor.domain_states[domain];
if (newstate < PM_SLEEP && dq_empty(&pdom->wakelock[newstate]))

View file

@ -94,7 +94,7 @@ static enum pm_state_e greedy_governor_checkstate(int domain)
irqstate_t flags;
int state;
pdom = &g_pmglobals.domain[domain];
pdom = &g_pmdomains[domain];
state = PM_NORMAL;
/* We disable interrupts since pm_stay()/pm_relax() could be simultaneously

View file

@ -53,6 +53,12 @@ struct pm_domain_s
uint8_t state;
/* Registry is a doubly-linked list of registered power management
* callback structures.
*/
dq_queue_t registry;
/* The power state lock count */
struct dq_queue_s wakelock[PM_COUNT];
@ -87,28 +93,6 @@ struct pm_domain_s
rmutex_t lock;
};
/* This structure encapsulates all of the global data used by the PM system */
struct pm_global_s
{
/* This rmutex manages mutually exclusive access to the power management
* registry. It must be initialized to the value 1.
*/
rmutex_t reglock;
/* registry is a doubly-linked list of registered power management
* callback structures. To ensure mutually exclusive access, this list
* must be locked by calling pm_lock() before it is accessed.
*/
dq_queue_t registry;
/* The state information for each PM domain */
struct pm_domain_s domain[CONFIG_PM_NDOMAINS];
};
/****************************************************************************
* Public Data
****************************************************************************/
@ -124,7 +108,7 @@ extern "C"
/* All PM global data: */
EXTERN struct pm_global_s g_pmglobals;
EXTERN struct pm_domain_s g_pmdomains[CONFIG_PM_NDOMAINS];
/****************************************************************************
* Public Function Prototypes

View file

@ -54,14 +54,14 @@ static void pm_waklock_cb(wdparm_t arg)
#ifdef CONFIG_PM_PROCFS
static void pm_wakelock_stats_rm(FAR struct pm_wakelock_s *wakelock)
{
FAR struct pm_domain_s *pdom = &g_pmglobals.domain[wakelock->domain];
FAR struct pm_domain_s *pdom = &g_pmdomains[wakelock->domain];
dq_rem(&wakelock->fsnode, &pdom->wakelockall);
}
static void pm_wakelock_stats(FAR struct pm_wakelock_s *wakelock, bool stay)
{
FAR struct pm_domain_s *pdom = &g_pmglobals.domain[wakelock->domain];
FAR struct pm_domain_s *pdom = &g_pmdomains[wakelock->domain];
struct timespec ts;
if (stay)
@ -121,9 +121,9 @@ void pm_activity(int domain, int priority)
{
DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS);
if (g_pmglobals.domain[domain].governor->activity)
if (g_pmdomains[domain].governor->activity)
{
g_pmglobals.domain[domain].governor->activity(domain, priority);
g_pmdomains[domain].governor->activity(domain, priority);
}
pm_auto_updatestate(domain);
@ -301,7 +301,7 @@ void pm_wakelock_uninit(FAR struct pm_wakelock_s *wakelock)
/* Get a convenience pointer to minimize all of the indexing */
domain = wakelock->domain;
pdom = &g_pmglobals.domain[domain];
pdom = &g_pmdomains[domain];
dq = &pdom->wakelock[wakelock->state];
wdog = &wakelock->wdog;
@ -350,7 +350,7 @@ void pm_wakelock_stay(FAR struct pm_wakelock_s *wakelock)
/* Get a convenience pointer to minimize all of the indexing */
domain = wakelock->domain;
pdom = &g_pmglobals.domain[domain];
pdom = &g_pmdomains[domain];
dq = &pdom->wakelock[wakelock->state];
flags = pm_domain_lock(domain);
@ -397,7 +397,7 @@ void pm_wakelock_relax(FAR struct pm_wakelock_s *wakelock)
/* Get a convenience pointer to minimize all of the indexing */
domain = wakelock->domain;
pdom = &g_pmglobals.domain[domain];
pdom = &g_pmdomains[domain];
dq = &pdom->wakelock[wakelock->state];
flags = pm_domain_lock(domain);
@ -448,7 +448,7 @@ void pm_wakelock_staytimeout(FAR struct pm_wakelock_s *wakelock, int ms)
/* Get a convenience pointer to minimize all of the indexing */
domain = wakelock->domain;
pdom = &g_pmglobals.domain[domain];
pdom = &g_pmdomains[domain];
dq = &pdom->wakelock[wakelock->state];
wdog = &wakelock->wdog;

View file

@ -73,7 +73,7 @@ static void pm_auto_updatestate_cb(FAR void *arg)
void pm_auto_updatestate(int domain)
{
FAR struct pm_domain_s *pdom;
pdom = &g_pmglobals.domain[domain];
pdom = &g_pmdomains[domain];
if (pdom->auto_update)
{
@ -113,7 +113,7 @@ void pm_auto_update(int domain, bool auto_update)
irqstate_t flags;
DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS);
pdom = &g_pmglobals.domain[domain];
pdom = &g_pmdomains[domain];
flags = pm_domain_lock(domain);
pdom->auto_update = auto_update;

View file

@ -106,7 +106,7 @@ static void pm_stats_preparefail(int domain,
int newstate, int ret)
{
struct timespec ts;
FAR struct pm_preparefail_s *pf = &callback->preparefail[domain];
FAR struct pm_preparefail_s *pf = &callback->preparefail;
if (pf->state != PM_RESTORE)
{
@ -153,20 +153,23 @@ static void pm_stats_preparefail(int domain,
static int pm_prepall(int domain, enum pm_state_e newstate, bool restore)
{
FAR struct pm_domain_s *pdom;
FAR struct pm_callback_s *cb;
FAR dq_entry_t *entry;
int ret = OK;
if (newstate <= g_pmglobals.domain[domain].state)
pdom = &g_pmdomains[domain];
if (newstate <= pdom->state)
{
/* Visit each registered callback structure in normal order. */
for (entry = dq_peek(&g_pmglobals.registry);
for (entry = dq_peek(&pdom->registry);
entry && ret == OK;
entry = dq_next(entry))
{
/* Is the prepare callback supported? */
FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry;
cb = (FAR struct pm_callback_s *)entry;
if (cb->prepare)
{
/* Yes.. prepare the driver */
@ -183,13 +186,13 @@ static int pm_prepall(int domain, enum pm_state_e newstate, bool restore)
{
/* Visit each registered callback structure in reverse order. */
for (entry = dq_tail(&g_pmglobals.registry);
for (entry = dq_tail(&pdom->registry);
entry && ret == OK;
entry = dq_prev(entry))
{
/* Is the prepare callback supported? */
FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry;
cb = (FAR struct pm_callback_s *)entry;
if (cb->prepare)
{
/* Yes.. prepare the driver */
@ -227,18 +230,21 @@ static int pm_prepall(int domain, enum pm_state_e newstate, bool restore)
static inline void pm_changeall(int domain, enum pm_state_e newstate)
{
FAR struct pm_domain_s *pdom;
FAR struct pm_callback_s *cb;
FAR dq_entry_t *entry;
if (newstate <= g_pmglobals.domain[domain].state)
pdom = &g_pmdomains[domain];
if (newstate <= pdom->state)
{
/* Visit each registered callback structure in normal order. */
for (entry = dq_peek(&g_pmglobals.registry);
for (entry = dq_peek(&pdom->registry);
entry; entry = dq_next(entry))
{
/* Is the notification callback supported? */
FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry;
cb = (FAR struct pm_callback_s *)entry;
if (cb->notify)
{
/* Yes.. notify the driver */
@ -251,12 +257,12 @@ static inline void pm_changeall(int domain, enum pm_state_e newstate)
{
/* Visit each registered callback structure in reverse order. */
for (entry = dq_tail(&g_pmglobals.registry);
for (entry = dq_tail(&pdom->registry);
entry; entry = dq_prev(entry))
{
/* Is the notification callback supported? */
FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry;
cb = (FAR struct pm_callback_s *)entry;
if (cb->notify)
{
/* Yes.. notify the driver */
@ -327,15 +333,15 @@ int pm_changestate(int domain, enum pm_state_e newstate)
* Revert to the preceding state.
*/
newstate = g_pmglobals.domain[domain].state;
newstate = g_pmdomains[domain].state;
pm_prepall(domain, newstate, true);
}
}
/* Statistics */
pm_stats(&g_pmglobals.domain[domain],
g_pmglobals.domain[domain].state, newstate);
pm_stats(&g_pmdomains[domain],
g_pmdomains[domain].state, newstate);
/* All drivers have agreed to the state change (or, one or more have
* disagreed and the state has been reverted). Set the new state.
@ -345,16 +351,16 @@ int pm_changestate(int domain, enum pm_state_e newstate)
/* Notify governor of (possible) state change */
if (g_pmglobals.domain[domain].governor->statechanged)
if (g_pmdomains[domain].governor->statechanged)
{
g_pmglobals.domain[domain].governor->statechanged(domain, newstate);
g_pmdomains[domain].governor->statechanged(domain, newstate);
}
/* Domain state update after statechanged done */
if (newstate != PM_RESTORE)
{
g_pmglobals.domain[domain].state = newstate;
g_pmdomains[domain].state = newstate;
}
/* Restore the interrupt state */
@ -380,7 +386,7 @@ int pm_changestate(int domain, enum pm_state_e newstate)
enum pm_state_e pm_querystate(int domain)
{
DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS);
return g_pmglobals.domain[domain].state;
return g_pmdomains[domain].state;
}
#endif /* CONFIG_PM */

View file

@ -73,9 +73,9 @@ enum pm_state_e pm_checkstate(int domain)
{
DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS);
if (g_pmglobals.domain[domain].governor->checkstate)
if (g_pmdomains[domain].governor->checkstate)
{
return g_pmglobals.domain[domain].governor->checkstate(domain);
return g_pmdomains[domain].governor->checkstate(domain);
}
return PM_NORMAL;

View file

@ -75,17 +75,17 @@ int pm_set_governor(int domain, FAR const struct pm_governor_s *gov)
return -EINVAL;
}
if (g_pmglobals.domain[domain].governor &&
g_pmglobals.domain[domain].governor->deinitialize)
if (g_pmdomains[domain].governor &&
g_pmdomains[domain].governor->deinitialize)
{
g_pmglobals.domain[domain].governor->deinitialize();
g_pmdomains[domain].governor->deinitialize();
}
g_pmglobals.domain[domain].governor = gov;
g_pmdomains[domain].governor = gov;
if (g_pmglobals.domain[domain].governor->initialize)
if (g_pmdomains[domain].governor->initialize)
{
g_pmglobals.domain[domain].governor->initialize();
g_pmdomains[domain].governor->initialize();
}
return 0;

View file

@ -38,16 +38,7 @@
/* All PM global data: */
/* Initialize the registry and the PM global data structures. The PM
* global data structure resides in .data which is zeroed at boot time. So
* it is only required to initialize non-zero elements of the PM global
* data structure here.
*/
struct pm_global_s g_pmglobals =
{
NXRMUTEX_INITIALIZER
};
struct pm_domain_s g_pmdomains[CONFIG_PM_NDOMAINS];
/****************************************************************************
* Public Functions
@ -98,10 +89,10 @@ void pm_initialize(void)
pm_set_governor(i, gov);
#if defined(CONFIG_PM_PROCFS)
clock_systime_timespec(&g_pmglobals.domain[i].start);
clock_systime_timespec(&g_pmdomains[i].start);
#endif
nxrmutex_init(&g_pmglobals.domain[i].lock);
nxrmutex_init(&g_pmdomains[i].lock);
#if CONFIG_PM_GOVERNOR_EXPLICIT_RELAX
for (state = 0; state < PM_COUNT; state++)

View file

@ -59,12 +59,12 @@ void pm_unlock(FAR rmutex_t *lock, irqstate_t flags)
irqstate_t pm_domain_lock(int domain)
{
return pm_lock(&g_pmglobals.domain[domain].lock);
return pm_lock(&g_pmdomains[domain].lock);
}
void pm_domain_unlock(int domain, irqstate_t flags)
{
pm_unlock(&g_pmglobals.domain[domain].lock, flags);
pm_unlock(&g_pmdomains[domain].lock, flags);
}
#endif /* CONFIG_PM */

View file

@ -288,7 +288,7 @@ static ssize_t pm_read_state(FAR struct file *filep, FAR char *buffer,
/* Recover our private data from the struct file instance */
pmfile = (FAR struct pm_file_s *)filep->f_priv;
dom = &g_pmglobals.domain[pmfile->domain];
dom = &g_pmdomains[pmfile->domain];
DEBUGASSERT(pmfile);
DEBUGASSERT(dom);
@ -378,7 +378,7 @@ static ssize_t pm_read_wakelock(FAR struct file *filep, FAR char *buffer,
/* Recover our private data from the struct file instance */
pmfile = (FAR struct pm_file_s *)filep->f_priv;
dom = &g_pmglobals.domain[pmfile->domain];
dom = &g_pmdomains[pmfile->domain];
DEBUGASSERT(pmfile);
DEBUGASSERT(dom);
@ -464,7 +464,7 @@ static ssize_t pm_read_preparefail(FAR struct file *filep, FAR char *buffer,
/* Recover our private data from the struct file instance */
pmfile = (FAR struct pm_file_s *)filep->f_priv;
dom = &g_pmglobals.domain[pmfile->domain];
dom = &g_pmdomains[pmfile->domain];
DEBUGASSERT(pmfile);
DEBUGASSERT(dom);
@ -480,11 +480,12 @@ static ssize_t pm_read_preparefail(FAR struct file *filep, FAR char *buffer,
totalsize += copysize;
flags = pm_domain_lock(pmfile->domain);
for (entry = dq_peek(&g_pmglobals.registry);
for (entry = dq_peek(&dom->registry);
entry; entry = dq_next(entry))
{
cb = (FAR struct pm_callback_s *)entry;
pf = &cb->preparefail[pmfile->domain];
pf = &cb->preparefail;
for (state = 0; state < PM_COUNT; state++)
{
sum += pf->duration[state].tv_sec;
@ -492,13 +493,13 @@ static ssize_t pm_read_preparefail(FAR struct file *filep, FAR char *buffer,
}
sum = sum ? sum : 1;
for (entry = dq_peek(&g_pmglobals.registry);
for (entry = dq_peek(&dom->registry);
entry; entry = dq_next(entry))
{
time_t total = 0;
cb = (FAR struct pm_callback_s *)entry;
pf = &cb->preparefail[pmfile->domain];
pf = &cb->preparefail;
for (state = 0; state < PM_COUNT; state++)
{
total += pf->duration[state].tv_sec;

View file

@ -39,14 +39,15 @@
****************************************************************************/
/****************************************************************************
* Name: pm_register
* Name: pm_domain_register
*
* Description:
* This function is called by a device driver in order to register to
* receive power management event callbacks.
*
* Input Parameters:
* callbacks - An instance of struct pm_callback_s providing the driver
* domain - Target register domain.
* cb - An instance of struct pm_callback_s providing the driver
* callback functions.
*
* Returned Value:
@ -54,27 +55,20 @@
*
****************************************************************************/
int pm_register(FAR struct pm_callback_s *callbacks)
int pm_domain_register(int domain, FAR struct pm_callback_s *cb)
{
irqstate_t flags;
DEBUGASSERT(callbacks);
FAR struct pm_domain_s *pdom = &g_pmdomains[domain];
flags = pm_lock(&pdom->lock);
/* Add the new entry to the end of the list of registered callbacks */
flags = pm_lock(&g_pmglobals.reglock);
dq_addlast(&callbacks->entry, &g_pmglobals.registry);
#ifdef CONFIG_PM_PROCFS
for (int domain = 0; domain < CONFIG_PM_NDOMAINS; domain++)
{
callbacks->preparefail[domain].state = PM_RESTORE;
}
dq_addlast(&cb->entry, &pdom->registry);
#if defined (CONFIG_PM_PROCFS)
cb->preparefail.state = PM_RESTORE;
#endif
pm_unlock(&g_pmglobals.reglock, flags);
return 0;
pm_unlock(&pdom->lock, flags);
return OK;
}
#endif /* CONFIG_PM */

View file

@ -38,14 +38,15 @@
****************************************************************************/
/****************************************************************************
* Name: pm_unregister
* Name: pm_domain_unregister
*
* Description:
* This function is called by a device driver in order to unregister
* previously registered power management event callbacks.
*
* Input parameters:
* callbacks - An instance of struct pm_callback_s providing the driver
* domain - Target unregister domain.
* cb - An instance of struct pm_callback_s providing the driver
* callback functions.
*
* Returned Value:
@ -53,19 +54,17 @@
*
****************************************************************************/
int pm_unregister(FAR struct pm_callback_s *callbacks)
int pm_domain_unregister(int domain, FAR struct pm_callback_s *cb)
{
irqstate_t flags;
DEBUGASSERT(callbacks);
struct pm_domain_s *pdom = &g_pmdomains[domain];
flags = pm_lock(&pdom->lock);
/* Remove entry from the list of registered callbacks. */
flags = pm_lock(&g_pmglobals.reglock);
dq_rem(&callbacks->entry, &g_pmglobals.registry);
pm_unlock(&g_pmglobals.reglock, flags);
return 0;
dq_rem(&cb->entry, &pdom->registry);
pm_unlock(&pdom->lock, flags);
return OK;
}
#endif /* CONFIG_PM */

View file

@ -158,7 +158,7 @@ static enum pm_state_e stability_governor_checkstate(int domain)
bool wdog_wakeup;
gdom = &g_stability_governor.domain[domain];
pdom = &g_pmglobals.domain[domain];
pdom = &g_pmdomains[domain];
state = PM_NORMAL;
/* We disable interrupts since pm_stay()/pm_relax() could be simultaneously

View file

@ -222,7 +222,7 @@ struct pm_callback_s
enum pm_state_e pmstate);
#ifdef CONFIG_PM_PROCFS
struct pm_preparefail_s preparefail[CONFIG_PM_NDOMAINS];
struct pm_preparefail_s preparefail;
#endif
};
@ -440,14 +440,15 @@ int pm_set_governor(int domain, FAR const struct pm_governor_s *gov);
void pm_auto_update(int domain, bool auto_update);
/****************************************************************************
* Name: pm_register
* Name: pm_domain_register
*
* Description:
* This function is called by a device driver in order to register to
* receive power management event callbacks.
*
* Input Parameters:
* callbacks - An instance of struct pm_callback_s providing the driver
* domain - Target register domain.
* cb - An instance of struct pm_callback_s providing the driver
* callback functions.
*
* Returned Value:
@ -455,17 +456,20 @@ void pm_auto_update(int domain, bool auto_update);
*
****************************************************************************/
int pm_register(FAR struct pm_callback_s *callbacks);
int pm_domain_register(int domain, FAR struct pm_callback_s *cb);
#define pm_register(cb) pm_domain_register(PM_IDLE_DOMAIN, cb)
/****************************************************************************
* Name: pm_unregister
* Name: pm_domain_unregister
*
* Description:
* This function is called by a device driver in order to unregister
* previously registered power management event callbacks.
*
* Input parameters:
* callbacks - An instance of struct pm_callback_s providing the driver
* domain - Target unregister domain.
* cb - An instance of struct pm_callback_s providing the driver
* callback functions.
*
* Returned Value:
@ -473,7 +477,9 @@ int pm_register(FAR struct pm_callback_s *callbacks);
*
****************************************************************************/
int pm_unregister(FAR struct pm_callback_s *callbacks);
int pm_domain_unregister(int domain, FAR struct pm_callback_s *cb);
#define pm_unregister(cb) pm_domain_unregister(PM_IDLE_DOMAIN, cb)
/****************************************************************************
* Name: pm_activity