1 /* Copyright (c) 2024 BayLibre SAS 2 * 3 * SPDX-License-Identifier: Apache-2.0 4 */ 5 6 #ifndef __SETTINGS_ZMS_H_ 7 #define __SETTINGS_ZMS_H_ 8 9 #include <zephyr/fs/zms.h> 10 #include <zephyr/settings/settings.h> 11 12 #ifdef __cplusplus 13 extern "C" { 14 #endif 15 16 /* In the ZMS backend, each setting is stored in two ZMS entries: 17 * 1. setting's name 18 * 2. setting's value 19 * 20 * The ZMS entry ID for the setting's value is determined implicitly based on 21 * the ID of the ZMS entry for the setting's name, once that is found. The 22 * difference between name and value ID is constant and equal to 23 * ZMS_NAME_ID_OFFSET. 24 * 25 * Setting's name is hashed into 29 bits minus hash_collisions_bits. 26 * The 2 MSB_bits have always the same value 10, the LL_bit for the name's hash is 0 27 * and the hash_collisions_bits is configurable through CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS. 28 * The resulted 32 bits is the ZMS_ID of the Setting's name. 29 * If we detect a collision between ZMS_IDs we increment the value within hash_collision_bits 30 * until we find a free ZMS_ID. 31 * Separately, we store a linked list using the Setting's name ZMS_ID but setting the lsb to 1. 32 * 33 * The linked list is used to maintain a relation between all ZMS_IDs. This is necessary to load 34 * all settings at initialization. 35 * The linked list contains at least a header followed by multiple linked list elements that 36 * we can refer to as LL_x (where x is the order of that element in that list). 37 * This is a representation of the Linked List that is stored in the storage. 38 * LL_header <--> LL_0 <--> LL_1 <--> LL_2. 39 * The "next_hash" pointer of each LL element refers to the next element in the linked list. 40 * The "previous_hash" pointer is referring the previous element in the linked list. 41 * 42 * The bit representation of the 32 bits ZMS_ID is the following: 43 * -------------------------------------------------------------- 44 * | MSB_bits | hash (truncated) | hash_collision_bits | LL_bit | 45 * -------------------------------------------------------------- 46 * Where: 47 * MSB_bits (2 bits width) : = 10 for Name IDs 48 * = 11 for Data IDs 49 * hash (29 bits - hash_collision_bits) : truncated hash obtained from sys_hash32 50 * hash_collision_bits (configurable width) : used to handle hash collisions 51 * LL_bit : = 0 when this is a name's ZMS_ID 52 * = 1 when this is the linked list ZMS_ID corresponding to the name 53 * 54 * if a settings element is deleted it won't be found. 55 */ 56 57 #define ZMS_LL_HEAD_HASH_ID 0x80000000 58 #define ZMS_DATA_ID_OFFSET 0x40000000 59 #define ZMS_HASH_MASK GENMASK(29, CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS + 1) 60 #define ZMS_COLLISIONS_MASK GENMASK(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS, 1) 61 #define ZMS_HASH_TOTAL_MASK GENMASK(29, 1) 62 #define ZMS_MAX_COLLISIONS (BIT(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS) - 1) 63 64 /* some useful macros */ 65 #define ZMS_NAME_ID_FROM_LL_NODE(x) (x & ~BIT(0)) 66 #define ZMS_UPDATE_COLLISION_NUM(x, y) \ 67 ((x & ~ZMS_COLLISIONS_MASK) | ((y << 1) & ZMS_COLLISIONS_MASK)) 68 #define ZMS_COLLISION_NUM(x) ((x & ZMS_COLLISIONS_MASK) >> 1) 69 70 struct settings_zms { 71 struct settings_store cf_store; 72 struct zms_fs cf_zms; 73 const struct device *flash_dev; 74 uint32_t last_hash_id; 75 uint32_t second_to_last_hash_id; 76 uint8_t hash_collision_num; 77 }; 78 79 struct settings_hash_linked_list { 80 uint32_t previous_hash; 81 uint32_t next_hash; 82 }; 83 84 #ifdef __cplusplus 85 } 86 #endif 87 88 #endif /* __SETTINGS_ZMS_H_ */ 89