diff --git a/arch/arc/core/dsp/Kconfig b/arch/arc/core/dsp/Kconfig index 48a910198ecd501..b675e04ef861b42 100644 --- a/arch/arc/core/dsp/Kconfig +++ b/arch/arc/core/dsp/Kconfig @@ -67,4 +67,14 @@ config ARC_AGU_LARGE Save and restore large AGU registers, including 12 address pointers regs, 8 address offset regs and 24 modifiers regs. +config ARC_VPX_COOPERATIVE_SHARING + bool "Cooperative sharing of ARC VPX vector registers" + depends on ARC_DSP + select SCHED_CPU_MASK if MP_MAX_NUM_CPUS > 1 + help + This option enables the cooperative sharing of the ARC VPX vector + registers. Threads that want to use those registers must successfully + call arc_vpx_lock() before using them, and call arc_vpx_unlock() + when done using them. + endmenu diff --git a/arch/arc/core/thread.c b/arch/arc/core/thread.c index 1c85a416ca6756c..99ece8d1de0083d 100644 --- a/arch/arc/core/thread.c +++ b/arch/arc/core/thread.c @@ -19,10 +19,15 @@ #include #endif -#if defined(CONFIG_ARC_DSP) && defined(CONFIG_DSP_SHARING) +#if defined(CONFIG_ARC_VPX_COOPERATIVE_SHARING) || defined(CONFIG_DSP_SHARING) #include static struct k_spinlock lock; + +#if defined(CONFIG_ARC_VPX_COOPERATIVE_SHARING) +static struct k_sem vpx_sem[CONFIG_MP_MAX_NUM_CPUS]; #endif +#endif + /* initial stack frame */ struct init_stack_frame { uintptr_t pc; @@ -320,3 +325,40 @@ void arc_dsp_enable(struct k_thread *thread, unsigned int options) k_spin_unlock(&lock, key); } #endif /* CONFIG_ARC_DSP && CONFIG_DSP_SHARING */ + +#if defined(CONFIG_ARC_VPX_COOPERATIVE_SHARING) +int arc_vpx_lock(unsigned int *id, k_timeout_t timeout) +{ + k_spinlock_key_t key; + + __ASSERT(id != NULL, ""); + + key = k_spin_lock(&lock); + + *id = _current_cpu->id; +#if (CONFIG_MP_MAX_NUM_CPUS > 1) && defined(CONFIG_SCHED_CPU_MASK) + __ASSERT(arch_is_in_isr() || (_current->base.cpu_mask == BIT(*id)), ""); +#endif + k_spin_unlock(&lock, key); + + return k_sem_take(&vpx_sem[*id], timeout); +} + +void arc_vpx_unlock(unsigned int id) +{ + __ASSERT((id >= 0) && (id < CONFIG_MP_MAX_NUM_CPUS), ""); + + k_sem_give(&vpx_sem[id]); +} + +static int arc_vpx_sem_init(void) +{ + for (unsigned int i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) { + k_sem_init(vpx_sem, 1, 1); + } + + return 0; +} + +SYS_INIT(arc_vpx_sem_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS); +#endif diff --git a/doc/hardware/arch/arc-support-status.rst b/doc/hardware/arch/arc-support-status.rst index 66d07771c663a9a..5a909bba1a51b9e 100644 --- a/doc/hardware/arch/arc-support-status.rst +++ b/doc/hardware/arch/arc-support-status.rst @@ -92,3 +92,23 @@ Notes .. [#f6] currently only ARC VPX scalar port is supported. The support of VPX vector pipeline, VCCM, STU is not included in this port, and require additional development and / or other runtime integration. + +VPX Vector Registers +-------------------- +Zephyr supports a limited form sharing of the VPX vector registers known as +cooperative sharing. Threads (or ISRs) that use these registers must bookend +the relevant sections with calls to :c:func:`arc_vpx_lock` and +:c_func:`arc_vpx_unlock` to control access to this resource. + +.. note:: + If the system has multiple CPUs, then it is the responsibility of the + application developer to both pin the thread to a single CPU before it + attempts to get the cooperative lock, and not modify the CPU affinity + while it is waiting for or holding that cooperative lock. + +Configuration Options +===================== + +The cooperative sharing of the VPX vector registers is selected when +configuration option :kconfig:option:`CONFIG_ARC_VPX_COOPERATIVE_SHARING` +is enabled. diff --git a/include/zephyr/arch/arc/v2/dsp/arc_dsp.h b/include/zephyr/arch/arc/v2/dsp/arc_dsp.h index 1561352d80746b2..f1994cd61dea3de 100644 --- a/include/zephyr/arch/arc/v2/dsp/arc_dsp.h +++ b/include/zephyr/arch/arc/v2/dsp/arc_dsp.h @@ -36,4 +36,36 @@ void arc_dsp_disable(struct k_thread *thread, unsigned int options); */ void arc_dsp_enable(struct k_thread *thread, unsigned int options); +/** + * @brief Obtain a cooperative lock on the VPX vector registers + * + * This function is used to obtain a cooperative lock on the current CPU's + * VPX vector registers before the calling thread or ISR uses them. Callers + * attempting to obtain the cooperative lock must be already restricted to + * executing on a single CPU, and continue to execute on that same CPU while + * both waiting and holding the lock. + * + * @note @a timeout must be set to K_NO_WAIT if called from an ISR. + * + * @param id Pointer to memory at which to store the ID of the cooperative + * lock on success + * @param timeout Waiting period to obtain the lock, or one of the special + * values K_NO_WAIT and K_FOREVER. + * + * @return Zero on success, otherwise error code + */ +int arc_vpx_lock(unsigned int *id, k_timeout_t timeout); + +/** + * @brief Release cooperative lock on the VPX vector registers + * + * This function is used to release the cooperative lock on the CPU's VPX + * vector registers. It is called after the current thread (or ISR) no + * longer needs to use the VPX vector registers, thereby allowing another + * thread (or ISR) to use them. + * + * @param id ID of the lock obtained from arc_vpx_lock() + */ +void arc_vpx_unlock(unsigned int id); + #endif /* ZEPHYR_INCLUDE_ARCH_ARC_V2_DSP_ARC_DSP_H_ */