From 60aea922a55cfa044c465f76e6157c360c2a23ee Mon Sep 17 00:00:00 2001 From: guanyi Date: Wed, 24 Jul 2024 22:07:43 +0800 Subject: [PATCH] [testcase] add driver pm testcase Signed-off-by: guanyi --- testing/drivertest/CMakeLists.txt | 16 ++ testing/drivertest/Makefile | 5 + testing/drivertest/drivertest_pm.c | 397 +++++++++++++++++++++++++++++ 3 files changed, 418 insertions(+) create mode 100644 testing/drivertest/drivertest_pm.c diff --git a/testing/drivertest/CMakeLists.txt b/testing/drivertest/CMakeLists.txt index 8b32aec3d..3548af95f 100644 --- a/testing/drivertest/CMakeLists.txt +++ b/testing/drivertest/CMakeLists.txt @@ -327,6 +327,22 @@ if(CONFIG_TESTING_DRIVER_TEST) drivertest_touchpanel.c) endif() + if(CONFIG_PM) + nuttx_add_application( + NAME + cmocka_driver_pm + PRIORITY + ${CONFIG_TESTING_DRIVER_TEST_PRIORITY} + STACKSIZE + ${CONFIG_TESTING_DRIVER_TEST_STACKSIZE} + MODULE + ${CONFIG_TESTING_DRIVER_TEST} + DEPENDS + cmocka + SRCS + drivertest_pm.c) + endif() + if(CONFIG_PM_RUNTIME) nuttx_add_application( NAME diff --git a/testing/drivertest/Makefile b/testing/drivertest/Makefile index 4118af1f5..e81783567 100644 --- a/testing/drivertest/Makefile +++ b/testing/drivertest/Makefile @@ -128,6 +128,11 @@ MAINSRC += drivertest_touchpanel.c PROGNAME += cmocka_driver_touchpanel endif +ifneq ($(CONFIG_PM),) +MAINSRC += drivertest_pm.c +PROGNAME += cmocka_driver_pm +endif + ifneq ($(CONFIG_PM_RUNTIME),) MAINSRC += drivertest_pm_runtime.c PROGNAME += cmocka_driver_pm_runtime diff --git a/testing/drivertest/drivertest_pm.c b/testing/drivertest/drivertest_pm.c new file mode 100644 index 000000000..d18b96b45 --- /dev/null +++ b/testing/drivertest/drivertest_pm.c @@ -0,0 +1,397 @@ +/**************************************************************************** + * apps/testing/drivertest/drivertest_pm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ASSERT_EQUAL_IF_CHECK(actual, expected, check) \ + { \ + if (check) \ + { \ + assert_int_equal(actual, expected); \ + } \ + } + +#define TEST_PM_LOOP_COUNT 1 + +/* please set num of domain by menuconfig, ensure TEST_DOMAIN is legal + * (TEST_DOMAIN < CONFIG_PM_NDOMAINS) and no driver or module use it + */ + +#define TEST_DOMAIN 0 +#define TEST_STAYTIMEOUT 100 /* in ms */ +#define TEST_WAITTIME 10000 /* in us */ + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +static int test_pm_callback_prepare(FAR struct pm_callback_s *cb, + int domain, + enum pm_state_e pmstate); +static void test_pm_callback_notify(FAR struct pm_callback_s *cb, + int domain, + enum pm_state_e pmstate); + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct test_pm_s +{ + enum pm_state_e state; + bool prepare_fail; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct pm_callback_s g_test_pm_callback = +{ + .prepare = test_pm_callback_prepare, + .notify = test_pm_callback_notify +}; + +static struct pm_wakelock_s g_test_wakelock[PM_COUNT]; +static char test_wakelock_name[PM_COUNT][32] = +{ + "test_pm_wakelock_normal", + "test_pm_wakelock_idle", + "test_pm_wakelock_standby", + "test_pm_wakelock_sleep" +}; + +static struct test_pm_s g_test_pm_dev; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int test_pm_fake_driver_init(void) +{ + g_test_pm_dev.state = PM_NORMAL; + g_test_pm_dev.prepare_fail = false; + return 0; +} + +static int test_pm_callback_prepare(FAR struct pm_callback_s *cb, + int domain, + enum pm_state_e pmstate) +{ + if (g_test_pm_dev.prepare_fail) + { + return -EBUSY; + } + + return 0; +} + +static void test_pm_callback_notify(FAR struct pm_callback_s *cb, + int domain, + enum pm_state_e pmstate) +{ + switch (pmstate) + { + case PM_NORMAL: + case PM_IDLE: + case PM_STANDBY: + case PM_SLEEP: + { + g_test_pm_dev.state = pmstate; + } + + break; + + default: + + break; + } + + return; +} + +static void test_pm(FAR void **argv) +{ + int ret; + int cnt; + int domain; + int staycount; + int init_delay; + bool check; + + ret = 0; + cnt = TEST_PM_LOOP_COUNT; + domain = TEST_DOMAIN; + + if (CONFIG_PM_GOVERNOR_EXPLICIT_RELAX < 0) + { + check = false; + init_delay = 0; + } + else + { + check = true; + init_delay = MAX(CONFIG_PM_GOVERNOR_EXPLICIT_RELAX, + CONFIG_SERIAL_PM_ACTIVITY_PRIORITY); + } + + while (cnt--) + { + ret = pm_domain_register(domain, &g_test_pm_callback); + assert_int_equal(ret, 0); + + usleep(init_delay * 1000000); + + /* test when pm prepare failed */ + + g_test_pm_dev.prepare_fail = true; + for (int state = 0; state < PM_COUNT; state++) + { + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 0, check); + + pm_stay(domain, state); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 1, check); + + pm_staytimeout(domain, state, TEST_STAYTIMEOUT); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 2, check); + usleep(TEST_STAYTIMEOUT * 1000); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 1, check); + + pm_relax(domain, state); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 0, check); + + pm_staytimeout(domain, state, TEST_STAYTIMEOUT); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 1, check); + usleep(TEST_STAYTIMEOUT * 1000); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 0, check); + } + + for (int state = 0; state < PM_COUNT; state++) + { + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 0, check); + + pm_wakelock_stay(&g_test_wakelock[state]); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 1, check); + + pm_wakelock_staytimeout(&g_test_wakelock[state], TEST_STAYTIMEOUT); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 2, check); + usleep(TEST_STAYTIMEOUT * 1000); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 1, check); + + pm_wakelock_relax(&g_test_wakelock[state]); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 0, check); + + pm_wakelock_staytimeout(&g_test_wakelock[state], TEST_STAYTIMEOUT); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 1, check); + usleep(TEST_STAYTIMEOUT * 1000); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 0, check); + } + + /* test when pm prepare succeeded */ + + test_pm_fake_driver_init(); + + for (int state = 0; state < PM_COUNT; state++) + { + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 0, check); + + pm_stay(domain, state); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, state); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), state, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 1, check); + + pm_staytimeout(domain, state, TEST_STAYTIMEOUT); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, state); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), state, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 2, check); + usleep(TEST_STAYTIMEOUT * 1000); + assert_int_equal(g_test_pm_dev.state, state); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), state, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 1, check); + + pm_relax(domain, state); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 0, check); + + pm_staytimeout(domain, state, TEST_STAYTIMEOUT); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, state); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), state, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 1, check); + usleep(TEST_STAYTIMEOUT * 1000); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + ASSERT_EQUAL_IF_CHECK(pm_staycount(domain, state), 0, check); + } + + for (int state = 0; state < PM_COUNT; state++) + { + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 0, check); + + pm_wakelock_stay(&g_test_wakelock[state]); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, state); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), state, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 1, check); + + pm_wakelock_staytimeout(&g_test_wakelock[state], TEST_STAYTIMEOUT); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, state); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), state, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 2, check); + usleep(TEST_STAYTIMEOUT * 1000); + assert_int_equal(g_test_pm_dev.state, state); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), state, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 1, check); + + pm_wakelock_relax(&g_test_wakelock[state]); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 0, check); + + pm_wakelock_staytimeout(&g_test_wakelock[state], TEST_STAYTIMEOUT); + usleep(TEST_WAITTIME); + assert_int_equal(g_test_pm_dev.state, state); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), state, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 1, check); + usleep(TEST_STAYTIMEOUT * 1000); + assert_int_equal(g_test_pm_dev.state, PM_SLEEP); + ASSERT_EQUAL_IF_CHECK(pm_querystate(domain), PM_SLEEP, check); + staycount = pm_wakelock_staycount(&g_test_wakelock[state]); + ASSERT_EQUAL_IF_CHECK(staycount, 0, check); + } + + ret = pm_domain_unregister(domain, &g_test_pm_callback); + assert_int_equal(ret, 0); + } +} + +static int setup(FAR void **argv) +{ + int domain = TEST_DOMAIN; + int ret = 0; + + ret = test_pm_fake_driver_init(); + if (ret < 0) + { + return ret; + } + + for (int state = 0; state < PM_COUNT; state++) + { + pm_wakelock_init(&g_test_wakelock[state], + test_wakelock_name[state], + domain, + state); + } + + return ret; +} + +static int teardown(FAR void **argv) +{ + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + const struct CMUnitTest tests[] = + { + cmocka_unit_test_prestate_setup_teardown(test_pm, setup, + teardown, NULL), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +}