From fe6b09a7acda62d91b4b3ea6a609558c43cb6b54 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 13 Dec 2024 00:56:33 +0200 Subject: [PATCH] lib: fast-get: Implement fast_get() and fast_put() functions Implement fast_get() and fast_put() functions. The purpose of these functions is to maintain shared SRAM copies of data stored in DRAM. fast_get() First checks if there is already an SRAM copy of the same DRAM chunk. If there isn't reserve an SRAM chunk of the same size and copy the contents there, store the both pointers, size and reference count to in an internal data structure, and return the SRAM pointer. If there is, return the pointer to the existing SRAM copy and increase the reference count. fast_put() Look up the internal data record based on the SRAM address and decrement reference count. Free the SRAM chunk and the data record if reference count reaches zero, Signed-off-by: Jyri Sarha --- Kconfig.sof | 11 +++ src/include/sof/lib/fast-get.h | 16 +++ src/lib/fast-get.c | 171 +++++++++++++++++++++++++++++++++ zephyr/CMakeLists.txt | 2 + 4 files changed, 200 insertions(+) create mode 100644 src/include/sof/lib/fast-get.h create mode 100644 src/lib/fast-get.c diff --git a/Kconfig.sof b/Kconfig.sof index 0833201e817d..5c3ea8755fe9 100644 --- a/Kconfig.sof +++ b/Kconfig.sof @@ -122,6 +122,17 @@ config COMPILER_INLINE_FUNCTION_OPTION help When enabled, -fno-inline-function option is not passed to compiler +config FAST_GET + bool "Enable simple refcounting dram data copier" + default n + help + Enable simple refcounting DRAM data copier for copying processing + module data from DRAM to SRAM when the data is needed and freeing + the SRAM when the data is not needed anymore. If multiple module + instances need the same chunk the same copy is used with reference + counting. Source is src/lib/gast-get.c. The option should be selected + by the modules using it. + rsource "src/Kconfig" # See zephyr/modules/Kconfig diff --git a/src/include/sof/lib/fast-get.h b/src/include/sof/lib/fast-get.h new file mode 100644 index 000000000000..cef1d3915fb4 --- /dev/null +++ b/src/include/sof/lib/fast-get.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2024 Intel Corporation. All rights reserved. + * + * Author: Jyri Sarha + */ + +#ifndef __SOF_LIB_FAST_GET_H__ +#define __SOF_LIB_FAST_GET_H__ + +#include + +void *fast_get(const void * const dram_ptr, size_t size); +void fast_put(void *sram_ptr); + +#endif /* __SOF_LIB_FAST_GET_H__ */ diff --git a/src/lib/fast-get.c b/src/lib/fast-get.c new file mode 100644 index 000000000000..f8767ea238e5 --- /dev/null +++ b/src/lib/fast-get.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Intel Corporation. All rights reserved. +// +// Author: Jyri Sarha + +#include +#include +#include + +#include +#include +#include +#include + +/* for cmocka environment */ +#ifndef EXPORT_SYMBOL +#define EXPORT_SYMBOL(a) +#endif + +struct sof_fast_get_entry { + const void *dram_ptr; + void *sram_ptr; + size_t size; + uint32_t refcount; +}; + +struct sof_fast_get_data { + struct k_spinlock lock; + size_t num_entries; + struct sof_fast_get_entry *entries; +}; + +static struct sof_fast_get_data fast_get_data = { + .num_entries = 0, + .entries = NULL, +}; + +LOG_MODULE_REGISTER(fast_get, CONFIG_SOF_LOG_LEVEL); + +static inline +int fast_get_realloc(struct sof_fast_get_data *data) +{ + struct sof_fast_get_entry *entries; + + if (!data->num_entries) { + data->entries = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + 32 * sizeof(*entries)); + if (!data->entries) + return -ENOMEM; + data->num_entries = 32; + return 0; + } + + entries = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + 2 * data->num_entries * sizeof(*entries)); + if (!entries) + return -ENOMEM; + + memcpy_s(entries, 2 * data->num_entries * sizeof(*entries), data->entries, + data->num_entries * sizeof(*entries)); + rfree(data->entries); + data->entries = entries; + data->num_entries = 2 * data->num_entries; + return 0; +} + +static inline +struct sof_fast_get_entry *fast_get_find_entry(struct sof_fast_get_data *data, + const void *dram_ptr) +{ + int i; + + for (i = 0; i < data->num_entries; i++) { + if (data->entries[i].dram_ptr == dram_ptr) + return &data->entries[i]; + } + + for (i = 0; i < data->num_entries; i++) { + if (data->entries[i].dram_ptr == NULL) + return &data->entries[i]; + } + + return NULL; +} + +void *fast_get(const void *dram_ptr, size_t size) +{ + struct sof_fast_get_data *data = &fast_get_data; + struct sof_fast_get_entry *entry; + k_spinlock_key_t key; + void *ret; + + key = k_spin_lock(&data->lock); + do { + entry = fast_get_find_entry(data, dram_ptr); + if (!entry) { + if (fast_get_realloc(data)) { + ret = NULL; + goto out; + } + } + } while (!entry); + + if (entry->sram_ptr) { + if (entry->size != size || entry->dram_ptr != dram_ptr) { + tr_err(fast_get, "size %u != %u or ptr %p != %p mismatch", + entry->size, size, entry->dram_ptr, dram_ptr); + ret = NULL; + goto out; + } + + ret = entry->sram_ptr; + entry->refcount++; + goto out; + } + + ret = rmalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, size); + if (!ret) + goto out; + entry->size = size; + entry->sram_ptr = ret; + memcpy_s(entry->sram_ptr, entry->size, dram_ptr, size); + entry->dram_ptr = dram_ptr; + entry->refcount = 1; +out: + k_spin_unlock(&data->lock, key); + tr_dbg(fast_get, "get %p, %p, size %u, refcnt %u", dram_ptr, ret, size, + entry ? entry->refcount : 0); + + return ret; +} +EXPORT_SYMBOL(fast_get); + +static inline +struct sof_fast_get_entry *fast_put_find_entry(struct sof_fast_get_data *data, + void *sram_ptr) +{ + int i; + + for (i = 0; i < data->num_entries; i++) { + if (data->entries[i].sram_ptr == sram_ptr) + return &data->entries[i]; + } + + return NULL; +} + +void fast_put(void *sram_ptr) +{ + struct sof_fast_get_data *data = &fast_get_data; + struct sof_fast_get_entry *entry; + k_spinlock_key_t key; + + key = k_spin_lock(&fast_get_data.lock); + entry = fast_put_find_entry(data, sram_ptr); + if (!entry) { + tr_err(fast_get, "Put called to unknown address %p", sram_ptr); + goto out; + } + entry->refcount--; + if (entry->refcount > 0) + goto out; + rfree(entry->sram_ptr); + memset(entry, 0, sizeof(*entry)); +out: + tr_dbg(fast_get, "put %p, dram %p size %u refcnt %u", sram_ptr, entry ? entry->dram_ptr : 0, + entry ? entry->size : 0, entry ? entry->refcount : 0); + k_spin_unlock(&data->lock, key); +} +EXPORT_SYMBOL(fast_put); diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 2e96668e119b..42380a104cdd 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -625,6 +625,8 @@ zephyr_library_sources_ifdef(CONFIG_TRACE zephyr_library_sources_ifdef(CONFIG_LOG_BACKEND_SOF_PROBE ${SOF_SRC_PATH}/logging/log_backend_probe.c) +zephyr_library_sources_ifdef(CONFIG_FAST_GET ${SOF_SRC_PATH}/lib/fast-get.c) + # Optional SOF sources - depends on Kconfig - WIP if(CONFIG_IPC_MAJOR_3)