Merge branch 'bugfix/tickless_idle_single_core' into 'master'

freertos, pm: fix tickless idle not entered in single core mode

See merge request idf/esp-idf!3584
This commit is contained in:
Ivan Grokhotkov 2018-11-06 12:15:03 +08:00
commit 28f1e1597b
2 changed files with 48 additions and 8 deletions

View file

@ -81,11 +81,20 @@ static uint32_t s_ccount_div;
static uint32_t s_ccount_mul;
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
/* Indicates if light sleep entry was successful for given CPU.
/* Indicates if light sleep entry was skipped in vApplicationSleep for given CPU.
* This in turn gets used in IDLE hook to decide if `waiti` needs
* to be invoked or not.
*/
static bool s_entered_light_sleep[portNUM_PROCESSORS];
static bool s_skipped_light_sleep[portNUM_PROCESSORS];
#if portNUM_PROCESSORS == 2
/* When light sleep is finished on one CPU, it is possible that the other CPU
* will enter light sleep again very soon, before interrupts on the first CPU
* get a chance to run. To avoid such situation, set a flag for the other CPU to
* skip light sleep attempt.
*/
static bool s_skip_light_sleep[portNUM_PROCESSORS];
#endif // portNUM_PROCESSORS == 2
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
/* Indicates to the ISR hook that CCOMPARE needs to be updated on the given CPU.
@ -465,10 +474,14 @@ void esp_pm_impl_waiti()
{
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
int core_id = xPortGetCoreID();
if (!s_entered_light_sleep[core_id]) {
if (s_skipped_light_sleep[core_id]) {
asm("waiti 0");
} else {
s_entered_light_sleep[core_id] = false;
/* Interrupt took the CPU out of waiti and s_rtos_lock_handle[core_id]
* is now taken. However since we are back to idle task, we can release
* the lock so that vApplicationSleep can attempt to enter light sleep.
*/
esp_pm_impl_idle_hook();
s_skipped_light_sleep[core_id] = false;
}
#else
asm("waiti 0");
@ -477,10 +490,35 @@ void esp_pm_impl_waiti()
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
static inline bool IRAM_ATTR should_skip_light_sleep(int core_id)
{
#if portNUM_PROCESSORS == 2
if (s_skip_light_sleep[core_id]) {
s_skip_light_sleep[core_id] = false;
s_skipped_light_sleep[core_id] = true;
return true;
}
#endif // portNUM_PROCESSORS == 2
if (s_mode != PM_MODE_LIGHT_SLEEP || s_is_switching) {
s_skipped_light_sleep[core_id] = true;
} else {
s_skipped_light_sleep[core_id] = false;
}
return s_skipped_light_sleep[core_id];
}
static inline void IRAM_ATTR other_core_should_skip_light_sleep(int core_id)
{
#if portNUM_PROCESSORS == 2
s_skip_light_sleep[!core_id] = true;
#endif
}
void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
{
portENTER_CRITICAL(&s_switch_lock);
if (s_mode == PM_MODE_LIGHT_SLEEP && !s_is_switching) {
int core_id = xPortGetCoreID();
if (!should_skip_light_sleep(core_id)) {
/* Calculate how much we can sleep */
int64_t next_esp_timer_alarm = esp_timer_get_next_alarm();
int64_t now = esp_timer_get_time();
@ -494,7 +532,6 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
#endif
/* Enter sleep */
int core_id = xPortGetCoreID();
ESP_PM_TRACE_ENTER(SLEEP, core_id);
int64_t sleep_start = esp_timer_get_time();
esp_light_sleep_start();
@ -516,7 +553,7 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
;
}
}
s_entered_light_sleep[core_id] = true;
other_core_should_skip_light_sleep(core_id);
}
}
portEXIT_CRITICAL(&s_switch_lock);

View file

@ -2147,6 +2147,8 @@ void vTaskSuspendAll( void )
#if ( configUSE_TICKLESS_IDLE != 0 )
#if ( portNUM_PROCESSORS > 1 )
static BaseType_t xHaveReadyTasks()
{
for (int i = tskIDLE_PRIORITY + 1; i < configMAX_PRIORITIES; ++i)
@ -2163,6 +2165,7 @@ void vTaskSuspendAll( void )
return pdFALSE;
}
#endif // portNUM_PROCESSORS > 1
static TickType_t prvGetExpectedIdleTime( void )
{