xref: /openbmc/libmctp/astlpc.c (revision 3a540664c5fbf8cabeca0c1a1af27b1b979eb253)
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 #if HAVE_ENDIAN_H
8 #include <endian.h>
9 #endif
10 
11 #include <assert.h>
12 #include <err.h>
13 #include <errno.h>
14 #include <inttypes.h>
15 #include <stdbool.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #define pr_fmt(x) "astlpc: " x
20 
21 #include "libmctp.h"
22 #include "libmctp-alloc.h"
23 #include "libmctp-log.h"
24 #include "libmctp-astlpc.h"
25 #include "container_of.h"
26 
27 #ifdef MCTP_HAVE_FILEIO
28 
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <sys/ioctl.h>
32 #include <sys/mman.h>
33 #include <linux/aspeed-lpc-ctrl.h>
34 
35 /* kernel interface */
36 static const char *kcs_path = "/dev/mctp0";
37 static const char *lpc_path = "/dev/aspeed-lpc-ctrl";
38 
39 #endif
40 
41 struct mctp_astlpc_buffer {
42 	uint32_t offset;
43 	uint32_t size;
44 };
45 
46 struct mctp_astlpc_layout {
47 	struct mctp_astlpc_buffer rx;
48 	struct mctp_astlpc_buffer tx;
49 };
50 
51 struct mctp_binding_astlpc {
52 	struct mctp_binding	binding;
53 
54 	void *lpc_map;
55 	struct mctp_astlpc_layout layout;
56 
57 	uint8_t mode;
58 	uint16_t version;
59 
60 	/* direct ops data */
61 	struct mctp_binding_astlpc_ops ops;
62 	void *ops_data;
63 
64 	/* fileio ops data */
65 	int kcs_fd;
66 	uint8_t kcs_status;
67 
68 	bool			running;
69 };
70 
71 #define binding_to_astlpc(b) \
72 	container_of(b, struct mctp_binding_astlpc, binding)
73 
74 #define astlpc_prlog(ctx, lvl, fmt, ...)                                       \
75 	do {                                                                   \
76 		bool __bmc = ((ctx)->mode == MCTP_BINDING_ASTLPC_MODE_BMC);    \
77 		mctp_prlog(lvl, pr_fmt("%s: " fmt), __bmc ? "bmc" : "host",    \
78 			   ##__VA_ARGS__);                                     \
79 	} while (0)
80 
81 #define astlpc_prerr(ctx, fmt, ...)                                            \
82 	astlpc_prlog(ctx, MCTP_LOG_ERR, fmt, ##__VA_ARGS__)
83 #define astlpc_prwarn(ctx, fmt, ...)                                           \
84 	astlpc_prlog(ctx, MCTP_LOG_WARNING, fmt, ##__VA_ARGS__)
85 #define astlpc_prinfo(ctx, fmt, ...)                                           \
86 	astlpc_prlog(ctx, MCTP_LOG_INFO, fmt, ##__VA_ARGS__)
87 #define astlpc_prdebug(ctx, fmt, ...)                                          \
88 	astlpc_prlog(ctx, MCTP_LOG_DEBUG, fmt, ##__VA_ARGS__)
89 
90 /* clang-format off */
91 #define ASTLPC_MCTP_MAGIC	0x4d435450
92 #define ASTLPC_VER_BAD	0
93 #define ASTLPC_VER_MIN	1
94 
95 /* Support testing of new binding protocols */
96 #ifndef ASTLPC_VER_CUR
97 #define ASTLPC_VER_CUR	1
98 #endif
99 
100 #define ASTLPC_PACKET_SIZE(sz)	(4 + (sz))
101 #define ASTLPC_BODY_SIZE(sz)	((sz) - 4)
102 /* clang-format on */
103 
104 struct mctp_lpcmap_hdr {
105 	uint32_t magic;
106 
107 	uint16_t bmc_ver_min;
108 	uint16_t bmc_ver_cur;
109 	uint16_t host_ver_min;
110 	uint16_t host_ver_cur;
111 	uint16_t negotiated_ver;
112 	uint16_t pad0;
113 
114 	struct {
115 		uint32_t rx_offset;
116 		uint32_t rx_size;
117 		uint32_t tx_offset;
118 		uint32_t tx_size;
119 	} layout;
120 } __attribute__((packed));
121 
122 static const uint32_t control_size = 0x100;
123 
124 #define LPC_WIN_SIZE                (1 * 1024 * 1024)
125 
126 #define KCS_STATUS_BMC_READY		0x80
127 #define KCS_STATUS_CHANNEL_ACTIVE	0x40
128 #define KCS_STATUS_IBF			0x02
129 #define KCS_STATUS_OBF			0x01
130 
131 #define MIN(a, b)                                                              \
132 	({                                                                     \
133 		typeof(a) _a = a;                                              \
134 		typeof(b) _b = b;                                              \
135 		_a < _b ? _a : _b;                                             \
136 	})
137 
138 #define MAX(a, b)                                                              \
139 	({                                                                     \
140 		typeof(a) _a = a;                                              \
141 		typeof(b) _b = b;                                              \
142 		_a > _b ? _a : _b;                                             \
143 	})
144 
145 static inline int mctp_astlpc_kcs_write(struct mctp_binding_astlpc *astlpc,
146 					enum mctp_binding_astlpc_kcs_reg reg,
147 					uint8_t val)
148 {
149 	return astlpc->ops.kcs_write(astlpc->ops_data, reg, val);
150 }
151 
152 static inline int mctp_astlpc_kcs_read(struct mctp_binding_astlpc *astlpc,
153 				       enum mctp_binding_astlpc_kcs_reg reg,
154 				       uint8_t *val)
155 {
156 	return astlpc->ops.kcs_read(astlpc->ops_data, reg, val);
157 }
158 
159 static inline int mctp_astlpc_lpc_write(struct mctp_binding_astlpc *astlpc,
160 					const void *buf, long offset,
161 					size_t len)
162 {
163 	astlpc_prdebug(astlpc, "%s: %zu bytes to 0x%lx", __func__, len, offset);
164 
165 	assert(offset >= 0);
166 
167 	/* Indirect access */
168 	if (astlpc->ops.lpc_write) {
169 		void *data = astlpc->ops_data;
170 
171 		return astlpc->ops.lpc_write(data, buf, offset, len);
172 	}
173 
174 	/* Direct mapping */
175 	assert(astlpc->lpc_map);
176 	memcpy(&((char *)astlpc->lpc_map)[offset], buf, len);
177 
178 	return 0;
179 }
180 
181 static inline int mctp_astlpc_lpc_read(struct mctp_binding_astlpc *astlpc,
182 				       void *buf, long offset, size_t len)
183 {
184 	astlpc_prdebug(astlpc, "%s: %zu bytes from 0x%lx", __func__, len,
185 		       offset);
186 
187 	assert(offset >= 0);
188 
189 	/* Indirect access */
190 	if (astlpc->ops.lpc_read) {
191 		void *data = astlpc->ops_data;
192 
193 		return astlpc->ops.lpc_read(data, buf, offset, len);
194 	}
195 
196 	/* Direct mapping */
197 	assert(astlpc->lpc_map);
198 	memcpy(buf, &((char *)astlpc->lpc_map)[offset], len);
199 
200 	return 0;
201 }
202 
203 static int mctp_astlpc_kcs_set_status(struct mctp_binding_astlpc *astlpc,
204 				      uint8_t status)
205 {
206 	uint8_t data;
207 	int rc;
208 
209 	/* Since we're setting the status register, we want the other endpoint
210 	 * to be interrupted. However, some hardware may only raise a host-side
211 	 * interrupt on an ODR event.
212 	 * So, write a dummy value of 0xff to ODR, which will ensure that an
213 	 * interrupt is triggered, and can be ignored by the host.
214 	 */
215 	data = 0xff;
216 	status |= KCS_STATUS_OBF;
217 
218 	rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, status);
219 	if (rc) {
220 		astlpc_prwarn(astlpc, "KCS status write failed");
221 		return -1;
222 	}
223 
224 	rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, data);
225 	if (rc) {
226 		astlpc_prwarn(astlpc, "KCS dummy data write failed");
227 		return -1;
228 	}
229 
230 	return 0;
231 }
232 
233 static int mctp_astlpc_layout_read(struct mctp_binding_astlpc *astlpc,
234 				   struct mctp_astlpc_layout *layout)
235 {
236 	struct mctp_lpcmap_hdr hdr;
237 	int rc;
238 
239 	rc = mctp_astlpc_lpc_read(astlpc, &hdr, 0, sizeof(hdr));
240 	if (rc < 0)
241 		return rc;
242 
243 	/* Flip the buffers as the names are defined in terms of the host */
244 	if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC) {
245 		layout->rx.offset = be32toh(hdr.layout.tx_offset);
246 		layout->rx.size = be32toh(hdr.layout.tx_size);
247 		layout->tx.offset = be32toh(hdr.layout.rx_offset);
248 		layout->tx.size = be32toh(hdr.layout.rx_size);
249 	} else {
250 		assert(astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST);
251 
252 		layout->rx.offset = be32toh(hdr.layout.rx_offset);
253 		layout->rx.size = be32toh(hdr.layout.rx_size);
254 		layout->tx.offset = be32toh(hdr.layout.tx_offset);
255 		layout->tx.size = be32toh(hdr.layout.tx_size);
256 	}
257 
258 	return 0;
259 }
260 
261 static int mctp_astlpc_layout_write(struct mctp_binding_astlpc *astlpc,
262 				    struct mctp_astlpc_layout *layout)
263 {
264 	uint32_t rx_size_be;
265 
266 	if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC) {
267 		struct mctp_lpcmap_hdr hdr;
268 
269 		/*
270 		 * Flip the buffers as the names are defined in terms of the
271 		 * host
272 		 */
273 		hdr.layout.rx_offset = htobe32(layout->tx.offset);
274 		hdr.layout.rx_size = htobe32(layout->tx.size);
275 		hdr.layout.tx_offset = htobe32(layout->rx.offset);
276 		hdr.layout.tx_size = htobe32(layout->rx.size);
277 
278 		return mctp_astlpc_lpc_write(astlpc, &hdr.layout,
279 				offsetof(struct mctp_lpcmap_hdr, layout),
280 				sizeof(hdr.layout));
281 	}
282 
283 	assert(astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST);
284 
285 	/*
286 	 * As of v2 we only need to write rx_size - the offsets are controlled
287 	 * by the BMC, as is the BMC's rx_size (host tx_size).
288 	 */
289 	rx_size_be = htobe32(layout->rx.size);
290 	return mctp_astlpc_lpc_write(astlpc, &rx_size_be,
291 			offsetof(struct mctp_lpcmap_hdr, layout.rx_size),
292 			sizeof(rx_size_be));
293 }
294 
295 static bool mctp_astlpc_buffer_validate(struct mctp_astlpc_buffer *buf,
296 					const char *name)
297 {
298 	/* Check for overflow */
299 	if (buf->offset + buf->size < buf->offset) {
300 		mctp_prerr(
301 			"%s packet buffer parameters overflow: offset: 0x%" PRIx32
302 			", size: %" PRIu32,
303 			name, buf->offset, buf->size);
304 		return false;
305 	}
306 
307 	/* Check that the buffers are contained within the allocated space */
308 	if (buf->offset + buf->size > LPC_WIN_SIZE) {
309 		mctp_prerr(
310 			"%s packet buffer parameters exceed %uM window size: offset: 0x%" PRIx32
311 			", size: %" PRIu32,
312 			name, (LPC_WIN_SIZE / (1024 * 1024)), buf->offset,
313 			buf->size);
314 		return false;
315 	}
316 
317 	/* Check that the baseline transmission unit is supported */
318 	if (buf->size < ASTLPC_PACKET_SIZE(MCTP_PACKET_SIZE(MCTP_BTU))) {
319 		mctp_prerr(
320 			"%s packet buffer too small: Require %zu bytes to support the %u byte baseline transmission unit, found %" PRIu32,
321 			name, ASTLPC_PACKET_SIZE(MCTP_PACKET_SIZE(MCTP_BTU)),
322 			MCTP_BTU, buf->size);
323 		return false;
324 	}
325 
326 	/* Check for overlap with the control space */
327 	if (buf->offset < control_size) {
328 		mctp_prerr(
329 			"%s packet buffer overlaps control region {0x%" PRIx32
330 			", %" PRIu32 "}: Rx {0x%" PRIx32 ", %" PRIu32 "}",
331 			name, 0U, control_size, buf->offset, buf->size);
332 		return false;
333 	}
334 
335 	return true;
336 }
337 
338 static bool mctp_astlpc_layout_validate(struct mctp_astlpc_layout *layout)
339 {
340 	struct mctp_astlpc_buffer *rx = &layout->rx;
341 	struct mctp_astlpc_buffer *tx = &layout->tx;
342 	bool rx_valid, tx_valid;
343 
344 	rx_valid = mctp_astlpc_buffer_validate(rx, "Rx");
345 	tx_valid = mctp_astlpc_buffer_validate(tx, "Tx");
346 
347 	if (!(rx_valid && tx_valid))
348 		return false;
349 
350 	/* Check that the buffers are disjoint */
351 	if ((rx->offset <= tx->offset && rx->offset + rx->size > tx->offset) ||
352 	    (tx->offset <= rx->offset && tx->offset + tx->size > rx->offset)) {
353 		mctp_prerr("Rx and Tx packet buffers overlap: Rx {0x%" PRIx32
354 			   ", %" PRIu32 "}, Tx {0x%" PRIx32 ", %" PRIu32 "}",
355 			   rx->offset, rx->size, tx->offset, tx->size);
356 		return false;
357 	}
358 
359 	return true;
360 }
361 
362 static int mctp_astlpc_init_bmc(struct mctp_binding_astlpc *astlpc)
363 {
364 	struct mctp_lpcmap_hdr hdr = { 0 };
365 	uint8_t status;
366 	size_t sz;
367 
368 	/*
369 	 * The largest buffer size is half of the allocated MCTP space
370 	 * excluding the control space.
371 	 */
372 	sz = ((LPC_WIN_SIZE - control_size) / 2);
373 
374 	/*
375 	 * Trim the MTU to a multiple of 16 to meet the requirements of 12.17
376 	 * Query Hop in DSP0236 v1.3.0.
377 	 */
378 	sz = MCTP_BODY_SIZE(ASTLPC_BODY_SIZE(sz));
379 	sz &= ~0xfUL;
380 	sz = ASTLPC_PACKET_SIZE(MCTP_PACKET_SIZE(sz));
381 
382 	/* Flip the buffers as the names are defined in terms of the host */
383 	astlpc->layout.tx.offset = control_size;
384 	astlpc->layout.tx.size = sz;
385 	astlpc->layout.rx.offset =
386 		astlpc->layout.tx.offset + astlpc->layout.tx.size;
387 	astlpc->layout.rx.size = sz;
388 
389 	/* Sanity check that can be eliminated if asserts are off */
390 	assert(mctp_astlpc_layout_validate(&astlpc->layout));
391 
392 	hdr = (struct mctp_lpcmap_hdr){
393 		.magic = htobe32(ASTLPC_MCTP_MAGIC),
394 		.bmc_ver_min = htobe16(ASTLPC_VER_MIN),
395 		.bmc_ver_cur = htobe16(ASTLPC_VER_CUR),
396 
397 		/* Flip the buffers back as we're now describing the host's
398 		 * configuration to the host */
399 		.layout.rx_offset = htobe32(astlpc->layout.tx.offset),
400 		.layout.rx_size = htobe32(astlpc->layout.tx.size),
401 		.layout.tx_offset = htobe32(astlpc->layout.rx.offset),
402 		.layout.tx_size = htobe32(astlpc->layout.rx.size),
403 	};
404 
405 	mctp_astlpc_lpc_write(astlpc, &hdr, 0, sizeof(hdr));
406 
407 	/* set status indicating that the BMC is now active */
408 	status = KCS_STATUS_BMC_READY | KCS_STATUS_OBF;
409 	return mctp_astlpc_kcs_set_status(astlpc, status);
410 }
411 
412 static int mctp_binding_astlpc_start_bmc(struct mctp_binding *b)
413 {
414 	struct mctp_binding_astlpc *astlpc =
415 		container_of(b, struct mctp_binding_astlpc, binding);
416 
417 	return mctp_astlpc_init_bmc(astlpc);
418 }
419 
420 static bool mctp_astlpc_validate_version(uint16_t bmc_ver_min,
421 					 uint16_t bmc_ver_cur,
422 					 uint16_t host_ver_min,
423 					 uint16_t host_ver_cur)
424 {
425 	if (!(bmc_ver_min && bmc_ver_cur && host_ver_min && host_ver_cur)) {
426 		mctp_prerr("Invalid version present in [%" PRIu16 ", %" PRIu16
427 			   "], [%" PRIu16 ", %" PRIu16 "]",
428 			   bmc_ver_min, bmc_ver_cur, host_ver_min,
429 			   host_ver_cur);
430 		return false;
431 	} else if (bmc_ver_min > bmc_ver_cur) {
432 		mctp_prerr("Invalid bmc version range [%" PRIu16 ", %" PRIu16
433 			   "]",
434 			   bmc_ver_min, bmc_ver_cur);
435 		return false;
436 	} else if (host_ver_min > host_ver_cur) {
437 		mctp_prerr("Invalid host version range [%" PRIu16 ", %" PRIu16
438 			   "]",
439 			   host_ver_min, host_ver_cur);
440 		return false;
441 	} else if ((host_ver_cur < bmc_ver_min) ||
442 		   (host_ver_min > bmc_ver_cur)) {
443 		mctp_prerr(
444 			"Unable to satisfy version negotiation with ranges [%" PRIu16
445 			", %" PRIu16 "] and [%" PRIu16 ", %" PRIu16 "]",
446 			bmc_ver_min, bmc_ver_cur, host_ver_min, host_ver_cur);
447 		return false;
448 	}
449 
450 	return true;
451 }
452 
453 static int mctp_astlpc_negotiate_layout_host(struct mctp_binding_astlpc *astlpc)
454 {
455 	struct mctp_astlpc_layout layout;
456 	uint32_t sz;
457 	int rc;
458 
459 	rc = mctp_astlpc_layout_read(astlpc, &layout);
460 	if (rc < 0)
461 		return rc;
462 
463 	if (!mctp_astlpc_layout_validate(&layout)) {
464 		astlpc_prerr(
465 			astlpc,
466 			"BMC provided invalid buffer layout: Rx {0x%" PRIx32
467 			", %" PRIu32 "}, Tx {0x%" PRIx32 ", %" PRIu32 "}",
468 			layout.rx.offset, layout.rx.size, layout.tx.offset,
469 			layout.tx.size);
470 		return -EINVAL;
471 	}
472 
473 	sz = ASTLPC_PACKET_SIZE(MCTP_PACKET_SIZE(MCTP_BTU));
474 	layout.rx.size = sz;
475 
476 	if (!mctp_astlpc_layout_validate(&layout)) {
477 		astlpc_prerr(
478 			astlpc,
479 			"Generated invalid buffer layout with size %" PRIu32
480 			": Rx {0x%" PRIx32 ", %" PRIu32 "}, Tx {0x%" PRIx32
481 			", %" PRIu32 "}",
482 			sz, layout.rx.offset, layout.rx.size, layout.tx.offset,
483 			layout.tx.size);
484 		return -EINVAL;
485 	}
486 
487 	astlpc_prinfo(astlpc, "Requesting MTU of %" PRIu32 " bytes", MCTP_BTU);
488 
489 	return mctp_astlpc_layout_write(astlpc, &layout);
490 }
491 
492 static int mctp_astlpc_init_host(struct mctp_binding_astlpc *astlpc)
493 {
494 	const uint16_t ver_min_be = htobe16(ASTLPC_VER_MIN);
495 	const uint16_t ver_cur_be = htobe16(ASTLPC_VER_CUR);
496 	uint16_t bmc_ver_min, bmc_ver_cur;
497 	struct mctp_lpcmap_hdr hdr;
498 	uint8_t status;
499 	int rc;
500 
501 	rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, &status);
502 	if (rc) {
503 		mctp_prwarn("KCS status read failed");
504 		return rc;
505 	}
506 
507 	astlpc->kcs_status = status;
508 
509 	if (!(status & KCS_STATUS_BMC_READY))
510 		return -EHOSTDOWN;
511 
512 	mctp_astlpc_lpc_read(astlpc, &hdr, 0, sizeof(hdr));
513 
514 	bmc_ver_min = be16toh(hdr.bmc_ver_min);
515 	bmc_ver_cur = be16toh(hdr.bmc_ver_cur);
516 
517 	if (!mctp_astlpc_validate_version(bmc_ver_min, bmc_ver_cur,
518 					  ASTLPC_VER_MIN, ASTLPC_VER_CUR)) {
519 		astlpc_prerr(astlpc, "Cannot negotiate with invalid versions");
520 		return -EINVAL;
521 	}
522 
523 	/*
524 	 * Negotation always chooses the highest protocol version that
525 	 * satisfies the version constraints. So check whether the BMC supports
526 	 * v2, and if so, negotiate in v2 style.
527 	 */
528 	if (ASTLPC_VER_CUR >= 2 && bmc_ver_cur >= 2) {
529 		rc = mctp_astlpc_negotiate_layout_host(astlpc);
530 		if (rc < 0)
531 			return rc;
532 	}
533 
534 	/* Version negotiation */
535 	mctp_astlpc_lpc_write(astlpc, &ver_min_be,
536 			      offsetof(struct mctp_lpcmap_hdr, host_ver_min),
537 			      sizeof(ver_min_be));
538 
539 	mctp_astlpc_lpc_write(astlpc, &ver_cur_be,
540 			      offsetof(struct mctp_lpcmap_hdr, host_ver_cur),
541 			      sizeof(ver_cur_be));
542 
543 	/* Send channel init command */
544 	rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, 0x0);
545 	if (rc) {
546 		astlpc_prwarn(astlpc, "KCS write failed");
547 	}
548 
549 	return rc;
550 }
551 
552 static int mctp_binding_astlpc_start_host(struct mctp_binding *b)
553 {
554 	struct mctp_binding_astlpc *astlpc =
555 		container_of(b, struct mctp_binding_astlpc, binding);
556 
557 	return mctp_astlpc_init_host(astlpc);
558 }
559 
560 static bool __mctp_astlpc_kcs_ready(struct mctp_binding_astlpc *astlpc,
561 				    uint8_t status, bool is_write)
562 {
563 	bool is_bmc;
564 	bool ready_state;
565 	uint8_t flag;
566 
567 	is_bmc = (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC);
568 	flag = (is_bmc ^ is_write) ? KCS_STATUS_IBF : KCS_STATUS_OBF;
569 	ready_state = is_write ? 0 : 1;
570 
571 	return !!(status & flag) == ready_state;
572 }
573 
574 static inline bool
575 mctp_astlpc_kcs_read_ready(struct mctp_binding_astlpc *astlpc, uint8_t status)
576 {
577 	return __mctp_astlpc_kcs_ready(astlpc, status, false);
578 }
579 
580 static inline bool
581 mctp_astlpc_kcs_write_ready(struct mctp_binding_astlpc *astlpc, uint8_t status)
582 {
583 	return __mctp_astlpc_kcs_ready(astlpc, status, true);
584 }
585 
586 static int mctp_astlpc_kcs_send(struct mctp_binding_astlpc *astlpc,
587 		uint8_t data)
588 {
589 	uint8_t status;
590 	int rc;
591 
592 	for (;;) {
593 		rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS,
594 					  &status);
595 		if (rc) {
596 			astlpc_prwarn(astlpc, "KCS status read failed");
597 			return -1;
598 		}
599 		if (mctp_astlpc_kcs_write_ready(astlpc, status))
600 			break;
601 		/* todo: timeout */
602 	}
603 
604 	rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, data);
605 	if (rc) {
606 		astlpc_prwarn(astlpc, "KCS data write failed");
607 		return -1;
608 	}
609 
610 	return 0;
611 }
612 
613 static int mctp_binding_astlpc_tx(struct mctp_binding *b,
614 		struct mctp_pktbuf *pkt)
615 {
616 	struct mctp_binding_astlpc *astlpc = binding_to_astlpc(b);
617 	uint32_t len, len_be;
618 	struct mctp_hdr *hdr;
619 
620 	hdr = mctp_pktbuf_hdr(pkt);
621 	len = mctp_pktbuf_size(pkt);
622 
623 	astlpc_prdebug(astlpc,
624 		       "%s: Transmitting %" PRIu32
625 		       "-byte packet (%hhu, %hhu, 0x%hhx)",
626 		       __func__, len, hdr->src, hdr->dest, hdr->flags_seq_tag);
627 
628 	if (len > ASTLPC_BODY_SIZE(astlpc->layout.tx.size)) {
629 		astlpc_prwarn(astlpc, "invalid TX len 0x%x", len);
630 		return -1;
631 	}
632 
633 	len_be = htobe32(len);
634 	mctp_astlpc_lpc_write(astlpc, &len_be, astlpc->layout.tx.offset,
635 			      sizeof(len_be));
636 	mctp_astlpc_lpc_write(astlpc, hdr, astlpc->layout.tx.offset + 4, len);
637 
638 	mctp_binding_set_tx_enabled(b, false);
639 
640 	mctp_astlpc_kcs_send(astlpc, 0x1);
641 	return 0;
642 }
643 
644 static uint16_t mctp_astlpc_negotiate_version(uint16_t bmc_ver_min,
645 					      uint16_t bmc_ver_cur,
646 					      uint16_t host_ver_min,
647 					      uint16_t host_ver_cur)
648 {
649 	if (!mctp_astlpc_validate_version(bmc_ver_min, bmc_ver_cur,
650 					  host_ver_min, host_ver_cur))
651 		return ASTLPC_VER_BAD;
652 
653 	if (bmc_ver_cur < host_ver_cur)
654 		return bmc_ver_cur;
655 
656 	return host_ver_cur;
657 }
658 
659 static uint32_t mctp_astlpc_calculate_mtu(struct mctp_binding_astlpc *astlpc,
660 					  struct mctp_astlpc_layout *layout)
661 {
662 	uint32_t low, high, limit;
663 
664 	/* Derive the largest MTU the BMC _can_ support */
665 	low = MIN(astlpc->layout.rx.offset, astlpc->layout.tx.offset);
666 	high = MAX(astlpc->layout.rx.offset, astlpc->layout.tx.offset);
667 	limit = high - low;
668 
669 
670 	/* Determine the accepted MTU, applied both directions by convention */
671 	return MCTP_BODY_SIZE(ASTLPC_BODY_SIZE(MIN(limit, layout->tx.size)));
672 }
673 
674 static int mctp_astlpc_negotiate_layout_bmc(struct mctp_binding_astlpc *astlpc)
675 {
676 	struct mctp_astlpc_layout proposed, pending;
677 	uint32_t sz, mtu;
678 	int rc;
679 
680 	/* Extract the host's proposed layout */
681 	rc = mctp_astlpc_layout_read(astlpc, &proposed);
682 	if (rc < 0)
683 		return rc;
684 
685 	if (!mctp_astlpc_layout_validate(&proposed))
686 		return -EINVAL;
687 
688 	/* Negotiate the MTU */
689 	mtu = mctp_astlpc_calculate_mtu(astlpc, &proposed);
690 	sz = ASTLPC_PACKET_SIZE(MCTP_PACKET_SIZE(mtu));
691 
692 	/*
693 	 * Use symmetric MTUs by convention and to pass constraints in rx/tx
694 	 * functions
695 	 */
696 	pending = astlpc->layout;
697 	pending.tx.size = sz;
698 	pending.rx.size = sz;
699 
700 	if (mctp_astlpc_layout_validate(&pending)) {
701 		/* We found a sensible Rx MTU, so honour it */
702 		astlpc->layout = pending;
703 
704 		/* Enforce the negotiated MTU */
705 		rc = mctp_astlpc_layout_write(astlpc, &astlpc->layout);
706 		if (rc < 0)
707 			return rc;
708 
709 		astlpc_prinfo(astlpc, "Negotiated an MTU of %" PRIu32 " bytes",
710 			      mtu);
711 	} else {
712 		astlpc_prwarn(astlpc, "MTU negotiation failed");
713 		return -EINVAL;
714 	}
715 
716 	if (astlpc->version >= 2)
717 		astlpc->binding.pkt_size = MCTP_PACKET_SIZE(mtu);
718 
719 	return 0;
720 }
721 
722 static void mctp_astlpc_init_channel(struct mctp_binding_astlpc *astlpc)
723 {
724 	uint16_t negotiated, negotiated_be;
725 	struct mctp_lpcmap_hdr hdr;
726 	uint8_t status;
727 	int rc;
728 
729 	mctp_astlpc_lpc_read(astlpc, &hdr, 0, sizeof(hdr));
730 
731 	/* Version negotiation */
732 	negotiated =
733 		mctp_astlpc_negotiate_version(ASTLPC_VER_MIN, ASTLPC_VER_CUR,
734 					      be16toh(hdr.host_ver_min),
735 					      be16toh(hdr.host_ver_cur));
736 
737 	/* Host Rx MTU negotiation: Failure terminates channel init */
738 	rc = mctp_astlpc_negotiate_layout_bmc(astlpc);
739 	if (rc < 0)
740 		negotiated = ASTLPC_VER_BAD;
741 
742 	/* Populate the negotiated version */
743 	astlpc->version = negotiated;
744 	negotiated_be = htobe16(negotiated);
745 	mctp_astlpc_lpc_write(astlpc, &negotiated_be,
746 			      offsetof(struct mctp_lpcmap_hdr, negotiated_ver),
747 			      sizeof(negotiated_be));
748 
749 	/* Finalise the configuration */
750 	status = KCS_STATUS_BMC_READY | KCS_STATUS_OBF;
751 	if (negotiated > 0) {
752 		astlpc_prinfo(astlpc, "Negotiated binding version %" PRIu16,
753 			      negotiated);
754 		status |= KCS_STATUS_CHANNEL_ACTIVE;
755 	} else {
756 		astlpc_prerr(astlpc, "Failed to initialise channel\n");
757 	}
758 
759 	mctp_astlpc_kcs_set_status(astlpc, status);
760 
761 	mctp_binding_set_tx_enabled(&astlpc->binding,
762 				    status & KCS_STATUS_CHANNEL_ACTIVE);
763 }
764 
765 static void mctp_astlpc_rx_start(struct mctp_binding_astlpc *astlpc)
766 {
767 	struct mctp_pktbuf *pkt;
768 	uint32_t len;
769 
770 	mctp_astlpc_lpc_read(astlpc, &len, astlpc->layout.rx.offset,
771 			     sizeof(len));
772 	len = be32toh(len);
773 
774 	if (len > ASTLPC_BODY_SIZE(astlpc->layout.rx.size)) {
775 		astlpc_prwarn(astlpc, "invalid RX len 0x%x", len);
776 		return;
777 	}
778 
779 	assert(astlpc->binding.pkt_size >= 0);
780 	if (len > (uint32_t)astlpc->binding.pkt_size) {
781 		mctp_prwarn("invalid RX len 0x%x", len);
782 		astlpc_prwarn(astlpc, "invalid RX len 0x%x", len);
783 		return;
784 	}
785 
786 	pkt = mctp_pktbuf_alloc(&astlpc->binding, len);
787 	if (!pkt)
788 		goto out_complete;
789 
790 	mctp_astlpc_lpc_read(astlpc, mctp_pktbuf_hdr(pkt),
791 			     astlpc->layout.rx.offset + 4, len);
792 
793 	mctp_bus_rx(&astlpc->binding, pkt);
794 
795 out_complete:
796 	mctp_astlpc_kcs_send(astlpc, 0x2);
797 }
798 
799 static void mctp_astlpc_tx_complete(struct mctp_binding_astlpc *astlpc)
800 {
801 	mctp_binding_set_tx_enabled(&astlpc->binding, true);
802 }
803 
804 static int mctp_astlpc_finalise_channel(struct mctp_binding_astlpc *astlpc)
805 {
806 	struct mctp_astlpc_layout layout;
807 	uint16_t negotiated;
808 	int rc;
809 
810 	rc = mctp_astlpc_lpc_read(astlpc, &negotiated,
811 				  offsetof(struct mctp_lpcmap_hdr,
812 					   negotiated_ver),
813 				  sizeof(negotiated));
814 	if (rc < 0)
815 		return rc;
816 
817 	negotiated = be16toh(negotiated);
818 
819 	if (negotiated == ASTLPC_VER_BAD || negotiated < ASTLPC_VER_MIN ||
820 	    negotiated > ASTLPC_VER_CUR) {
821 		astlpc_prerr(astlpc, "Failed to negotiate version, got: %u\n",
822 			     negotiated);
823 		return -EINVAL;
824 	}
825 
826 	astlpc->version = negotiated;
827 
828 	rc = mctp_astlpc_layout_read(astlpc, &layout);
829 	if (rc < 0)
830 		return rc;
831 
832 	if (!mctp_astlpc_layout_validate(&layout)) {
833 		mctp_prerr("BMC proposed invalid buffer parameters");
834 		return -EINVAL;
835 	}
836 
837 	astlpc->layout = layout;
838 
839 	if (negotiated >= 2)
840 		astlpc->binding.pkt_size =
841 			ASTLPC_BODY_SIZE(astlpc->layout.tx.size);
842 
843 	return 0;
844 }
845 
846 static int mctp_astlpc_update_channel(struct mctp_binding_astlpc *astlpc,
847 				      uint8_t status)
848 {
849 	uint8_t updated;
850 	int rc = 0;
851 
852 	assert(astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST);
853 
854 	updated = astlpc->kcs_status ^ status;
855 
856 	astlpc_prdebug(astlpc, "%s: status: 0x%x, update: 0x%x", __func__,
857 		       status, updated);
858 
859 	if (updated & KCS_STATUS_BMC_READY) {
860 		if (status & KCS_STATUS_BMC_READY) {
861 			astlpc->kcs_status = status;
862 			return astlpc->binding.start(&astlpc->binding);
863 		} else {
864 			mctp_binding_set_tx_enabled(&astlpc->binding, false);
865 		}
866 	}
867 
868 	if (astlpc->version == 0 || updated & KCS_STATUS_CHANNEL_ACTIVE) {
869 		bool enable;
870 
871 		rc = mctp_astlpc_finalise_channel(astlpc);
872 		enable = (status & KCS_STATUS_CHANNEL_ACTIVE) && rc == 0;
873 
874 		mctp_binding_set_tx_enabled(&astlpc->binding, enable);
875 	}
876 
877 	astlpc->kcs_status = status;
878 
879 	return rc;
880 }
881 
882 int mctp_astlpc_poll(struct mctp_binding_astlpc *astlpc)
883 {
884 	uint8_t status, data;
885 	int rc;
886 
887 	rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, &status);
888 	if (rc) {
889 		astlpc_prwarn(astlpc, "KCS read error");
890 		return -1;
891 	}
892 
893 	astlpc_prdebug(astlpc, "%s: status: 0x%hhx", __func__, status);
894 
895 	if (!mctp_astlpc_kcs_read_ready(astlpc, status))
896 		return 0;
897 
898 	rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_DATA, &data);
899 	if (rc) {
900 		astlpc_prwarn(astlpc, "KCS data read error");
901 		return -1;
902 	}
903 
904 	astlpc_prdebug(astlpc, "%s: data: 0x%hhx", __func__, data);
905 
906 	switch (data) {
907 	case 0x0:
908 		mctp_astlpc_init_channel(astlpc);
909 		break;
910 	case 0x1:
911 		mctp_astlpc_rx_start(astlpc);
912 		break;
913 	case 0x2:
914 		mctp_astlpc_tx_complete(astlpc);
915 		break;
916 	case 0xff:
917 		/* No responsibilities for the BMC on 0xff */
918 		if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST) {
919 			rc = mctp_astlpc_update_channel(astlpc, status);
920 			if (rc < 0)
921 				return rc;
922 		}
923 		break;
924 	default:
925 		astlpc_prwarn(astlpc, "unknown message 0x%x", data);
926 	}
927 
928 	/* Handle silent loss of bmc-ready */
929 	if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST) {
930 		if (!(status & KCS_STATUS_BMC_READY && data == 0xff))
931 			return mctp_astlpc_update_channel(astlpc, status);
932 	}
933 
934 	return rc;
935 }
936 
937 /* allocate and basic initialisation */
938 static struct mctp_binding_astlpc *__mctp_astlpc_init(uint8_t mode,
939 						      uint32_t mtu)
940 {
941 	struct mctp_binding_astlpc *astlpc;
942 
943 	assert((mode == MCTP_BINDING_ASTLPC_MODE_BMC) ||
944 	       (mode == MCTP_BINDING_ASTLPC_MODE_HOST));
945 
946 	astlpc = __mctp_alloc(sizeof(*astlpc));
947 	if (!astlpc)
948 		return NULL;
949 
950 	memset(astlpc, 0, sizeof(*astlpc));
951 	astlpc->mode = mode;
952 	astlpc->lpc_map = NULL;
953 	astlpc->binding.name = "astlpc";
954 	astlpc->binding.version = 1;
955 	astlpc->binding.pkt_size = MCTP_PACKET_SIZE(mtu);
956 	astlpc->binding.pkt_pad = 0;
957 	astlpc->binding.tx = mctp_binding_astlpc_tx;
958 	if (mode == MCTP_BINDING_ASTLPC_MODE_BMC)
959 		astlpc->binding.start = mctp_binding_astlpc_start_bmc;
960 	else if (mode == MCTP_BINDING_ASTLPC_MODE_HOST)
961 		astlpc->binding.start = mctp_binding_astlpc_start_host;
962 	else {
963 		astlpc_prerr(astlpc, "%s: Invalid mode: %d\n", __func__, mode);
964 		__mctp_free(astlpc);
965 		return NULL;
966 	}
967 
968 	return astlpc;
969 }
970 
971 struct mctp_binding *mctp_binding_astlpc_core(struct mctp_binding_astlpc *b)
972 {
973 	return &b->binding;
974 }
975 
976 struct mctp_binding_astlpc *
977 mctp_astlpc_init(uint8_t mode, uint32_t mtu, void *lpc_map,
978 		 const struct mctp_binding_astlpc_ops *ops, void *ops_data)
979 {
980 	struct mctp_binding_astlpc *astlpc;
981 
982 	if (!(mode == MCTP_BINDING_ASTLPC_MODE_BMC ||
983 	      mode == MCTP_BINDING_ASTLPC_MODE_HOST)) {
984 		mctp_prerr("Unknown binding mode: %u", mode);
985 		return NULL;
986 	}
987 
988 	if (mtu != MCTP_BTU) {
989 		mctp_prwarn("Unable to negotiate the MTU, using %u instead",
990 			    MCTP_BTU);
991 		mtu = MCTP_BTU;
992 	}
993 
994 	astlpc = __mctp_astlpc_init(mode, mtu);
995 	if (!astlpc)
996 		return NULL;
997 
998 	memcpy(&astlpc->ops, ops, sizeof(astlpc->ops));
999 	astlpc->ops_data = ops_data;
1000 	astlpc->lpc_map = lpc_map;
1001 	astlpc->mode = mode;
1002 
1003 	return astlpc;
1004 }
1005 
1006 struct mctp_binding_astlpc *
1007 mctp_astlpc_init_ops(const struct mctp_binding_astlpc_ops *ops, void *ops_data,
1008 		     void *lpc_map)
1009 {
1010 	return mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, lpc_map,
1011 				ops, ops_data);
1012 }
1013 
1014 void mctp_astlpc_destroy(struct mctp_binding_astlpc *astlpc)
1015 {
1016 	/* Clear channel-active and bmc-ready */
1017 	if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC)
1018 		mctp_astlpc_kcs_set_status(astlpc, KCS_STATUS_OBF);
1019 	__mctp_free(astlpc);
1020 }
1021 
1022 #ifdef MCTP_HAVE_FILEIO
1023 
1024 static int mctp_astlpc_init_fileio_lpc(struct mctp_binding_astlpc *astlpc)
1025 {
1026 	struct aspeed_lpc_ctrl_mapping map = {
1027 		.window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY,
1028 		.window_id = 0, /* There's only one */
1029 		.flags = 0,
1030 		.addr = 0,
1031 		.offset = 0,
1032 		.size = 0
1033 	};
1034 	void *lpc_map_base;
1035 	int fd, rc;
1036 
1037 	fd = open(lpc_path, O_RDWR | O_SYNC);
1038 	if (fd < 0) {
1039 		astlpc_prwarn(astlpc, "LPC open (%s) failed", lpc_path);
1040 		return -1;
1041 	}
1042 
1043 	rc = ioctl(fd, ASPEED_LPC_CTRL_IOCTL_GET_SIZE, &map);
1044 	if (rc) {
1045 		astlpc_prwarn(astlpc, "LPC GET_SIZE failed");
1046 		close(fd);
1047 		return -1;
1048 	}
1049 
1050 	lpc_map_base =
1051 		mmap(NULL, map.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1052 	if (lpc_map_base == MAP_FAILED) {
1053 		astlpc_prwarn(astlpc, "LPC mmap failed");
1054 		rc = -1;
1055 	} else {
1056 		astlpc->lpc_map = lpc_map_base + map.size - LPC_WIN_SIZE;
1057 	}
1058 
1059 	close(fd);
1060 
1061 	return rc;
1062 }
1063 
1064 static int mctp_astlpc_init_fileio_kcs(struct mctp_binding_astlpc *astlpc)
1065 {
1066 	astlpc->kcs_fd = open(kcs_path, O_RDWR);
1067 	if (astlpc->kcs_fd < 0)
1068 		return -1;
1069 
1070 	return 0;
1071 }
1072 
1073 static int __mctp_astlpc_fileio_kcs_read(void *arg,
1074 		enum mctp_binding_astlpc_kcs_reg reg, uint8_t *val)
1075 {
1076 	struct mctp_binding_astlpc *astlpc = arg;
1077 	off_t offset = reg;
1078 	int rc;
1079 
1080 	rc = pread(astlpc->kcs_fd, val, 1, offset);
1081 
1082 	return rc == 1 ? 0 : -1;
1083 }
1084 
1085 static int __mctp_astlpc_fileio_kcs_write(void *arg,
1086 		enum mctp_binding_astlpc_kcs_reg reg, uint8_t val)
1087 {
1088 	struct mctp_binding_astlpc *astlpc = arg;
1089 	off_t offset = reg;
1090 	int rc;
1091 
1092 	rc = pwrite(astlpc->kcs_fd, &val, 1, offset);
1093 
1094 	return rc == 1 ? 0 : -1;
1095 }
1096 
1097 int mctp_astlpc_get_fd(struct mctp_binding_astlpc *astlpc)
1098 {
1099 	return astlpc->kcs_fd;
1100 }
1101 
1102 struct mctp_binding_astlpc *mctp_astlpc_init_fileio(void)
1103 {
1104 	struct mctp_binding_astlpc *astlpc;
1105 	int rc;
1106 
1107 	/*
1108 	 * If we're doing file IO then we're very likely not running
1109 	 * freestanding, so lets assume that we're on the BMC side
1110 	 */
1111 	astlpc = __mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU);
1112 	if (!astlpc)
1113 		return NULL;
1114 
1115 	/* Set internal operations for kcs. We use direct accesses to the lpc
1116 	 * map area */
1117 	astlpc->ops.kcs_read = __mctp_astlpc_fileio_kcs_read;
1118 	astlpc->ops.kcs_write = __mctp_astlpc_fileio_kcs_write;
1119 	astlpc->ops_data = astlpc;
1120 
1121 	rc = mctp_astlpc_init_fileio_lpc(astlpc);
1122 	if (rc) {
1123 		free(astlpc);
1124 		return NULL;
1125 	}
1126 
1127 	rc = mctp_astlpc_init_fileio_kcs(astlpc);
1128 	if (rc) {
1129 		free(astlpc);
1130 		return NULL;
1131 	}
1132 
1133 	return astlpc;
1134 }
1135 #else
1136 struct mctp_binding_astlpc * __attribute__((const))
1137 	mctp_astlpc_init_fileio(void)
1138 {
1139 	astlpc_prerr(astlpc, "Missing support for file IO");
1140 	return NULL;
1141 }
1142 
1143 int __attribute__((const)) mctp_astlpc_get_fd(
1144 		struct mctp_binding_astlpc *astlpc __attribute__((unused)))
1145 {
1146 	astlpc_prerr(astlpc, "Missing support for file IO");
1147 	return -1;
1148 }
1149 #endif
1150