Skip to content

Comments

[wip] bm_storage: updates#611

Open
lemrey wants to merge 31 commits intonrfconnect:mainfrom
lemrey:storage
Open

[wip] bm_storage: updates#611
lemrey wants to merge 31 commits intonrfconnect:mainfrom
lemrey:storage

Conversation

@lemrey
Copy link
Contributor

@lemrey lemrey commented Jan 12, 2026

  • Support for compiling more than one backend at a time
  • Add relative addressing and deprecate absolute addressing
  • Add erase operation in SD backend
  • Add chunking of writes
  • Add configurable automatic padding for write operations
  • Internal refactoring of states
  • Cleanup alignment checks and docs
  • Misc fixes
  • Tests

@github-actions github-actions bot added the changelog-entry-required Update changelog before merge. Remove label if entry is not needed or already added. label Jan 12, 2026
@github-actions
Copy link

You can find the documentation preview for this PR here.

@github-actions github-actions bot removed the changelog-entry-required Update changelog before merge. Remove label if entry is not needed or already added. label Jan 12, 2026
@lemrey lemrey force-pushed the storage branch 8 times, most recently from 9698bc0 to 6b25fd0 Compare January 16, 2026 12:33
@lemrey lemrey marked this pull request as ready for review January 16, 2026 12:52
@lemrey lemrey requested review from a team and rghaddab as code owners January 16, 2026 12:52
@lemrey lemrey requested review from a team and rghaddab as code owners January 16, 2026 12:52
@github-actions github-actions bot added the doc-required PR must not be merged without tech writer approval. label Jan 16, 2026
Copy link
Contributor

@eivindj-nordic eivindj-nordic left a comment

Choose a reason for hiding this comment

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

Did a first pass.

};

