[EFR32] Rework NVM3 instances and refactor our KVS implementation to use nvm3 (#16877)

* Merge chip_nvm3 section into silabs default nvm3 section. Rework the efr32Config nvm3 driver, tweaks to linkerfile for the nvm3 section

* Refactore efr32 kvs implementation to use silabs nvm3 driver

* Fix some return codes for KVS

* Update ldscript for mg24. Add verifications in kvs implementation. Regroup nvm3 and kvs init. Set ble default connection params

* Delay keymap commit to nvm, Build argument for kvs entry count, Clean up

* Add build option in efr32_sdk.gni and  detail in build script

* add info in read me

* Fix typo, add NVM to wordlist

* undo unwanted change to zap and pigweed submodule.

* remove mv command
diff --git a/src/platform/EFR32/BLEManagerImpl.cpp b/src/platform/EFR32/BLEManagerImpl.cpp
index bbbf591..13805fe 100644
--- a/src/platform/EFR32/BLEManagerImpl.cpp
+++ b/src/platform/EFR32/BLEManagerImpl.cpp
@@ -76,6 +76,14 @@
 #define BLE_CONFIG_RF_PATH_GAIN_TX (0)
 #define BLE_CONFIG_RF_PATH_GAIN_RX (0)
 
+// Default Connection  parameters
+#define BLE_CONFIG_MIN_INTERVAL (16) // Time = Value x 1.25 ms = 30ms
+#define BLE_CONFIG_MAX_INTERVAL (80) // Time = Value x 1.25 ms = 100ms
+#define BLE_CONFIG_LATENCY (0)
+#define BLE_CONFIG_TIMEOUT (100)          // Time = Value x 10 ms = 1s
+#define BLE_CONFIG_MIN_CE_LENGTH (0)      // Leave to min value
+#define BLE_CONFIG_MAX_CE_LENGTH (0xFFFF) // Leave to max value
+
 TimerHandle_t sbleAdvTimeoutTimer; // FreeRTOS sw timer.
 
 /* Bluetooth stack configuration parameters (see "UG136: Silicon Labs Bluetooth C Application Developer's Guide" for
@@ -249,6 +257,8 @@
                 RAIL_GetVersion(&railVer, true);
                 ChipLogProgress(DeviceLayer, "RAIL version:, v%d.%d.%d-b%d", railVer.major, railVer.minor, railVer.rev,
                                 railVer.build);
+                sl_bt_connection_set_default_parameters(BLE_CONFIG_MIN_INTERVAL, BLE_CONFIG_MAX_INTERVAL, BLE_CONFIG_LATENCY,
+                                                        BLE_CONFIG_TIMEOUT, BLE_CONFIG_MIN_CE_LENGTH, BLE_CONFIG_MAX_CE_LENGTH);
             }
             break;
 
@@ -257,7 +267,7 @@
             }
             break;
             case sl_bt_evt_connection_parameters_id: {
-                // ChipLogProgress(DeviceLayer, "Connection parameter ID received. Nothing to do");
+                // ChipLogProgress(DeviceLayer, "Connection parameter ID received");
             }
             break;
             case sl_bt_evt_connection_phy_status_id: {
@@ -307,6 +317,11 @@
             }
             break;
 
+            case sl_bt_evt_connection_remote_used_features_id: {
+                // ChipLogProgress(DeviceLayer, "link layer features supported by the remote device");
+            }
+            break;
+
             default:
                 ChipLogProgress(DeviceLayer, "evt_UNKNOWN id = %08" PRIx32, SL_BT_MSG_ID(bluetooth_evt->header));
                 break;
diff --git a/src/platform/EFR32/CHIPDevicePlatformConfig.h b/src/platform/EFR32/CHIPDevicePlatformConfig.h
index ba22bed..0303a7b 100644
--- a/src/platform/EFR32/CHIPDevicePlatformConfig.h
+++ b/src/platform/EFR32/CHIPDevicePlatformConfig.h
@@ -56,51 +56,6 @@
 // These are configuration options that are unique to the EFR32 platform.
 // These can be overridden by the application as needed.
 
-// -------------- EFR32 NVM3 Storage Configuration -------------
-
-/**
- *  @def CHIP_DEVICE_CONFIG_NVM3_MAX_NUM_OBJECTS
- *
- *  @brief
- *    Configures the size of the nvm3 cache and should be set >= the
- *    maximum number of Chip Config objects, e.g...
- *    Factory configs[5], System configs[23], Counter configs[32] + margin[4] = 64.
- *
- */
-#ifndef CHIP_DEVICE_CONFIG_NVM3_MAX_NUM_OBJECTS
-#define CHIP_DEVICE_CONFIG_NVM3_MAX_NUM_OBJECTS 64
-#endif // CHIP_DEVICE_CONFIG_NVM3_MAX_NUM_OBJECTS
-
-/**
- *  @def CHIP_DEVICE_CONFIG_NVM3_MAX_OBJECT_SIZE
- *
- *  @brief
- *    This determines the max size for any Chip nvm3 object
- *    (e.g. for Config 'string' or 'binary' types).
- */
-#ifndef CHIP_DEVICE_CONFIG_NVM3_MAX_OBJECT_SIZE
-#define CHIP_DEVICE_CONFIG_NVM3_MAX_OBJECT_SIZE 1000
-#endif // CHIP_DEVICE_CONFIG_NVM3_MAX_OBJECT_SIZE
-
-/**
- *  @def CHIP_DEVICE_CONFIG_NVM3_NUM_FLASH_PAGES_FOR_STORAGE
- *
- *  @brief
- *    This determines the Flash size used for nvm3 data storage:-
- *    (assuming 2k Flash page size) => Total Flash size for nvm3: 8 * 2k = 16k
- *    The total size should allow sufficient margin for wear-levelling and
- *    repacking.
- *
- *    MG21 and MG 24 a 8k per page. 3 * 8k = 24k
- */
-#ifndef CHIP_DEVICE_CONFIG_NVM3_NUM_FLASH_PAGES_FOR_STORAGE
-#if defined(EFR32MG21) || defined(EFR32MG24)
-#define CHIP_DEVICE_CONFIG_NVM3_NUM_FLASH_PAGES_FOR_STORAGE 3
-#else
-#define CHIP_DEVICE_CONFIG_NVM3_NUM_FLASH_PAGES_FOR_STORAGE 8
-#endif
-#endif // CHIP_DEVICE_CONFIG_NVM3_NUM_FLASH_PAGES_FOR_STORAGE
-
 // ========== Platform-specific Configuration Overrides =========
 
 #ifndef CHIP_DEVICE_CONFIG_BLE_LL_TASK_PRIORITY
diff --git a/src/platform/EFR32/ConfigurationManagerImpl.cpp b/src/platform/EFR32/ConfigurationManagerImpl.cpp
index b5a2664..9c370bf 100644
--- a/src/platform/EFR32/ConfigurationManagerImpl.cpp
+++ b/src/platform/EFR32/ConfigurationManagerImpl.cpp
@@ -284,9 +284,7 @@
 
 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
 
-#if CHIP_KVS_AVAILABLE
     PersistedStorage::KeyValueStoreMgrImpl().ErasePartition();
-#endif // CHIP_KVS_AVAILABLE
 
 #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
     ChipLogProgress(DeviceLayer, "Clearing WiFi provision");
diff --git a/src/platform/EFR32/ConfigurationManagerImpl.h b/src/platform/EFR32/ConfigurationManagerImpl.h
index 7a157cc..baa3e58 100644
--- a/src/platform/EFR32/ConfigurationManagerImpl.h
+++ b/src/platform/EFR32/ConfigurationManagerImpl.h
@@ -26,7 +26,7 @@
 
 #include <platform/internal/GenericConfigurationManagerImpl.h>
 
-#include "EFR32Config.h"
+#include <platform/EFR32/EFR32Config.h>
 
 namespace chip {
 namespace DeviceLayer {
diff --git a/src/platform/EFR32/EFR32Config.cpp b/src/platform/EFR32/EFR32Config.cpp
index da1734e..f78797c 100644
--- a/src/platform/EFR32/EFR32Config.cpp
+++ b/src/platform/EFR32/EFR32Config.cpp
@@ -31,55 +31,38 @@
 
 #include "FreeRTOS.h"
 #include "nvm3.h"
+#include "nvm3_default.h"
 #include "nvm3_hal_flash.h"
 
+// Substitute the GSDK weak nvm3_lockBegin and nvm3_lockEnd
+// for an application controlled re-entrance protection
+#define EFR32_SEM_TIMEOUT_ms 5
+static SemaphoreHandle_t nvm3_Sem;
+static StaticSemaphore_t nvm3_SemStruct;
+
+void nvm3_lockBegin(void)
+{
+    VerifyOrDie(nvm3_Sem != NULL);
+    xSemaphoreTake(nvm3_Sem, EFR32_SEM_TIMEOUT_ms);
+}
+
+void nvm3_lockEnd(void)
+{
+    VerifyOrDie(nvm3_Sem != NULL);
+    xSemaphoreGive(nvm3_Sem);
+}
+
 namespace chip {
 namespace DeviceLayer {
 namespace Internal {
 
-// Two macros are provided to support the creation of the Silicon Labs NVM3 area and
-// initialization data- NVM3_DEFINE_SECTION_STATIC_DATA() and NVM3_DEFINE_SECTION_INIT_DATA().
-// A linker section called 'name'_section is defined by NVM3_DEFINE_SECTION_STATIC_DATA().
-// The NVM3 area is placed at the top of the device FLASH section by the linker
-// script file: chip-efr32-bringup-MG12P.ld. An error is returned
-// by nvm3_open() on alignment or size violation.
-
-// Local version of SDK macro (avoids uninitialized var compile error).
-#define CHIP_NVM3_DEFINE_SECTION_STATIC_DATA(name, nvmSize, cacheSize)                                                             \
-    static nvm3_CacheEntry_t name##_cache[cacheSize];                                                                              \
-    static uint8_t name##_nvm[nvmSize] SL_ATTRIBUTE_SECTION(STRINGIZE(name##_section))
-
-// Local version of SDK macro (allows CHIP to configure the maximum nvm3 object size and headroom).
-#define CHIP_NVM3_DEFINE_SECTION_INIT_DATA(name, maxObjectSize, repackHeadroom)                                                    \
-    static nvm3_Init_t name = {                                                                                                    \
-        (nvm3_HalPtr_t) name##_nvm,                                                                                                \
-        sizeof(name##_nvm),                                                                                                        \
-        name##_cache,                                                                                                              \
-        sizeof(name##_cache) / sizeof(nvm3_CacheEntry_t),                                                                          \
-        maxObjectSize,                                                                                                             \
-        repackHeadroom,                                                                                                            \
-        &nvm3_halFlashHandle,                                                                                                      \
-    }
-
-#define CHIP_NVM3_REPACK_HEADROOM 64 // Threshold for User non-forced nvm3 flash repacking.
-
-#define EFR32_SEM_TIMEOUT_ms 5
-
-static nvm3_Handle_t handle;
-static SemaphoreHandle_t nvm3_Sem;
-static StaticSemaphore_t nvm3_SemStruct;
-
-// Declare NVM3 data area and cache.
-
-CHIP_NVM3_DEFINE_SECTION_STATIC_DATA(chipNvm3, CHIP_DEVICE_CONFIG_NVM3_NUM_FLASH_PAGES_FOR_STORAGE * FLASH_PAGE_SIZE,
-                                     CHIP_DEVICE_CONFIG_NVM3_MAX_NUM_OBJECTS);
-
-CHIP_NVM3_DEFINE_SECTION_INIT_DATA(chipNvm3, CHIP_DEVICE_CONFIG_NVM3_MAX_OBJECT_SIZE, CHIP_NVM3_REPACK_HEADROOM);
+// Matter NVM3 space is placed in the silabs default nvm3 section shared with other stack.
+// 'kMatterNvm3KeyDomain' identify the matter nvm3 domain.
+// The NVM3 default section is placed at end of Flash minus 1 page byt the linker file
+// See examples/platform/efr32/ldscripts/efr32mgXX.ld
 
 CHIP_ERROR EFR32Config::Init()
 {
-    CHIP_ERROR err;
-
     nvm3_Sem = xSemaphoreCreateBinaryStatic(&nvm3_SemStruct);
 
     if (nvm3_Sem == NULL)
@@ -87,12 +70,13 @@
         return CHIP_ERROR_NO_MEMORY;
     }
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
+    return MapNvm3Error(nvm3_open(nvm3_defaultHandle, nvm3_defaultInit));
+}
 
-exit:
-    OnExit();
-    return err;
+void EFR32Config::DeInit()
+{
+    vSemaphoreDelete(nvm3_Sem);
+    nvm3_close(nvm3_defaultHandle);
 }
 
 CHIP_ERROR EFR32Config::ReadConfigValue(Key key, bool & val)
@@ -102,28 +86,18 @@
     size_t dataLen;
     bool tmpVal;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
     // Get nvm3 object info.
-    err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
+    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
     SuccessOrExit(err);
 
     // Read nvm3 bytes into tmp.
-    err = MapNvm3Error(nvm3_readData(&handle, key, &tmpVal, dataLen));
+    err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, &tmpVal, dataLen));
     SuccessOrExit(err);
     val = tmpVal;
 
 exit:
-    OnExit();
     return err;
 }
 
@@ -134,27 +108,18 @@
     size_t dataLen;
     uint32_t tmpVal;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
     // Get nvm3 object info.
-    err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
+    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
     SuccessOrExit(err);
 
     // Read nvm3 bytes into tmp.
-    err = MapNvm3Error(nvm3_readData(&handle, key, &tmpVal, dataLen));
+    err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, &tmpVal, dataLen));
     SuccessOrExit(err);
     val = tmpVal;
 
 exit:
-    OnExit();
     return err;
 }
 
@@ -165,28 +130,18 @@
     size_t dataLen;
     uint64_t tmpVal;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
     // Get nvm3 object info.
-    err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
+    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
     SuccessOrExit(err);
 
     // Read nvm3 bytes into tmp.
-    err = MapNvm3Error(nvm3_readData(&handle, key, &tmpVal, dataLen));
+    err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, &tmpVal, dataLen));
     SuccessOrExit(err);
     val = tmpVal;
 
 exit:
