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