Skip to content

Commit

Permalink
device: Refactor device structures
Browse files Browse the repository at this point in the history
When the device driver model got introduced, there were no concept of
SYS_INIT() which can be seen as software service. These were introduced
afterwards and reusing the device infrastructure for simplicity.
However, it meant to allocate a bit too much for something that only
required an initialization function to be called at right time.

Thus refactoring the devices structures relevantly:
- introducing struct init_entry which is a generic init end-point
- struct deviceconfig is removed and struct device owns everything now.
- SYS_INIT() generates only a struct init_entry via calling
  INIT_ENTRY_DEFINE()
- DEVICE_AND_API_INIT() generates a struct device and calls
  INIT_ENTRY_DEFINE()
- init objects sections are in ROM
- device objects sections are in RAM (but will end up in ROM once they
  will be 'constified')

It also generate a tiny memory gain on both ROM and RAM, which is nice.

Perhaps kernel/device.c could be renamed to something more relevant.

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
  • Loading branch information
Tomasz Bursztyka authored and carlescufi committed May 8, 2020
1 parent 48b784a commit 8d7bb8f
Show file tree
Hide file tree
Showing 11 changed files with 302 additions and 248 deletions.
6 changes: 3 additions & 3 deletions drivers/flash/flash_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
#define BUF_ARRAY_CNT 16
#define TEST_ARR_SIZE 0x1000

extern struct device __device_init_start[];
extern struct device __device_init_end[];
extern struct device __device_start[];
extern struct device __device_end[];

static u8_t test_arr[TEST_ARR_SIZE];

Expand Down Expand Up @@ -229,7 +229,7 @@ static void device_name_get(size_t idx, struct shell_static_entry *entry)
entry->help = NULL;
entry->subcmd = &dsub_device_name;