-    OnExit();
     return err;
 }
 
@@ -198,19 +153,10 @@
 
     outLen = 0;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
     // Get nvm3 object info.
-    err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
+    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
     SuccessOrExit(err);
     VerifyOrExit(dataLen > 0, err = CHIP_ERROR_INVALID_STRING_LENGTH);
 
@@ -221,7 +167,7 @@
         // terminator char).
         VerifyOrExit((bufSize > dataLen), err = CHIP_ERROR_BUFFER_TOO_SMALL);
 
-        err = MapNvm3Error(nvm3_readData(&handle, key, buf, dataLen));
+        err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, buf, dataLen));
         SuccessOrExit(err);
 
         outLen      = ((dataLen == 1) && (buf[0] == 0)) ? 0 : dataLen;
@@ -237,7 +183,7 @@
         {
             // Read the first byte of the nvm3 string into a tmp var.
             char firstByte;
-            err = MapNvm3Error(nvm3_readData(&handle, key, &firstByte, 1));
+            err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, &firstByte, 1));
             SuccessOrExit(err);
 
             outLen = (firstByte == 0) ? 0 : dataLen;
@@ -245,7 +191,6 @@
     }
 
 exit:
-    OnExit();
     return err;
 }
 
@@ -256,19 +201,10 @@
     size_t dataLen;
 
     outLen = 0;
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
     // Get nvm3 object info.
