60aea922a5
Signed-off-by: guanyi <guanyi@xiaomi.com>
398 lines
14 KiB
C
398 lines
14 KiB
C
/****************************************************************************
|
|
* 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 <nuttx/config.h>
|
|
#include <nuttx/nuttx.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <setjmp.h>
|
|
#include <string.h>
|
|
#include <cmocka.h>
|
|
#include <nuttx/power/pm.h>
|
|
#include <sys/param.h>
|
|
#include <unistd.h>
|
|
|
|
/****************************************************************************
|
|
* 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);
|
|
}
|