| /* |
| * Copyright (c) 2017 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /** |
| * @file |
| * |
| * This test case verifies the correctness of irq_offload(), an important |
| * routine used in many other test cases for running a function in interrupt |
| * context, on the IRQ stack. |
| * |
| */ |
| #include <zephyr.h> |
| #include <ztest.h> |
| #include <kernel_structs.h> |
| #include <irq_offload.h> |
| |
| volatile uint32_t sentinel; |
| #define SENTINEL_VALUE 0xDEADBEEF |
| |
| static void offload_function(const void *param) |
| { |
| uint32_t x = POINTER_TO_INT(param); |
| |
| /* Make sure we're in IRQ context */ |
| zassert_true(k_is_in_isr(), "Not in IRQ context!"); |
| |
| sentinel = x; |
| } |
| |
| /** |
| * @brief Verify thread context |
| * |
| * @ingroup kernel_interrupt_tests |
| * |
| * @details Check whether offloaded running function is in interrupt |
| * context, on the IRQ stack or not. |
| */ |
| void test_irq_offload(void) |
| { |
| /* Simple validation of nested locking. */ |
| unsigned int key1, key2; |
| |
| key1 = arch_irq_lock(); |
| zassert_true(arch_irq_unlocked(key1), |
| "IRQs should have been unlocked, but key is 0x%x\n", |
| key1); |
| key2 = arch_irq_lock(); |
| zassert_false(arch_irq_unlocked(key2), |
| "IRQs should have been locked, but key is 0x%x\n", |
| key2); |
| arch_irq_unlock(key2); |
| arch_irq_unlock(key1); |
| |
| /**TESTPOINT: Offload to IRQ context*/ |
| irq_offload(offload_function, (const void *)SENTINEL_VALUE); |
| |
| zassert_equal(sentinel, SENTINEL_VALUE, |
| "irq_offload() didn't work properly"); |
| } |
| |
| /** |
| * @brief Test the arch_nop() by invoking and measure it. |
| * |
| * @details This test is mainly for coverage of the code. arch_nop() |
| * is a special implementation and it will behave differently on |
| * different platforms. By the way, this also measures how many |
| * cycles it spends for platforms that support it. |
| * |
| * FYI: The potential uses of arch_nop() could be: |
| * - Code alignment: Although in this case it's much more likely the |
| * compiler doing so (or you're in an assembly file, in which case |
| * you're not calling arch_nop() anyway). And this would require |
| * that arch_nop() be ALWAYS_INLINE. |
| * - Giving you a guaranteed place to put a breakpoint / trace trigger |
| * / etc. when debugging. This is on main usage of arch_nop(); it |
| * inherently is generally debugging code removed before actually |
| * pushing. |
| * - Giving you a guaranteed place to put a patchpoint. E.g. ARMv7 |
| * allows nop (and a few other instructions) to be modified |
| * concurrently with execution, but not most other instructions. |
| * - Delaying a few instructions, e.g. for tight timing loops on |
| * M-cores. |
| * |
| * Our test here mainly aims at the 4th scenario mentioned above but |
| * also potentially tests the 1st scenario. So no optimization here to |
| * prevent arch_nop() has optimized by the compiler is necessary. |
| * |
| * @ingroup kernel_common_tests |
| * |
| * @see arch_nop() |
| */ |
| __no_optimization void test_nop(void) |
| { |
| uint32_t t_get_time, t_before, t_after, diff; |
| |
| t_before = k_cycle_get_32(); |
| t_after = k_cycle_get_32(); |
| |
| /* calculate time spent between two k_cycle_get_32() call */ |
| t_get_time = t_after - t_before; |
| |
| printk("time k_cycle_get_32() takes %d cycles\n", t_get_time); |
| |
| /* |
| * If two k_cycle_get_32() call take zero cycle here, this |
| * means it cannot comes out a correct result, in these |
| * case, we skip this test, such as native posix. |
| */ |
| if (t_get_time == 0) { |
| ztest_test_skip(); |
| } |
| |
| t_before = k_cycle_get_32(); |
| |
| arch_nop(); |
| |
| #if defined(CONFIG_RISCV) |
| /* do 2 nop instructions more to cost cycles */ |
| arch_nop(); |
| arch_nop(); |
| #if defined(CONFIG_RISCV_MACHINE_TIMER_SYSTEM_CLOCK_DIVIDER) |
| /* When the case machine timer clock uses the divided system clock, |
| * k_cycle_get_32() can't measure accurately how many cycles elapsed. |
| * |
| * For example, use the value as timer clock obtained by dividing |
| * the system clock by 4. |
| * In this case, measuring a duration with k_cycle_get32() has up to 3 |
| * (4-1) cycles systematic error. |
| * |
| * To run this test, we need to insert an appropriate of nops |
| * with consideration for the errors. |
| * 'nop' can not repeat with for loop. |
| * Must insert as separated statement. |
| * But we don't have a convenient function such as |
| * BOOST_PP_REPEAT in C++. |
| * |
| * At this time, Implementing a generic test is a bit difficult. |
| * Skipping this test in the case. |
| */ |
| ztest_test_skip(); |
| #endif |
| #elif defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) || \ |
| defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) |
| /* do 4 nop instructions more to cost cycles */ |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| #elif defined(CONFIG_ARC) |
| /* do 7 nop instructions more to cost cycles */ |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| #elif defined(CONFIG_SPARC) |
| /* do 9 nop instructions more to cost cycles */ |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| arch_nop(); |
| |
| #elif defined(CONFIG_ARMV8_A) || defined(CONFIG_BOARD_EHL_CRB) \ |
| || (CONFIG_BOARD_UP_SQUARED) || (CONFIG_SOC_FAMILY_INTEL_ADSP) |
| /* the ARMv8-A ARM states the following: |
| * No Operation does nothing, other than advance the value of |
| * the program counter by 4. This instruction can be used for |
| * instruction alignment purposes. |
| * Note: The timing effects of including a NOP instruction in |
| * a program are not guaranteed. It can increase execution time |
| * ,leave it unchanged, or even reduce it. Therefore, NOP |
| * instructions are not suitable for timing loops. |
| * |
| * So we skip this test, it will get a negative cycles. |
| * |
| * And on physical EHL_CRB, up squared and INTEL ADSP boards, |
| * we also got a similar situation, we skip the check as well. |
| */ |
| ztest_test_skip(); |
| #endif |
| |
| t_after = k_cycle_get_32(); |
| |
| /* Calculate delta time of arch_nop(). */ |
| diff = t_after - t_before - t_get_time; |
| printk("arch_nop() takes %d cycles\n", diff); |
| |
| /* An arch_nop() call should spend actual cpu cycles */ |
| zassert_true(diff > 0, |
| "arch_nop() takes %d cpu cycles", diff); |
| } |