-    err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
+    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
     SuccessOrExit(err);
     VerifyOrExit(dataLen > 0, err = CHIP_ERROR_INVALID_STRING_LENGTH);
 
@@ -278,14 +214,51 @@
         // enough to take the data.
         VerifyOrExit((bufSize >= dataLen), err = CHIP_ERROR_BUFFER_TOO_SMALL);
 
-        err = MapNvm3Error(nvm3_readData(&handle, key, buf, dataLen));
+        err = MapNvm3Error(nvm3_readData(nvm3_defaultHandle, key, buf, dataLen));
         SuccessOrExit(err);
+
+        outLen = dataLen;
     }
 
-    outLen = dataLen;
-
 exit:
-    OnExit();
+    return err;
+}
+
+CHIP_ERROR EFR32Config::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen, size_t offset)
+{
+    CHIP_ERROR err;
+    uint32_t objectType;
+    size_t dataLen;
+
+    outLen = 0;
+    VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
+
+    // Get nvm3 object info.
+    err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
+    SuccessOrExit(err);
+    VerifyOrExit(dataLen > 0, err = CHIP_ERROR_INVALID_STRING_LENGTH);
+
+    if (buf != NULL)
+    {
+        // Read nvm3 bytes directly into output buffer- check buffer is long enough to take the data
+        // else read what we can but return CHIP_ERROR_BUFFER_TOO_SMALL.
+        size_t maxReadLength = dataLen - offset;
+        if (bufSize >= maxReadLength)
+        {
+            err = MapNvm3Error(nvm3_readPartialData(nvm3_defaultHandle, key, buf, offset, maxReadLength));
+            SuccessOrExit(err);
+            outLen = maxReadLength;
+        }
+        else
+        {
+            err = MapNvm3Error(nvm3_readPartialData(nvm3_defaultHandle, key, buf, offset, bufSize));
+            SuccessOrExit(err);
+            // read was successful, but we did not read all the data from the object.
+            err    = CHIP_ERROR_BUFFER_TOO_SMALL;
+            outLen = bufSize;
+        }
+    }
+exit:
     return err;
 }
 
@@ -293,26 +266,16 @@
 {
     CHIP_ERROR err;
     uint32_t tmpVal;
-    Key key = kMinConfigKey_ChipCounter + counterIdx;
-
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
+    Key key = kMinConfigKey_MatterCounter + counterIdx;
 
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
     // Read bytes into tmp.
-    err = MapNvm3Error(nvm3_readCounter(&handle, key, &tmpVal));
+    err = MapNvm3Error(nvm3_readCounter(nvm3_defaultHandle, key, &tmpVal));
     SuccessOrExit(err);
     val = tmpVal;
 
 exit:
-    OnExit();
     return err;
 }
 
@@ -320,22 +283,12 @@
 {
     CHIP_ERROR err;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
     VerifyOrExit(ValidConfigKey(key), err = CHIP_ERROR_INVALID_ARGUMENT); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
-    err = MapNvm3Error(nvm3_writeData(&handle, key, &val, sizeof(val)));
+    err = MapNvm3Error(nvm3_writeData(nvm3_defaultHandle, key, &val, sizeof(val)));
     SuccessOrExit(err);
 
 exit:
-    OnExit();
     return err;
 }
 
@@ -343,22 +296,12 @@
 {
     CHIP_ERROR err;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
-    err = MapNvm3Error(nvm3_writeData(&handle, key, &val, sizeof(val)));
+    err = MapNvm3Error(nvm3_writeData(nvm3_defaultHandle, key, &val, sizeof(val)));
     SuccessOrExit(err);
 
 exit:
-    OnExit();
     return err;
 }
 
@@ -366,22 +309,12 @@
 {
     CHIP_ERROR err;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
-    err = MapNvm3Error(nvm3_writeData(&handle, key, &val, sizeof(val)));
+    err = MapNvm3Error(nvm3_writeData(nvm3_defaultHandle, key, &val, sizeof(val)));
     SuccessOrExit(err);
 
 exit:
-    OnExit();
     return err;
 }
 
@@ -394,31 +327,21 @@
 {
     CHIP_ERROR err;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
     if (str != NULL)
     {
         // Write the string to nvm3 without the terminator char (apart from
         // empty strings where only the terminator char is stored in nvm3).
-        err = MapNvm3Error(nvm3_writeData(&handle, key, str, (strLen > 0) ? strLen : 1));
+        err = MapNvm3Error(nvm3_writeData(nvm3_defaultHandle, key, str, (strLen > 0) ? strLen : 1));
         SuccessOrExit(err);
     }
     else
     {
-        nvm3_deleteObject(&handle, key); // no error checking here.
+        nvm3_deleteObject(nvm3_defaultHandle, key); // no error checking here.
     }
 
 exit:
-    OnExit();
     return err;
 }
 
@@ -426,57 +349,37 @@
 {
     CHIP_ERROR err;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
     if (data != NULL)
     {
         if (dataLen > 0)
         {
             // Write the binary data to nvm3.
-            err = MapNvm3Error(nvm3_writeData(&handle, key, data, dataLen));
+            err = MapNvm3Error(nvm3_writeData(nvm3_defaultHandle, key, data, dataLen));
             SuccessOrExit(err);
         }
     }
     else
     {
-        nvm3_deleteObject(&handle, key); // no error checking here.
+        nvm3_deleteObject(nvm3_defaultHandle, key); // no error checking here.
     }
 
 exit:
-    OnExit();
     return err;
 }
 
 CHIP_ERROR EFR32Config::WriteConfigValueCounter(uint8_t counterIdx, uint32_t val)
 {
     CHIP_ERROR err;
-    Key key = kMinConfigKey_ChipCounter + counterIdx;
-
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
+    Key key = kMinConfigKey_MatterCounter + counterIdx;
 
     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
 
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
-    err = MapNvm3Error(nvm3_writeCounter(&handle, key, val));
+    err = MapNvm3Error(nvm3_writeCounter(nvm3_defaultHandle, key, val));
     SuccessOrExit(err);
 
 exit:
-    OnExit();
     return err;
 }
 
@@ -484,44 +387,21 @@
 {
     CHIP_ERROR err;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
     // Delete the nvm3 object with the given key id.
-    err = MapNvm3Error(nvm3_deleteObject(&handle, key));
+    err = MapNvm3Error(nvm3_deleteObject(nvm3_defaultHandle, key));
     SuccessOrExit(err);
 
 exit:
-    OnExit();
     return err;
 }
 
 bool EFR32Config::ConfigValueExists(Key key)
 {
-    CHIP_ERROR err;
     uint32_t objectType;
     size_t dataLen;
 
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
-
-    err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-    SuccessOrExit(err);
-
     // Find object with key id.
-    err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
-
-exit:
-    OnExit();
+    CHIP_ERROR err = MapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, key, &objectType, &dataLen));
     return (err == CHIP_NO_ERROR);
 }
 
@@ -533,15 +413,14 @@
     CHIP_ERROR err;
 
     // Iterate over all the CHIP Config nvm3 records and delete each one...
