zephyr/subsys/settings/include/settings/settings_zms.h
Riadh Ghaddab 457ade48b4 settings: zms: code style clean up
Clean some parts of the code and refactor it to avoid multiple nested
conditions.

Signed-off-by: Riadh Ghaddab <rghaddab@baylibre.com>
2025-05-15 17:53:26 +02:00

99 lines
3.9 KiB
C

/* Copyright (c) 2024 BayLibre SAS
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SETTINGS_ZMS_H_
#define __SETTINGS_ZMS_H_
#include <zephyr/fs/zms.h>
#include <zephyr/settings/settings.h>
#ifdef __cplusplus
extern "C" {
#endif
/* In the ZMS backend, each setting is stored in two ZMS entries:
* 1. setting's name
* 2. setting's value
*
* The ZMS entry ID for the setting's value is determined implicitly based on
* the ID of the ZMS entry for the setting's name, once that is found. The
* difference between name and value ID is constant and equal to
* ZMS_DATA_ID_OFFSET.
*
* Setting's name is hashed into 29 bits minus hash_collisions_bits.
* The 2 MSB_bits have always the same value 10, the LL_bit for the name's hash is 0
* and the hash_collisions_bits is configurable through CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS.
* The resulted 32 bits is the ZMS_ID of the Setting's name.
* If we detect a collision between ZMS_IDs we increment the value within hash_collision_bits
* until we find a free ZMS_ID.
* Separately, we store a linked list using the Setting's name ZMS_ID but setting the lsb to 1.
*
* The linked list is used to maintain a relation between all ZMS_IDs. This is necessary to load
* all settings at initialization.
* The linked list contains at least a header followed by multiple linked list elements that
* we can refer to as LL_x (where x is the order of that element in that list).
* This is a representation of the Linked List that is stored in the storage.
* LL_header <--> LL_0 <--> LL_1 <--> LL_2.
* The "next_hash" pointer of each LL element refers to the next element in the linked list.
* The "previous_hash" pointer is referring the previous element in the linked list.
*
* The bit representation of the 32 bits ZMS_ID is the following:
* --------------------------------------------------------------
* | MSB_bits | hash (truncated) | hash_collision_bits | LL_bit |
* --------------------------------------------------------------
* Where:
* MSB_bits (2 bits width) : = 10 for Name IDs
* = 11 for Data IDs
* hash (29 bits - hash_collision_bits) : truncated hash obtained from sys_hash32
* hash_collision_bits (configurable width) : used to handle hash collisions
* LL_bit : = 0 when this is a name's ZMS_ID
* = 1 when this is the linked list ZMS_ID corresponding to the name
*
* if a settings element is deleted it won't be found.
*/
#define ZMS_LL_HEAD_HASH_ID 0x80000000
#define ZMS_DATA_ID_OFFSET 0x40000000
#define ZMS_HASH_MASK GENMASK(29, CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS + 1)
#define ZMS_COLLISIONS_MASK GENMASK(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS, 1)
#define ZMS_HASH_TOTAL_MASK GENMASK(29, 1)
#define ZMS_MAX_COLLISIONS (BIT(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS) - 1)
/* some useful macros */
#define ZMS_NAME_ID_FROM_LL_NODE(x) (x & ~BIT(0))
#define ZMS_LL_NODE_FROM_NAME_ID(x) (x | BIT(0))
#define ZMS_UPDATE_COLLISION_NUM(x, y) \
((x & ~ZMS_COLLISIONS_MASK) | ((y << 1) & ZMS_COLLISIONS_MASK))
#define ZMS_COLLISION_NUM(x) ((x & ZMS_COLLISIONS_MASK) >> 1)
#define ZMS_NAME_ID_FROM_HASH(x) ((x & ZMS_HASH_TOTAL_MASK) | BIT(31))
#define ZMS_DATA_ID_FROM_HASH(x) (ZMS_NAME_ID_FROM_HASH(x) + ZMS_DATA_ID_OFFSET)
#define ZMS_DATA_ID_FROM_NAME(x) (x + ZMS_DATA_ID_OFFSET)
#define ZMS_DATA_ID_FROM_LL_NODE(x) (ZMS_NAME_ID_FROM_LL_NODE(x) + ZMS_DATA_ID_OFFSET)
struct settings_hash_linked_list {
uint32_t previous_hash;
uint32_t next_hash;
};
struct settings_zms {
struct settings_store cf_store;
struct zms_fs cf_zms;
const struct device *flash_dev;
#if CONFIG_SETTINGS_ZMS_LL_CACHE
struct settings_hash_linked_list ll_cache[CONFIG_SETTINGS_ZMS_LL_CACHE_SIZE];
uint32_t ll_cache_next;
bool ll_has_changed;
#endif /* CONFIG_SETTINGS_ZMS_LL_CACHE */
uint32_t last_hash_id;
uint32_t second_to_last_hash_id;
uint8_t hash_collision_num;
};
#ifdef __cplusplus
}
#endif
#endif /* __SETTINGS_ZMS_H_ */