Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add retention subsystem #55125

Merged
merged 14 commits into from
Apr 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions MAINTAINERS.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,17 @@ RISCV arch:
labels:
- "area: RISCV"

Retention:
status: maintained
maintainers:
- nordicjm
files:
- dts/bindings/retention/
- include/zephyr/retention/
- subsys/retention/
labels:
- "area: Retention"

Twister:
status: maintained
maintainers:
Expand Down
8 changes: 6 additions & 2 deletions doc/develop/api/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,17 @@ between major releases are available in the :ref:`zephyr_release_notes`.
- Experimental
- 2.4

* - :ref:`reset_api`
- Experimental
- 3.1

* - :ref:`retained_mem_api`
- Experimental
- 3.4

* - :ref:`reset_api`
* - :ref:`retention_api`
- Experimental
- 3.1
- 3.4

* - :ref:`rtc_api`
- Experimental
Expand Down
22 changes: 22 additions & 0 deletions doc/releases/release-notes-3.4.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ Deprecated in this release
board-specific configuration in board Kconfig fragments in the ``boards``
folder of the application.

* On nRF51 and nRF52-based boards, the behaviour of the reset reason being
provided to :c:func:`sys_reboot` and being set in the GPREGRET register has
been dropped. This function will now just reboot the device without changing
the register contents. The new method for setting this register uses the boot
mode feature of the retention subsystem, see the
:ref:`boot mode API <boot_mode_api>` for details. To restore the deprecated
functionality, enable
:kconfig:option:`CONFIG_NRF_STORE_REBOOT_TYPE_GPREGRET`.

Stable API changes in this release
==================================

Expand Down Expand Up @@ -485,6 +494,19 @@ Libraries / Subsystems
correctly, allowing other transports or other parts of the application
code to use it.

* Retention

* Retention subsystem has been added which adds enhanced features over
retained memory drivers allowing for partitioning, magic headers and
checksum validation. See :ref:`retention API <retention_api>` for details.
Support for the retention subsystem is experimental.

* Boot mode retention module has been added which allows for setting/checking
the boot mode of an application, initial support has also been added to
MCUboot to allow for applications to use this as an entrance method for
MCUboot serial recovery mode. See :ref:`boot mode API <boot_mode_api>` for
details.

* RTIO

