| /* |
| * Copyright (c) 2023 Enphase Energy |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/ztest.h> |
| |
| #include "eth_ivshmem_priv.h" |
| |
| #define SHMEM_SECTION_SIZE KB(4) |
| |
| #define VRING_DESC_LEN 32 |
| #define VRING_HEADER_SIZE 1792 |
| #define VRING_DATA_MAX_LEN 2304 |
| |
| static struct eth_ivshmem_queue q1, q2; |
| static uint8_t shmem_buff[2][SHMEM_SECTION_SIZE] __aligned(KB(4)); |
| static const void *rx_message; |
| static size_t rx_len; |
| |
| static void test_init_queues(void) |
| { |
| int res; |
| |
| res = eth_ivshmem_queue_init( |
| &q1, (uintptr_t)shmem_buff[0], |
| (uintptr_t)shmem_buff[1], SHMEM_SECTION_SIZE); |
| zassert_ok(res); |
| res = eth_ivshmem_queue_init( |
| &q2, (uintptr_t)shmem_buff[1], |
| (uintptr_t)shmem_buff[0], SHMEM_SECTION_SIZE); |
| zassert_ok(res); |
| } |
| |
| static inline int queue_tx(struct eth_ivshmem_queue *q, const void *data, size_t len) |
| { |
| void *dest; |
| int res = eth_ivshmem_queue_tx_get_buff(q, &dest, len); |
| |
| if (res == 0) { |
| memcpy(dest, data, len); |
| res = eth_ivshmem_queue_tx_commit_buff(q); |
| } |
| return res; |
| } |
| |
| static void test_setup(void *fixture) |
| { |
| ARG_UNUSED(fixture); |
| rx_message = NULL; |
| rx_len = 0; |
| test_init_queues(); |
| } |
| |
| |
| ZTEST(eth_ivshmem_queue_tests, test_init) |
| { |
| zassert_equal(q1.desc_max_len, VRING_DESC_LEN); |
| zassert_equal(q1.vring_header_size, VRING_HEADER_SIZE); |
| zassert_equal(q1.vring_data_max_len, VRING_DATA_MAX_LEN); |
| zassert_equal_ptr(q1.tx.shmem, shmem_buff[0]); |
| zassert_equal_ptr(q1.rx.shmem, shmem_buff[1]); |
| zassert_equal_ptr(q2.tx.shmem, shmem_buff[1]); |
| zassert_equal_ptr(q2.rx.shmem, shmem_buff[0]); |
| } |
| |
| ZTEST(eth_ivshmem_queue_tests, test_simple_send_receive) |
| { |
| /* Send */ |
| int x = 42; |
| |
| zassert_ok(queue_tx(&q1, &x, sizeof(x))); |
| |
| /* Receive */ |
| zassert_ok(eth_ivshmem_queue_rx(&q2, &rx_message, &rx_len)); |
| zassert_equal(rx_len, sizeof(x)); |
| zassert_equal(*(int *)rx_message, x); |
| zassert_ok(eth_ivshmem_queue_rx_complete(&q2)); |
| } |
| |
| ZTEST(eth_ivshmem_queue_tests, test_send_receive_both_directions) |
| { |
| /* Send q1 */ |
| int q1_tx_data = 42; |
| |
| zassert_ok(queue_tx(&q1, &q1_tx_data, sizeof(q1_tx_data))); |
| |
| /* Send q2 */ |
| int q2_tx_data = 21; |
| |
| zassert_ok(queue_tx(&q2, &q2_tx_data, sizeof(q2_tx_data))); |
| |
| /* Receive q2 */ |
| zassert_ok(eth_ivshmem_queue_rx(&q2, &rx_message, &rx_len)); |
| zassert_equal(rx_len, sizeof(q1_tx_data)); |
| zassert_equal(*(int *)rx_message, q1_tx_data); |
| zassert_ok(eth_ivshmem_queue_rx_complete(&q2)); |
| |
| /* Receive q1 */ |
| zassert_ok(eth_ivshmem_queue_rx(&q1, &rx_message, &rx_len)); |
| zassert_equal(rx_len, sizeof(q2_tx_data)); |
| zassert_equal(*(int *)rx_message, q2_tx_data); |
| zassert_ok(eth_ivshmem_queue_rx_complete(&q1)); |
| } |
| |
| ZTEST(eth_ivshmem_queue_tests, test_queue_empty) |
| { |
| /* Read with empty queue */ |
| zassert_equal(eth_ivshmem_queue_rx(&q1, &rx_message, &rx_len), -EWOULDBLOCK); |
| |
| /* Complete with empty queue */ |
| zassert_equal(eth_ivshmem_queue_rx_complete(&q1), -EWOULDBLOCK); |
| |
| /* TX commit without getting buffer */ |
| zassert_equal(eth_ivshmem_queue_tx_commit_buff(&q1), -EINVAL); |
| |
| /* Getting a buffer (without committing) should not modify/overflow the queue */ |
| for (int i = 0; i < 100; i++) { |
| void *data; |
| |
| zassert_ok(eth_ivshmem_queue_tx_get_buff(&q1, &data, KB(1))); |
| } |
| } |
| |
| ZTEST(eth_ivshmem_queue_tests, test_queue_descriptors_full) |
| { |
| /* Fill queue descriptors */ |
| for (int i = 0; i < VRING_DESC_LEN; i++) { |
| zassert_ok(queue_tx(&q1, &i, sizeof(i))); |
| } |
| |
| /* Fail to add another */ |
| int x = 0; |
| |
| zassert_equal(queue_tx(&q1, &x, sizeof(x)), -ENOBUFS); |
| |
| /* Read 3 */ |
| for (int i = 0; i < 3; i++) { |
| zassert_ok(eth_ivshmem_queue_rx(&q2, &rx_message, &rx_len)); |
| zassert_equal(rx_len, sizeof(i)); |
| zassert_equal(*(int *)rx_message, i); |
| zassert_ok(eth_ivshmem_queue_rx_complete(&q2)); |
| } |
| |
| /* Can now add 3 more */ |
| for (int i = 0; i < 3; i++) { |
| zassert_ok(queue_tx(&q1, &i, sizeof(i))); |
| } |
| |
| /* Fail to add another */ |
| zassert_equal(queue_tx(&q1, &x, sizeof(x)), -ENOBUFS); |
| } |
| |
| ZTEST(eth_ivshmem_queue_tests, test_queue_shmem_full) |
| { |
| static uint8_t large_message[KB(1)]; |
| |
| /* Fill queue shmem */ |
| for (int i = 0; i < VRING_DATA_MAX_LEN / sizeof(large_message); i++) { |
| zassert_ok(queue_tx(&q1, large_message, sizeof(large_message))); |
| } |
| |
| /* Fail to add another */ |
| zassert_equal(queue_tx(&q1, large_message, sizeof(large_message)), -ENOBUFS); |
| |
| /* Read 1 */ |
| zassert_ok(eth_ivshmem_queue_rx(&q2, &rx_message, &rx_len)); |
| zassert_equal(rx_len, sizeof(large_message)); |
| zassert_ok(eth_ivshmem_queue_rx_complete(&q2)); |
| |
| /* Can now add 1 more */ |
| zassert_ok(queue_tx(&q1, large_message, sizeof(large_message))); |
| |
| /* Fail to add another */ |
| zassert_equal(queue_tx(&q1, large_message, sizeof(large_message)), -ENOBUFS); |
| } |
| |
| ZTEST_SUITE(eth_ivshmem_queue_tests, NULL, NULL, test_setup, NULL, NULL); |