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