1 /*
2  * Copyright (c) 2024 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  */
7 
8 #include <zephyr/sys/__assert.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/uart.h>
11 #include <zephyr/pmci/mctp/mctp_uart.h>
12 #include <crc-16-ccitt.h>
13 
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(mctp_uart, CONFIG_MCTP_LOG_LEVEL);
16 
17 #define MCTP_UART_REVISION     0x01
18 #define MCTP_UART_FRAMING_FLAG 0x7e
19 #define MCTP_UART_ESCAPE       0x7d
20 
21 const char *UART_EVENT_STRING[] = {
22 	"TX Done",     "TX Aborted", "RX Ready", "RX Buffer Request", "RX Buffer Released",
23 	"RX Disabled", "RX Stopped",
24 };
25 
26 const char *MCTP_STATE_STRING[] = {
27 	"Wait: Sync Start", "Wait: Revision", "Wait: Len",  "Data",
28 	"Data: Escaped",    "Wait: FCS1",     "Wait: FCS2", "Wait: Sync End",
29 };
30 
31 struct mctp_serial_header {
32 	uint8_t flag;
33 	uint8_t revision;
34 	uint8_t len;
35 };
36 
37 struct mctp_serial_trailer {
38 	uint8_t fcs_msb;
39 	uint8_t fcs_lsb;
40 	uint8_t flag;
41 };
42 
binding_to_uart(struct mctp_binding * b)43 static inline struct mctp_binding_uart *binding_to_uart(struct mctp_binding *b)
44 {
45 	return (struct mctp_binding_uart *)b;
46 }
47 
mctp_uart_finish_pkt(struct mctp_binding_uart * uart,bool valid)48 static void mctp_uart_finish_pkt(struct mctp_binding_uart *uart, bool valid)
49 {
50 	struct mctp_pktbuf *pkt = uart->rx_pkt;
51 
52 
53 	if (valid) {
54 		__ASSERT_NO_MSG(pkt);
55 
56 		mctp_bus_rx(&uart->binding, pkt);
57 	}
58 
59 	uart->rx_pkt = NULL;
60 }
61 
mctp_uart_start_pkt(struct mctp_binding_uart * uart,uint8_t len)62 static void mctp_uart_start_pkt(struct mctp_binding_uart *uart, uint8_t len)
63 {
64 	__ASSERT_NO_MSG(uart->rx_pkt == NULL);
65 
66 	uart->rx_pkt = mctp_pktbuf_alloc(&uart->binding, len);
67 
68 	__ASSERT_NO_MSG(uart->rx_pkt);
69 }
70 
mctp_uart_pkt_escape(struct mctp_pktbuf * pkt,uint8_t * buf)71 static size_t mctp_uart_pkt_escape(struct mctp_pktbuf *pkt, uint8_t *buf)
72 {
73 	uint8_t total_len;
74 	uint8_t *p;
75 	int i, j;
76 
77 	total_len = pkt->end - pkt->mctp_hdr_off;
78 
79 	p = (void *)mctp_pktbuf_hdr(pkt);
80 
81 	for (i = 0, j = 0; i < total_len; i++, j++) {
82 		uint8_t c = p[i];
83 
84 		if (c == MCTP_UART_FRAMING_FLAG || c == MCTP_UART_ESCAPE) {
85 			if (buf) {
86 				buf[j] = MCTP_UART_ESCAPE;
87 			}
88 			j++;
89 			c ^= 0x20;
90 		}
91 		if (buf) {
92 			buf[j] = c;
93 		}
94 	}
95 
96 	return j;
97 }
98 
99 /*
100  * Each byte coming from the uart is run through this state machine which
101  * does the MCTP packet decoding.
102  *
103  * The actual packet and buffer being read into is owned by the binding!
104  */
mctp_uart_consume(struct mctp_binding_uart * uart,uint8_t c)105 static void mctp_uart_consume(struct mctp_binding_uart *uart, uint8_t c)
106 {
107 	struct mctp_pktbuf *pkt = uart->rx_pkt;
108 	bool valid = false;
109 
110 	LOG_DBG("uart consume start state: %d:%s, char 0x%02x", uart->rx_state,
111 		MCTP_STATE_STRING[uart->rx_state], c);
112 
113 	__ASSERT_NO_MSG(!pkt == (uart->rx_state == STATE_WAIT_SYNC_START ||
114 				 uart->rx_state == STATE_WAIT_REVISION ||
115 				 uart->rx_state == STATE_WAIT_LEN));
116 
117 	switch (uart->rx_state) {
118 	case STATE_WAIT_SYNC_START:
119 		if (c != MCTP_UART_FRAMING_FLAG) {
120 			LOG_DBG("lost sync, dropping packet");
121 			if (pkt) {
122 				mctp_uart_finish_pkt(uart, false);
123 			}
124 		} else {
125 			uart->rx_state = STATE_WAIT_REVISION;
126 		}
127 		break;
128 	case STATE_WAIT_REVISION:
129 		if (c == MCTP_UART_REVISION) {
130 			uart->rx_state = STATE_WAIT_LEN;
131 			uart->rx_fcs_calc = crc_16_ccitt_byte(FCS_INIT_16, c);
132 		} else if (c == MCTP_UART_FRAMING_FLAG) {
133 			/* Handle the case where there are bytes dropped in request,
134 			 * and the state machine is out of sync. The failed request's
135 			 * trailing footer i.e. 0x7e would be interpreted as next
136 			 * request's framing footer. So if we are in STATE_WAIT_REVISION
137 			 * and receive 0x7e byte, then continue to stay in
138 			 * STATE_WAIT_REVISION
139 			 */
140 			LOG_DBG("Received serial framing flag 0x%02x while waiting"
141 				" for serial revision 0x%02x.",
142 				c, MCTP_UART_REVISION);
143 		} else {
144 			LOG_DBG("invalid revision 0x%02x", c);
145 			uart->rx_state = STATE_WAIT_SYNC_START;
146 		}
147 		break;
148 	case STATE_WAIT_LEN:
149 		if (c > uart->binding.pkt_size || c < sizeof(struct mctp_hdr)) {
150 			LOG_DBG("invalid size %d", c);
151 			uart->rx_state = STATE_WAIT_SYNC_START;
152 		} else {
153 			mctp_uart_start_pkt(uart, 0);
154 			pkt = uart->rx_pkt;
155 			uart->rx_exp_len = c;
156 			uart->rx_state = STATE_DATA;
157 			uart->rx_fcs_calc = crc_16_ccitt_byte(uart->rx_fcs_calc, c);
158 		}
159 		break;
160 	case STATE_DATA:
161 		if (c == MCTP_UART_ESCAPE) {
162 			uart->rx_state = STATE_DATA_ESCAPED;
163 		} else {
164 			mctp_pktbuf_push(pkt, &c, 1);
165 			uart->rx_fcs_calc = crc_16_ccitt_byte(uart->rx_fcs_calc, c);
166 			if (pkt->end - pkt->mctp_hdr_off == uart->rx_exp_len) {
167 				uart->rx_state = STATE_WAIT_FCS1;
168 			}
169 		}
170 		break;
171 	case STATE_DATA_ESCAPED:
172 		c ^= 0x20;
173 		mctp_pktbuf_push(pkt, &c, 1);
174 		uart->rx_fcs_calc = crc_16_ccitt_byte(uart->rx_fcs_calc, c);
175 		if (pkt->end - pkt->mctp_hdr_off == uart->rx_exp_len) {
176 			uart->rx_state = STATE_WAIT_FCS1;
177 		} else {
178 			uart->rx_state = STATE_DATA;
179 		}
180 		break;
181 
182 	case STATE_WAIT_FCS1:
183 		uart->rx_fcs = c << 8;
184 		uart->rx_state = STATE_WAIT_FCS2;
185 		break;
186 	case STATE_WAIT_FCS2:
187 		uart->rx_fcs |= c;
188 		uart->rx_state = STATE_WAIT_SYNC_END;
189 		break;
190 	case STATE_WAIT_SYNC_END:
191 		if (uart->rx_fcs == uart->rx_fcs_calc) {
192 			if (c == MCTP_UART_FRAMING_FLAG) {
193 				valid = true;
194 			} else {
195 				valid = false;
196 				LOG_DBG("missing end frame marker");
197 			}
198 		} else {
199 			valid = false;
200 			LOG_DBG("invalid fcs : 0x%04x, expect 0x%04x", uart->rx_fcs,
201 				uart->rx_fcs_calc);
202 		}
203 
204 		mctp_uart_finish_pkt(uart, valid);
205 		uart->rx_state = STATE_WAIT_SYNC_START;
206 		break;
207 	}
208 
209 	LOG_DBG("uart consume end state: %d:%s, char 0x%02x", uart->rx_state,
210 		MCTP_STATE_STRING[uart->rx_state], c);
211 }
212 
mctp_uart_callback(const struct device * dev,struct uart_event * evt,void * userdata)213 static void mctp_uart_callback(const struct device *dev, struct uart_event *evt, void *userdata)
214 {
215 	struct mctp_binding_uart *binding = userdata;
216 
217 	switch (evt->type) {
218 	case UART_TX_DONE:
219 		binding->tx_res = 0;
220 		break;
221 	case UART_TX_ABORTED:
222 		binding->tx_res = -EIO;
223 		break;
224 	case UART_RX_RDY:
225 		/* buffer being read into is ready */
226 		binding->rx_res = evt->data.rx.len;
227 		/* parse the buffer */
228 		for (size_t i = 0; i < evt->data.rx.len; i++) {
229 			mctp_uart_consume(binding, evt->data.rx.buf[evt->data.rx.offset + i]);
230 		}
231 		break;
232 	case UART_RX_BUF_REQUEST:
233 		for (int i = 0; i < sizeof(binding->rx_buf_used); i++) {
234 			if (!binding->rx_buf_used[i]) {
235 				binding->rx_buf_used[i] = true;
236 				uart_rx_buf_rsp(dev, binding->rx_buf[i],
237 						sizeof(binding->rx_buf[i]));
238 				break;
239 			}
240 		}
241 		break;
242 	case UART_RX_BUF_RELEASED:
243 		for (int i = 0; i < sizeof(binding->rx_buf_used); i++) {
244 			if (binding->rx_buf[i] == evt->data.rx_buf.buf) {
245 				binding->rx_buf_used[i] = false;
246 				break;
247 			}
248 		}
249 		break;
250 	case UART_RX_STOPPED:
251 		break;
252 	case UART_RX_DISABLED:
253 		break;
254 	}
255 }
256 
mctp_uart_start_rx(struct mctp_binding_uart * uart)257 void mctp_uart_start_rx(struct mctp_binding_uart *uart)
258 {
259 	int res = uart_callback_set(uart->dev, mctp_uart_callback, uart);
260 
261 	__ASSERT_NO_MSG(res == 0);
262 	uart->rx_buf_used[0] = true;
263 	res = uart_rx_enable(uart->dev, uart->rx_buf[0], sizeof(uart->rx_buf[0]), 1000);
264 	__ASSERT_NO_MSG(res == 0);
265 }
266 
mctp_uart_tx(struct mctp_binding * b,struct mctp_pktbuf * pkt)267 int mctp_uart_tx(struct mctp_binding *b, struct mctp_pktbuf *pkt)
268 {
269 	struct mctp_binding_uart *uart = binding_to_uart(b);
270 	struct mctp_serial_header *hdr;
271 	struct mctp_serial_trailer *tlr;
272 	uint8_t *buf;
273 	size_t len;
274 	uint16_t fcs;
275 
276 	LOG_DBG("uart tx pkt %p", pkt);
277 
278 	/* the length field in the header excludes serial framing
279 	 * and escape sequences
280 	 */
281 	len = mctp_pktbuf_size(pkt);
282 
283 	hdr = (void *)uart->tx_buf;
284 	hdr->flag = MCTP_UART_FRAMING_FLAG;
285 	hdr->revision = MCTP_UART_REVISION;
286 	hdr->len = len;
287 
288 	/* Calculate fcs */
289 	fcs = crc_16_ccitt(FCS_INIT_16, (const uint8_t *)hdr + 1, 2);
290 	fcs = crc_16_ccitt(fcs, (const uint8_t *)mctp_pktbuf_hdr(pkt), len);
291 	LOG_DBG("calculated crc %d", fcs);
292 
293 	buf = (void *)(hdr + 1);
294 
295 	len = mctp_uart_pkt_escape(pkt, NULL);
296 	if (len + sizeof(*hdr) + sizeof(*tlr) > sizeof(uart->tx_buf)) {
297 		return -EMSGSIZE;
298 	}
299 
300 	mctp_uart_pkt_escape(pkt, buf);
301 
302 	buf += len;
303 
304 	tlr = (void *)buf;
305 	tlr->flag = MCTP_UART_FRAMING_FLAG;
306 	tlr->fcs_msb = fcs >> 8;
307 	tlr->fcs_lsb = fcs & 0xff;
308 
309 	len += sizeof(*hdr) + sizeof(*tlr);
310 
311 	int res = uart_tx(uart->dev, (const uint8_t *)uart->tx_buf, len, SYS_FOREVER_US);
312 
313 	if (res != 0) {
314 		LOG_ERR("Failed sending data, %d", res);
315 		return res;
316 	}
317 
318 	return uart->tx_res;
319 }
320 
mctp_uart_start(struct mctp_binding * binding)321 int mctp_uart_start(struct mctp_binding *binding)
322 {
323 	mctp_binding_set_tx_enabled(binding, true);
324 	return 0;
325 }
326