diff --git a/test_pool/power_wakeup/u001.c b/test_pool/power_wakeup/u001.c index 20d4e5a..5c962a4 100644 --- a/test_pool/power_wakeup/u001.c +++ b/test_pool/power_wakeup/u001.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2019, 2021-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2019, 2021-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -48,8 +48,9 @@ payload1() { uint32_t intid; uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); - uint64_t delay_loop = val_get_counter_frequency() * g_wakeup_timeout; - uint64_t timer_expire_val = val_get_counter_frequency() * g_wakeup_timeout; + uint32_t delay_loop = MAX_SPIN_LOOPS; + uint32_t timer_expire_val = + (uint32_t)((uint64_t)val_get_safe_timeout_ticks() * g_wakeup_timeout); intid = val_timer_get_info(TIMER_INFO_PHY_EL1_INTID, 0); if (val_gic_install_isr(intid, isr1)) { @@ -63,6 +64,10 @@ payload1() /* Add a delay loop after WFI called in case PE needs some time to enter WFI state * exit if test int comes + * + * This delay loop is a bounded spin wait used only to wait for the + * interrupt to arrive. It is not time-based and does not represent + * system counter ticks. */ while (delay_loop && (g_el1phy_int_received == 0)) { delay_loop--; diff --git a/test_pool/power_wakeup/u002.c b/test_pool/power_wakeup/u002.c index 53a5c83..9281e61 100644 --- a/test_pool/power_wakeup/u002.c +++ b/test_pool/power_wakeup/u002.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2019, 2021-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2019, 2021-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -48,7 +48,8 @@ void wakeup_set_failsafe() { uint32_t intid; - uint64_t timer_expire_val = val_get_counter_frequency() * (g_wakeup_timeout + 1); + uint32_t timer_expire_val = + (uint32_t)((uint64_t)val_get_safe_timeout_ticks() * (g_wakeup_timeout + 1)); intid = val_timer_get_info(TIMER_INFO_PHY_EL1_INTID, 0); val_gic_install_isr(intid, isr_failsafe); val_timer_set_phy_el1(timer_expire_val); @@ -83,8 +84,8 @@ payload2() { uint32_t intid; uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); - uint64_t delay_loop = val_get_counter_frequency() * g_wakeup_timeout; - uint64_t timer_expire_val = val_get_counter_frequency() * g_wakeup_timeout; + uint32_t delay_loop = MAX_SPIN_LOOPS; + uint32_t timer_expire_val = (uint32_t)((uint64_t)val_get_safe_timeout_ticks() * g_wakeup_timeout); intid = val_timer_get_info(TIMER_INFO_VIR_EL1_INTID, 0); if (val_gic_install_isr(intid, isr2)) { @@ -101,6 +102,10 @@ payload2() /* Add a delay loop after WFI called in case PE needs some time to enter WFI state * exit in case test or failsafe int is received + * + * This delay loop is a bounded spin wait used only to wait for the + * interrupt to arrive. It is not time-based and does not represent + * system counter ticks. */ while (delay_loop && (g_el1vir_int_received == 0) && (g_failsafe_int_rcvd == 0)) { delay_loop--; diff --git a/test_pool/power_wakeup/u003.c b/test_pool/power_wakeup/u003.c index 72270bb..f3f2fa6 100644 --- a/test_pool/power_wakeup/u003.c +++ b/test_pool/power_wakeup/u003.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2019, 2021-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2019, 2021-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -64,7 +64,8 @@ void wakeup_set_failsafe() { uint32_t intid; - uint64_t timer_expire_val = val_get_counter_frequency() * (g_wakeup_timeout + 1); + uint32_t timer_expire_val = + (uint32_t)((uint64_t)val_get_safe_timeout_ticks() * (g_wakeup_timeout + 1)); intid = val_timer_get_info(TIMER_INFO_PHY_EL1_INTID, 0); val_gic_install_isr(intid, isr_failsafe); @@ -84,8 +85,8 @@ payload3() { uint32_t intid; uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); - uint64_t delay_loop = val_get_counter_frequency() * g_wakeup_timeout; - uint64_t timer_expire_val = val_get_counter_frequency() * g_wakeup_timeout; + uint32_t delay_loop = MAX_SPIN_LOOPS; + uint32_t timer_expire_val = (uint32_t)((uint64_t)val_get_safe_timeout_ticks() * g_wakeup_timeout); intid = val_timer_get_info(TIMER_INFO_PHY_EL2_INTID, 0); if (val_gic_install_isr(intid, isr3)) { @@ -102,6 +103,10 @@ payload3() /* Add a delay loop after WFI called in case PE needs some time to enter WFI state * exit in case test or failsafe int is received + * + * This delay loop is a bounded spin wait used only to wait for the + * interrupt to arrive. It is not time-based and does not represent + * system counter ticks. */ while (delay_loop && (g_el2phy_int_rcvd == 0) && (g_failsafe_int_rcvd == 0)) { delay_loop--; diff --git a/test_pool/power_wakeup/u004.c b/test_pool/power_wakeup/u004.c index 7216863..eeb2f31 100644 --- a/test_pool/power_wakeup/u004.c +++ b/test_pool/power_wakeup/u004.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2019, 2021-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2019, 2021-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -63,7 +63,7 @@ void wakeup_set_failsafe() { uint32_t intid; - uint64_t timer_expire_val = (val_get_counter_frequency() * 3 * g_wakeup_timeout) / 2; + uint64_t timer_expire_val = (uint32_t)((uint64_t)val_get_safe_timeout_ticks() * g_wakeup_timeout); intid = val_timer_get_info(TIMER_INFO_PHY_EL1_INTID, 0); val_gic_install_isr(intid, isr_failsafe); @@ -84,9 +84,9 @@ payload4() uint32_t status; uint32_t ns_wdg = 0; uint32_t intid; - uint32_t delay_loop; + uint32_t delay_loop = MAX_SPIN_LOOPS; uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); - uint64_t timer_expire_val = 1 * g_wakeup_timeout; + uint32_t timer_expire_val = 1 * g_wakeup_timeout; wd_num = val_wd_get_info(0, WD_INFO_COUNT); @@ -129,8 +129,11 @@ payload4() /* Add a delay loop after WFI called in case PE needs some time to enter WFI state * exit in case test or failsafe int is received + * + * This delay loop is a bounded spin wait used only to wait for the + * interrupt to arrive. It is not time-based and does not represent + * system counter ticks. */ - delay_loop = val_get_counter_frequency() * g_wakeup_timeout; while (delay_loop && (g_wd_int_received == 0) && (g_failsafe_int_received == 0)) { delay_loop--; } diff --git a/test_pool/power_wakeup/u005.c b/test_pool/power_wakeup/u005.c index a114911..66daffb 100644 --- a/test_pool/power_wakeup/u005.c +++ b/test_pool/power_wakeup/u005.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2019, 2021-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2019, 2021-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -65,7 +65,8 @@ void wakeup_set_failsafe() { uint32_t intid; - uint64_t timer_expire_val = val_get_counter_frequency() * (g_wakeup_timeout + 1); + uint32_t timer_expire_val = + (uint32_t)((uint64_t)val_get_safe_timeout_ticks() * (g_wakeup_timeout + 1)); intid = val_timer_get_info(TIMER_INFO_PHY_EL1_INTID, 0); val_gic_install_isr(intid, isr_failsafe); @@ -87,9 +88,9 @@ payload5() uint32_t ns_timer = 0; uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); uint32_t intid; - uint64_t delay_loop; + uint32_t delay_loop = MAX_SPIN_LOOPS; uint64_t cnt_base_n; - uint64_t timer_expire_val = val_get_counter_frequency() * g_wakeup_timeout; + uint32_t timer_expire_val = (uint32_t)((uint64_t)val_get_safe_timeout_ticks() * g_wakeup_timeout); timer_num = val_timer_get_info(TIMER_INFO_NUM_PLATFORM_TIMERS, 0); if (!timer_num) { @@ -128,8 +129,11 @@ payload5() /* Add a delay loop after WFI called in case PE needs some time to enter WFI state * exit in case test or failsafe int is received + * + * This delay loop is a bounded spin wait used only to wait for the + * interrupt to arrive. It is not time-based and does not represent + * system counter ticks. */ - delay_loop = val_get_counter_frequency() * g_wakeup_timeout; while (delay_loop && (g_timer_int_rcvd == 0) && (g_failsafe_int_rcvd == 0)) { delay_loop--; } diff --git a/test_pool/power_wakeup/u006.c b/test_pool/power_wakeup/u006.c index 856bbc0..b4dedd1 100644 --- a/test_pool/power_wakeup/u006.c +++ b/test_pool/power_wakeup/u006.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2018,2021,2024-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2018,2021,2024-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -121,10 +121,13 @@ static void payload() { - uint64_t timeout = TIMEOUT_SMALL; + uint32_t timeout = TIMEOUT_SMALL; uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); uint32_t target_pe, status; - uint64_t timer_expire_ticks = TIMEOUT_SMALL; + uint64_t timer_expire_ticks; + + /* Scale watchdog expiry to ensure it fires before system-timer failsafe */ + timer_expire_ticks = TIMEOUT_SMALL * 1024; // Step1: Choose the index of the target PE if ((index + 1) >= val_pe_get_num()) diff --git a/test_pool/timer/t005.c b/test_pool/timer/t005.c index 24b2900..3e36374 100644 --- a/test_pool/timer/t005.c +++ b/test_pool/timer/t005.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2021, 2023-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -52,12 +52,27 @@ void payload() { uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); - uint64_t sys_timer_ticks = val_get_counter_frequency() * 1; - uint64_t pe_timer_ticks = val_get_counter_frequency() * 2; + uint32_t sys_timer_ticks; + uint32_t pe_timer_ticks; uint32_t ns_timer = 0; uint64_t timer_num, timer_cnt; int32_t status; + uint64_t freq = val_get_counter_frequency(); + uint64_t ticks; + + /* System timer */ + ticks = freq * 1; + if (ticks > 0xFFFFFFFF) + ticks = 0xFFFFFFFF; + sys_timer_ticks = (uint32_t)ticks; + + /* PE timer */ + ticks = freq * 2; + if (ticks > 0xFFFFFFFF) + ticks = 0xFFFFFFFF; + pe_timer_ticks = (uint32_t)ticks; + timer_num = val_timer_get_info(TIMER_INFO_NUM_PLATFORM_TIMERS, 0); while (timer_num--) { diff --git a/test_pool/watchdog/w002.c b/test_pool/watchdog/w002.c index dd14ba8..adbe7f0 100644 --- a/test_pool/watchdog/w002.c +++ b/test_pool/watchdog/w002.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2018,2021, 2023-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2018,2021, 2023-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -69,7 +69,8 @@ void wakeup_set_failsafe() { uint32_t intid; - uint64_t timer_expire_val = (val_get_counter_frequency() * 3 * g_wakeup_timeout) / 2; + uint32_t timer_expire_val = + (uint32_t)(((uint64_t)val_get_safe_timeout_ticks() * 3 * g_wakeup_timeout) / 2); intid = val_timer_get_info(TIMER_INFO_PHY_EL1_INTID, 0); val_gic_install_isr(intid, isr_failsafe); @@ -89,7 +90,7 @@ payload() { uint32_t status, ns_wdg = 0; - uint64_t timeout; + uint32_t timeout; uint64_t timer_expire_ticks = 1 * g_wakeup_timeout; uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); wd_num = val_wd_get_info(0, WD_INFO_COUNT); @@ -146,7 +147,7 @@ payload() } wakeup_set_failsafe(); - timeout = val_get_counter_frequency() * 2 * g_wakeup_timeout; + timeout = (uint32_t)(((uint64_t)val_get_safe_timeout_ticks() * g_wakeup_timeout) / 2); while (timeout && (g_wd_int_received == 0) && (g_failsafe_int_received == 0)) { val_data_cache_ops_by_va((addr_t)&g_wd_int_received, INVALIDATE); val_data_cache_ops_by_va((addr_t)&g_failsafe_int_received, INVALIDATE); diff --git a/val/include/acs_timer.h b/val/include/acs_timer.h index 24a77bf..a52379c 100644 --- a/val/include/acs_timer.h +++ b/val/include/acs_timer.h @@ -1,6 +1,6 @@ /** @file - * Copyright (c) 2016-2018, 2021, 2024-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2018, 2021, 2024-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,6 +39,8 @@ #define CNTP_CTL 0x2C #define COUNTER_ID 0xFD0 +#define MAX_WAKEUP_TIMEOUT 5 + uint32_t t001_entry(uint32_t num_pe); uint32_t t002_entry(uint32_t num_pe); uint32_t t003_entry(uint32_t num_pe); diff --git a/val/include/acs_wakeup.h b/val/include/acs_wakeup.h index 2ea8761..fe2b3e5 100644 --- a/val/include/acs_wakeup.h +++ b/val/include/acs_wakeup.h @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2018,2021,2024-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2018,2021,2024-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,6 +18,8 @@ #ifndef __ACS_WAKEUP_H__ #define __ACS_WAKEUP_H__ +#define MAX_SPIN_LOOPS 1000000U + uint32_t u001_entry(uint32_t num_pe); uint32_t u002_entry(uint32_t num_pe); uint32_t u003_entry(uint32_t num_pe); diff --git a/val/include/val_interface.h b/val/include/val_interface.h index deb40d2..51071b9 100644 --- a/val/include/val_interface.h +++ b/val/include/val_interface.h @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -220,18 +220,19 @@ typedef enum { #define BSA_TIMER_FLAG_ALWAYS_ON 0x4 void val_timer_create_info_table(uint64_t *timer_info_table); void val_timer_free_info_table(void); -void val_timer_set_phy_el1(uint64_t timeout); -void val_timer_set_vir_el1(uint64_t timeout); +void val_timer_set_phy_el1(uint32_t timeout); +void val_timer_set_vir_el1(uint32_t timeout); void val_platform_timer_get_entry_index(uint64_t instance, uint32_t *block, uint32_t *index); uint64_t val_timer_get_info(TIMER_INFO_e info_type, uint64_t instance); uint64_t val_get_phy_el2_timer_count(void); uint32_t val_bsa_timer_execute_tests(uint32_t num_pe, uint32_t *g_sw_view); -void val_timer_set_phy_el2(uint64_t timeout); -void val_timer_set_vir_el2(uint64_t timeout); +void val_timer_set_phy_el2(uint32_t timeout); +void val_timer_set_vir_el2(uint32_t timeout); void val_timer_set_system_timer(addr_t cnt_base_n, uint32_t timeout); void val_timer_disable_system_timer(addr_t cnt_base_n); uint32_t val_timer_skip_if_cntbase_access_not_allowed(uint64_t index); uint64_t val_get_phy_el1_timer_count(void); +uint32_t val_get_safe_timeout_ticks(void); /* Watchdog VAL APIs */ typedef enum { diff --git a/val/src/acs_timer.c b/val/src/acs_timer.c index 60e734f..2567006 100644 --- a/val/src/acs_timer.c +++ b/val/src/acs_timer.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2019, 2021-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2019, 2021-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -184,12 +184,12 @@ val_get_phy_el2_timer_count(void) @return None **/ void -val_timer_set_phy_el1(uint64_t timeout) +val_timer_set_phy_el1(uint32_t timeout) { - + uint64_t temp = timeout; if (timeout != 0) { ArmGenericTimerDisableTimer(CntpCtl); - ArmArchTimerWriteReg(CntpTval, &timeout); + ArmArchTimerWriteReg(CntpTval, &temp); ArmGenericTimerEnableTimer(CntpCtl); } else { ArmGenericTimerDisableTimer(CntpCtl); @@ -205,12 +205,12 @@ val_timer_set_phy_el1(uint64_t timeout) @return None **/ void -val_timer_set_vir_el1(uint64_t timeout) +val_timer_set_vir_el1(uint32_t timeout) { - + uint64_t temp = timeout; if (timeout != 0) { ArmGenericTimerDisableTimer(CntvCtl); - ArmArchTimerWriteReg(CntvTval, &timeout); + ArmArchTimerWriteReg(CntvTval, &temp); ArmGenericTimerEnableTimer(CntvCtl); } else { ArmGenericTimerDisableTimer(CntvCtl); @@ -329,12 +329,12 @@ val_get_phy_el1_timer_count(void) @return None **/ void -val_timer_set_phy_el2(uint64_t timeout) +val_timer_set_phy_el2(uint32_t timeout) { - + uint64_t temp = timeout; if (timeout != 0) { ArmGenericTimerDisableTimer(CnthpCtl); - ArmArchTimerWriteReg(CnthpTval, &timeout); + ArmArchTimerWriteReg(CnthpTval, &temp); ArmGenericTimerEnableTimer(CnthpCtl); } else { ArmGenericTimerDisableTimer(CnthpCtl); @@ -350,12 +350,12 @@ val_timer_set_phy_el2(uint64_t timeout) @return None **/ void -val_timer_set_vir_el2(uint64_t timeout) +val_timer_set_vir_el2(uint32_t timeout) { - + uint64_t temp = timeout; if (timeout != 0) { ArmGenericTimerDisableTimer(CnthvCtl); - ArmArchTimerWriteReg(CnthvTval, &timeout); + ArmArchTimerWriteReg(CnthvTval, &temp); ArmGenericTimerEnableTimer(CnthvCtl); } else { ArmGenericTimerDisableTimer(CnthvCtl); @@ -433,3 +433,28 @@ val_timer_skip_if_cntbase_access_not_allowed(uint64_t index) return ACS_STATUS_SKIP; } + +/** + @brief Get a safe timeout value in timer ticks. + + @param None + + @return uint32_t Timeout value computed as (counter frequency / MAX_WAKEUP_TIMEOUT), + guaranteed to fit in 32-bit timer registers. +**/ +uint32_t +val_get_safe_timeout_ticks(void) +{ + /* + * Compute a safe timer tick value based on the maximum supported + * wakeup timeout. This ensures the returned value always fits in + * a 32-bit timer register even on high-frequency systems. + */ + uint64_t freq = val_get_counter_frequency(); + uint64_t ticks = freq / MAX_WAKEUP_TIMEOUT; + + if (ticks > 0xFFFFFFFF) + ticks = 0xFFFFFFFF; + + return (uint32_t)ticks; +} diff --git a/val/src/acs_wd.c b/val/src/acs_wd.c index e933019..008526e 100644 --- a/val/src/acs_wd.c +++ b/val/src/acs_wd.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -139,6 +139,7 @@ uint32_t val_wd_set_ws0(uint32_t index, uint32_t timeout) { uint64_t counter_freq; + uint64_t freq; uint32_t wor_l; uint32_t wor_h = 0; uint64_t ctrl_base; @@ -154,7 +155,22 @@ val_wd_set_ws0(uint32_t index, uint32_t timeout) /* W_IIDR.Architecture Revision [19:16] = 0x1 for Watchdog Rev 1 */ data = VAL_EXTRACT_BITS(val_mmio_read(ctrl_base + WD_IIDR_OFFSET), 16, 19); - counter_freq = val_get_counter_frequency(); + /* + * The common system_counter_to_watchdog_counter frequency ratio can be + * anywhere from 1x to 256x, meaning the watchdog counter typically runs + * slower than the system counter. If we used the system counter frequency + * directly, the system-counter-based failsafe interrupt could fire before + * the watchdog interrupt, which would break the watchdog tests. + * + * To avoid this, we divide the watchdog counter frequency by 1024 so that + * the watchdog interrupt always occurs before the system-counter-based + * failsafe interrupt.Ensure the resulting frequency is never zero. + */ + freq = val_get_counter_frequency(); + counter_freq = freq / 1024; + + if (counter_freq == 0) + counter_freq = 1; /* Check if the timeout value exceeds */ if (data == 0)