device_list_get has been deprecated for 2 releases so remove the code associated with it. Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
492 lines
13 KiB
C
492 lines
13 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr.h>
|
|
#include <device.h>
|
|
#include <init.h>
|
|
#include <ztest.h>
|
|
#include <sys/printk.h>
|
|
#include "abstract_driver.h"
|
|
|
|
|
|
#define DUMMY_PORT_1 "dummy"
|
|
#define DUMMY_PORT_2 "dummy_driver"
|
|
#define BAD_DRIVER "bad_driver"
|
|
|
|
#define MY_DRIVER_A "my_driver_A"
|
|
#define MY_DRIVER_B "my_driver_B"
|
|
|
|
extern void test_mmio_multiple(void);
|
|
extern void test_mmio_toplevel(void);
|
|
extern void test_mmio_single(void);
|
|
extern void test_mmio_device_map(void);
|
|
|
|
/**
|
|
* @brief Test cases to verify device objects
|
|
*
|
|
* Verify zephyr device driver apis with different device types
|
|
*
|
|
* @defgroup kernel_device_tests Device
|
|
*
|
|
* @ingroup all_tests
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief Test device object binding
|
|
*
|
|
* Validates device binding for an existing and a non-existing device object.
|
|
* It creates a dummy_driver device object with basic init and configuration
|
|
* information and validates its binding.
|
|
*
|
|
* Validates three kinds situations of driver object:
|
|
* 1. A non-existing device object.
|
|
* 2. An existing device object with basic init and configuration information.
|
|
* 3. A failed init device object.
|
|
*
|
|
* @ingroup kernel_device_tests
|
|
*
|
|
* @see device_get_binding(), device_busy_set(), device_busy_clear(),
|
|
* DEVICE_DEFINE()
|
|
*/
|
|
void test_dummy_device(void)
|
|
{
|
|
const struct device *dev;
|
|
|
|
/* Validates device binding for a non-existing device object */
|
|
dev = device_get_binding(DUMMY_PORT_1);
|
|
zassert_equal(dev, NULL, NULL);
|
|
|
|
/* Validates device binding for an existing device object */
|
|
dev = device_get_binding(DUMMY_PORT_2);
|
|
zassert_false((dev == NULL), NULL);
|
|
|
|
device_busy_set(dev);
|
|
device_busy_clear(dev);
|
|
|
|
/* device_get_binding() returns false for device object
|
|
* with failed init.
|
|
*/
|
|
dev = device_get_binding(BAD_DRIVER);
|
|
zassert_true((dev == NULL), NULL);
|
|
}
|
|
|
|
/**
|
|
* @brief Test device binding for existing device
|
|
*
|
|
* Validates device binding for an existing device object.
|
|
*
|
|
* @see device_get_binding(), DEVICE_DEFINE()
|
|
*/
|
|
static void test_dynamic_name(void)
|
|
{
|
|
const struct device *mux;
|
|
char name[sizeof(DUMMY_PORT_2)];
|
|
|
|
snprintk(name, sizeof(name), "%s", DUMMY_PORT_2);
|
|
mux = device_get_binding(name);
|
|
zassert_true(mux != NULL, NULL);
|
|
}
|
|
|
|
/**
|
|
* @brief Test device binding for non-existing device
|
|
*
|
|
* Validates binding of a random device driver(non-defined driver) named
|
|
* "ANOTHER_BOGUS_NAME".
|
|
*
|
|
* @see device_get_binding(), DEVICE_DEFINE()
|
|
*/
|
|
static void test_bogus_dynamic_name(void)
|
|
{
|
|
const struct device *mux;
|
|
char name[64];
|
|
|
|
snprintk(name, sizeof(name), "ANOTHER_BOGUS_NAME");
|
|
mux = device_get_binding(name);
|
|
zassert_true(mux == NULL, NULL);
|
|
}
|
|
|
|
/**
|
|
* @brief Test device binding for passing null name
|
|
*
|
|
* Validates device binding for device object when given dynamic name is null.
|
|
*
|
|
* @see device_get_binding(), DEVICE_DEFINE()
|
|
*/
|
|
static void test_null_dynamic_name(void)
|
|
{
|
|
/* Supplying a NULL dynamic name may trigger a SecureFault and
|
|
* lead to system crash in TrustZone enabled Non-Secure builds.
|
|
*/
|
|
#if defined(CONFIG_USERSPACE) && !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE)
|
|
const struct device *mux;
|
|
char *drv_name = NULL;
|
|
|
|
mux = device_get_binding(drv_name);
|
|
zassert_equal(mux, 0, NULL);
|
|
#else
|
|
ztest_test_skip();
|
|
#endif
|
|
}
|
|
|
|
static struct init_record {
|
|
bool pre_kernel;
|
|
bool is_in_isr;
|
|
bool is_pre_kernel;
|
|
} init_records[4];
|
|
|
|
static struct init_record *rp = init_records;
|
|
|
|
static int add_init_record(bool pre_kernel)
|
|
{
|
|
rp->pre_kernel = pre_kernel;
|
|
rp->is_pre_kernel = k_is_pre_kernel();
|
|
rp->is_in_isr = k_is_in_isr();
|
|
++rp;
|
|
return 0;
|
|
}
|
|
|
|
static int pre1_fn(const struct device *dev)
|
|
{
|
|
return add_init_record(true);
|
|
}
|
|
|
|
static int pre2_fn(const struct device *dev)
|
|
{
|
|
return add_init_record(true);
|
|
}
|
|
|
|
static int post_fn(const struct device *dev)
|
|
{
|
|
return add_init_record(false);
|
|
}
|
|
|
|
static int app_fn(const struct device *dev)
|
|
{
|
|
return add_init_record(false);
|
|
}
|
|
|
|
SYS_INIT(pre1_fn, PRE_KERNEL_1, 0);
|
|
SYS_INIT(pre2_fn, PRE_KERNEL_2, 0);
|
|
SYS_INIT(post_fn, POST_KERNEL, 0);
|
|
SYS_INIT(app_fn, APPLICATION, 0);
|
|
|
|
/* This is an error case which driver initializes failed in SYS_INIT .*/
|
|
static int null_driver_init(const struct device *dev)
|
|
{
|
|
ARG_UNUSED(dev);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SYS_INIT(null_driver_init, POST_KERNEL, 0);
|
|
|
|
/**
|
|
* @brief Test detection of initialization before kernel services available.
|
|
*
|
|
* Confirms check is correct.
|
|
*
|
|
* @see k_is_pre_kernel()
|
|
*/
|
|
void test_pre_kernel_detection(void)
|
|
{
|
|
struct init_record *rpe = rp;
|
|
|
|
zassert_equal(rp - init_records, 4U,
|
|
"bad record count");
|
|
rp = init_records;
|
|
while ((rp < rpe) && rp->pre_kernel) {
|
|
zassert_equal(rp->is_in_isr, false,
|
|
"rec %zu isr", rp - init_records);
|
|
zassert_equal(rp->is_pre_kernel, true,
|
|
"rec %zu pre-kernel", rp - init_records);
|
|
++rp;
|
|
}
|
|
zassert_equal(rp - init_records, 2U,
|
|
"bad pre-kernel count");
|
|
|
|
while (rp < rpe) {
|
|
zassert_equal(rp->is_in_isr, false,
|
|
"rec %zu isr", rp - init_records);
|
|
zassert_equal(rp->is_pre_kernel, false,
|
|
"rec %zu post-kernel", rp - init_records);
|
|
++rp;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_PM_DEVICE
|
|
/**
|
|
* @brief Test system device list query API with PM enabled.
|
|
*
|
|
* It queries the list of devices in the system, used to suspend or
|
|
* resume the devices in PM applications.
|
|
*
|
|
* @see z_device_get_all_static()
|
|
*/
|
|
static void test_build_suspend_device_list(void)
|
|
{
|
|
struct device const *devices;
|
|
size_t devcount = z_device_get_all_static(&devices);
|
|
|
|
zassert_false((devcount == 0), NULL);
|
|
}
|
|
|
|
/**
|
|
* @brief Test APIs to enable and disable automatic idle power management
|
|
*
|
|
* @details Test the API enable and disable, cause we do not implement our PM
|
|
* API here, it will use the default function to handle power status. So when
|
|
* we try to get power state by device_get_power_state(), it will default
|
|
* return power state zero. And we check it.
|
|
*
|
|
* @ingroup kernel_device_tests
|
|
*/
|
|
static void test_enable_and_disable_automatic_idle_pm(void)
|
|
{
|
|
const struct device *dev;
|
|
int ret;
|
|
unsigned int device_power_state = 0;
|
|
|
|
dev = device_get_binding(DUMMY_PORT_2);
|
|
zassert_false((dev == NULL), NULL);
|
|
|
|
/* check its status at first */
|
|
/* for cases that cannot run IDLE power, we skip it now */
|
|
ret = device_get_power_state(dev, &device_power_state);
|
|
if (ret == -ENOTSUP) {
|
|
TC_PRINT("Power management not supported on device");
|
|
ztest_test_skip();
|
|
return;
|
|
}
|
|
|
|
zassert_true((ret == 0),
|
|
"Unable to get active state to device");
|
|
|
|
/* enable automatic idle PM and check its status */
|
|
device_pm_enable(dev);
|
|
zassert_not_null((dev->pm), "No device pm");
|
|
zassert_true((dev->pm->enable), "Pm is not enable");
|
|
|
|
/* disable automatic idle PM and check its status */
|
|
device_pm_disable(dev);
|
|
zassert_false((dev->pm->enable), "Pm shall not be enable");
|
|
}
|
|
|
|
/**
|
|
* @brief Test device binding for existing device with PM enabled.
|
|
*
|
|
* Validates device binding for an existing device object with Power management
|
|
* enabled. It also checks if the device is in the middle of a transaction,
|
|
* sets/clears busy status and validates status again.
|
|
*
|
|
* @see device_get_binding(), device_busy_set(), device_busy_clear(),
|
|
* device_busy_check(), device_any_busy_check(),
|
|
* device_set_power_state()
|
|
*/
|
|
void test_dummy_device_pm(void)
|
|
{
|
|
const struct device *dev;
|
|
int busy, ret;
|
|
unsigned int device_power_state = 0;
|
|
|
|
dev = device_get_binding(DUMMY_PORT_2);
|
|
zassert_false((dev == NULL), NULL);
|
|
|
|
busy = device_any_busy_check();
|
|
zassert_true((busy == 0), NULL);
|
|
|
|
/* Set device state to BUSY*/
|
|
device_busy_set(dev);
|
|
|
|
busy = device_any_busy_check();
|
|
zassert_false((busy == 0), NULL);
|
|
|
|
busy = device_busy_check(dev);
|
|
zassert_false((busy == 0), NULL);
|
|
|
|
/* Clear device BUSY state*/
|
|
device_busy_clear(dev);
|
|
|
|
busy = device_busy_check(dev);
|
|
zassert_true((busy == 0), NULL);
|
|
|
|
test_build_suspend_device_list();
|
|
|
|
/* Set device state to DEVICE_PM_ACTIVE_STATE */
|
|
ret = device_set_power_state(dev, DEVICE_PM_ACTIVE_STATE, NULL, NULL);
|
|
if (ret == -ENOTSUP) {
|
|
TC_PRINT("Power management not supported on device");
|
|
ztest_test_skip();
|
|
return;
|
|
}
|
|
|
|
zassert_true((ret == 0),
|
|
"Unable to set active state to device");
|
|
|
|
ret = device_get_power_state(dev, &device_power_state);
|
|
zassert_true((ret == 0),
|
|
"Unable to get active state to device");
|
|
zassert_true((device_power_state == DEVICE_PM_ACTIVE_STATE),
|
|
"Error power status");
|
|
|
|
/* Set device state to DEVICE_PM_FORCE_SUSPEND_STATE */
|
|
ret = device_set_power_state(dev,
|
|
DEVICE_PM_FORCE_SUSPEND_STATE, NULL, NULL);
|
|
|
|
zassert_true((ret == 0), "Unable to force suspend device");
|
|
|
|
ret = device_get_power_state(dev, &device_power_state);
|
|
zassert_true((ret == 0),
|
|
"Unable to get suspend state to device");
|
|
zassert_true((device_power_state == DEVICE_PM_ACTIVE_STATE),
|
|
"Error power status");
|
|
}
|
|
#else
|
|
static void test_enable_and_disable_automatic_idle_pm(void)
|
|
{
|
|
ztest_test_skip();
|
|
}
|
|
|
|
static void test_build_suspend_device_list(void)
|
|
{
|
|
ztest_test_skip();
|
|
}
|
|
|
|
void test_dummy_device_pm(void)
|
|
{
|
|
ztest_test_skip();
|
|
}
|
|
#endif
|
|
|
|
/* this is for storing sequence during initializtion */
|
|
extern int init_level_sequence[4];
|
|
extern int init_priority_sequence[4];
|
|
extern unsigned int seq_level_cnt;
|
|
extern unsigned int seq_priority_cnt;
|
|
|
|
/**
|
|
* @brief Test initialization level for device driver instances
|
|
*
|
|
* @details After the defined device instances have initialized, we check the
|
|
* sequence number that each driver stored during initialization. If the
|
|
* sequence of initial level stored is corresponding with our expectation, it
|
|
* means assigning the level for driver instance works.
|
|
*
|
|
* @ingroup kernel_device_tests
|
|
*/
|
|
void test_device_init_level(void)
|
|
{
|
|
bool seq_correct = true;
|
|
|
|
/* we check if the stored executing sequence for different level is
|
|
* correct, and it should be 1, 2, 3, 4
|
|
*/
|
|
for (int i = 0; i < 4; i++) {
|
|
if (init_level_sequence[i] != (i+1))
|
|
seq_correct = false;
|
|
}
|
|
|
|
zassert_true((seq_correct == true),
|
|
"init sequence is not correct");
|
|
}
|
|
|
|
/**
|
|
* @brief Test initialization priorities for device driver instances
|
|
*
|
|
* details After the defined device instances have initialized, we check the
|
|
* sequence number that each driver stored during initialization. If the
|
|
* sequence of initial priority stored is corresponding with our expectation, it
|
|
* means assigning the priority for driver instance works.
|
|
*
|
|
* @ingroup kernel_device_tests
|
|
*/
|
|
void test_device_init_priority(void)
|
|
{
|
|
bool sequence_correct = true;
|
|
|
|
/* we check if the stored pexecuting sequence for priority is correct,
|
|
* and it should be 1, 2, 3, 4
|
|
*/
|
|
for (int i = 0; i < 4; i++) {
|
|
if (init_priority_sequence[i] != (i+1))
|
|
sequence_correct = false;
|
|
}
|
|
|
|
zassert_true((sequence_correct == true),
|
|
"init sequence is not correct");
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Test abstraction of device drivers with common functionalities
|
|
*
|
|
* @details Abstraction of device drivers with common functionalities
|
|
* shall be provided as an intermediate interface between applications
|
|
* and device drivers, where such interface is implemented by individual
|
|
* device drivers. We verify this by following step:
|
|
|
|
* 1. Define a subsystem api for drivers.
|
|
* 2. Define and create two driver instances.
|
|
* 3. Two drivers call the same subsystem API, and we verify that each
|
|
* driver instance will call their own implementations.
|
|
*
|
|
* @ingroup kernel_device_tests
|
|
*/
|
|
void test_abstraction_driver_common(void)
|
|
{
|
|
const struct device *dev;
|
|
int ret;
|
|
int foo = 2;
|
|
int bar = 1;
|
|
unsigned int baz = 0;
|
|
|
|
/* verify driver A API has called */
|
|
dev = device_get_binding(MY_DRIVER_A);
|
|
zassert_false((dev == NULL), NULL);
|
|
|
|
ret = subsystem_do_this(dev, foo, bar);
|
|
zassert_true(ret == (foo + bar), "common API do_this fail");
|
|
|
|
subsystem_do_that(dev, &baz);
|
|
zassert_true(baz == 1, "common API do_that fail");
|
|
|
|
/* verify driver B API has called */
|
|
dev = device_get_binding(MY_DRIVER_B);
|
|
zassert_false((dev == NULL), NULL);
|
|
|
|
ret = subsystem_do_this(dev, foo, bar);
|
|
zassert_true(ret == (foo - bar), "common API do_this fail");
|
|
|
|
subsystem_do_that(dev, &baz);
|
|
zassert_true(baz == 2, "common API do_that fail");
|
|
}
|
|
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
void test_main(void)
|
|
{
|
|
ztest_test_suite(device,
|
|
ztest_unit_test(test_dummy_device_pm),
|
|
ztest_unit_test(test_build_suspend_device_list),
|
|
ztest_unit_test(test_dummy_device),
|
|
ztest_unit_test(test_enable_and_disable_automatic_idle_pm),
|
|
ztest_unit_test(test_pre_kernel_detection),
|
|
ztest_user_unit_test(test_bogus_dynamic_name),
|
|
ztest_user_unit_test(test_null_dynamic_name),
|
|
ztest_user_unit_test(test_dynamic_name),
|
|
ztest_unit_test(test_device_init_level),
|
|
ztest_unit_test(test_device_init_priority),
|
|
ztest_unit_test(test_abstraction_driver_common),
|
|
ztest_unit_test(test_mmio_single),
|
|
ztest_unit_test(test_mmio_multiple),
|
|
ztest_unit_test(test_mmio_toplevel),
|
|
ztest_unit_test(test_mmio_device_map));
|
|
ztest_run_test_suite(device);
|
|
}
|