struct bm_storage_sd_state {
struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

static?

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

Copy link
Contributor

Choose a reason for hiding this comment

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

needs fixing in first commit, not later commit

int bm_storage_sd_on_state_evt(enum nrf_sdh_state_evt evt, void *ctx)
{
switch (evt) {
{ switch (evt) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Extra {
6cd2050

return 0;
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Extra }

if (!storage || !config) {
return -EFAULT;
}
if (storage->initialized) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Add line after } before new if?

enum {
OP_NONE,
OP_EXECUTING,
} operation_state;
Copy link
Contributor

Choose a reason for hiding this comment

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

I find this a bit confusing together with operation_ongoing. What is used where? Should they be merged?

Update: I think it is clearer if this is squashed with the commit removing operation_ongoing.

@@ -0,0 +1,44 @@
#
# Copyright (c) 2025 Nordic Semiconductor ASA
Copy link
Contributor

Choose a reason for hiding this comment

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

2026 Here and other.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated


const struct bm_storage_info bm_storage_info = {
.program_unit = SD_WRITE_BLOCK_SIZE,
.program_unit = 4,
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this value (and erase_unit) be taken from somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could use the DT value, but that value is correct only for the hardware. There may be limitations in the backend itself, like in this case, we are limited by the SoftDevice API which writes words. So while 1 byte is correct for the hardware, 4 bytes is the minimum for this backend.

Copy link
Contributor

Choose a reason for hiding this comment

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

stick with a define so it is clear, the magic number loses all concept

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, updated

} operation_state;
/* Number of times an operation has been retried on timeout. */
uint32_t retries;
/* Number of times an operation has been retried on timeout */
Copy link
Contributor

Choose a reason for hiding this comment

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

. is used in comments elsewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, reverted

#define STORAGE_B_START STORAGE_A_END
#define STORAGE_B_END (STORAGE_B_START + BUFFER_BLOCK_SIZE)

extern const struct bm_storage_api bm_storage_sd_api;
Copy link
Contributor

Choose a reason for hiding this comment

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

Wonder if there is a better way to do this than with an extern (?).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I am not very fond of this solution for this particular use-case. Need to think about it, suggestions welcome.

};

struct bm_storage_sd_state {
struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

+1


static void on_soc_evt(uint32_t evt, void *ctx);
static int on_state_evt_change(enum nrf_sdh_state_evt evt, void *ctx);
void bm_storage_sd_on_soc_evt(uint32_t evt, void *ctx);
Copy link
Contributor

Choose a reason for hiding this comment

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

static

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This needs to be global so I can invoke it in the unit tests to simulate receiving an SoC event from the SoftDevice.

Copy link
Contributor

Choose a reason for hiding this comment

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

in that case make it being static or not depend on the unit test Kconfig, normal applications should not have public visibility for this function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was hoping I could avoid the noise, but have added #ifdefs now

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll look at that in another PR

};

struct bm_storage_sd_state {
struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

needs fixing in first commit, not later commit


find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

project(bm_storage)
Copy link
Contributor

Choose a reason for hiding this comment

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

bm_storage_sd


config BM_STORAGE_BACKEND_SD_QUEUE_SIZE
default 4
config BM_STORAGE_BACKEND_SD_MAX_RETRIES
Copy link
Contributor

Choose a reason for hiding this comment

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

missing newlines, fix in whole file/whole PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Corrected

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hang on, I need one more commit here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed


const struct bm_storage_info bm_storage_info = {
.program_unit = SD_WRITE_BLOCK_SIZE,
.program_unit = 4,
Copy link
Contributor

Choose a reason for hiding this comment

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

stick with a define so it is clear, the magic number loses all concept

int (*uninit)(struct bm_storage *storage);
int (*read)(const struct bm_storage *storage, uint32_t src, void *dest, uint32_t len);
int (*write)(const struct bm_storage *storage, uint32_t dest, const void *src,
uint32_t len, void *ctx);
Copy link
Contributor

Choose a reason for hiding this comment

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

misalignment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Corrected

@lemrey lemrey force-pushed the storage branch 3 times, most recently from 59444c2 to fcdda1b Compare January 20, 2026 12:33
Rename the variable holding the backend state `type`, to something
more meaningful, i.e. `state`. Rename the `bm_storage_sd_state_type`
enum to simply `bm_storage_sd_state`.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Wrap loading of items from the ring buffer into a function so that
if done from multiple places we don't forget about locking IRQs,
and add some semantics to it.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
It is an error to try and initialize the same instance twice,
given that each instance has one owner.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
These are checked by the upper layer, since they are common across
backends.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
The backends should support unitialization.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Remove the `paused` field and merge that with the queue state.
Create a separate operations state to determine when to load
the next operation.

Remove the `operation_ongoing` flag, which did not indicate
whether an operation was ongoing, and it wasn't protecting
any shared resource.

Add unit test suite.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Add unit tests for bm_storage_rram backend.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
For now the erase operation works by writing the erase value in chunks
as big as the erase unit. Initialize both the erase unit and erase value
in the bm_storage_info structure.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Add chunking of write operations, similarly to how it was done in
the nRF5 SDK. This feature allows to tweak the largest amount of
bytes requested to be written by sd_flash_write().

Tweaking this value can help to successfully schedule NVM operations,
and optimize the NVM wear.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Create an internal buffer that is filled with the erased value
and use that to erase multiple erase units at once, instead of erasing
one unit at a time. This speeds up the operation at the cost of little
RAM, equal to the _MAX_WRITE_SIZE.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Wrap storing of operations into the queue in a function.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Use a single byte to keep count, to save a few bytes.
Add a range to the Kconfig that controls how many times an operation
can be retried.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Use a uint8_t rather than a bool, since that's the type accepted as
an argument to sd_softdevice_is_enabled().

Rename variable from `sd_enabled` to `softdevice_is_enabled` for
clarity.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
The `nvm_info` field is set by `bm_storage` itself upon initialization.
Do not check whether it has been set correctly, there is a dedicated
field to keep track of whether initialization has happened or not.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
The library should support having multiple instances operating on
different backends, for example, the internal NVM on the SoC and
an external serial memory.

This patch allows choosing the API for an instance during initialization.
The bm_storage_backend.h header is removed, instead an API structure
is added.

The non-volatile memory information is copied by the backend
into the storage structure, rather than being just exported
by the backend.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
The event dispatch mode must not be determined by looking at whether
a context was provided or not. The operation context is fully opaque
for the library. Instead, simply check the SoftDevice state.

Rename the type from _DISPATCH_TYE to _DISPATCH_MODE for clarity,
and verify in the tests that the event mode is reported correctly.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
This error should indicate that we are out of memory to perform
the requested operation. Update the SoftDevice backend to return this
error instead of EIO when the queue of operations is full.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Add tests for retries and failed operations.
Continue processing the queue when an operation fails to be scheduled.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
NVM addresses and operation lengths must be multiples of operation
unit. Enforce this check (re-using Zephry macros) in bm_storage and
remove redundant checks from the backends.

Use EINVAL instead of EFAULT when there is an alignment or out-of-bounds
error. Use EFAULT only when a check against a NULL pointer fails.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Update doxygen comment for EPERM return values.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Add two new fields to the configuration structure to set the partition
starting address and size. This is aligned with how partitions are
defined elsewhere.

When `addr` and `size` are set, the API uses relative addressing.
Otherwise, it uses absolute addressing.
Deprecate the `start_addr` and `end_addr` fields.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Use relative addressing.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Let each backend define its options in a separate file, and put each
in a menu for clarity.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Add a flag to automatically pad write operations based on the backend
requirements. This simplifies the upper layers that now have
an option to avoid adding logic for padding.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
That's now done automatically by the backend.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Add a function to retrieve the NVM info.
It would not be correct to do so by peeking into a `bm_storage` structure.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Avoid repeating "Bare Metal Storage" everywhere.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Minor doxygen updates.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
It is a byte pattern after all.
Re-arrange the fields in `bm_storage_info` to optimize for size.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc-required PR must not be merged without tech writer approval.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants