1 /*
2  * Copyright (c) 2024 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 
9 #include <zephyr/arch/arc/v2/vpx/arc_vpx.h>
10 
11 #ifndef CONFIG_ARC_VPX_COOPERATIVE_SHARING
12 #error "Rebuild with the ARC_VPX_COOPERATIVE_SHARING config option enabled"
13 #endif
14 
15 #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
16 
17 static void timer_func(struct k_timer *timer);
18 
19 K_THREAD_STACK_DEFINE(payload_stack, STACK_SIZE);
20 
21 static K_TIMER_DEFINE(my_timer, timer_func, NULL);
22 
23 static struct k_thread payload_thread;
24 
25 static volatile int isr_result;
26 static volatile unsigned int isr_vpx_lock_id;
27 
28 /**
29  * Obtain the current CPU id.
30  */
current_cpu_id_get(void)31 static int current_cpu_id_get(void)
32 {
33 	int key;
34 	int id;
35 
36 	key = arch_irq_lock();
37 	id = _current_cpu->id;
38 	arch_irq_unlock(key);
39 
40 	return id;
41 }
42 
timer_func(struct k_timer * timer)43 static void timer_func(struct k_timer *timer)
44 {
45 	arc_vpx_unlock_force(isr_vpx_lock_id);
46 }
47 
arc_vpx_lock_unlock_timed_payload(void * p1,void * p2,void * p3)48 static void arc_vpx_lock_unlock_timed_payload(void *p1, void *p2, void *p3)
49 {
50 	int status;
51 	unsigned int cpu_id;
52 	unsigned int lock_id;
53 
54 	cpu_id = (unsigned int)(uintptr_t)(p1);
55 	ARG_UNUSED(p2);
56 	ARG_UNUSED(p3);
57 
58 	status = arc_vpx_lock(K_NO_WAIT);
59 	zassert_equal(0, status, "Expected return value %d, not %d\n", 0, status);
60 
61 	/*
62 	 * In 1 second, forcibly release the VPX lock. However, wait up to
63 	 * 5 seconds before considering this a failure.
64 	 */
65 
66 	isr_vpx_lock_id = cpu_id;
67 	k_timer_start(&my_timer, K_MSEC(1000), K_FOREVER);
68 
69 	status = arc_vpx_lock(K_MSEC(5000));
70 	zassert_equal(0, status, "Expected return value %d, not %d\n", 0, status);
71 
72 	arc_vpx_unlock();
73 }
74 
ZTEST(vpx_lock,test_arc_vpx_lock_unlock_timed)75 ZTEST(vpx_lock, test_arc_vpx_lock_unlock_timed)
76 {
77 	int priority;
78 	int cpu_id;
79 
80 	priority = k_thread_priority_get(k_current_get());
81 	cpu_id = current_cpu_id_get();
82 
83 	k_thread_create(&payload_thread, payload_stack, STACK_SIZE,
84 			arc_vpx_lock_unlock_timed_payload,
85 			(void *)(uintptr_t)cpu_id, NULL, NULL,
86 			priority - 2, 0, K_FOREVER);
87 
88 #if defined(CONFIG_SCHED_CPU_MASK) && (CONFIG_MP_MAX_NUM_CPUS > 1)
89 	k_thread_cpu_pin(&payload_thread, cpu_id);
90 #endif
91 	k_thread_start(&payload_thread);
92 
93 	k_thread_join(&payload_thread, K_FOREVER);
94 }
95 
arc_vpx_lock_unlock_payload(void * p1,void * p2,void * p3)96 static void arc_vpx_lock_unlock_payload(void *p1, void *p2, void *p3)
97 {
98 	int status;
99 
100 	ARG_UNUSED(p1);
101 	ARG_UNUSED(p2);
102 	ARG_UNUSED(p3);
103 
104 	/* The VPX lock is available; take it. */
105 
106 	status = arc_vpx_lock(K_NO_WAIT);
107 	zassert_equal(0, status, "Expected return value %d, not %d\n", 0, status);
108 
109 	/* The VPX lock has already been taken; expect errors */
110 
111 	status = arc_vpx_lock(K_NO_WAIT);
112 	zassert_equal(-EBUSY, status, "Expected return value %d (-EBUSY), not %d\n",
113 		      -EBUSY, status);
114 
115 	status = arc_vpx_lock(K_MSEC(10));
116 	zassert_equal(-EAGAIN, status, "Expected return value %d (-EAGAIN), not %d\n",
117 		      -EAGAIN, status);
118 
119 	/* Verify that unlocking makes it available */
120 
121 	arc_vpx_unlock();
122 
123 	status = arc_vpx_lock(K_NO_WAIT);
124 	zassert_equal(0, status, "Expected return value %d, not %d\n", 0, status);
125 	arc_vpx_unlock();
126 }
127 
ZTEST(vpx_lock,test_arc_vpx_lock_unlock)128 ZTEST(vpx_lock, test_arc_vpx_lock_unlock)
129 {
130 	int priority;
131 	int cpu_id;
132 
133 	priority = k_thread_priority_get(k_current_get());
134 	cpu_id = current_cpu_id_get();
135 
136 	k_thread_create(&payload_thread, payload_stack, STACK_SIZE,
137 			arc_vpx_lock_unlock_payload, NULL, NULL, NULL,
138 			priority - 2, 0, K_FOREVER);
139 
140 #if defined(CONFIG_SCHED_CPU_MASK) && (CONFIG_MP_MAX_NUM_CPUS > 1)
141 	k_thread_cpu_pin(&payload_thread, cpu_id);
142 #endif
143 	k_thread_start(&payload_thread);
144 
145 	k_thread_join(&payload_thread, K_FOREVER);
146 }
147 
148 ZTEST_SUITE(vpx_lock, NULL, NULL, NULL, NULL, NULL);
149