From 0ee1e28a2f5f118b09a1689e78500218eb1f64cc Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 9 Oct 2023 12:31:56 -0700 Subject: [PATCH] xtensa: polish doxygen and add to missing doc This polishes doxygen to, hopefully, make it better looking on the API doc. Also adds missing doc to various functions and macros. Signed-off-by: Daniel Leung --- include/zephyr/arch/xtensa/arch.h | 108 ++++++++++++++++----- include/zephyr/arch/xtensa/arch_inlines.h | 29 ++++++ include/zephyr/arch/xtensa/atomic_xtensa.h | 39 +++++++- include/zephyr/arch/xtensa/cache.h | 22 ++++- include/zephyr/arch/xtensa/gdbstub.h | 40 ++++---- include/zephyr/arch/xtensa/irq.h | 3 + 6 files changed, 196 insertions(+), 45 deletions(-) diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 745288da1719db..26325a984e1623 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -7,7 +7,7 @@ * @file * @brief Xtensa specific kernel interface header * This header contains the Xtensa specific kernel interface. It is included - * by the generic kernel interface header (include/arch/cpu.h) + * by the generic kernel interface header (include/zephyr/arch/cpu.h) */ #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_ARCH_H_ @@ -33,6 +33,8 @@ #include #include +#include + #include /** @@ -61,7 +63,23 @@ struct arch_mem_domain { sys_snode_t node; }; +/** + * @brief Generate hardware exception. + * + * This generates hardware exception which is used by ARCH_EXCEPT(). + * + * @param reason_p Reason for exception. + */ extern void xtensa_arch_except(int reason_p); + +/** + * @brief Generate kernel oops. + * + * This generates kernel oops which is used by arch_syscall_oops(). + * + * @param reason_p Reason for exception. + * @param ssf Stack pointer. + */ extern void xtensa_arch_kernel_oops(int reason_p, void *ssf); #ifdef CONFIG_USERSPACE @@ -79,9 +97,9 @@ extern void xtensa_arch_kernel_oops(int reason_p, void *ssf); #else #define ARCH_EXCEPT(reason_p) do { \ - xtensa_arch_except(reason_p); \ - CODE_UNREACHABLE; \ -} while (false) + xtensa_arch_except(reason_p); \ + CODE_UNREACHABLE; \ + } while (false) #endif @@ -93,44 +111,47 @@ __syscall void xtensa_user_fault(unsigned int reason); extern void z_irq_priority_set(uint32_t irq, uint32_t prio, uint32_t flags); #define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ -{ \ - Z_ISR_DECLARE(irq_p, flags_p, isr_p, isr_param_p); \ -} - -extern uint32_t sys_clock_cycle_get_32(void); + { \ + Z_ISR_DECLARE(irq_p, flags_p, isr_p, isr_param_p); \ + } +/** Implementation of @ref arch_k_cycle_get_32. */ static inline uint32_t arch_k_cycle_get_32(void) { return sys_clock_cycle_get_32(); } -extern uint64_t sys_clock_cycle_get_64(void); - +/** Implementation of @ref arch_k_cycle_get_64. */ static inline uint64_t arch_k_cycle_get_64(void) { return sys_clock_cycle_get_64(); } +/** Implementation of @ref arch_nop. */ static ALWAYS_INLINE void arch_nop(void) { __asm__ volatile("nop"); } +/** + * @brief Lock VECBASE if supported by hardware. + * + * The bit 0 of VECBASE acts as a lock bit on hardware supporting + * this feature. When this bit is set, VECBASE cannot be changed + * until it is cleared by hardware reset. When the hardware does not + * support this bit, it is hardwired to 0. + */ static ALWAYS_INLINE void xtensa_vecbase_lock(void) { int vecbase; __asm__ volatile("rsr.vecbase %0" : "=r" (vecbase)); - - /* In some targets the bit 0 of VECBASE works as lock bit. - * When this bit set, VECBASE can't be changed until it is cleared by - * reset. When the target does not have it, it is hardwired to 0. - **/ __asm__ volatile("wsr.vecbase %0; rsync" : : "r" (vecbase | 1)); } -#if defined(CONFIG_XTENSA_RPO_CACHE) -#if defined(CONFIG_ARCH_HAS_COHERENCE) +#if defined(CONFIG_XTENSA_RPO_CACHE) || defined(__DOXYGEN__) +#if defined(CONFIG_ARCH_HAS_COHERENCE) || defined(__DOXYGEN__) +/** Implementation of @ref arch_mem_coherent. */ static inline bool arch_mem_coherent(void *ptr) { size_t addr = (size_t) ptr; @@ -139,6 +160,19 @@ static inline bool arch_mem_coherent(void *ptr) } #endif +/** + * @brief Test if a pointer is in cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the cached, coherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is in cached region. + * @retval False if pointer is not in cached region. + */ static inline bool arch_xtensa_is_ptr_cached(void *ptr) { size_t addr = (size_t) ptr; @@ -146,6 +180,19 @@ static inline bool arch_xtensa_is_ptr_cached(void *ptr) return (addr >> 29) == CONFIG_XTENSA_CACHED_REGION; } +/** + * @brief Test if a pointer is in un-cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the un-cached, incoherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is not in cached region. + * @retval False if pointer is in cached region. + */ static inline bool arch_xtensa_is_ptr_uncached(void *ptr) { size_t addr = (size_t) ptr; @@ -173,6 +220,7 @@ static ALWAYS_INLINE uint32_t z_xtrpoflip(uint32_t addr, uint32_t rto, uint32_t return (addr & ~(7U << 29)) | rto; } } + /** * @brief Return cached pointer to a RAM address * @@ -271,10 +319,14 @@ static inline void *arch_xtensa_uncached_ptr(void __sparse_cache *ptr) addr += addrincr; \ } while (0) -#define ARCH_XTENSA_SET_RPO_TLB() do { \ - register uint32_t addr = 0, addrincr = 0x20000000; \ - FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \ -} while (0) +/** + * @brief Setup RPO TLB registers. + */ +#define ARCH_XTENSA_SET_RPO_TLB() \ + do { \ + register uint32_t addr = 0, addrincr = 0x20000000; \ + FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \ + } while (0) #else /* CONFIG_XTENSA_RPO_CACHE */ @@ -304,7 +356,17 @@ static inline void *arch_xtensa_uncached_ptr(void *ptr) #endif /* CONFIG_XTENSA_RPO_CACHE */ -#ifdef CONFIG_XTENSA_MMU +#if defined(CONFIG_XTENSA_MMU) || defined(__DOXYGEN__) +/** + * @brief Peform additional steps after MMU initialization. + * + * This performs additional steps related to memory management + * after the main MMU initialization code. This needs to defined + * in the SoC layer. Default is do no nothing. + * + * @param is_core0 True if this is called while executing on + * CPU core #0. + */ extern void arch_xtensa_mmu_post_init(bool is_core0); #endif diff --git a/include/zephyr/arch/xtensa/arch_inlines.h b/include/zephyr/arch/xtensa/arch_inlines.h index d5fcc55af47c80..4e7b52002768ac 100644 --- a/include/zephyr/arch/xtensa/arch_inlines.h +++ b/include/zephyr/arch/xtensa/arch_inlines.h @@ -13,26 +13,53 @@ #include #include +/** + * @brief Read a special register. + * + * @param sr Name of special register. + * + * @return Value of special register. + */ #define XTENSA_RSR(sr) \ ({uint32_t v; \ __asm__ volatile ("rsr." sr " %0" : "=a"(v)); \ v; }) +/** + * @brief Write to a special register. + * + * @param sr Name of special register. + * @param v Value to be written to special register. + */ #define XTENSA_WSR(sr, v) \ do { \ __asm__ volatile ("wsr." sr " %0" : : "r"(v)); \ } while (false) +/** + * @brief Read a user register. + * + * @param ur Name of user register. + * + * @return Value of user register. + */ #define XTENSA_RUR(ur) \ ({uint32_t v; \ __asm__ volatile ("rur." ur " %0" : "=a"(v)); \ v; }) +/** + * @brief Write to a user register. + * + * @param ur Name of user register. + * @param v Value to be written to user register. + */ #define XTENSA_WUR(ur, v) \ do { \ __asm__ volatile ("wur." ur " %0" : : "r"(v)); \ } while (false) +/** Implementation of @ref arch_curr_cpu. */ static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) { _cpu_t *cpu; @@ -42,6 +69,7 @@ static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) return cpu; } +/** Implementation of @ref arch_proc_id. */ static ALWAYS_INLINE uint32_t arch_proc_id(void) { uint32_t prid; @@ -54,6 +82,7 @@ static ALWAYS_INLINE uint32_t arch_proc_id(void) extern unsigned int soc_num_cpus; #endif +/** Implementation of @ref arch_num_cpus. */ static ALWAYS_INLINE unsigned int arch_num_cpus(void) { #ifdef CONFIG_SOC_HAS_RUNTIME_NUM_CPUS diff --git a/include/zephyr/arch/xtensa/atomic_xtensa.h b/include/zephyr/arch/xtensa/atomic_xtensa.h index c518f4df4ed492..a8f5d0f78e9542 100644 --- a/include/zephyr/arch/xtensa/atomic_xtensa.h +++ b/include/zephyr/arch/xtensa/atomic_xtensa.h @@ -1,11 +1,12 @@ -/** +/* * Copyright (c) 2021 Intel Corporation * SPDX-License-Identifier: Apache-2.0 */ + #ifndef ZEPHYR_INCLUDE_ATOMIC_XTENSA_H_ #define ZEPHYR_INCLUDE_ATOMIC_XTENSA_H_ -/* Included from */ +/* Included from */ /* Recent GCC versions actually do have working atomics support on * Xtensa (and so should work with CONFIG_ATOMIC_OPERATIONS_BUILTIN), @@ -13,6 +14,7 @@ * inline implementation here that is more or less identical */ +/** Implementation of @ref atomic_get. */ static ALWAYS_INLINE atomic_val_t atomic_get(const atomic_t *target) { atomic_val_t ret; @@ -28,6 +30,23 @@ static ALWAYS_INLINE atomic_val_t atomic_get(const atomic_t *target) return ret; } +/** + * @brief Xtensa specific atomic compare-and-set (CAS). + * + * @param addr Address of atomic variable. + * @param oldval Original value to compare against. + * @param newval New value to store. + * + * This utilizes SCOMPARE1 register and s32c1i instruction to + * perform compare-and-set atomic operation. This will + * unconditionally read from the atomic variable at @p addr + * before the comparison. This value is returned from + * the function. + * + * @return The value at the memory location before CAS. + * + * @see atomic_cas. + */ static ALWAYS_INLINE atomic_val_t xtensa_cas(atomic_t *addr, atomic_val_t oldval, atomic_val_t newval) @@ -38,12 +57,14 @@ atomic_val_t xtensa_cas(atomic_t *addr, atomic_val_t oldval, return newval; /* got swapped with the old memory by s32c1i */ } +/** Implementation of @ref atomic_cas. */ static ALWAYS_INLINE bool atomic_cas(atomic_t *target, atomic_val_t oldval, atomic_val_t newval) { return oldval == xtensa_cas(target, oldval, newval); } +/** Implementation of @ref atomic_ptr_cas. */ static ALWAYS_INLINE bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval) { @@ -57,7 +78,6 @@ bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval) * specified expression. Evaluates to the old value which was * atomically replaced. */ - #define Z__GEN_ATOMXCHG(expr) ({ \ atomic_val_t res, cur; \ do { \ @@ -66,75 +86,88 @@ bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval) } while (res != cur); \ res; }) +/** Implementation of @ref atomic_set. */ static ALWAYS_INLINE atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(value); } +/** Implementation of @ref atomic_add. */ static ALWAYS_INLINE atomic_val_t atomic_add(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur + value); } +/** Implementation of @ref atomic_sub. */ static ALWAYS_INLINE atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur - value); } +/** Implementation of @ref atomic_inc. */ static ALWAYS_INLINE atomic_val_t atomic_inc(atomic_t *target) { return Z__GEN_ATOMXCHG(cur + 1); } +/** Implementation of @ref atomic_dec. */ static ALWAYS_INLINE atomic_val_t atomic_dec(atomic_t *target) { return Z__GEN_ATOMXCHG(cur - 1); } +/** Implementation of @ref atomic_or. */ static ALWAYS_INLINE atomic_val_t atomic_or(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur | value); } +/** Implementation of @ref atomic_xor. */ static ALWAYS_INLINE atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur ^ value); } +/** Implementation of @ref atomic_and. */ static ALWAYS_INLINE atomic_val_t atomic_and(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur & value); } +/** Implementation of @ref atomic_nand. */ static ALWAYS_INLINE atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(~(cur & value)); } +/** Implementation of @ref atomic_ptr_get. */ static ALWAYS_INLINE void *atomic_ptr_get(const atomic_ptr_t *target) { return (void *) atomic_get((atomic_t *)target); } +/** Implementation of @ref atomic_ptr_set. */ static ALWAYS_INLINE void *atomic_ptr_set(atomic_ptr_t *target, void *value) { return (void *) atomic_set((atomic_t *) target, (atomic_val_t) value); } +/** Implementation of @ref atomic_clear. */ static ALWAYS_INLINE atomic_val_t atomic_clear(atomic_t *target) { return atomic_set(target, 0); } +/** Implementation of @ref atomic_ptr_clear. */ static ALWAYS_INLINE void *atomic_ptr_clear(atomic_ptr_t *target) { return (void *) atomic_set((atomic_t *) target, 0); diff --git a/include/zephyr/arch/xtensa/cache.h b/include/zephyr/arch/xtensa/cache.h index 8a190d0d3718ed..6fb64ef30d5e15 100644 --- a/include/zephyr/arch/xtensa/cache.h +++ b/include/zephyr/arch/xtensa/cache.h @@ -22,7 +22,9 @@ BUILD_ASSERT(Z_IS_POW2(XCHAL_DCACHE_LINESIZE)); BUILD_ASSERT(Z_IS_POW2(Z_DCACHE_MAX)); #endif -#if defined(CONFIG_DCACHE) +#if defined(CONFIG_DCACHE) || defined(__DOXYGEN__) + +/** Implementation of @ref arch_dcache_flush_range. */ static ALWAYS_INLINE int arch_dcache_flush_range(void *addr, size_t bytes) { #if XCHAL_DCACHE_SIZE @@ -38,6 +40,7 @@ static ALWAYS_INLINE int arch_dcache_flush_range(void *addr, size_t bytes) return 0; } +/** Implementation of @ref arch_dcache_flush_and_invd_range. */ static ALWAYS_INLINE int arch_dcache_flush_and_invd_range(void *addr, size_t bytes) { #if XCHAL_DCACHE_SIZE @@ -53,6 +56,7 @@ static ALWAYS_INLINE int arch_dcache_flush_and_invd_range(void *addr, size_t byt return 0; } +/** Implementation of @ref arch_dcache_invd_range. */ static ALWAYS_INLINE int arch_dcache_invd_range(void *addr, size_t bytes) { #if XCHAL_DCACHE_SIZE @@ -68,6 +72,7 @@ static ALWAYS_INLINE int arch_dcache_invd_range(void *addr, size_t bytes) return 0; } +/** Implementation of @ref arch_dcache_invd_all. */ static ALWAYS_INLINE int arch_dcache_invd_all(void) { #if XCHAL_DCACHE_SIZE @@ -81,6 +86,7 @@ static ALWAYS_INLINE int arch_dcache_invd_all(void) return 0; } +/** Implementation of @ref arch_dcache_flush_all. */ static ALWAYS_INLINE int arch_dcache_flush_all(void) { #if XCHAL_DCACHE_SIZE @@ -94,6 +100,7 @@ static ALWAYS_INLINE int arch_dcache_flush_all(void) return 0; } +/** Implementation of @ref arch_dcache_flush_and_invd_all. */ static ALWAYS_INLINE int arch_dcache_flush_and_invd_all(void) { #if XCHAL_DCACHE_SIZE @@ -107,11 +114,13 @@ static ALWAYS_INLINE int arch_dcache_flush_and_invd_all(void) return 0; } +/** Implementation of @ref arch_dcache_enable. */ static ALWAYS_INLINE void arch_dcache_enable(void) { /* nothing */ } +/** Implementation of @ref arch_dcache_disable. */ static ALWAYS_INLINE void arch_dcache_disable(void) { /* nothing */ @@ -119,18 +128,21 @@ static ALWAYS_INLINE void arch_dcache_disable(void) #endif /* CONFIG_DCACHE */ -#if defined(CONFIG_ICACHE) +#if defined(CONFIG_ICACHE) || defined(__DOXYGEN__) +/** Implementation of @ref arch_icache_line_size_get. */ static ALWAYS_INLINE size_t arch_icache_line_size_get(void) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_flush_all. */ static ALWAYS_INLINE int arch_icache_flush_all(void) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_invd_all. */ static ALWAYS_INLINE int arch_icache_invd_all(void) { #if XCHAL_ICACHE_SIZE @@ -139,16 +151,19 @@ static ALWAYS_INLINE int arch_icache_invd_all(void) return 0; } +/** Implementation of @ref arch_icache_flush_and_invd_all. */ static ALWAYS_INLINE int arch_icache_flush_and_invd_all(void) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_flush_range. */ static ALWAYS_INLINE int arch_icache_flush_range(void *addr, size_t size) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_invd_range. */ static ALWAYS_INLINE int arch_icache_invd_range(void *addr, size_t size) { #if XCHAL_ICACHE_SIZE @@ -157,16 +172,19 @@ static ALWAYS_INLINE int arch_icache_invd_range(void *addr, size_t size) return 0; } +/** Implementation of @ref arch_icache_flush_and_invd_range. */ static ALWAYS_INLINE int arch_icache_flush_and_invd_range(void *addr, size_t size) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_enable. */ static ALWAYS_INLINE void arch_icache_enable(void) { /* nothing */ } +/** Implementation of @ref arch_icache_disable. */ static ALWAYS_INLINE void arch_icache_disable(void) { /* nothing */ diff --git a/include/zephyr/arch/xtensa/gdbstub.h b/include/zephyr/arch/xtensa/gdbstub.h index 627bb79e6785bb..89aabb02905628 100644 --- a/include/zephyr/arch/xtensa/gdbstub.h +++ b/include/zephyr/arch/xtensa/gdbstub.h @@ -17,8 +17,8 @@ #define XTREG_GRP_SPECIAL 0x0200 #define XTREG_GRP_USER 0x0300 -/* - * Register description fot GDB stub. +/** + * @brief Register description for GDB stub. * * Values are based on gdb/gdb/xtensa-config.c in the Xtensa overlay, * where registers are defined using XTREG() macro: @@ -35,32 +35,35 @@ * gpkt_offset : ofs */ struct xtensa_register { - /* Register value */ + /** Register value */ uint32_t val; - /* GDB register index (for p/P packets) */ + /** GDB register index (for p/P packets) */ uint8_t idx; - /* Size of register */ + /** Size of register */ uint8_t byte_size; - /* Xtensa register number */ + /** Xtensa register number */ uint16_t regno; - /* Offset of this register in GDB G-packet. + /** + * Offset of this register in GDB G-packet. * -1 if register is not in G-packet. */ int16_t gpkt_offset; - /* Offset of saved register in stack frame. + /** + * Offset of saved register in stack frame. * 0 if not saved in stack frame. */ int8_t stack_offset; - /* Sequence number */ + /** Sequence number */ uint8_t seqno; - /* Set 1 to if register should not be written + /** + * Set to 1 if register should not be written * to during debugging. */ uint8_t is_read_only:1; @@ -78,26 +81,29 @@ struct xtensa_register { */ #include +/** + * @brief Architecture specific GDB context. + */ struct gdb_ctx { - /* Exception reason */ + /** Exception reason */ unsigned int exception; - /* Register descriptions */ + /** Register descriptions */ struct xtensa_register *regs; - /* Number of registers */ + /** Number of registers */ uint8_t num_regs; - /* Sequence number */ + /** Sequence number */ uint8_t seqno; - /* Index in register descriptions of A0 register */ + /** Index in register descriptions of A0 register */ uint8_t a0_idx; - /* Index in register descriptions of AR0 register */ + /** Index in register descriptions of AR0 register */ uint8_t ar_idx; - /* Index in register descriptions of WINDOWBASE register */ + /** Index in register descriptions of WINDOWBASE register */ uint8_t wb_idx; }; diff --git a/include/zephyr/arch/xtensa/irq.h b/include/zephyr/arch/xtensa/irq.h index 22d4800f8b9bf0..938ab7b2303c2e 100644 --- a/include/zephyr/arch/xtensa/irq.h +++ b/include/zephyr/arch/xtensa/irq.h @@ -130,6 +130,7 @@ static ALWAYS_INLINE void xtensa_irq_disable(uint32_t irq) z_xt_ints_off(1 << irq); } +/** Implementation of @ref arch_irq_lock. */ static ALWAYS_INLINE unsigned int arch_irq_lock(void) { unsigned int key; @@ -139,12 +140,14 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) return key; } +/** Implementation of @ref arch_irq_unlock. */ static ALWAYS_INLINE void arch_irq_unlock(unsigned int key) { __asm__ volatile("wsr.ps %0; rsync" :: "r"(key) : "memory"); } +/** Implementation of @ref arch_irq_unlocked. */ static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) { return (key & 0xf) == 0; /* INTLEVEL field */