From c3ac598c7f0f386115671140907791188af83e4f Mon Sep 17 00:00:00 2001 From: Aziz Idomar Date: Tue, 27 Jun 2023 08:51:04 +0200 Subject: [PATCH] drivers: introduce hardware spinlock framework The intention of hardware spinlock is to allow two processors, that have no alternative mechanism for accomplish synchronization and mutual exclusion operations, to share resources (such as memory and/or any other element). Here, we add the hwspinlock framework, that makes possible to use those hwspinlock devices and stay platform-independent. Each platform wishing to support hardware spinlock must describe a driver using this framework. Signed-off-by: Aziz Idomar --- drivers/CMakeLists.txt | 1 + drivers/Kconfig | 1 + drivers/hwspinlock/CMakeLists.txt | 5 + drivers/hwspinlock/Kconfig | 19 +++ drivers/hwspinlock/hwspinlock_handlers.c | 40 ++++++ include/zephyr/drivers/hwspinlock.h | 159 +++++++++++++++++++++++ 6 files changed, 225 insertions(+) create mode 100644 drivers/hwspinlock/CMakeLists.txt create mode 100644 drivers/hwspinlock/Kconfig create mode 100644 drivers/hwspinlock/hwspinlock_handlers.c create mode 100644 include/zephyr/drivers/hwspinlock.h diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 6005b4589b6..a9caf9f0320 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -79,3 +79,4 @@ add_subdirectory_ifdef(CONFIG_WATCHDOG watchdog) add_subdirectory_ifdef(CONFIG_WIFI wifi) add_subdirectory_ifdef(CONFIG_RTC rtc) add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_DRIVER sip_svc) +add_subdirectory_ifdef(CONFIG_HWSPINLOCK hwspinlock) diff --git a/drivers/Kconfig b/drivers/Kconfig index d615249727c..0a369875f6f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -82,5 +82,6 @@ source "drivers/watchdog/Kconfig" source "drivers/wifi/Kconfig" source "drivers/xen/Kconfig" source "drivers/sip_svc/Kconfig" +source "drivers/hwspinlock/Kconfig" endmenu diff --git a/drivers/hwspinlock/CMakeLists.txt b/drivers/hwspinlock/CMakeLists.txt new file mode 100644 index 00000000000..458f545f75d --- /dev/null +++ b/drivers/hwspinlock/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_USERSPACE hwspinlock_handlers.c) diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig new file mode 100644 index 00000000000..6b12ca50d59 --- /dev/null +++ b/drivers/hwspinlock/Kconfig @@ -0,0 +1,19 @@ +# HW spinlock configuration options + +# Copyright (c) 2023 Sequans Communications. +# SPDX-License-Identifier: Apache-2.0 + +menuconfig HWSPINLOCK + bool "HW spinlock Support" + help + Include support for HW spinlock. + +if HWSPINLOCK + +config HWSPINLOCK_INIT_PRIORITY + int "HW spinlock init priority" + default KERNEL_INIT_PRIORITY_DEVICE + help + HW spinlock driver device initialization priority. + +endif diff --git a/drivers/hwspinlock/hwspinlock_handlers.c b/drivers/hwspinlock/hwspinlock_handlers.c new file mode 100644 index 00000000000..a8e6c2a132e --- /dev/null +++ b/drivers/hwspinlock/hwspinlock_handlers.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Sequans Communications + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static inline int z_vrfy_hwspinlock_trylock(const struct device *dev, uint32_t id) +{ + Z_OOPS(Z_SYSCALL_DRIVER_HWSPINLOCK(dev, trylock)); + return z_impl_hwspinlock_trylock(dev, id); +} + +#include + +static inline void z_vrfy_hwspinlock_lock(const struct device *dev, uint32_t id) +{ + Z_OOPS(Z_SYSCALL_DRIVER_HWSPINLOCK(dev, lock)); + z_impl_hwspinlock_lock(dev, id); +} + +#include + +static inline void z_vrfy_hwspinlock_unlock(const struct device *dev, uint32_t id) +{ + Z_OOPS(Z_SYSCALL_DRIVER_HWSPINLOCK(dev, unlock)); + z_impl_hwspinlock_unlock(dev, id); +} + +#include + +static inline uint32_t z_vrfy_hwspinlock_get_max_id(const struct device *dev) +{ + Z_OOPS(Z_SYSCALL_DRIVER_HWSPINLOCK(dev, get_max_id)); + return z_impl_hwspinlock_get_max_id(dev); +} + +#include diff --git a/include/zephyr/drivers/hwspinlock.h b/include/zephyr/drivers/hwspinlock.h new file mode 100644 index 00000000000..9f9fd994ea2 --- /dev/null +++ b/include/zephyr/drivers/hwspinlock.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023 Sequans Communications + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_HWSPINLOCK_H_ +#define ZEPHYR_INCLUDE_DRIVERS_HWSPINLOCK_H_ + +/** + * @brief HW spinlock Interface + * @defgroup hwspinlock_interface HW spinlock Interface + * @ingroup io_interfaces + * @{ + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +/** + * @brief Callback API for trying to lock HW spinlock + * @see hwspinlock_trylock(). + */ +typedef int (*hwspinlock_api_trylock)(const struct device *dev, uint32_t id); + +/** + * @brief Callback API to lock HW spinlock + * @see hwspinlock_lock(). + */ +typedef void (*hwspinlock_api_lock)(const struct device *dev, uint32_t id); + +/** + * @brief Callback API to unlock HW spinlock + * @see hwspinlock_unlock(). + */ +typedef void (*hwspinlock_api_unlock)(const struct device *dev, uint32_t id); + +/** + * @brief Callback API to get HW spinlock max ID + * @see hwspinlock_get_max_id(). + */ +typedef uint32_t (*hwspinlock_api_get_max_id)(const struct device *dev); + +__subsystem struct hwspinlock_driver_api { + hwspinlock_api_trylock trylock; + hwspinlock_api_lock lock; + hwspinlock_api_unlock unlock; + hwspinlock_api_get_max_id get_max_id; +}; +/** + * @endcond + */ + +/** + * @brief Try to lock HW spinlock + * + * This function is used for try to lock specific HW spinlock. It should + * be called before a critical section that we want to protect. + * + * @param dev HW spinlock device instance. + * @param id Spinlock identifier. + * + * @retval 0 If successful. + * @retval -errno In case of any failure. + */ +__syscall int hwspinlock_trylock(const struct device *dev, uint32_t id); + +static inline int z_impl_hwspinlock_trylock(const struct device *dev, uint32_t id) +{ + const struct hwspinlock_driver_api *api = + (const struct hwspinlock_driver_api *)dev->api; + + if (api->trylock == NULL) + return -ENOSYS; + + return api->trylock(dev, id); +} + +/** + * @brief Lock HW spinlock + * + * This function is used to lock specific HW spinlock. It should be + * called before a critical section that we want to protect. + * + * @param dev HW spinlock device instance. + * @param id Spinlock identifier. + */ +__syscall void hwspinlock_lock(const struct device *dev, uint32_t id); + +static inline void z_impl_hwspinlock_lock(const struct device *dev, uint32_t id) +{ + const struct hwspinlock_driver_api *api = + (const struct hwspinlock_driver_api *)dev->api; + + if (api->lock != NULL) + api->lock(dev, id); +} + +/** + * @brief Try to unlock HW spinlock + * + * This function is used for try to unlock specific HW spinlock. It should + * be called after a critical section that we want to protect. + * + * @param dev HW spinlock device instance. + * @param id Spinlock identifier. + */ +__syscall void hwspinlock_unlock(const struct device *dev, uint32_t id); + +static inline void z_impl_hwspinlock_unlock(const struct device *dev, uint32_t id) +{ + const struct hwspinlock_driver_api *api = + (const struct hwspinlock_driver_api *)dev->api; + + if (api->unlock != NULL) + api->unlock(dev, id); +} + +/** + * @brief Get HW spinlock max ID + * + * This function is used to get the HW spinlock maximum ID. It should + * be called before attempting to lock/unlock a specific HW spinlock. + * + * @param dev HW spinlock device instance. + * + * @retval HW spinlock max ID. + * @retval 0 if the function is not implemented by the driver. + */ +__syscall uint32_t hwspinlock_get_max_id(const struct device *dev); + +static inline uint32_t z_impl_hwspinlock_get_max_id(const struct device *dev) +{ + const struct hwspinlock_driver_api *api = + (const struct hwspinlock_driver_api *)dev->api; + + if (api->get_max_id == NULL) + return 0; + + return api->get_max_id(dev); +} + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#include + +#endif /* ZEPHYR_INCLUDE_DRIVERS_HWSPINLOCK_H_ */