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 <aidomar@sequans.com>
This commit is contained in:
Aziz Idomar 2023-06-27 08:51:04 +02:00 committed by Carles Cufí
commit c3ac598c7f
6 changed files with 225 additions and 0 deletions

View file

@ -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)

View file

@ -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

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_USERSPACE hwspinlock_handlers.c)

View file

@ -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

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2023 Sequans Communications
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/hwspinlock.h>
#include <zephyr/syscall_handler.h>
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 <syscalls/hwspinlock_trylock_mrsh.c>
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 <syscalls/hwspinlock_lock_mrsh.c>
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 <syscalls/hwspinlock_unlock_mrsh.c>
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 <syscalls/hwspinlock_get_max_id_mrsh.c>

View file

@ -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 <errno.h>
#include <zephyr/types.h>
#include <zephyr/sys/util.h>
#include <zephyr/device.h>
#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 <syscalls/hwspinlock.h>
#endif /* ZEPHYR_INCLUDE_DRIVERS_HWSPINLOCK_H_ */