* Added policy that every ``sqe`` will generate a ``cqe`` (previously an RTIO_SQE_TRANSACTION
Expand Down
1 change: 1 addition & 0 deletions doc/services/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ OS Services
tfm/index
usb/index.rst
virtualization/index.rst
retention/index.rst
rtio/index.rst
zbus/index.rst
misc.rst
198 changes: 198 additions & 0 deletions doc/services/retention/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
.. _retention_api:

Retention System
################

The retention system provides an API which allows applications to read and
write data from and to memory areas or devices that retain the data while the
device is powered. This allows for sharing information between different
applications or within a single application without losing state information
when a device reboots. The stored data should not persist in the event of a
power failure (or during some low-power modes on some devices) nor should it be
stored to a non-volatile storage like :ref:`flash_api`, :ref:`eeprom_api`, or
battery-backed RAM.

The retention system builds on top of the retained data driver, and adds
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please link to docs that describe retained data driver.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant was to put the link in the rst.

Copy link
Member

@wbober wbober Apr 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is my understanding correct that the subsystem is might not be compatible with some retained mem drivers? For example, this would not work with https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/retained_mem/retained_mem_nrf_gpregret.c, correct?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would work fine with it. You can even see the test here d7d180b which runs on nRF52

additional software-level features to it for ensuring the validity of data.
Optionally, a magic header can be used to check if the front of
the retained data memory section contains this specific value, and an optional
checksum (1, 2, or 4-bytes in size) of the stored data can be appended to the
end of the data. Additionally, the retention system API allows partitioning of
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
end of the data. Additionally, the retention system API allows partitioning of
end of the data. Additionally, the retention system API allows for the partitioning of

the retained data sections into multiple distinct areas. For example, a 64-byte
retained data area could be split up into 4 bytes for a boot mode, 16 bytes for
a timestamp, 44 bytes for a last log message. All of these sections can be
accessed or updated independently. The prefix and checksum can be set
per-instance using devicetree.

Devicetree setup
****************

To use the retention system, a retained data driver must be setup for the board
you are using, there is a zephyr driver which can be used which will use some
Copy link
Member

@wbober wbober Apr 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which zephyr driver?

From my understanding of the code this must be retained_mem_zephyr_ram.c driver. Correct? If that is correct, please state this in the doc.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, any retained memory driver.

RAM as non-init for this purpose. The retention system is then initialised as a
child node of this device 1 or more times - note that the memory region will
need to be decremented to account for this reserved portion of RAM. See the
following example (examples in this guide are based on the
:ref:`nrf52840dk_nrf52840` board and memory layout):

.. code-block:: devicetree

/ {
sram@2003FC00 {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x2003FC00 DT_SIZE_K(1)>;
zephyr,memory-region = "RetainedMem";
status = "okay";

retainedmem {
compatible = "zephyr,retained-ram";
status = "okay";
#address-cells = <1>;
#size-cells = <1>;

/* This creates a 256-byte partition */
retention0: retention@0 {
compatible = "zephyr,retention";
status = "okay";

/* The total size of this area is 256
* bytes which includes the prefix and
* checksum, this means that the usable
* data storage area is 256 - 3 = 253
* bytes
*/
reg = <0x0 0x100>;

/* This is the prefix which must appear
* at the front of the data
*/
prefix = [08 04];

/* This uses a 1-byte checksum */
checksum = <1>;
};

/* This creates a 768-byte partition */
retention1: retention@100 {
compatible = "zephyr,retention";
status = "okay";

/* Start position must be after the end
* of the previous partition. The total
* size of this area is 768 bytes which
* includes the prefix and checksum,
* this means that the usable data
* storage area is 768 - 6 = 762 bytes
*/
reg = <0x100 0x300>;

/* This is the prefix which must appear
* at the front of the data
*/
prefix = [00 11 55 88 fa bc];

/* If omitted, there will be no
* checksum
*/
};
};
};
};

/* Reduce SRAM0 usage by 1KB to account for non-init area */
&sram0 {
reg = <0x20000000 DT_SIZE_K(255)>;
};

The retention areas can then be accessed using the data retention API (once
enabled with :kconfig:option:`CONFIG_RETENTION`, which requires that
:kconfig:option:`CONFIG_RETAINED_MEM` be enabled) by getting the device by
using:

.. code-block:: C

#include <zephyr/device.h>
#include <zephyr/retention/retention.h>

const struct device *retention1 = DEVICE_DT_GET(DT_NODELABEL(retention1));
const struct device *retention2 = DEVICE_DT_GET(DT_NODELABEL(retention2));

When the write function is called, the magic header and checksum (if enabled)
will be set on the area, and it will be marked as valid from that point
onwards.

.. _boot_mode_api:

Boot mode
*********

An addition to the retention subsystem is a boot mode interface, this can be
used to dynamically change the state of an application or run a different
application with a minimal set of functions when a device is rebooted (an
example is to have a buttonless way of entering mcuboot's serial recovery
feature from the main application).

To use the boot mode feature, a data retention entry must exist in the device
tree, which is dedicated for use as the boot mode selection (the user area data
size only needs to be a single byte), and this area be assigned to the chosen
node of ``zephyr,boot-mode``. See the following example:

.. code-block:: devicetree

/ {
sram@2003FFFF {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x2003FFFF 0x1>;
zephyr,memory-region = "RetainedMem";
status = "okay";

retainedmem {
compatible = "zephyr,retained-ram";
status = "okay";
#address-cells = <1>;
#size-cells = <1>;

retention0: retention@0 {
compatible = "zephyr,retention";
status = "okay";
reg = <0x0 0x1>;
};
};
};

chosen {
zephyr,boot-mode = &retention0;
};
};

/* Reduce SRAM0 usage by 1 byte to account for non-init area */
&sram0 {
reg = <0x20000000 0x3FFFF>;
};

The boot mode interface can be enabled with
:kconfig:option:`CONFIG_RETENTION_BOOT_MODE` and then accessed by using the
boot mode functions. If using mcuboot with serial recovery, it can be built
with ``CONFIG_MCUBOOT_SERIAL`` and ``CONFIG_BOOT_SERIAL_BOOT_MODE`` enabled
which will allow rebooting directly into the serial recovery mode by using:

.. code-block:: C

#include <zephyr/retention/bootmode.h>
#include <zephyr/sys/reboot.h>

bootmode_set(BOOT_MODE_TYPE_BOOTLOADER);
sys_reboot(0);

API Reference
*************

Retention system API
====================

.. doxygengroup:: retention_api

Boot mode interface
===================

.. doxygengroup:: boot_mode_interface
9 changes: 9 additions & 0 deletions drivers/retained_mem/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ config RETAINED_MEM_INIT_PRIORITY
help
Retained memory devices initialization priority,

config RETAINED_MEM_MUTEXES
bool "Retained memory mutex support"
default y
depends on MULTITHREADING
help
Use mutexes to prevent issues with concurrent retained memory access.
Should only be disabled whereby retained memory access is required
in an ISR or for special use cases.

module = RETAINED_MEM
module-str = retained_mem
source "subsys/logging/Kconfig.template.log_config"
Expand Down
12 changes: 6 additions & 6 deletions drivers/retained_mem/retained_mem_nrf_gpregret.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

LOG_MODULE_REGISTER(retained_mem_nrf_gpregret, CONFIG_RETAINED_MEM_LOG_LEVEL);

#ifdef CONFIG_MULTITHREADING
#ifdef CONFIG_RETAINED_MEM_MUTEXES
struct nrf_gpregret_data {
struct k_mutex lock;
};
Expand All @@ -29,7 +29,7 @@ struct nrf_gpregret_config {

static inline void nrf_gpregret_lock_take(const struct device *dev)
{
#ifdef CONFIG_MULTITHREADING
#ifdef CONFIG_RETAINED_MEM_MUTEXES
struct nrf_gpregret_data *data = dev->data;

k_mutex_lock(&data->lock, K_FOREVER);
Expand All @@ -40,7 +40,7 @@ static inline void nrf_gpregret_lock_take(const struct device *dev)

static inline void nrf_gpregret_lock_release(const struct device *dev)
{
#ifdef CONFIG_MULTITHREADING
#ifdef CONFIG_RETAINED_MEM_MUTEXES
struct nrf_gpregret_data *data = dev->data;

k_mutex_unlock(&data->lock);
Expand All @@ -51,7 +51,7 @@ static inline void nrf_gpregret_lock_release(const struct device *dev)

static int nrf_gpregret_init(const struct device *dev)
{
#ifdef CONFIG_MULTITHREADING
#ifdef CONFIG_RETAINED_MEM_MUTEXES
struct nrf_gpregret_data *data = dev->data;

k_mutex_init(&data->lock);
Expand Down Expand Up @@ -115,7 +115,7 @@ static const struct retained_mem_driver_api nrf_gpregret_api = {
};

#define NRF_GPREGRET_DEVICE(inst) \
IF_ENABLED(CONFIG_MULTITHREADING, \
IF_ENABLED(CONFIG_RETAINED_MEM_MUTEXES, \
(static struct nrf_gpregret_data nrf_gpregret_data_##inst;) \
) \
static const struct nrf_gpregret_config nrf_gpregret_config_##inst = { \
Expand All @@ -125,7 +125,7 @@ static const struct retained_mem_driver_api nrf_gpregret_api = {
DEVICE_DT_INST_DEFINE(inst, \
&nrf_gpregret_init, \
NULL, \
COND_CODE_1(CONFIG_MULTITHREADING, \
COND_CODE_1(CONFIG_RETAINED_MEM_MUTEXES, \
(&nrf_gpregret_data_##inst), (NULL) \
), \
&nrf_gpregret_config_##inst, \
Expand Down
Loading