for (dev = __device_init_start; dev != __device_init_end; dev++) {
for (dev = __device_start; dev != __device_end; dev++) {
if ((dev->driver_api != NULL) &&
strcmp(dev->config->name, "") && (dev->config->name != NULL)) {
if (idx == device_idx) {
Expand Down
6 changes: 3 additions & 3 deletions drivers/i2c/i2c_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ LOG_MODULE_REGISTER(i2c_shell, CONFIG_LOG_DEFAULT_LEVEL);

#define I2C_DEVICE_PREFIX "I2C_"

extern struct device __device_init_start[];
extern struct device __device_init_end[];
extern struct device __device_start[];
extern struct device __device_end[];

static int cmd_i2c_scan(const struct shell *shell,
size_t argc, char **argv)
Expand Down Expand Up @@ -80,7 +80,7 @@ static void device_name_get(size_t idx, struct shell_static_entry *entry)
entry->help = NULL;
entry->subcmd = &dsub_device_name;

for (dev = __device_init_start; dev != __device_init_end; dev++) {
for (dev = __device_start; dev != __device_end; dev++) {
if ((dev->driver_api != NULL) &&
strstr(dev->config->name, I2C_DEVICE_PREFIX) != NULL &&
strcmp(dev->config->name, "") && (dev->config->name != NULL)) {
Expand Down
6 changes: 3 additions & 3 deletions drivers/sensor/sensor_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"when no channels are provided. Syntax:\n" \
"<device_name> <channel name 0> .. <channel name N>"

extern struct device __device_init_start[];
extern struct device __device_init_end[];
extern struct device __device_start[];
extern struct device __device_end[];

const char *sensor_channel_name[SENSOR_CHAN_ALL] = {
[SENSOR_CHAN_ACCEL_X] = "accel_x",
Expand Down Expand Up @@ -170,7 +170,7 @@ static void device_name_get(size_t idx, struct shell_static_entry *entry)
entry->help = NULL;
entry->subcmd = &dsub_channel_name;

for (dev = __device_init_start; dev != __device_init_end; dev++) {
for (dev = __device_start; dev != __device_end; dev++) {
if ((dev->driver_api != NULL) &&
strcmp(dev->config->name, "") && (dev->config->name != NULL)) {
if (idx == device_idx) {
Expand Down
182 changes: 81 additions & 101 deletions include/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
#ifndef ZEPHYR_INCLUDE_DEVICE_H_
#define ZEPHYR_INCLUDE_DEVICE_H_

#include <kernel.h>

/**
* @brief Device Driver APIs
* @defgroup io_interfaces Device Driver APIs
Expand All @@ -21,14 +19,35 @@
* @{
*/

#include <zephyr/types.h>
#include <init.h>

#ifdef __cplusplus
extern "C" {
#endif

#define Z_DEVICE_MAX_NAME_LEN 48


/**
* @def SYS_DEVICE_DEFINE
*
* @brief Run an initialization function at boot at specified priority,
* and define device PM control function.
*
* @details This macro lets you run a function at system boot.
*
* @param drv_name Name of this system device
* @param init_fn Pointer to the boot function to run
* @param pm_control_fn Pointer to device_pm_control function.
* Can be empty function (device_pm_control_nop) if not implemented.
* @param level The initialization level, See Z_INIT_ENTRY_DEFINE for details.
* @param prio Priority within the selected initialization level. See
* Z_INIT_ENTRY_DEFINE for details.
*/
#define SYS_DEVICE_DEFINE(drv_name, init_fn, pm_control_fn, level, prio) \
DEVICE_DEFINE(Z_SYS_NAME(init_fn), drv_name, init_fn, pm_control_fn, \
NULL, NULL, level, prio, NULL)

/**
* @def DEVICE_INIT
*
Expand All @@ -53,36 +72,10 @@ extern "C" {
* @param cfg_info The address to the structure containing the
* configuration information for this instance of the driver.
*
* @param level The initialization level at which configuration occurs.
* Must be one of the following symbols, which are listed in the order
* they are performed by the kernel:
* \n
* \li PRE_KERNEL_1: Used for devices that have no dependencies, such as those
* that rely solely on hardware present in the processor/SOC. These devices
* cannot use any kernel services during configuration, since they are not
* yet available.
* \n
* \li PRE_KERNEL_2: Used for devices that rely on the initialization of devices
* initialized as part of the PRE_KERNEL_1 level. These devices cannot use any
* kernel services during configuration, since they are not yet available.
* \n
* \li POST_KERNEL: Used for devices that require kernel services during
* configuration.
* \n
* \li POST_KERNEL_SMP: Used for devices that require kernel services during
* configuration after SMP initialization.
* \n
* \li APPLICATION: Used for application components (i.e. non-kernel components)
* that need automatic configuration. These devices can use all services
* provided by the kernel during configuration.
*
* @param prio The initialization priority of the device, relative to
* other devices of the same initialization level. Specified as an integer
* value in the range 0 to 99; lower values indicate earlier initialization.
* Must be a decimal integer literal without leading zeroes or sign (e.g. 32),
* or an equivalent symbolic name (e.g. \#define MY_INIT_PRIO 32); symbolic
* expressions are *not* permitted
* (e.g. CONFIG_KERNEL_INIT_PRIORITY_DEFAULT + 5).
* @param level The initialization level, See Z_INIT_ENTRY_DEFINE for details.
*
* @param prio Priority within the selected initialization level. See
* Z_INIT_ENTRY_DEFINE for details.
*/
#define DEVICE_INIT(dev_name, drv_name, init_fn, data, cfg_info, level, prio) \
DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, \
Expand All @@ -102,19 +95,18 @@ extern "C" {
* during initialization.
*/
#ifndef CONFIG_DEVICE_POWER_MANAGEMENT
#define DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info, \
level, prio, api) \
static const struct device_config _CONCAT(__config_, dev_name) __used \
__attribute__((__section__(".devconfig.init"))) = { \
.name = drv_name, .init = (init_fn), \
.config_info = (cfg_info) \
}; \
static Z_DECL_ALIGN(struct device) _CONCAT(__device_, dev_name) __used \
__attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \
.config = &_CONCAT(__config_, dev_name), \
.driver_api = api, \
.driver_data = data \
}
#define DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info, \
level, prio, api) \
static Z_DECL_ALIGN(struct device) \
_CONCAT(__device_, dev_name) __used \
__attribute__((__section__(".device_" #level STRINGIFY(prio)))) = { \
.name = drv_name, \
.config_info = (cfg_info), \
.driver_api = (api), \
.driver_data = (data), \
}; \
Z_INIT_ENTRY_DEFINE(_CONCAT(__device_, dev_name), init_fn, \
(&_CONCAT(__device_, dev_name)), level, prio)
#else
/*
* Use the default device_pm_control for devices that do not call the
Expand Down Expand Up @@ -146,32 +138,32 @@ extern "C" {
DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info, \
level, prio, api)
#else
#define DEVICE_DEFINE(dev_name, drv_name, init_fn, pm_control_fn, \
data, cfg_info, level, prio, api) \
static struct device_pm _CONCAT(__pm_, dev_name) __used \
= { \
.usage = ATOMIC_INIT(0), \
.lock = Z_SEM_INITIALIZER( \
_CONCAT(__pm_, dev_name).lock, 1, 1), \
.signal = K_POLL_SIGNAL_INITIALIZER( \
_CONCAT(__pm_, dev_name).signal), \
.event = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, \
K_POLL_MODE_NOTIFY_ONLY, \
&_CONCAT(__pm_, dev_name).signal), \
}; \
static struct device_config _CONCAT(__config_, dev_name) __used \
__attribute__((__section__(".devconfig.init"))) = { \
.name = drv_name, .init = (init_fn), \
.device_pm_control = (pm_control_fn), \
.pm = &_CONCAT(__pm_, dev_name), \
.config_info = (cfg_info) \
}; \
static Z_DECL_ALIGN(struct device) _CONCAT(__device_, dev_name) __used \
__attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \
.config = &_CONCAT(__config_, dev_name), \
.driver_api = api, \
.driver_data = data, \
}
#define DEVICE_DEFINE(dev_name, drv_name, init_fn, pm_control_fn, \
data, cfg_info, level, prio, api) \
static struct device_pm _CONCAT(__pm_, dev_name) __used = { \
.usage = ATOMIC_INIT(0), \
.lock = Z_SEM_INITIALIZER( \
_CONCAT(__pm_, dev_name).lock, 1, 1), \
.signal = K_POLL_SIGNAL_INITIALIZER( \
_CONCAT(__pm_, dev_name).signal), \
.event = K_POLL_EVENT_INITIALIZER( \
K_POLL_TYPE_SIGNAL, \
K_POLL_MODE_NOTIFY_ONLY, \
&_CONCAT(__pm_, dev_name).signal), \
}; \
static Z_DECL_ALIGN(struct device) \
_CONCAT(__device_, dev_name) __used \
__attribute__((__section__(".device_" #level STRINGIFY(prio)))) = { \
.name = drv_name, \
.config_info = (cfg_info), \
.driver_api = (api), \
.driver_data = (data), \
.device_pm_control = (pm_control_fn), \
.pm = &_CONCAT(__pm_, dev_name), \
}; \
Z_INIT_ENTRY_DEFINE(_CONCAT(__device_, dev_name), init_fn, \
(&_CONCAT(__device_, dev_name)), level, prio)

#endif

/**
Expand Down Expand Up @@ -222,8 +214,6 @@ extern "C" {
*/
#define DEVICE_DECLARE(name) static struct device DEVICE_NAME_GET(name)

struct device;

typedef void (*device_pm_cb)(struct device *dev,
int status, void *context, void *arg);

Expand All @@ -250,38 +240,28 @@ struct device_pm {
};

/**
* @brief Static device information (In ROM) Per driver instance
* @brief Runtime device structure (in memory) per driver instance
*
* @param name name of the device
* @param init init function for the driver
* @param config_info address of driver instance config information
*/
struct device_config {
const char *name;
int (*init)(struct device *device);
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
int (*device_pm_control)(struct device *device, u32_t command,
void *context, device_pm_cb cb, void *arg);
struct device_pm *pm;
#endif
const void *config_info;
};

/**
* @brief Runtime device structure (In memory) Per driver instance
* @param device_config Build time config information
* @param driver_api pointer to structure containing the API functions for
* the device type. This pointer is filled in by the driver at init time.
* the device type.
* @param driver_data driver instance data. For driver use only
*/
struct device {
const struct device_config *config;
const char *name;
const void *config_info;
const void *driver_api;
void *driver_data;
void * const driver_data;
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
int (*device_pm_control)(struct device *device, u32_t command,
void *context, device_pm_cb cb, void *arg);
struct device_pm * const pm;
#endif
};

void z_sys_device_do_config_level(s32_t level);

/**
* @brief Retrieve the device structure for a driver by name
*
Expand Down Expand Up @@ -432,9 +412,9 @@ static inline int device_set_power_state(struct device *device,
u32_t device_power_state,
device_pm_cb cb, void *arg)
{
return device->config->device_pm_control(device,
DEVICE_PM_SET_POWER_STATE,
&device_power_state, cb, arg);
return device->device_pm_control(device,
DEVICE_PM_SET_POWER_STATE,
&device_power_state, cb, arg);
}

/**
Expand All @@ -453,10 +433,10 @@ static inline int device_set_power_state(struct device *device,
static inline int device_get_power_state(struct device *device,
u32_t *device_power_state)
{
return device->config->device_pm_control(device,
DEVICE_PM_GET_POWER_STATE,
device_power_state,
NULL, NULL);
return device->device_pm_control(device,
DEVICE_PM_GET_POWER_STATE,
device_power_state,
NULL, NULL);
}

/**
Expand Down
Loading

0 comments on commit 8d7bb8f

Please sign in to comment.