diff --git a/ChangeLog b/ChangeLog index 26ab44a22c0..c2309760fad 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11588,5 +11588,9 @@ 7.16 2016-xx-xx Gregory Nutt - * PM: Add activity domain to all PM driver callbacks (2016-03-27). - + * PM: Add activity domain to all PM interfaces and driver callbacks. If + CONFIG_PM_NDOMAINS == 1, then the legacy behavior is preserved. If + CONFIG_PM_NDOMAINS > 1, then multiple PM domains are supported. This + will allow separate control for certain power management groups. For + example, a network can be shut down without affect an ongoing UI (and + vice versa) (2016-03-27). diff --git a/Documentation b/Documentation index a15cb168507..6e43c1ef42c 160000 --- a/Documentation +++ b/Documentation @@ -1 +1 @@ -Subproject commit a15cb168507bf218b37a3325902df18085ede4a6 +Subproject commit 6e43c1ef42c8204d18610771482e460f24034c69 diff --git a/arch b/arch index f4b99ebe1fd..d5fbee30366 160000 --- a/arch +++ b/arch @@ -1 +1 @@ -Subproject commit f4b99ebe1fd5ab77e9a6adda04611787b4a26205 +Subproject commit d5fbee30366a95c69d6c2fab19b2c52f48b73137 diff --git a/configs b/configs index 07937231ef9..11a38b29129 160000 --- a/configs +++ b/configs @@ -1 +1 @@ -Subproject commit 07937231ef92ab88e2043dc9a17d2d677e26903c +Subproject commit 11a38b291293ba4fc18e91343b4a0ca94edf670d diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index bcebe1cabf6..6f8623a4607 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -217,7 +217,7 @@ config PM_SLEEPEXIT_THRESH config PM_SLEEPENTER_COUNT int "PM SLEEP enter count" - default 50 + default 70 ---help--- State changes then occur when the weight activity account crosses threshold values for certain periods of time (time slice count). diff --git a/drivers/power/pm.h b/drivers/power/pm.h index 9df1ec5c0cc..3c036b6c841 100644 --- a/drivers/power/pm.h +++ b/drivers/power/pm.h @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/power/pm * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -96,12 +96,12 @@ /**************************************************************************** * Public Types ****************************************************************************/ -/* This structure encapsulates all of the global data used by the PM module */ +/* This describes the activity and state for one domain */ -struct pm_global_s +struct pm_domain_s { - /* state - The current state (as determined by an explicit call to - * pm_changestate() + /* state - The current state for this PM domain (as determined by an + * explicit call to pm_changestate()) * recommended - The recommended state based on the PM algorithm in * function pm_update(). * mndex - The index to the next slot in the memory[] array to use. @@ -138,6 +138,15 @@ struct pm_global_s /* stime - The time (in ticks) at the start of the current time slice */ systime_t stime; +}; + +/* This structure encapsulates all of the global data used by the PM module */ + +struct pm_global_s +{ + /* The activity/state information for each PM domain */ + + struct pm_domain_s domain[CONFIG_PM_NDOMAINS]; /* This semaphore manages mutually exclusive access to the power management * registry. It must be initialized to the value 1. @@ -186,6 +195,7 @@ EXTERN struct pm_global_s g_pmglobals; * update driver activity metrics and recommended states. * * Input Parameters: + * domain - The domain associated with the accumulator. * accum - The value of the activity accumulator at the end of the time * slice. * @@ -200,7 +210,7 @@ EXTERN struct pm_global_s g_pmglobals; * ****************************************************************************/ -EXTERN void pm_update(int16_t accum); +EXTERN void pm_update(int domain, int16_t accum); #undef EXTERN #if defined(__cplusplus) diff --git a/drivers/power/pm_activity.c b/drivers/power/pm_activity.c index 83944180000..5a608d1289c 100644 --- a/drivers/power/pm_activity.c +++ b/drivers/power/pm_activity.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/power/pm_activity.c * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -47,30 +47,6 @@ #ifdef CONFIG_PM -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -85,6 +61,7 @@ * power states. * * Input Parameters: + * domain - The domain of the PM activity * priority - Activity priority, range 0-9. Larger values correspond to * higher priorities. Higher priority activity can prevent the system * from entering reduced power states for a longer period of time. @@ -101,12 +78,18 @@ * ****************************************************************************/ -void pm_activity(int priority) +void pm_activity(int domain, int priority) { + FAR struct pm_domain_s *pdom; systime_t now; uint32_t accum; irqstate_t flags; + /* Get a convenience pointer to minimize all of the indexing */ + + DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS); + pdom = &g_pmglobals.domain[domain]; + /* Just increment the activity count in the current time slice. The priority * is simply the number of counts that are added. */ @@ -116,7 +99,7 @@ void pm_activity(int priority) /* Add the priority to the accumulated counts in a critical section. */ flags = enter_critical_section(); - accum = (uint32_t)g_pmglobals.accum + priority; + accum = (uint32_t)pdom->accum + priority; /* Make sure that we do not overflow the underlying uint16_t representation */ @@ -127,7 +110,7 @@ void pm_activity(int priority) /* Save the updated count */ - g_pmglobals.accum = (int16_t)accum; + pdom->accum = (int16_t)accum; /* Check the elapsed time. In periods of low activity, time slicing is * controlled by IDLE loop polling; in periods of higher activity, time @@ -138,7 +121,7 @@ void pm_activity(int priority) */ now = clock_systimer(); - if (now - g_pmglobals.stime >= TIME_SLICE_TICKS) + if (now - pdom->stime >= TIME_SLICE_TICKS) { int16_t tmp; @@ -147,16 +130,16 @@ void pm_activity(int priority) * still disabled. */ - tmp = g_pmglobals.accum; - g_pmglobals.stime = now; - g_pmglobals.accum = 0; + tmp = pdom->accum; + pdom->stime = now; + 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(tmp); + (void)pm_update(domain, tmp); } leave_critical_section(flags); @@ -164,4 +147,3 @@ void pm_activity(int priority) } #endif /* CONFIG_PM */ - diff --git a/drivers/power/pm_changestate.c b/drivers/power/pm_changestate.c index 37caa12b88a..5884d58e9a0 100644 --- a/drivers/power/pm_changestate.c +++ b/drivers/power/pm_changestate.c @@ -46,26 +46,6 @@ #ifdef CONFIG_PM -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - /**************************************************************************** * Private Functions ****************************************************************************/ @@ -213,7 +193,7 @@ int pm_changestate(int domain, enum pm_state_e newstate) * the preceding state. */ - newstate = g_pmglobals.state; + newstate = g_pmglobals.domain[domain].state; (void)pm_prepall(domain, newstate); } @@ -222,7 +202,7 @@ int pm_changestate(int domain, enum pm_state_e newstate) */ pm_changeall(domain, newstate); - g_pmglobals.state = newstate; + g_pmglobals.domain[domain].state = newstate; /* Restore the interrupt state */ diff --git a/drivers/power/pm_checkstate.c b/drivers/power/pm_checkstate.c index 7ec0f83b63d..024fe136e1d 100644 --- a/drivers/power/pm_checkstate.c +++ b/drivers/power/pm_checkstate.c @@ -47,30 +47,6 @@ #ifdef CONFIG_PM -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -99,18 +75,24 @@ * is completed. * * Input Parameters: - * None + * domain - the PM domain to check * * Returned Value: * The recommended power management state. * ****************************************************************************/ -enum pm_state_e pm_checkstate(void) +enum pm_state_e pm_checkstate(int domain) { + FAR struct pm_domain_s *pdom; systime_t now; irqstate_t flags; + /* Get a convenience pointer to minimize all of the indexing */ + + DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS); + pdom = &g_pmglobals.domain[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 * logic in pm_activity(). @@ -127,7 +109,7 @@ enum pm_state_e pm_checkstate(void) */ now = clock_systimer(); - if (now - g_pmglobals.stime >= TIME_SLICE_TICKS) + if (now - pdom->stime >= TIME_SLICE_TICKS) { int16_t accum; @@ -136,16 +118,16 @@ enum pm_state_e pm_checkstate(void) * still disabled. */ - accum = g_pmglobals.accum; - g_pmglobals.stime = now; - g_pmglobals.accum = 0; + accum = pdom->accum; + pdom->stime = now; + 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(accum); + (void)pm_update(domain, accum); } leave_critical_section(flags); @@ -156,7 +138,7 @@ enum pm_state_e pm_checkstate(void) * state should be current: */ - return g_pmglobals.recommended; + return pdom->recommended; } #endif /* CONFIG_PM */ diff --git a/drivers/power/pm_initialize.c b/drivers/power/pm_initialize.c index 298448974f6..1ac58788615 100644 --- a/drivers/power/pm_initialize.c +++ b/drivers/power/pm_initialize.c @@ -47,22 +47,6 @@ #ifdef CONFIG_PM -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - /**************************************************************************** * Public Data ****************************************************************************/ @@ -71,10 +55,6 @@ struct pm_global_s g_pmglobals; -/**************************************************************************** - * Private Functions - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/drivers/power/pm_register.c b/drivers/power/pm_register.c index f8776acee2b..31514fdc4c7 100644 --- a/drivers/power/pm_register.c +++ b/drivers/power/pm_register.c @@ -48,30 +48,6 @@ #ifdef CONFIG_PM -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/drivers/power/pm_update.c b/drivers/power/pm_update.c index 1d5a64bfff3..66b251bbbef 100644 --- a/drivers/power/pm_update.c +++ b/drivers/power/pm_update.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/power/pm_update.c * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -39,6 +39,7 @@ #include +#include #include #include @@ -48,14 +49,22 @@ #ifdef CONFIG_PM -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - /**************************************************************************** * 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 ****************************************************************************/ @@ -134,7 +143,7 @@ static const uint16_t g_pmcount[3] = * Name: pm_worker * * Description: - * This worker function is queue at the end of a time slice in order to + * This worker function is queued at the end of a time slice in order to * update driver activity metrics and recommended states. * * Input Parameters: @@ -151,22 +160,42 @@ static const uint16_t g_pmcount[3] = void pm_worker(FAR void *arg) { - int16_t accum = (int16_t)((intptr_t)arg); + union pm_worker_param_u parameter; + FAR struct pm_domain_s *pdom; int32_t Y; + int16_t accum; int index; - #if CONFIG_PM_MEMORY > 1 int32_t denom; - int i, j; + int i; + int j; +#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 */ + + DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS); + pdom = &g_pmglobals.domain[index]; + +#if CONFIG_PM_MEMORY > 1 /* We won't bother to do anything until we have accumulated * CONFIG_PM_MEMORY-1 samples. */ - if (g_pmglobals.mcnt < CONFIG_PM_MEMORY-1) + if (pdom->mcnt < CONFIG_PM_MEMORY-1) { - g_pmglobals.memory[g_pmglobals.mcnt] = accum; - g_pmglobals.mcnt++; + index = pdom->mcnt++; + pdom->memory[index] = accum; return; } @@ -184,29 +213,32 @@ void pm_worker(FAR void *arg) denom = CONFIG_PM_COEFN; /* Then calculate Y += SUM(Ai*Yi), i = 1..n-1. The oldest sample will - * reside at g_pmglobals.mndx (and this is the value that we will overwrite + * reside at the domain's mndx (and this is the value that we will overwrite * with the new value). */ - for (i = 0, j = g_pmglobals.mndx; i < CONFIG_PM_MEMORY-1; i++, j++) + for (i = 0, j = pdom->mndx; + i < CONFIG_PM_MEMORY-1; + i++, j++) { if (j >= CONFIG_PM_MEMORY-1) { j = 0; } - Y += g_pmcoeffs[i] * g_pmglobals.memory[j]; + Y += g_pmcoeffs[i] * pdom->memory[j]; denom += g_pmcoeffs[i]; } /* Compute and save the new activity value */ Y /= denom; - g_pmglobals.memory[g_pmglobals.mndx] = Y; - g_pmglobals.mndx++; - if (g_pmglobals.mndx >= CONFIG_PM_MEMORY-1) + + index = pdom->mndx++; + pdom->memory[index] = Y; + if (pdom->mndx >= CONFIG_PM_MEMORY-1) { - g_pmglobals.mndx = 0; + pdom->mndx = 0; } #else @@ -223,13 +255,13 @@ void pm_worker(FAR void *arg) * probably does apply for the IDLE state. */ - if (g_pmglobals.state > PM_NORMAL) + if (pdom->state > PM_NORMAL) { /* Get the table index for the current state (which will be the * current state minus one) */ - index = g_pmglobals.state - 1; + index = pdom->state - 1; /* Has the threshold to return to normal power consumption state been * exceeded? @@ -239,8 +271,8 @@ void pm_worker(FAR void *arg) { /* Yes... reset the count and recommend the normal state. */ - g_pmglobals.thrcnt = 0; - g_pmglobals.recommended = PM_NORMAL; + pdom->thrcnt = 0; + pdom->recommended = PM_NORMAL; return; } } @@ -251,7 +283,7 @@ void pm_worker(FAR void *arg) * surprised to be executing!). */ - if (g_pmglobals.state < PM_SLEEP) + if (pdom->state < PM_SLEEP) { unsigned int nextstate; @@ -259,8 +291,8 @@ void pm_worker(FAR void *arg) * be the current state) */ - index = g_pmglobals.state; - nextstate = g_pmglobals.state + 1; + index = pdom->state; + nextstate = pdom->state + 1; /* Has the threshold to enter the next lower power consumption state * been exceeded? @@ -270,26 +302,26 @@ void pm_worker(FAR void *arg) { /* No... reset the count and recommend the current state */ - g_pmglobals.thrcnt = 0; - g_pmglobals.recommended = g_pmglobals.state; + pdom->thrcnt = 0; + pdom->recommended = pdom->state; } /* Yes.. have we already recommended this state? If so, do nothing */ - else if (g_pmglobals.recommended < nextstate) + else if (pdom->recommended < nextstate) { /* No.. increment the count. Has it passed the count required * for a state transition? */ - if (++g_pmglobals.thrcnt >= g_pmcount[index]) + if (++pdom->thrcnt >= g_pmcount[index]) { /* Yes, recommend the new state and set up for the next * transition. */ - g_pmglobals.thrcnt = 0; - g_pmglobals.recommended = nextstate; + pdom->thrcnt = 0; + pdom->recommended = nextstate; } } } @@ -307,6 +339,7 @@ void pm_worker(FAR void *arg) * 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. * @@ -323,13 +356,26 @@ void pm_worker(FAR void *arg) * ****************************************************************************/ -void pm_update(int16_t accum) +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 *)((intptr_t)accum), 0); + (FAR void *)parameter.i, 0); } #endif /* CONFIG_PM */ diff --git a/include/nuttx/power/pm.h b/include/nuttx/power/pm.h index 3dc9e4c38e3..72caa6e8b2f 100644 --- a/include/nuttx/power/pm.h +++ b/include/nuttx/power/pm.h @@ -402,6 +402,7 @@ int pm_register(FAR struct pm_callback_s *callbacks); * power states. * * Input Parameters: + * domain - The domain of the PM activity * priority - Activity priority, range 0-9. Larger values correspond to * higher priorities. Higher priority activity can prevent the system * from entering reduced power states for a longer period of time. @@ -418,7 +419,7 @@ int pm_register(FAR struct pm_callback_s *callbacks); * ****************************************************************************/ -void pm_activity(int priority); +void pm_activity(int domain, int priority); /**************************************************************************** * Name: pm_checkstate @@ -444,14 +445,14 @@ void pm_activity(int priority); * is completed. * * Input Parameters: - * None + * domain - The PM domain to check * * Returned Value: * The recommended power management state. * ****************************************************************************/ -enum pm_state_e pm_checkstate(void); +enum pm_state_e pm_checkstate(int domain); /**************************************************************************** * Name: pm_changestate @@ -501,10 +502,10 @@ int pm_changestate(int domain, enum pm_state_e newstate); */ # define pm_initialize() -# define pm_register(cb) (0) -# define pm_activity(prio) -# define pm_checkstate() (0) -# define pm_changestate(state) +# define pm_register(cb) (0) +# define pm_activity(domain,prio) +# define pm_checkstate(domain) (0) +# define pm_changestate(domain,state) #endif /* CONFIG_PM */ #endif /* __INCLUDE_NUTTX_POWER_PM_H */