-    err = ForEachRecord(kMinConfigKey_ChipConfig, kMaxConfigKey_ChipConfig, false,
+    err = ForEachRecord(kMinConfigKey_MatterConfig, kMaxConfigKey_MatterConfig, false,
                         [](const Key & nvm3Key, const size_t & length) -> CHIP_ERROR {
                             CHIP_ERROR err2;
                             // Delete the nvm3 object with the given key id.
-                            err2 = MapNvm3Error(nvm3_deleteObject(&handle, nvm3Key));
+                            err2 = ClearConfigValue(nvm3Key);
                             SuccessOrExit(err2);
 
                         exit:
-                            nvm3_close(&handle);
                             return err2;
                         });
 
@@ -580,11 +459,6 @@
     // Invokes the callers CB function when appropriate.
 
     CHIP_ERROR err = CHIP_NO_ERROR;
-    if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
-    {
-        err = CHIP_ERROR_TIMEOUT;
-        SuccessOrExit(err);
-    }
 
     for (Key nvm3Key = firstNvm3Key; nvm3Key <= lastNvm3Key; ++nvm3Key)
     {
@@ -592,12 +466,8 @@
         uint32_t objectType;
         size_t dataLen;
 
-        // Open nvm3 handle for reading on each iteration.
-        err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
-        SuccessOrExit(err);
-
         // Find nvm3 object with current nvm3 iteration key.
-        nvm3Res = nvm3_getObjectInfo(&handle, nvm3Key, &objectType, &dataLen);
+        nvm3Res = nvm3_getObjectInfo(nvm3_defaultHandle, nvm3Key, &objectType, &dataLen);
         switch (nvm3Res)
         {
         case ECODE_NVM3_OK:
@@ -624,16 +494,14 @@
         SuccessOrExit(err);
     }
 
-exit:
-    OnExit();
+exit:;
     return err;
 }
 
 bool EFR32Config::ValidConfigKey(Key key)
 {
-    // Returns true if the key is in the valid CHIP Config nvm3 key range.
-
-    if ((key >= kMinConfigKey_ChipFactory) && (key <= kMaxConfigKey_ChipCounter))
+    // Returns true if the key is in the valid Matter Config nvm3 key range.
+    if ((key >= kMinConfigKey_MatterFactory) && (key <= kMaxConfigKey_MatterKvs))
     {
         return true;
     }
@@ -652,13 +520,7 @@
     // Repack nvm3 flash if nvm3 space < headroom threshold.
     // Note- checking periodically during idle periods should prevent
     // forced repack events on any write operation.
-    nvm3_repack(&handle);
-}
-
-void EFR32Config::OnExit()
-{
-    xSemaphoreGive(nvm3_Sem);
-    nvm3_close(&handle);
+    nvm3_repack(nvm3_defaultHandle);
 }
 
 } // namespace Internal
diff --git a/src/platform/EFR32/EFR32Config.h b/src/platform/EFR32/EFR32Config.h
index 638dd53..6b8bf52 100644
--- a/src/platform/EFR32/EFR32Config.h
+++ b/src/platform/EFR32/EFR32Config.h
@@ -31,6 +31,13 @@
 #include "nvm3.h"
 #include "nvm3_hal_flash.h"
 
