diff --git a/kernel/timeout.c b/kernel/timeout.c index c7e16c1b92a84..e2e2ad39607a2 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -341,6 +341,7 @@ void z_vrfy_sys_clock_tick_set(uint64_t tick) #if CONFIG_SOC_FAMILY_REALTEK_BEE /* To support RTK PM */ extern void sys_clock_only_add_cycle_count(int32_t ticks); +extern void CPU_DLPS_Exit(void); struct _timeout *get_first_timeout(void) { return first(); @@ -371,6 +372,7 @@ void sys_clock_restore_tick_and_cycle(void) void sys_clock_announce_process_timeout(void) { + /* Update the timeout list: only handle pended ticks. */ k_spinlock_key_t key = k_spin_lock(&timeout_lock); struct _timeout *t; @@ -388,11 +390,24 @@ void sys_clock_announce_process_timeout(void) pended_ticks = 0; - /* Separate the handling of pending tick counts and timeout - * callback functions to avoid errors when a timer is started + k_spin_unlock(&timeout_lock, key); + + /* Resume NVIC to trigger interrupts that occurred during DLPS. + * ISR might update the timout list, so ensure this is done after updating + * the timeout list. + */ + __disable_irq(); + CPU_DLPS_Exit(); + __enable_irq(); + + /* Manually trigger processing of the timeout callback. + * Separating updating pended ticks and timeout + * callback processing to avoid errors if timer behaivor happens * during the timer callback. */ + key = k_spin_lock(&timeout_lock); + for (t = first(); (t != NULL) && (t->dticks == 0); t = first()) { remove_timeout(t); diff --git a/soc/arm/realtek_bee/rtl87x2g/power.c b/soc/arm/realtek_bee/rtl87x2g/power.c index d1889af738d3e..e01eca4bc9a28 100644 --- a/soc/arm/realtek_bee/rtl87x2g/power.c +++ b/soc/arm/realtek_bee/rtl87x2g/power.c @@ -161,8 +161,6 @@ void pm_resume_devices_rtk(void) PM_DEVICE_ACTION_RESUME); } - CPU_DLPS_Exit(); - num_susp_rtk = 0; } @@ -183,7 +181,8 @@ void pm_reusme_systick_and_process_timeout(void) sys_clock_restore_tick_and_cycle(); __enable_irq(); - /* Subtract the pended tick from the timeout list and manually trigger a timeout process. */ + /* Subtract the pended tick from the timeout list, resume NVIC and manually trigger the + * timeout callback process. */ sys_clock_announce_process_timeout(); } diff --git a/tests/boards/rtl8762gn_evb/pm/timeout_wakeup/src/main.c b/tests/boards/rtl8762gn_evb/pm/timeout_wakeup/src/main.c index e17acf8de128a..b01a47e45658b 100644 --- a/tests/boards/rtl8762gn_evb/pm/timeout_wakeup/src/main.c +++ b/tests/boards/rtl8762gn_evb/pm/timeout_wakeup/src/main.c @@ -89,7 +89,7 @@ ZTEST(timeout_wakeup, test_k_thread_wakeup) uint32_t wakeup_count_thread; power_get_statistics(&wakeup_count_before_test, &last_wakeup_clk, &last_sleep_clk); - while (test_thread_sleep_num <= THREAD_SLEEP_NUMBERS) { + while (test_thread_sleep_num < THREAD_SLEEP_NUMBERS) { k_msleep(100); test_thread_sleep_num++; } @@ -97,8 +97,7 @@ ZTEST(timeout_wakeup, test_k_thread_wakeup) wakeup_count_thread = wakeup_count_after_test - wakeup_count_before_test; TC_PRINT("wakeupCount: %d, last_wakeup_clk:%d, last_sleep_clk:%d\n", wakeup_count_thread, last_wakeup_clk, last_sleep_clk); - zassert_true(wakeup_count_thread <= THREAD_SLEEP_NUMBERS + 1 && wakeup_count_thread >= - THREAD_SLEEP_NUMBERS - 1, "test_k_timer_wakeup failed, wakeup Count: %d\n", + zassert_true(wakeup_count_thread == THREAD_SLEEP_NUMBERS, "test_k_timer_wakeup failed, wakeup Count: %d\n", wakeup_count_thread); } @@ -152,10 +151,6 @@ ZTEST(timeout_wakeup, test_triggered_work_wakeup) tag2 = k_uptime_get(); time_diff = tag2-tag1; LOG_INF("after dlps!");/*check log time stamp*/ - zassert_true(time_diff >= TRIGGERED_WORK_NUMBERS*100 && time_diff <= - TRIGGERED_WORK_NUMBERS * 100 + 1020, - "k_uptime_get is not accurate after dlps! time diff (ms) is %lld", - time_diff); power_get_statistics(&wakeup_count_after_test, &last_wakeup_clk, &last_sleep_clk); wakeup_count_triggered_work = wakeup_count_after_test - wakeup_count_before_test; TC_PRINT("wakeupCount: %d, last_wakeup_clk:%d, last_sleep_clk:%d\n", @@ -163,6 +158,10 @@ ZTEST(timeout_wakeup, test_triggered_work_wakeup) zassert_true(wakeup_count_triggered_work <= TRIGGERED_WORK_NUMBERS + 1 && wakeup_count_triggered_work >= TRIGGERED_WORK_NUMBERS - 1, "test_k_timer_wakeup failed, wakeup Count: %d\n", wakeup_count_triggered_work); + zassert_true(time_diff >= TRIGGERED_WORK_NUMBERS*100 && time_diff <= + TRIGGERED_WORK_NUMBERS * 100 + 1400, + "k_uptime_get is not accurate after dlps! time diff (ms) is %lld", + time_diff); } void teardown_fn(void *data)