1*e5b941d9SMatt Johnston /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2*e5b941d9SMatt Johnston
3*e5b941d9SMatt Johnston #if HAVE_CONFIG_H
4*e5b941d9SMatt Johnston #include "config.h"
5*e5b941d9SMatt Johnston #endif
6*e5b941d9SMatt Johnston
7*e5b941d9SMatt Johnston #include "compiler.h"
8*e5b941d9SMatt Johnston #include "range.h"
9*e5b941d9SMatt Johnston #include "libmctp-log.h"
10*e5b941d9SMatt Johnston #include "libmctp-i2c.h"
11*e5b941d9SMatt Johnston #include "libmctp-sizes.h"
12*e5b941d9SMatt Johnston #include "libmctp-alloc.h"
13*e5b941d9SMatt Johnston
14*e5b941d9SMatt Johnston /* For access to mctp_bninding_i2c internals */
15*e5b941d9SMatt Johnston #include "i2c-internal.h"
16*e5b941d9SMatt Johnston
17*e5b941d9SMatt Johnston #ifdef NDEBUG
18*e5b941d9SMatt Johnston #undef NDEBUG
19*e5b941d9SMatt Johnston #endif
20*e5b941d9SMatt Johnston
21*e5b941d9SMatt Johnston #include <assert.h>
22*e5b941d9SMatt Johnston #include <errno.h>
23*e5b941d9SMatt Johnston #include <fcntl.h>
24*e5b941d9SMatt Johnston #include <stdbool.h>
25*e5b941d9SMatt Johnston #include <stdio.h>
26*e5b941d9SMatt Johnston #include <string.h>
27*e5b941d9SMatt Johnston #include <unistd.h>
28*e5b941d9SMatt Johnston #include <stdlib.h>
29*e5b941d9SMatt Johnston
30*e5b941d9SMatt Johnston struct mctp_binding_serial_pipe {
31*e5b941d9SMatt Johnston int ingress;
32*e5b941d9SMatt Johnston int egress;
33*e5b941d9SMatt Johnston
34*e5b941d9SMatt Johnston struct mctp_binding_serial *serial;
35*e5b941d9SMatt Johnston };
36*e5b941d9SMatt Johnston
37*e5b941d9SMatt Johnston // Sized to test fragmentation and >8 bit length
38*e5b941d9SMatt Johnston #define TEST_MSG_LEN 300
39*e5b941d9SMatt Johnston static uint8_t mctp_msg_src[TEST_MSG_LEN];
40*e5b941d9SMatt Johnston
41*e5b941d9SMatt Johnston struct i2c_test {
42*e5b941d9SMatt Johnston struct mctp_binding_i2c *i2c;
43*e5b941d9SMatt Johnston struct mctp *mctp;
44*e5b941d9SMatt Johnston
45*e5b941d9SMatt Johnston uint8_t rx_msg[TEST_MSG_LEN];
46*e5b941d9SMatt Johnston size_t rx_len;
47*e5b941d9SMatt Johnston
48*e5b941d9SMatt Johnston /* Physical addresses. These get set regardless of whether the packet
49*e5b941d9SMatt Johnston * is dropped by the stack (no match etc) */
50*e5b941d9SMatt Johnston uint8_t last_rx_i2c_src;
51*e5b941d9SMatt Johnston uint8_t last_tx_i2c_dst;
52*e5b941d9SMatt Johnston };
53*e5b941d9SMatt Johnston
54*e5b941d9SMatt Johnston static const uint8_t I2C_ADDR_A = 0x20;
55*e5b941d9SMatt Johnston static const uint8_t I2C_ADDR_B = 0x21;
56*e5b941d9SMatt Johnston static const uint8_t EID_A = 50;
57*e5b941d9SMatt Johnston static const uint8_t EID_B = 51;
58*e5b941d9SMatt Johnston
test_i2c_tx(const void * buf,size_t len,void * ctx)59*e5b941d9SMatt Johnston static int test_i2c_tx(const void *buf, size_t len, void *ctx)
60*e5b941d9SMatt Johnston {
61*e5b941d9SMatt Johnston struct i2c_test *test_pair = ctx;
62*e5b941d9SMatt Johnston struct i2c_test *tx_test = &test_pair[0];
63*e5b941d9SMatt Johnston struct i2c_test *rx_test = &test_pair[1];
64*e5b941d9SMatt Johnston
65*e5b941d9SMatt Johnston mctp_prdebug("test_i2c_tx len %zu", len);
66*e5b941d9SMatt Johnston
67*e5b941d9SMatt Johnston const struct mctp_i2c_hdr *hdr = buf;
68*e5b941d9SMatt Johnston tx_test->last_tx_i2c_dst = hdr->dest >> 1;
69*e5b941d9SMatt Johnston rx_test->last_rx_i2c_src = hdr->source >> 1;
70*e5b941d9SMatt Johnston
71*e5b941d9SMatt Johnston mctp_i2c_rx(rx_test->i2c, buf, len);
72*e5b941d9SMatt Johnston return 0;
73*e5b941d9SMatt Johnston }
74*e5b941d9SMatt Johnston
test_i2c_rxmsg(uint8_t src_eid,bool tag_owner,uint8_t msg_tag,void * ctx,void * msg,size_t len)75*e5b941d9SMatt Johnston static void test_i2c_rxmsg(uint8_t src_eid, bool tag_owner, uint8_t msg_tag,
76*e5b941d9SMatt Johnston void *ctx, void *msg, size_t len)
77*e5b941d9SMatt Johnston {
78*e5b941d9SMatt Johnston struct i2c_test *test_pair = ctx;
79*e5b941d9SMatt Johnston // struct i2c_test *tx_test = &test_pair[0];
80*e5b941d9SMatt Johnston struct i2c_test *rx_test = &test_pair[1];
81*e5b941d9SMatt Johnston
82*e5b941d9SMatt Johnston mctp_prdebug("test_i2c_rx src %d len %zu tag %d owner %d", src_eid, len,
83*e5b941d9SMatt Johnston msg_tag, tag_owner);
84*e5b941d9SMatt Johnston
85*e5b941d9SMatt Johnston // Must be cleared by previous test runs
86*e5b941d9SMatt Johnston assert(rx_test->rx_len == 0);
87*e5b941d9SMatt Johnston memcpy(rx_test->rx_msg, msg, len);
88*e5b941d9SMatt Johnston rx_test->rx_len = len;
89*e5b941d9SMatt Johnston }
90*e5b941d9SMatt Johnston
91*e5b941d9SMatt Johnston /* Transmits a MCTP message and checks the received message matches */
run_tx_test(struct i2c_test * tx_test,uint8_t dest_eid,size_t tx_len,struct i2c_test * rx_test)92*e5b941d9SMatt Johnston static void run_tx_test(struct i2c_test *tx_test, uint8_t dest_eid,
93*e5b941d9SMatt Johnston size_t tx_len, struct i2c_test *rx_test)
94*e5b941d9SMatt Johnston {
95*e5b941d9SMatt Johnston int rc;
96*e5b941d9SMatt Johnston const uint8_t msg_tag = 2;
97*e5b941d9SMatt Johnston const bool tag_owner = false;
98*e5b941d9SMatt Johnston
99*e5b941d9SMatt Johnston assert(tx_len <= sizeof(mctp_msg_src));
100*e5b941d9SMatt Johnston rc = mctp_message_tx(tx_test->mctp, dest_eid, tag_owner, msg_tag,
101*e5b941d9SMatt Johnston mctp_msg_src, tx_len);
102*e5b941d9SMatt Johnston assert(rc == 0);
103*e5b941d9SMatt Johnston
104*e5b941d9SMatt Johnston while (!mctp_is_tx_ready(tx_test->mctp, dest_eid)) {
105*e5b941d9SMatt Johnston mctp_i2c_tx_poll(tx_test->i2c);
106*e5b941d9SMatt Johnston }
107*e5b941d9SMatt Johnston
108*e5b941d9SMatt Johnston assert(rx_test->rx_len == tx_len);
109*e5b941d9SMatt Johnston assert(memcmp(rx_test->rx_msg, mctp_msg_src, tx_len) == 0);
110*e5b941d9SMatt Johnston
111*e5b941d9SMatt Johnston rx_test->rx_len = 0;
112*e5b941d9SMatt Johnston }
113*e5b941d9SMatt Johnston
test_neigh_expiry(struct i2c_test * tx_test,struct i2c_test * rx_test)114*e5b941d9SMatt Johnston static void test_neigh_expiry(struct i2c_test *tx_test,
115*e5b941d9SMatt Johnston struct i2c_test *rx_test)
116*e5b941d9SMatt Johnston {
117*e5b941d9SMatt Johnston const uint8_t msg_tag = 2;
118*e5b941d9SMatt Johnston const bool tag_owner = true;
119*e5b941d9SMatt Johnston const size_t msg_len = 5;
120*e5b941d9SMatt Johnston int rc;
121*e5b941d9SMatt Johnston
122*e5b941d9SMatt Johnston (void)rx_test;
123*e5b941d9SMatt Johnston
124*e5b941d9SMatt Johnston /* Clear the tx neighbour table */
125*e5b941d9SMatt Johnston memset(tx_test->i2c->neigh, 0x0, sizeof(tx_test->i2c->neigh));
126*e5b941d9SMatt Johnston
127*e5b941d9SMatt Johnston /* Check that all EIDs fail */
128*e5b941d9SMatt Johnston rx_test->rx_len = 0;
129*e5b941d9SMatt Johnston for (size_t eid = 8; eid < 254; eid++) {
130*e5b941d9SMatt Johnston mctp_message_tx(tx_test->mctp, eid, tag_owner, msg_tag,
131*e5b941d9SMatt Johnston mctp_msg_src, msg_len);
132*e5b941d9SMatt Johnston /* Not received */
133*e5b941d9SMatt Johnston assert(rx_test->rx_len == 0);
134*e5b941d9SMatt Johnston }
135*e5b941d9SMatt Johnston
136*e5b941d9SMatt Johnston /* Add one entry */
137*e5b941d9SMatt Johnston rc = mctp_i2c_set_neighbour(tx_test->i2c, EID_B,
138*e5b941d9SMatt Johnston rx_test->i2c->own_addr);
139*e5b941d9SMatt Johnston assert(rc == 0);
140*e5b941d9SMatt Johnston rx_test->rx_len = 0;
141*e5b941d9SMatt Johnston mctp_message_tx(tx_test->mctp, EID_B, tag_owner, msg_tag, mctp_msg_src,
142*e5b941d9SMatt Johnston msg_len);
143*e5b941d9SMatt Johnston assert(rx_test->rx_len == msg_len);
144*e5b941d9SMatt Johnston assert(tx_test->last_tx_i2c_dst == rx_test->i2c->own_addr);
145*e5b941d9SMatt Johnston
146*e5b941d9SMatt Johnston /* Replace the entry */
147*e5b941d9SMatt Johnston rx_test->i2c->own_addr++;
148*e5b941d9SMatt Johnston rc = mctp_i2c_set_neighbour(tx_test->i2c, EID_B,
149*e5b941d9SMatt Johnston rx_test->i2c->own_addr);
150*e5b941d9SMatt Johnston assert(rc == 0);
151*e5b941d9SMatt Johnston rx_test->rx_len = 0;
152*e5b941d9SMatt Johnston mctp_message_tx(tx_test->mctp, EID_B, tag_owner, msg_tag, mctp_msg_src,
153*e5b941d9SMatt Johnston msg_len);
154*e5b941d9SMatt Johnston assert(rc == 0);
155*e5b941d9SMatt Johnston assert(rx_test->rx_len == msg_len);
156*e5b941d9SMatt Johnston assert(tx_test->last_tx_i2c_dst == rx_test->i2c->own_addr);
157*e5b941d9SMatt Johnston
158*e5b941d9SMatt Johnston /* Check only one entry is set */
159*e5b941d9SMatt Johnston size_t count = 0;
160*e5b941d9SMatt Johnston for (size_t i = 0; i < MCTP_I2C_NEIGH_COUNT; i++) {
161*e5b941d9SMatt Johnston struct mctp_i2c_neigh *n = &tx_test->i2c->neigh[i];
162*e5b941d9SMatt Johnston if (n->used) {
163*e5b941d9SMatt Johnston assert(n->eid == EID_B);
164*e5b941d9SMatt Johnston count++;
165*e5b941d9SMatt Johnston }
166*e5b941d9SMatt Johnston }
167*e5b941d9SMatt Johnston assert(count == 1);
168*e5b941d9SMatt Johnston
169*e5b941d9SMatt Johnston /* Ensure we can iterate without overflow.
170*e5b941d9SMatt Johnston * If MCTP_I2C_NEIGH_COUNT increases too large this test would need rethinking
171*e5b941d9SMatt Johnston * (and eviction may become impossible) */
172*e5b941d9SMatt Johnston assert((int)EID_B + MCTP_I2C_NEIGH_COUNT < 254);
173*e5b941d9SMatt Johnston assert((int)I2C_ADDR_B + MCTP_I2C_NEIGH_COUNT < 0x7f);
174*e5b941d9SMatt Johnston
175*e5b941d9SMatt Johnston /* Fill entries. -1 because one was already filled. */
176*e5b941d9SMatt Johnston for (size_t i = 0; i < MCTP_I2C_NEIGH_COUNT - 1; i++) {
177*e5b941d9SMatt Johnston /* Unused addresses */
178*e5b941d9SMatt Johnston uint8_t addr = rx_test->i2c->own_addr + i + 1;
179*e5b941d9SMatt Johnston uint8_t eid = EID_B + i + 1;
180*e5b941d9SMatt Johnston rc = mctp_i2c_set_neighbour(tx_test->i2c, eid, addr);
181*e5b941d9SMatt Johnston assert(rc == 0);
182*e5b941d9SMatt Johnston }
183*e5b941d9SMatt Johnston
184*e5b941d9SMatt Johnston /* Check all are used */
185*e5b941d9SMatt Johnston for (size_t i = 0; i < MCTP_I2C_NEIGH_COUNT; i++) {
186*e5b941d9SMatt Johnston struct mctp_i2c_neigh *n = &tx_test->i2c->neigh[i];
187*e5b941d9SMatt Johnston assert(n->used);
188*e5b941d9SMatt Johnston }
189*e5b941d9SMatt Johnston
190*e5b941d9SMatt Johnston /* Test eviction */
191*e5b941d9SMatt Johnston {
192*e5b941d9SMatt Johnston uint8_t addr =
193*e5b941d9SMatt Johnston rx_test->i2c->own_addr + MCTP_I2C_NEIGH_COUNT + 1;
194*e5b941d9SMatt Johnston uint8_t eid = EID_B + MCTP_I2C_NEIGH_COUNT + 1;
195*e5b941d9SMatt Johnston rc = mctp_i2c_set_neighbour(tx_test->i2c, eid, addr);
196*e5b941d9SMatt Johnston assert(rc == 0);
197*e5b941d9SMatt Johnston
198*e5b941d9SMatt Johnston /* EID_B got evicted, send should fail */
199*e5b941d9SMatt Johnston rx_test->rx_len = 0;
200*e5b941d9SMatt Johnston mctp_message_tx(tx_test->mctp, EID_B, tag_owner, msg_tag,
201*e5b941d9SMatt Johnston mctp_msg_src, msg_len);
202*e5b941d9SMatt Johnston /* Not received */
203*e5b941d9SMatt Johnston assert(rx_test->rx_len == 0);
204*e5b941d9SMatt Johnston }
205*e5b941d9SMatt Johnston
206*e5b941d9SMatt Johnston /* Add EID_B again */
207*e5b941d9SMatt Johnston rc = mctp_i2c_set_neighbour(tx_test->i2c, EID_B,
208*e5b941d9SMatt Johnston rx_test->i2c->own_addr);
209*e5b941d9SMatt Johnston assert(rc == 0);
210*e5b941d9SMatt Johnston rx_test->rx_len = 0;
211*e5b941d9SMatt Johnston mctp_message_tx(tx_test->mctp, EID_B, tag_owner, msg_tag, mctp_msg_src,
212*e5b941d9SMatt Johnston msg_len);
213*e5b941d9SMatt Johnston /* Is received */
214*e5b941d9SMatt Johnston assert(rx_test->rx_len == msg_len);
215*e5b941d9SMatt Johnston }
216*e5b941d9SMatt Johnston
main(void)217*e5b941d9SMatt Johnston int main(void)
218*e5b941d9SMatt Johnston {
219*e5b941d9SMatt Johnston struct i2c_test scenario[2];
220*e5b941d9SMatt Johnston struct i2c_test *tx_test = &scenario[0];
221*e5b941d9SMatt Johnston struct i2c_test *rx_test = &scenario[1];
222*e5b941d9SMatt Johnston
223*e5b941d9SMatt Johnston mctp_set_log_stdio(MCTP_LOG_DEBUG);
224*e5b941d9SMatt Johnston
225*e5b941d9SMatt Johnston memset(scenario, 0x0, sizeof(scenario));
226*e5b941d9SMatt Johnston
227*e5b941d9SMatt Johnston /* Setup a source buffer */
228*e5b941d9SMatt Johnston for (size_t i = 0; i < sizeof(mctp_msg_src); i++) {
229*e5b941d9SMatt Johnston mctp_msg_src[i] = i & 0xff;
230*e5b941d9SMatt Johnston }
231*e5b941d9SMatt Johnston
232*e5b941d9SMatt Johnston tx_test->mctp = mctp_init();
233*e5b941d9SMatt Johnston assert(tx_test->mctp);
234*e5b941d9SMatt Johnston tx_test->i2c = malloc(MCTP_SIZEOF_BINDING_I2C);
235*e5b941d9SMatt Johnston assert(tx_test->i2c);
236*e5b941d9SMatt Johnston rx_test->mctp = mctp_init();
237*e5b941d9SMatt Johnston assert(rx_test->mctp);
238*e5b941d9SMatt Johnston rx_test->i2c = malloc(MCTP_SIZEOF_BINDING_I2C);
239*e5b941d9SMatt Johnston assert(rx_test->i2c);
240*e5b941d9SMatt Johnston
241*e5b941d9SMatt Johnston /* TX side */
242*e5b941d9SMatt Johnston mctp_i2c_setup(tx_test->i2c, I2C_ADDR_A, test_i2c_tx, scenario);
243*e5b941d9SMatt Johnston mctp_register_bus(tx_test->mctp, mctp_binding_i2c_core(tx_test->i2c),
244*e5b941d9SMatt Johnston EID_A);
245*e5b941d9SMatt Johnston mctp_set_rx_all(tx_test->mctp, NULL, NULL);
246*e5b941d9SMatt Johnston mctp_i2c_set_neighbour(tx_test->i2c, EID_B, I2C_ADDR_B);
247*e5b941d9SMatt Johnston
248*e5b941d9SMatt Johnston /* RX side */
249*e5b941d9SMatt Johnston mctp_i2c_setup(rx_test->i2c, I2C_ADDR_B, NULL, NULL);
250*e5b941d9SMatt Johnston mctp_register_bus(rx_test->mctp, mctp_binding_i2c_core(rx_test->i2c),
251*e5b941d9SMatt Johnston EID_B);
252*e5b941d9SMatt Johnston mctp_set_rx_all(rx_test->mctp, test_i2c_rxmsg, scenario);
253*e5b941d9SMatt Johnston // mctp_i2c_set_neighbour(rx_test->i2c, EID_A, I2C_ADDR_A);
254*e5b941d9SMatt Johnston
255*e5b941d9SMatt Johnston /* Try all message sizes */
256*e5b941d9SMatt Johnston for (size_t i = 1; i < sizeof(mctp_msg_src); i++) {
257*e5b941d9SMatt Johnston run_tx_test(tx_test, EID_B, i, rx_test);
258*e5b941d9SMatt Johnston }
259*e5b941d9SMatt Johnston
260*e5b941d9SMatt Johnston test_neigh_expiry(tx_test, rx_test);
261*e5b941d9SMatt Johnston
262*e5b941d9SMatt Johnston return 0;
263*e5b941d9SMatt Johnston }
264