drivers/power/: PM: Don't update the power state in work thread: (1) Simplify the code logic and remove the work queue dependence, (2) Power calculation is too simple to delay into the work queue

This commit is contained in:
Xiang Xiao 2018-08-27 13:20:28 -06:00 committed by Gregory Nutt
parent 7d9787d530
commit af284c1e23
4 changed files with 12 additions and 123 deletions

View File

@ -47,7 +47,6 @@
#include <nuttx/semaphore.h> #include <nuttx/semaphore.h>
#include <nuttx/clock.h> #include <nuttx/clock.h>
#include <nuttx/wqueue.h>
#include <nuttx/power/pm.h> #include <nuttx/power/pm.h>
#ifdef CONFIG_PM #ifdef CONFIG_PM
@ -57,10 +56,6 @@
****************************************************************************/ ****************************************************************************/
/* Configuration ************************************************************/ /* Configuration ************************************************************/
#ifndef CONFIG_SCHED_WORKQUEUE
# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
#endif
/* Convert the time slice interval into system clock ticks. /* Convert the time slice interval into system clock ticks.
* *
* CONFIG_PM_SLICEMS provides the duration of one time slice in milliseconds. * CONFIG_PM_SLICEMS provides the duration of one time slice in milliseconds.
@ -159,10 +154,6 @@ struct pm_global_s
sem_t regsem; sem_t regsem;
/* For work that has been deferred to the worker thread */
struct work_s work;
/* registry is a singly-linked list of registered power management /* registry is a singly-linked list of registered power management
* callback structures. To ensure mutually exclusive access, this list * callback structures. To ensure mutually exclusive access, this list
* must be locked by calling pm_lock() before it is accessed. * must be locked by calling pm_lock() before it is accessed.
@ -210,8 +201,7 @@ EXTERN struct pm_global_s g_pmglobals;
* Assumptions: * Assumptions:
* This function may be called from a driver, perhaps even at the interrupt * This function may be called from a driver, perhaps even at the interrupt
* level. It may also be called from the IDLE loop at the lowest possible * level. It may also be called from the IDLE loop at the lowest possible
* priority level. To reconcile these various conditions, all work is * priority level.
* performed on the worker thread at a user-selectable priority.
* *
****************************************************************************/ ****************************************************************************/

View File

@ -137,11 +137,6 @@ void pm_activity(int domain, int priority)
pdom->stime = now; pdom->stime = now;
pdom->accum = 0; pdom->accum = 0;
/* Reassessing the PM state may require some computation. However,
* the work will actually be performed on a worker thread at a user-
* controlled priority.
*/
(void)pm_update(domain, tmp); (void)pm_update(domain, tmp);
} }

View File

@ -125,11 +125,6 @@ enum pm_state_e pm_checkstate(int domain)
pdom->stime = now; pdom->stime = now;
pdom->accum = 0; pdom->accum = 0;
/* Reassessing the PM state may require some computation. However,
* the work will actually be performed on a worker thread at a user-
* controlled priority.
*/
(void)pm_update(domain, accum); (void)pm_update(domain, accum);
} }
@ -146,12 +141,6 @@ enum pm_state_e pm_checkstate(int domain)
leave_critical_section(flags); leave_critical_section(flags);
/* Return the recommended state. Assuming that we are called from the
* IDLE thread at the lowest priority level, any updates scheduled on the
* worker thread above should have already been peformed and the recommended
* state should be current:
*/
return pdom->recommended; return pdom->recommended;
} }

View File

