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