+#ifndef KVS_MAX_ENTRIES
+#define KVS_MAX_ENTRIES 75 // Available key slot count for Kvs Key mapping.
+#endif
+
+static_assert((KVS_MAX_ENTRIES <= 255), "Implementation supports up to 255 Kvs entries");
+static_assert((KVS_MAX_ENTRIES >= 30), "Mininimal Kvs entries requirement is not met");
+
 namespace chip {
 namespace DeviceLayer {
 namespace Internal {
@@ -46,78 +53,94 @@
  * the template class (e.g. the ReadConfigValue() method).
  */
 
-// Silabs NVM3 objects use a 20-bit number, however User key range is
-// restricted to 16 bits i.e. 0x0000 -> 0xFFFF.
-// e.g. key = 0xA201
+// Silabs NVM3 objects use a 20-bit number,
+// NVM3 Key 19:16 Stack region
+// NVM3 Key 15:0 Available NVM3 keys 0x0000 -> 0xFFFF.
+// e.g. key = 0x0AA201
+// '0A' = Matter nvm3 region
 // 'A2' = the nv group base offest (Factory, Config or Counter)
 // '01' = the id offset inside the group.
+constexpr uint32_t kMatterNvm3KeyDomain = 0x0A0000U;
 constexpr inline uint32_t EFR32ConfigKey(uint8_t keyBaseOffset, uint8_t id)
 {
-    return static_cast<uint32_t>(keyBaseOffset) << 8 | id;
+    return kMatterNvm3KeyDomain | static_cast<uint32_t>(keyBaseOffset) << 8 | id;
 }
 
 class EFR32Config
 {
 public:
-public:
     // Definitions for Silicon Labs EFR32 NVM3 driver:-
 
     using Key = uint32_t;
 
     // NVM3 key base offsets used by the CHIP Device Layer.
-    static constexpr uint8_t kChipFactory_KeyBase =
-        0xA2; // Persistent config values set at manufacturing time. Retained during factory reset.
-    static constexpr uint8_t kChipConfig_KeyBase = 0xA3; // Persistent config values set at runtime. Cleared during factory reset.
-    static constexpr uint8_t kChipCounter_KeyBase =
-        0xA4; // Persistent counter values set at runtime. Retained during factory reset.
+    // Persistent config values set at manufacturing time. Retained during factory reset.
+    static constexpr uint8_t kMatterFactory_KeyBase = 0xA2;
+    // Persistent config values set at runtime. Cleared during factory reset.
+    static constexpr uint8_t kMatterConfig_KeyBase = 0xA3;
+    // Persistent counter values set at runtime. Retained during factory reset.
+    static constexpr uint8_t kMatterCounter_KeyBase = 0xA4;
+    // Persistent config values set at runtime. Cleared during factory reset.
+    static constexpr uint8_t kMatterKvs_KeyBase = 0xA5;
 
     // Key definitions for well-known configuration values.
     // Factory config keys
-    static constexpr Key kConfigKey_SerialNum             = EFR32ConfigKey(kChipFactory_KeyBase, 0x00);
-    static constexpr Key kConfigKey_MfrDeviceId           = EFR32ConfigKey(kChipFactory_KeyBase, 0x01);
-    static constexpr Key kConfigKey_MfrDeviceCert         = EFR32ConfigKey(kChipFactory_KeyBase, 0x02);
-    static constexpr Key kConfigKey_MfrDevicePrivateKey   = EFR32ConfigKey(kChipFactory_KeyBase, 0x03);
-    static constexpr Key kConfigKey_ManufacturingDate     = EFR32ConfigKey(kChipFactory_KeyBase, 0x04);
-    static constexpr Key kConfigKey_SetupPinCode          = EFR32ConfigKey(kChipFactory_KeyBase, 0x05);
-    static constexpr Key kConfigKey_MfrDeviceICACerts     = EFR32ConfigKey(kChipFactory_KeyBase, 0x06);
-    static constexpr Key kConfigKey_SetupDiscriminator    = EFR32ConfigKey(kChipFactory_KeyBase, 0x07);
-    static constexpr Key kConfigKey_Spake2pIterationCount = EFR32ConfigKey(kChipFactory_KeyBase, 0x08);
-    static constexpr Key kConfigKey_Spake2pSalt           = EFR32ConfigKey(kChipFactory_KeyBase, 0x09);
-    static constexpr Key kConfigKey_Spake2pVerifier       = EFR32ConfigKey(kChipFactory_KeyBase, 0x0A);
-    // CHIP Config Keys
-    static constexpr Key kConfigKey_FabricId           = EFR32ConfigKey(kChipConfig_KeyBase, 0x00);
-    static constexpr Key kConfigKey_ServiceConfig      = EFR32ConfigKey(kChipConfig_KeyBase, 0x01);
-    static constexpr Key kConfigKey_PairedAccountId    = EFR32ConfigKey(kChipConfig_KeyBase, 0x02);
-    static constexpr Key kConfigKey_ServiceId          = EFR32ConfigKey(kChipConfig_KeyBase, 0x03);
-    static constexpr Key kConfigKey_FabricSecret       = EFR32ConfigKey(kChipConfig_KeyBase, 0x04);
-    static constexpr Key kConfigKey_LastUsedEpochKeyId = EFR32ConfigKey(kChipConfig_KeyBase, 0x05);
-    static constexpr Key kConfigKey_FailSafeArmed      = EFR32ConfigKey(kChipConfig_KeyBase, 0x06);
-    static constexpr Key kConfigKey_GroupKey           = EFR32ConfigKey(kChipConfig_KeyBase, 0x07);
-    static constexpr Key kConfigKey_HardwareVersion    = EFR32ConfigKey(kChipConfig_KeyBase, 0x08);
-    static constexpr Key kConfigKey_RegulatoryLocation = EFR32ConfigKey(kChipConfig_KeyBase, 0x09);
-    static constexpr Key kConfigKey_CountryCode        = EFR32ConfigKey(kChipConfig_KeyBase, 0x0A);
-    static constexpr Key kConfigKey_Breadcrumb         = EFR32ConfigKey(kChipConfig_KeyBase, 0x0B);
-    static constexpr Key kConfigKey_WiFiSSID           = EFR32ConfigKey(kChipConfig_KeyBase, 0x0C);
-    static constexpr Key kConfigKey_WiFiPSK            = EFR32ConfigKey(kChipConfig_KeyBase, 0x0D);
-    static constexpr Key kConfigKey_WiFiSEC            = EFR32ConfigKey(kChipConfig_KeyBase, 0x0E);
-    static constexpr Key kConfigKey_GroupKeyBase       = EFR32ConfigKey(kChipConfig_KeyBase, 0x0F);
-    static constexpr Key kConfigKey_GroupKeyMax = EFR32ConfigKey(kChipConfig_KeyBase, 0x1E); // Allows 16 Group Keys to be created.
-    static constexpr Key kConfigKey_UniqueId    = EFR32ConfigKey(kChipFactory_KeyBase, 0x1F);
+    static constexpr Key kConfigKey_SerialNum             = EFR32ConfigKey(kMatterFactory_KeyBase, 0x00);
+    static constexpr Key kConfigKey_MfrDeviceId           = EFR32ConfigKey(kMatterFactory_KeyBase, 0x01);
+    static constexpr Key kConfigKey_MfrDeviceCert         = EFR32ConfigKey(kMatterFactory_KeyBase, 0x02);
+    static constexpr Key kConfigKey_MfrDevicePrivateKey   = EFR32ConfigKey(kMatterFactory_KeyBase, 0x03);
+    static constexpr Key kConfigKey_ManufacturingDate     = EFR32ConfigKey(kMatterFactory_KeyBase, 0x04);
+    static constexpr Key kConfigKey_SetupPinCode          = EFR32ConfigKey(kMatterFactory_KeyBase, 0x05);
+    static constexpr Key kConfigKey_MfrDeviceICACerts     = EFR32ConfigKey(kMatterFactory_KeyBase, 0x06);
+    static constexpr Key kConfigKey_SetupDiscriminator    = EFR32ConfigKey(kMatterFactory_KeyBase, 0x07);
+    static constexpr Key kConfigKey_Spake2pIterationCount = EFR32ConfigKey(kMatterFactory_KeyBase, 0x08);
+    static constexpr Key kConfigKey_Spake2pSalt           = EFR32ConfigKey(kMatterFactory_KeyBase, 0x09);
+    static constexpr Key kConfigKey_Spake2pVerifier       = EFR32ConfigKey(kMatterFactory_KeyBase, 0x0A);
+    // Matter Config Keys
+    static constexpr Key kConfigKey_FabricId           = EFR32ConfigKey(kMatterConfig_KeyBase, 0x00);
+    static constexpr Key kConfigKey_ServiceConfig      = EFR32ConfigKey(kMatterConfig_KeyBase, 0x01);
+    static constexpr Key kConfigKey_PairedAccountId    = EFR32ConfigKey(kMatterConfig_KeyBase, 0x02);
+    static constexpr Key kConfigKey_ServiceId          = EFR32ConfigKey(kMatterConfig_KeyBase, 0x03);
+    static constexpr Key kConfigKey_FabricSecret       = EFR32ConfigKey(kMatterConfig_KeyBase, 0x04);
+    static constexpr Key kConfigKey_LastUsedEpochKeyId = EFR32ConfigKey(kMatterConfig_KeyBase, 0x05);
+    static constexpr Key kConfigKey_FailSafeArmed      = EFR32ConfigKey(kMatterConfig_KeyBase, 0x06);
+    static constexpr Key kConfigKey_GroupKey           = EFR32ConfigKey(kMatterConfig_KeyBase, 0x07);
+    static constexpr Key kConfigKey_HardwareVersion    = EFR32ConfigKey(kMatterConfig_KeyBase, 0x08);
+    static constexpr Key kConfigKey_RegulatoryLocation = EFR32ConfigKey(kMatterConfig_KeyBase, 0x09);
+    static constexpr Key kConfigKey_CountryCode        = EFR32ConfigKey(kMatterConfig_KeyBase, 0x0A);
+    static constexpr Key kConfigKey_Breadcrumb         = EFR32ConfigKey(kMatterConfig_KeyBase, 0x0B);
+    static constexpr Key kConfigKey_WiFiSSID           = EFR32ConfigKey(kMatterConfig_KeyBase, 0x0C);
+    static constexpr Key kConfigKey_WiFiPSK            = EFR32ConfigKey(kMatterConfig_KeyBase, 0x0D);
+    static constexpr Key kConfigKey_WiFiSEC            = EFR32ConfigKey(kMatterConfig_KeyBase, 0x0E);
+    static constexpr Key kConfigKey_GroupKeyBase       = EFR32ConfigKey(kMatterConfig_KeyBase, 0x0F);
+    static constexpr Key kConfigKey_GroupKeyMax =
+        EFR32ConfigKey(kMatterConfig_KeyBase, 0x1E); // Allows 16 Group Keys to be created.
+    static constexpr Key kConfigKey_UniqueId = EFR32ConfigKey(kMatterFactory_KeyBase, 0x1F);
 
-    // CHIP Counter Keys
-    static constexpr Key kConfigKey_BootCount             = EFR32ConfigKey(kChipCounter_KeyBase, 0x00);
-    static constexpr Key kConfigKey_TotalOperationalHours = EFR32ConfigKey(kChipCounter_KeyBase, 0x01);
+    // Matter Counter Keys
+    static constexpr Key kConfigKey_BootCount             = EFR32ConfigKey(kMatterCounter_KeyBase, 0x00);
+    static constexpr Key kConfigKey_TotalOperationalHours = EFR32ConfigKey(kMatterCounter_KeyBase, 0x01);
+
+    // Matter KVS storage Keys
+    static constexpr Key kConfigKey_KvsStringKeyMap = EFR32ConfigKey(kMatterKvs_KeyBase, 0x00);
+    static constexpr Key kConfigKey_KvsFirstKeySlot = EFR32ConfigKey(kMatterKvs_KeyBase, 0x01);
+    static constexpr Key kConfigKey_KvsLastKeySlot  = EFR32ConfigKey(kMatterKvs_KeyBase, KVS_MAX_ENTRIES);
 
     // Set key id limits for each group.
-    static constexpr Key kMinConfigKey_ChipFactory = EFR32ConfigKey(kChipFactory_KeyBase, 0x00);
-    static constexpr Key kMaxConfigKey_ChipFactory = EFR32ConfigKey(kChipFactory_KeyBase, 0x0A);
-    static constexpr Key kMinConfigKey_ChipConfig  = EFR32ConfigKey(kChipConfig_KeyBase, 0x00);
-    static constexpr Key kMaxConfigKey_ChipConfig  = EFR32ConfigKey(kChipConfig_KeyBase, 0x1B);
-    static constexpr Key kMinConfigKey_ChipCounter = EFR32ConfigKey(kChipCounter_KeyBase, 0x00);
-    static constexpr Key kMaxConfigKey_ChipCounter =
-        EFR32ConfigKey(kChipCounter_KeyBase, 0x1F); // Allows 32 Counters to be created.
+    static constexpr Key kMinConfigKey_MatterFactory = EFR32ConfigKey(kMatterFactory_KeyBase, 0x00);
+    static constexpr Key kMaxConfigKey_MatterFactory = EFR32ConfigKey(kMatterFactory_KeyBase, 0x0A);
+    static constexpr Key kMinConfigKey_MatterConfig  = EFR32ConfigKey(kMatterConfig_KeyBase, 0x00);
+    static constexpr Key kMaxConfigKey_MatterConfig  = EFR32ConfigKey(kMatterConfig_KeyBase, 0x1B);
+
+    // Allows 32 Counters to be created.
+    static constexpr Key kMinConfigKey_MatterCounter = EFR32ConfigKey(kMatterCounter_KeyBase, 0x00);
+    static constexpr Key kMaxConfigKey_MatterCounter = EFR32ConfigKey(kMatterCounter_KeyBase, 0x1F);
+
+    static constexpr Key kMinConfigKey_MatterKvs = EFR32ConfigKey(kMatterKvs_KeyBase, 0x00);
+    static constexpr Key kMaxConfigKey_MatterKvs = EFR32ConfigKey(kMatterKvs_KeyBase, 0xFF);
 
     static CHIP_ERROR Init(void);
+    static void DeInit(void);
 
     // Configuration methods used by the GenericConfigurationManagerImpl<> template.
     static CHIP_ERROR ReadConfigValue(Key key, bool & val);
@@ -125,6 +148,7 @@
     static CHIP_ERROR ReadConfigValue(Key key, uint64_t & val);
     static CHIP_ERROR ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen);
     static CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen);
+    static CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen, size_t offset);
     static CHIP_ERROR ReadConfigValueCounter(uint8_t counterIdx, uint32_t & val);
     static CHIP_ERROR WriteConfigValue(Key key, bool val);
     static CHIP_ERROR WriteConfigValue(Key key, uint32_t val);
@@ -147,7 +171,6 @@
 
 private:
     static CHIP_ERROR MapNvm3Error(Ecode_t nvm3Res);
-    static void OnExit(void);
 };
 
 } // namespace Internal