@ -49,26 +49,6 @@
#ifdef CONFIG_PM #ifdef CONFIG_PM
/****************************************************************************
* Private Types
****************************************************************************/
struct pm_worker_param_s
{
uint8_t domndx;
int16_t accum;
};
union pm_worker_param_u
{
struct pm_worker_param_s s;
uintptr_t i;
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
****************************************************************************/ ****************************************************************************/
@ -132,38 +112,35 @@ static const uint16_t g_pmcount[3] =
}; };
/**************************************************************************** /****************************************************************************
* Public Data * Public Functions
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Private Functions * Name: pm_update
****************************************************************************/
/****************************************************************************
* Name: pm_worker
* *
* Description: * Description:
* This worker function is queued at the end of a time slice in order to * This internal function is called at the end of a time slice in order to
* update driver activity metrics and recommended states. * update driver activity metrics and recommended states.
* *
* Input Parameters: * Input Parameters:
* arg - The value of the activity accumulator at the end of the time * domain - The PM domain associated with the accumulator
* accum - The value of the activity accumulator at the end of the time
* slice. * slice.
* *
* Returned Value: * Returned Value:
* None. * None.
* *
* Assumptions: * Assumptions:
* This function runs on the worker thread. * This function may be called from a driver, perhaps even at the interrupt
* level. It may also be called from the IDLE loop at the lowest possible
* priority level.
* *
****************************************************************************/ ****************************************************************************/
void pm_worker(FAR void *arg) void pm_update(int domain, int16_t accum)
{ {
union pm_worker_param_u parameter;
FAR struct pm_domain_s *pdom; FAR struct pm_domain_s *pdom;
int32_t Y; int32_t Y;
int16_t accum;
int index; int index;
#if CONFIG_PM_MEMORY > 1 #if CONFIG_PM_MEMORY > 1
int32_t denom; int32_t denom;
@ -171,21 +148,10 @@ void pm_worker(FAR void *arg)
int j; int j;
#endif #endif
/* Decode the domain and accumulator as a scaler value.
*
* REVISIT: domain will fit in a uint8_t and accum is int16_t. Assuming
* that sizeof(FAR void *) >=3, the following will work. It will not work
* for 16-bit addresses!
*/
parameter.i = (uintptr_t)arg;
index = parameter.s.domndx;
accum = parameter.s.accum;
/* Get a convenience pointer to minimize all of the indexing */ /* Get a convenience pointer to minimize all of the indexing */
DEBUGASSERT(index >= 0 && index < CONFIG_PM_NDOMAINS); DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS);
pdom = &g_pmglobals.domain[index]; pdom = &g_pmglobals.domain[domain];
#if CONFIG_PM_MEMORY > 1 #if CONFIG_PM_MEMORY > 1
/* We won't bother to do anything until we have accumulated /* We won't bother to do anything until we have accumulated
@ -327,55 +293,4 @@ void pm_worker(FAR void *arg)
} }
} }
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: pm_update
*
* Description:
* This internal function is called at the end of a time slice in order to
* update driver activity metrics and recommended states.
*
* Input Parameters:
* domain - The PM domain associated with the accumulator
* accum - The value of the activity accumulator at the end of the time
* slice.
*
* Returned Value:
* None.
*
* Assumptions:
* This function may be called from a driver, perhaps even at the interrupt
* level. It may also be called from the IDLE loop at the lowest possible
* priority level. To reconcile these various conditions, all work is
* performed on the worker thread at a user-selectable priority. This will
* also serialize all of the updates and eliminate any need for additional
* protection.
*
****************************************************************************/
void pm_update(int domain, int16_t accum)
{
union pm_worker_param_u parameter;
/* Encode the domain and accumulator as a scaler value.
*
* REVISIT: domain will fit in a uint8_t and accum is int16_t. Assuming
* that sizeof(FAR void *) >=3, the following will work. It will not work
* for 16-bit addresses!
*/
DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS);
parameter.s.domndx = (uint8_t)domain;
parameter.s.accum = accum;
/* The work will be performed on the worker thread */
DEBUGASSERT(g_pmglobals.work.worker == NULL);
(void)work_queue(HPWORK, &g_pmglobals.work, pm_worker,
(FAR void *)parameter.i, 0);
}
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */