1 /*
2 * Copyright (c) 2023 Enphase Energy
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9
10 #include "eth_ivshmem_priv.h"
11
12 #define SHMEM_SECTION_SIZE KB(4)
13
14 #define VRING_DESC_LEN 32
15 #define VRING_HEADER_SIZE 1792
16 #define VRING_DATA_MAX_LEN 2304
17
18 static struct eth_ivshmem_queue q1, q2;
19 static uint8_t shmem_buff[2][SHMEM_SECTION_SIZE] __aligned(KB(4));
20 static const void *rx_message;
21 static size_t rx_len;
22
test_init_queues(void)23 static void test_init_queues(void)
24 {
25 int res;
26
27 res = eth_ivshmem_queue_init(
28 &q1, (uintptr_t)shmem_buff[0],
29 (uintptr_t)shmem_buff[1], SHMEM_SECTION_SIZE);
30 zassert_ok(res);
31 res = eth_ivshmem_queue_init(
32 &q2, (uintptr_t)shmem_buff[1],
33 (uintptr_t)shmem_buff[0], SHMEM_SECTION_SIZE);
34 zassert_ok(res);
35 }
36
queue_tx(struct eth_ivshmem_queue * q,const void * data,size_t len)37 static inline int queue_tx(struct eth_ivshmem_queue *q, const void *data, size_t len)
38 {
39 void *dest;
40 int res = eth_ivshmem_queue_tx_get_buff(q, &dest, len);
41
42 if (res == 0) {
43 memcpy(dest, data, len);
44 res = eth_ivshmem_queue_tx_commit_buff(q);
45 }
46 return res;
47 }
48
test_setup(void * fixture)49 static void test_setup(void *fixture)
50 {
51 ARG_UNUSED(fixture);
52 rx_message = NULL;
53 rx_len = 0;
54 test_init_queues();
55 }
56
57
ZTEST(eth_ivshmem_queue_tests,test_init)58 ZTEST(eth_ivshmem_queue_tests, test_init)
59 {
60 zassert_equal(q1.desc_max_len, VRING_DESC_LEN);
61 zassert_equal(q1.vring_header_size, VRING_HEADER_SIZE);
62 zassert_equal(q1.vring_data_max_len, VRING_DATA_MAX_LEN);
63 zassert_equal_ptr(q1.tx.shmem, shmem_buff[0]);
64 zassert_equal_ptr(q1.rx.shmem, shmem_buff[1]);
65 zassert_equal_ptr(q2.tx.shmem, shmem_buff[1]);
66 zassert_equal_ptr(q2.rx.shmem, shmem_buff[0]);
67 }
68
ZTEST(eth_ivshmem_queue_tests,test_simple_send_receive)69 ZTEST(eth_ivshmem_queue_tests, test_simple_send_receive)
70 {
71 /* Send */
72 int x = 42;
73
74 zassert_ok(queue_tx(&q1, &x, sizeof(x)));
75
76 /* Receive */
77 zassert_ok(eth_ivshmem_queue_rx(&q2, &rx_message, &rx_len));
78 zassert_equal(rx_len, sizeof(x));
79 zassert_equal(*(int *)rx_message, x);
80 zassert_ok(eth_ivshmem_queue_rx_complete(&q2));
81 }
82
ZTEST(eth_ivshmem_queue_tests,test_send_receive_both_directions)83 ZTEST(eth_ivshmem_queue_tests, test_send_receive_both_directions)
84 {
85 /* Send q1 */
86 int q1_tx_data = 42;
87
88 zassert_ok(queue_tx(&q1, &q1_tx_data, sizeof(q1_tx_data)));
89
90 /* Send q2 */
91 int q2_tx_data = 21;
92
93 zassert_ok(queue_tx(&q2, &q2_tx_data, sizeof(q2_tx_data)));
94
95 /* Receive q2 */
96 zassert_ok(eth_ivshmem_queue_rx(&q2, &rx_message, &rx_len));
97 zassert_equal(rx_len, sizeof(q1_tx_data));
98 zassert_equal(*(int *)rx_message, q1_tx_data);
99 zassert_ok(eth_ivshmem_queue_rx_complete(&q2));
100
101 /* Receive q1 */
102 zassert_ok(eth_ivshmem_queue_rx(&q1, &rx_message, &rx_len));
103 zassert_equal(rx_len, sizeof(q2_tx_data));
104 zassert_equal(*(int *)rx_message, q2_tx_data);
105 zassert_ok(eth_ivshmem_queue_rx_complete(&q1));
106 }
107
ZTEST(eth_ivshmem_queue_tests,test_queue_empty)108 ZTEST(eth_ivshmem_queue_tests, test_queue_empty)
109 {
110 /* Read with empty queue */
111 zassert_equal(eth_ivshmem_queue_rx(&q1, &rx_message, &rx_len), -EWOULDBLOCK);
112
113 /* Complete with empty queue */
114 zassert_equal(eth_ivshmem_queue_rx_complete(&q1), -EWOULDBLOCK);
115
116 /* TX commit without getting buffer */
117 zassert_equal(eth_ivshmem_queue_tx_commit_buff(&q1), -EINVAL);
118
119 /* Getting a buffer (without committing) should not modify/overflow the queue */
120 for (int i = 0; i < 100; i++) {
121 void *data;
122
123 zassert_ok(eth_ivshmem_queue_tx_get_buff(&q1, &data, KB(1)));
124 }
125 }
126
ZTEST(eth_ivshmem_queue_tests,test_queue_descriptors_full)127 ZTEST(eth_ivshmem_queue_tests, test_queue_descriptors_full)
128 {
129 /* Fill queue descriptors */
130 for (int i = 0; i < VRING_DESC_LEN; i++) {
131 zassert_ok(queue_tx(&q1, &i, sizeof(i)));
132 }
133
134 /* Fail to add another */
135 int x = 0;
136
137 zassert_equal(queue_tx(&q1, &x, sizeof(x)), -ENOBUFS);
138
139 /* Read 3 */
140 for (int i = 0; i < 3; i++) {
141 zassert_ok(eth_ivshmem_queue_rx(&q2, &rx_message, &rx_len));
142 zassert_equal(rx_len, sizeof(i));
143 zassert_equal(*(int *)rx_message, i);
144 zassert_ok(eth_ivshmem_queue_rx_complete(&q2));
145 }
146
147 /* Can now add 3 more */
148 for (int i = 0; i < 3; i++) {
149 zassert_ok(queue_tx(&q1, &i, sizeof(i)));
150 }
151
152 /* Fail to add another */
153 zassert_equal(queue_tx(&q1, &x, sizeof(x)), -ENOBUFS);
154 }
155
ZTEST(eth_ivshmem_queue_tests,test_queue_shmem_full)156 ZTEST(eth_ivshmem_queue_tests, test_queue_shmem_full)
157 {
158 static uint8_t large_message[KB(1)];
159
160 /* Fill queue shmem */
161 for (int i = 0; i < VRING_DATA_MAX_LEN / sizeof(large_message); i++) {
162 zassert_ok(queue_tx(&q1, large_message, sizeof(large_message)));
163 }
164
165 /* Fail to add another */
166 zassert_equal(queue_tx(&q1, large_message, sizeof(large_message)), -ENOBUFS);
167
168 /* Read 1 */
169 zassert_ok(eth_ivshmem_queue_rx(&q2, &rx_message, &rx_len));
170 zassert_equal(rx_len, sizeof(large_message));
171 zassert_ok(eth_ivshmem_queue_rx_complete(&q2));
172
173 /* Can now add 1 more */
174 zassert_ok(queue_tx(&q1, large_message, sizeof(large_message)));
175
176 /* Fail to add another */
177 zassert_equal(queue_tx(&q1, large_message, sizeof(large_message)), -ENOBUFS);
178 }
179
180 ZTEST_SUITE(eth_ivshmem_queue_tests, NULL, NULL, test_setup, NULL, NULL);
181