diff --git a/src/platform/EFR32/KeyValueStoreManagerImpl.cpp b/src/platform/EFR32/KeyValueStoreManagerImpl.cpp
index 28f6ea4..d46079f 100644
--- a/src/platform/EFR32/KeyValueStoreManagerImpl.cpp
+++ b/src/platform/EFR32/KeyValueStoreManagerImpl.cpp
@@ -21,122 +21,183 @@
  *          Platform-specific key value storage implementation for EFR32
  */
 
+#include <lib/support/CodeUtils.h>
+#include <platform/CHIPDeviceLayer.h>
+#include <platform/EFR32/EFR32Config.h>
 #include <platform/KeyValueStoreManager.h>
+#include <stdio.h>
+#include <string.h>
 
-/* ignore GCC Wconversion warnings for pigweed */
-#if defined(__GNUC__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wconversion"
-#endif
+using namespace ::chip;
+using namespace ::chip::DeviceLayer::Internal;
 
-#include <pw_log/log.h>
-
-#if defined(__GNUC__)
-#pragma GCC diagnostic pop
-#endif
+#define CONVERT_KEYMAP_INDEX_TO_NVM3KEY(index) (EFR32Config::kConfigKey_KvsFirstKeySlot + index)
+#define CONVERT_NVM3KEY_TO_KEYMAP_INDEX(nvm3Key) (nvm3Key - EFR32Config::kConfigKey_KvsFirstKeySlot)
 
 namespace chip {
 namespace DeviceLayer {
 namespace PersistedStorage {
 
 KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance;
+char mKvsStoredKeyString[KeyValueStoreManagerImpl::kMaxEntries][PersistentStorageDelegate::kKeyLengthMax + 1];
 
-#if defined(CHIP_KVS_AVAILABLE) && CHIP_KVS_AVAILABLE
+CHIP_ERROR KeyValueStoreManagerImpl::Init(void)
+{
+    CHIP_ERROR err;
+    err = EFR32Config::Init();
+    SuccessOrExit(err);
+
+    memset(mKvsStoredKeyString, 0, sizeof(mKvsStoredKeyString));
+    size_t outLen;
+    err = EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_KvsStringKeyMap, reinterpret_cast<uint8_t *>(mKvsStoredKeyString),
+                                          sizeof(mKvsStoredKeyString), outLen);
+
+    if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) // Initial boot
+    {
+        err = CHIP_NO_ERROR;
+    }
+
+exit:
+    return err;
+}
+
+bool KeyValueStoreManagerImpl::IsValidKvsNvm3Key(uint32_t nvm3Key) const
+{
+    return ((EFR32Config::kConfigKey_KvsFirstKeySlot <= nvm3Key) && (nvm3Key <= EFR32Config::kConfigKey_KvsLastKeySlot));
+}
+
+CHIP_ERROR KeyValueStoreManagerImpl::MapKvsKeyToNvm3(const char * key, uint32_t & nvm3Key, bool isSlotNeeded) const
+{
+    CHIP_ERROR err;
+    uint8_t firstEmptyKeySlot = kMaxEntries;
+    for (uint8_t keyIndex = 0; keyIndex < kMaxEntries; keyIndex++)
+    {
+        if (strcmp(key, mKvsStoredKeyString[keyIndex]) == 0)
+        {
+            nvm3Key = CONVERT_KEYMAP_INDEX_TO_NVM3KEY(keyIndex);
+            VerifyOrDie(IsValidKvsNvm3Key(nvm3Key) == true);
+            return CHIP_NO_ERROR;
+        }
+
+        if (isSlotNeeded && (firstEmptyKeySlot == kMaxEntries) && (mKvsStoredKeyString[keyIndex][0] == 0))
+        {
+            firstEmptyKeySlot = keyIndex;
+        }
+    }
+
+    if (isSlotNeeded)
+    {
+        if (firstEmptyKeySlot != kMaxEntries)
+        {
+            nvm3Key = CONVERT_KEYMAP_INDEX_TO_NVM3KEY(firstEmptyKeySlot);
+            VerifyOrDie(IsValidKvsNvm3Key(nvm3Key) == true);
+            err = CHIP_NO_ERROR;
+        }
+        else
+        {
+            err = CHIP_ERROR_PERSISTED_STORAGE_FAILED;
+        }
+    }
+    else
+    {
+        err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
+    }
+    return err;
+}
+
+void KeyValueStoreManagerImpl::OnScheduledKeyMapSave(System::Layer * systemLayer, void * appState)
+{
+    EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_KvsStringKeyMap,
+                                     reinterpret_cast<const uint8_t *>(mKvsStoredKeyString), sizeof(mKvsStoredKeyString));
+}
+
+void KeyValueStoreManagerImpl::ScheduleKeyMapSave(void)
+{
+    /*
+        During commissioning, the key map will be modified multiples times subsequently.
+        Commit the key map in nvm once it as stabilized.
+    */
+    SystemLayer().StartTimer(std::chrono::duration_cast<System::Clock::Timeout>(System::Clock::Seconds32(5)),
+                             KeyValueStoreManagerImpl::OnScheduledKeyMapSave, NULL);
+}
 
 CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size,
                                           size_t offset_bytes) const
 {
-    assert(CHIP_KVS_AVAILABLE);
-    auto status_and_size = mKvs.Get(key, std::span<std::byte>(reinterpret_cast<std::byte *>(value), value_size), offset_bytes);
+    VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrReturnError(value != 0, CHIP_ERROR_INVALID_ARGUMENT);
+
+    uint32_t nvm3Key;
+    CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key);
+    VerifyOrReturnError(err == CHIP_NO_ERROR, err);
+
+    size_t outLen;
+    err = EFR32Config::ReadConfigValueBin(nvm3Key, reinterpret_cast<uint8_t *>(value), value_size, outLen, offset_bytes);
     if (read_bytes_size)
     {
-        *read_bytes_size = status_and_size.size();
+        *read_bytes_size = outLen;
     }
-    switch (status_and_size.status().code())
-    {
-    case pw::OkStatus().code():
-        return CHIP_NO_ERROR;
-    case pw::Status::NotFound().code():
-        return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
-    case pw::Status::DataLoss().code():
-        return CHIP_ERROR_INTEGRITY_CHECK_FAILED;
-    case pw::Status::ResourceExhausted().code():
-        return CHIP_ERROR_BUFFER_TOO_SMALL;
-    case pw::Status::FailedPrecondition().code():
-        return CHIP_ERROR_WELL_UNINITIALIZED;
-    case pw::Status::InvalidArgument().code():
-        return CHIP_ERROR_INVALID_ARGUMENT;
-    default:
-        break;
-    }
-    return CHIP_ERROR_INTERNAL; // Unexpected KVS status.
+
+    return err;
 }
 
 CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value, size_t value_size)
 {
-    assert(CHIP_KVS_AVAILABLE);
-    auto status = mKvs.Put(key, std::span<const std::byte>(reinterpret_cast<const std::byte *>(value), value_size));
-    switch (status.code())
+    VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+
+    uint32_t nvm3Key;
+    CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key, /* isSlotNeeded */ true);
+    VerifyOrReturnError(err == CHIP_NO_ERROR, err);
+
+    err = EFR32Config::WriteConfigValueBin(nvm3Key, reinterpret_cast<const uint8_t *>(value), value_size);
+    if (err == CHIP_NO_ERROR)
     {
-    case pw::OkStatus().code():
-        return CHIP_NO_ERROR;
-    case pw::Status::DataLoss().code():
-        return CHIP_ERROR_INTEGRITY_CHECK_FAILED;
-    case pw::Status::ResourceExhausted().code():
-    case pw::Status::AlreadyExists().code():
-        return CHIP_ERROR_PERSISTED_STORAGE_FAILED;
-    case pw::Status::FailedPrecondition().code():
-        return CHIP_ERROR_WELL_UNINITIALIZED;
-    case pw::Status::InvalidArgument().code():
-        return CHIP_ERROR_INVALID_ARGUMENT;
-    default:
-        break;
+        uint32_t keyIndex = nvm3Key - EFR32Config::kConfigKey_KvsFirstKeySlot;
+        strncpy(mKvsStoredKeyString[keyIndex], key, sizeof(mKvsStoredKeyString[keyIndex]) - 1);
+        ScheduleKeyMapSave();
     }
-    return CHIP_ERROR_INTERNAL; // Unexpected KVS status.
+
+    return err;
 }
 
 CHIP_ERROR KeyValueStoreManagerImpl::_Delete(const char * key)
 {
-    assert(CHIP_KVS_AVAILABLE);
-    auto status = mKvs.Delete(key);
-    switch (status.code())
+    VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+
+    uint32_t nvm3Key;
+    CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key);
+    VerifyOrReturnError(err == CHIP_NO_ERROR, err);
+
+    err = EFR32Config::ClearConfigValue(nvm3Key);
+    if (err == CHIP_NO_ERROR)
     {
-    case pw::OkStatus().code():
-        return CHIP_NO_ERROR;
-    case pw::Status::NotFound().code():
-        return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
-    case pw::Status::DataLoss().code():
-        return CHIP_ERROR_INTEGRITY_CHECK_FAILED;
-    case pw::Status::ResourceExhausted().code():
-        return CHIP_ERROR_PERSISTED_STORAGE_FAILED;
-    case pw::Status::FailedPrecondition().code():
-        return CHIP_ERROR_WELL_UNINITIALIZED;
-    case pw::Status::InvalidArgument().code():
-        return CHIP_ERROR_INVALID_ARGUMENT;
-    default:
-        break;
+        uint32_t keyIndex = CONVERT_NVM3KEY_TO_KEYMAP_INDEX(nvm3Key);
+        memset(mKvsStoredKeyString[keyIndex], 0, sizeof(mKvsStoredKeyString[keyIndex]));
+        ScheduleKeyMapSave();
     }
-    return CHIP_ERROR_INTERNAL; // Unexpected KVS status.
+
+    return err;
 }
 
-CHIP_ERROR KeyValueStoreManagerImpl::ErasePartition()
+CHIP_ERROR KeyValueStoreManagerImpl::ErasePartition(void)
 {
-    assert(CHIP_KVS_AVAILABLE);
-    auto status = mKvsPartition.Erase();
-    switch (status.code())
+    // Iterate over all the Matter Kvs nvm3 records and delete each one...
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    for (uint32_t nvm3Key = EFR32Config::kMinConfigKey_MatterKvs; nvm3Key < EFR32Config::kMaxConfigKey_MatterKvs; nvm3Key++)
     {
-    case pw::OkStatus().code():
-        return CHIP_NO_ERROR;
-    case pw::Status::DeadlineExceeded().code():
-        return CHIP_ERROR_TIMEOUT;
-    case pw::Status::PermissionDenied().code():
-        return CHIP_ERROR_ACCESS_DENIED;
-    default:
-        break;
+        err = EFR32Config::ClearConfigValue(nvm3Key);
+
+        if (err != CHIP_NO_ERROR)
+        {
+            break;
+        }
     }
-    return CHIP_ERROR_INTERNAL; // Unexpected KVS status.
+
+    memset(mKvsStoredKeyString, 0, sizeof(mKvsStoredKeyString));
+    return err;
 }
-#endif // defined(CHIP_KVS_AVAILABLE) && CHIP_KVS_AVAILABLE
 
 } // namespace PersistedStorage
 } // namespace DeviceLayer
diff --git a/src/platform/EFR32/KeyValueStoreManagerImpl.h b/src/platform/EFR32/KeyValueStoreManagerImpl.h
index 32650db..daf5ff8 100644
--- a/src/platform/EFR32/KeyValueStoreManagerImpl.h
+++ b/src/platform/EFR32/KeyValueStoreManagerImpl.h
@@ -23,35 +23,14 @@
  */
 
 #pragma once
-
-#include "em_msc.h"
-
-/* ignore GCC Wconversion warnings for pigweed */
-#if defined(__GNUC__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wconversion"
-#endif
-
-#include <pw_kvs/crc16_checksum.h>
-#include <pw_kvs/flash_memory.h>
-#include <pw_kvs/key_value_store.h>
-
-#if defined(__GNUC__)
-#pragma GCC diagnostic pop
-#endif
-
-// KVS is only available for EFR32 when these macros are defined.
-#if defined(CHIP_KVS_SECTOR_COUNT) && defined(CHIP_KVS_BASE_SECTOR_INDEX)
-#define CHIP_KVS_AVAILABLE 1
-#else // defined(CHIP_KVS_SECTOR_COUNT) && defined(CHIP_KVS_BASE_ADDRESS)
-#define CHIP_KVS_AVAILABLE 0
-#endif // defined(CHIP_KVS_SECTOR_COUNT) && defined(CHIP_KVS_BASE_ADDRESS)
+#include <lib/core/CHIPPersistentStorageDelegate.h>
+#include <system/SystemClock.h>
+#include <system/SystemLayer.h>
 
 namespace chip {
 namespace DeviceLayer {
 namespace PersistedStorage {
 
-#if defined(CHIP_KVS_AVAILABLE) && CHIP_KVS_AVAILABLE
 class KeyValueStoreManagerImpl final : public KeyValueStoreManager
 {
     // Allow the KeyValueStoreManager interface class to delegate method calls to
@@ -59,136 +38,27 @@
     friend class KeyValueStoreManager;
 
 public:
-    void Init() { mKvs.Init(); }
-
-    CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0) const;
-
-    CHIP_ERROR _Delete(const char * key);
-
-    /**
-     * @brief
-     * Erases all data in the KVS partition, KVS needs to be initialized after
-     * this operation.
-     *
-     * @return CHIP_NO_ERROR the partiton was erased.
-     *         CHIP_ERROR_TIMEOUT timed out while doing erase.
-     *         CHIP_ERROR_ACCESS_DENIED flash locked, erase failed.
-     */
-    CHIP_ERROR ErasePartition();
-
+    CHIP_ERROR Init(void);
     CHIP_ERROR _Put(const char * key, const void * value, size_t value_size);
+    CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0) const;
+    CHIP_ERROR _Delete(const char * key);
+    CHIP_ERROR ErasePartition(void);
+
+    static constexpr size_t kMaxEntries = KVS_MAX_ENTRIES;
 
 private:
-    // KVS flash interface
-    class Efr32FlashMemory : public pw::kvs::FlashMemory
-    {
-    public:
-        Efr32FlashMemory() : pw::kvs::FlashMemory(FLASH_PAGE_SIZE, FLASH_SIZE / FLASH_PAGE_SIZE, sizeof(uint32_t), FLASH_BASE) {}
+    static void OnScheduledKeyMapSave(System::Layer * systemLayer, void * appState);
+    void ScheduleKeyMapSave(void);
+    bool IsValidKvsNvm3Key(const uint32_t nvm3Key) const;
+    CHIP_ERROR MapKvsKeyToNvm3(const char * key, uint32_t & nvm3Key, bool isSlotNeeded = false) const;
 
-        // Enabling flash handled by platform
-        pw::Status Enable() override { return pw::OkStatus(); }
-        pw::Status Disable() override { return pw::OkStatus(); }
-        bool IsEnabled() const override { return true; }
-
-        pw::Status Erase(Address flash_address, size_t num_sectors) override
-        {
-            assert((flash_address % sizeof(uint32_t)) == 0);
-            for (size_t i = 0; i < num_sectors; i++)
-            {
-                auto status =
-                    MscStatusToPwStatus(MSC_ErasePage(reinterpret_cast<uint32_t *>(flash_address + i * sector_size_bytes())));
-                if (!status.ok())
-                {
-                    return status;
-                }
-            }
-            return pw::OkStatus();
-        }
-
-        pw::StatusWithSize Read(Address address, std::span<std::byte> output) override
-        {
-            memcpy(output.data(), reinterpret_cast<void *>(address), output.size());
-            return pw::StatusWithSize(output.size());
-        }
-
-        pw::StatusWithSize Write(Address destination_flash_address, std::span<const std::byte> data) override
-        {
-            assert((destination_flash_address % sizeof(uint32_t)) == 0);
-            return pw::StatusWithSize(MscStatusToPwStatus(MSC_WriteWord(reinterpret_cast<uint32_t *>(destination_flash_address),
-                                                                        data.data(), data.size())),
-                                      data.size());
-        }
-
-    private:
-        static pw::Status MscStatusToPwStatus(MSC_Status_TypeDef msc_status)
-        {
-            switch (msc_status)
-            {
-            case mscReturnOk:
-                return pw::OkStatus();
-            case mscReturnUnaligned:
-            case mscReturnInvalidAddr:
-                return pw::Status::InvalidArgument();
-            case mscReturnLocked:
-                return pw::Status::PermissionDenied();
-            case mscReturnTimeOut:
-                return pw::Status::DeadlineExceeded();
-            default:
-                break;
-            }
-            return pw::Status::Internal();
-        }
-    };
-
-    static constexpr size_t kMaxEntries = 50;
-    pw::kvs::ChecksumCrc16 mKvsChecksum;
-    const pw::kvs::EntryFormat kEntryFormat{ .magic = 0x64d51134, .checksum = &mKvsChecksum };
-
-    Efr32FlashMemory mFlash;
-    pw::kvs::FlashPartition mKvsPartition{ &mFlash, CHIP_KVS_BASE_SECTOR_INDEX, CHIP_KVS_SECTOR_COUNT };
-    pw::kvs::KeyValueStoreBuffer<kMaxEntries, CHIP_KVS_SECTOR_COUNT> mKvs{ &mKvsPartition, kEntryFormat };
-
-    // ===== Members for internal use by the following friends.
-
+    //  ===== Members for internal use by the following friends.
     friend KeyValueStoreManager & KeyValueStoreMgr();
     friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl();
 
     static KeyValueStoreManagerImpl sInstance;
 };
 
-#else //  defined(CHIP_KVS_AVAILABLE) && CHIP_KVS_AVAILABLE
-
-// Empty implementation which just asserts if used
-class KeyValueStoreManagerImpl final : public KeyValueStoreManager
-{
-public:
-    CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0) const
-    {
-        assert(CHIP_KVS_AVAILABLE);
-        return CHIP_ERROR_NOT_IMPLEMENTED;
-    }
-    CHIP_ERROR _Delete(const char * key)
-    {
-        assert(CHIP_KVS_AVAILABLE);
-        return CHIP_ERROR_NOT_IMPLEMENTED;
-    }
-    CHIP_ERROR _Put(const char * key, const void * value, size_t value_size)
-    {
-        assert(CHIP_KVS_AVAILABLE);
-        return CHIP_ERROR_NOT_IMPLEMENTED;
-    }
-
-private:
-    // ===== Members for internal use by the following friends.
-
-    friend KeyValueStoreManager & KeyValueStoreMgr();
-    friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl();
-
-    static KeyValueStoreManagerImpl sInstance;
-};
-
-#endif //  defined(CHIP_KVS_AVAILABLE) && CHIP_KVS_AVAILABLE
-
 /**
  * Returns the public interface of the KeyValueStoreManager singleton object.
  *
diff --git a/src/platform/EFR32/PlatformManagerImpl.cpp b/src/platform/EFR32/PlatformManagerImpl.cpp
index 5acf098..391e2be 100644
--- a/src/platform/EFR32/PlatformManagerImpl.cpp
+++ b/src/platform/EFR32/PlatformManagerImpl.cpp
@@ -26,6 +26,7 @@
 
 #include <platform/EFR32/DiagnosticDataProviderImpl.h>
 #include <platform/FreeRTOS/SystemTimeSupport.h>
+#include <platform/KeyValueStoreManager.h>
 #include <platform/PlatformManager.h>
 #include <platform/internal/GenericPlatformManagerImpl_FreeRTOS.ipp>
 
@@ -44,8 +45,9 @@
     CHIP_ERROR err;
 
     // Initialize the configuration system.
-    err = Internal::EFR32Config::Init();
+    err = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init();
     SuccessOrExit(err);
+
     SetConfigurationMgr(&ConfigurationManagerImpl::GetDefaultInstance());
     SetDiagnosticDataProvider(&DiagnosticDataProviderImpl::GetDefaultInstance());
 
diff --git a/src/test_driver/efr32/src/main.cpp b/src/test_driver/efr32/src/main.cpp
index a99e39e..c3d6028 100644
--- a/src/test_driver/efr32/src/main.cpp
+++ b/src/test_driver/efr32/src/main.cpp
@@ -186,7 +186,6 @@
     mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree);
 
     chip::Platform::MemoryInit();
-    chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init();
 
     chip::DeviceLayer::PlatformMgr().InitChipStack();