blob: 807b6fc28a2137efce2733220388d930da0eeccd [file] [log] [blame]
Jeremy Kerr3d36ee22019-05-30 11:15:37 +08001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Jeremy Kerr672c8852019-03-01 12:18:07 +08002
Andrew Jeffery3286f172020-03-17 23:04:13 +10303#if HAVE_CONFIG_H
4#include "config.h"
5#endif
6
7#if HAVE_ENDIAN_H
Jeremy Kerr92a10a62019-08-28 16:55:54 +05308#include <endian.h>
Andrew Jeffery3286f172020-03-17 23:04:13 +10309#endif
10
11#include <assert.h>
Andrew Jeffery59c6a5c2020-01-17 15:52:51 +103012#include <err.h>
Andrew Jeffery7cd72f12020-05-12 20:27:59 +093013#include <errno.h>
Andrew Jefferyedfe3832020-02-06 11:52:11 +103014#include <inttypes.h>
Jeremy Kerr672c8852019-03-01 12:18:07 +080015#include <stdbool.h>
16#include <stdlib.h>
17#include <string.h>
Jeremy Kerr672c8852019-03-01 12:18:07 +080018
Jeremy Kerr672c8852019-03-01 12:18:07 +080019#define pr_fmt(x) "astlpc: " x
20
Andrew Jefferyeba19a32021-03-09 23:09:40 +103021#include "container_of.h"
22#include "crc32.h"
Jeremy Kerr672c8852019-03-01 12:18:07 +080023#include "libmctp.h"
24#include "libmctp-alloc.h"
25#include "libmctp-log.h"
26#include "libmctp-astlpc.h"
Andrew Jeffery4622cad2020-11-03 22:20:18 +103027#include "range.h"
Jeremy Kerr672c8852019-03-01 12:18:07 +080028
Jeremy Kerrb214c642019-11-27 11:34:00 +080029#ifdef MCTP_HAVE_FILEIO
Jeremy Kerr92a10a62019-08-28 16:55:54 +053030
Jeremy Kerrc6f676d2019-12-19 09:24:06 +080031#include <unistd.h>
Jeremy Kerr92a10a62019-08-28 16:55:54 +053032#include <fcntl.h>
33#include <sys/ioctl.h>
34#include <sys/mman.h>
35#include <linux/aspeed-lpc-ctrl.h>
36
37/* kernel interface */
38static const char *kcs_path = "/dev/mctp0";
39static const char *lpc_path = "/dev/aspeed-lpc-ctrl";
40
41#endif
42
Andrew Jeffery7cd72f12020-05-12 20:27:59 +093043struct mctp_astlpc_buffer {
44 uint32_t offset;
45 uint32_t size;
46};
47
48struct mctp_astlpc_layout {
49 struct mctp_astlpc_buffer rx;
50 struct mctp_astlpc_buffer tx;
51};
52
Andrew Jeffery88412be2021-03-09 22:05:22 +103053struct mctp_astlpc_protocol {
54 uint16_t version;
55 uint32_t (*packet_size)(uint32_t body);
56 uint32_t (*body_size)(uint32_t packet);
Andrew Jefferyeba19a32021-03-09 23:09:40 +103057 void (*pktbuf_protect)(struct mctp_pktbuf *pkt);
58 bool (*pktbuf_validate)(struct mctp_pktbuf *pkt);
Andrew Jeffery88412be2021-03-09 22:05:22 +103059};
60
Jeremy Kerr672c8852019-03-01 12:18:07 +080061struct mctp_binding_astlpc {
62 struct mctp_binding binding;
Jeremy Kerrbc53d352019-08-28 14:26:14 +053063
Andrew Jeffery55fb90b2020-05-12 13:54:37 +093064 void *lpc_map;
Andrew Jeffery7cd72f12020-05-12 20:27:59 +093065 struct mctp_astlpc_layout layout;
66
67 uint8_t mode;
Andrew Jefferya9368982020-06-09 13:07:39 +093068 uint32_t requested_mtu;
Jeremy Kerrbc53d352019-08-28 14:26:14 +053069
Andrew Jeffery88412be2021-03-09 22:05:22 +103070 const struct mctp_astlpc_protocol *proto;
71
Jeremy Kerrbc53d352019-08-28 14:26:14 +053072 /* direct ops data */
Andrew Jeffery55fb90b2020-05-12 13:54:37 +093073 struct mctp_binding_astlpc_ops ops;
74 void *ops_data;
Jeremy Kerrbc53d352019-08-28 14:26:14 +053075
76 /* fileio ops data */
Andrew Jeffery979c6a12020-05-23 20:04:49 +093077 int kcs_fd;
78 uint8_t kcs_status;
Jeremy Kerr672c8852019-03-01 12:18:07 +080079};
80
Jeremy Kerr672c8852019-03-01 12:18:07 +080081#define binding_to_astlpc(b) \
82 container_of(b, struct mctp_binding_astlpc, binding)
83
Andrew Jeffery9101a2a2020-05-22 16:08:03 +093084#define astlpc_prlog(ctx, lvl, fmt, ...) \
85 do { \
86 bool __bmc = ((ctx)->mode == MCTP_BINDING_ASTLPC_MODE_BMC); \
87 mctp_prlog(lvl, pr_fmt("%s: " fmt), __bmc ? "bmc" : "host", \
88 ##__VA_ARGS__); \
89 } while (0)
90
91#define astlpc_prerr(ctx, fmt, ...) \
92 astlpc_prlog(ctx, MCTP_LOG_ERR, fmt, ##__VA_ARGS__)
93#define astlpc_prwarn(ctx, fmt, ...) \
94 astlpc_prlog(ctx, MCTP_LOG_WARNING, fmt, ##__VA_ARGS__)
95#define astlpc_prinfo(ctx, fmt, ...) \
96 astlpc_prlog(ctx, MCTP_LOG_INFO, fmt, ##__VA_ARGS__)
97#define astlpc_prdebug(ctx, fmt, ...) \
98 astlpc_prlog(ctx, MCTP_LOG_DEBUG, fmt, ##__VA_ARGS__)
99
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930100/* clang-format off */
101#define ASTLPC_MCTP_MAGIC 0x4d435450
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930102#define ASTLPC_VER_BAD 0
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930103#define ASTLPC_VER_MIN 1
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930104
Andrew Jeffery3a540662020-05-26 19:55:30 +0930105/* Support testing of new binding protocols */
106#ifndef ASTLPC_VER_CUR
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030107#define ASTLPC_VER_CUR 3
Andrew Jeffery3a540662020-05-26 19:55:30 +0930108#endif
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930109/* clang-format on */
Jeremy Kerr672c8852019-03-01 12:18:07 +0800110
Andrew Jeffery88412be2021-03-09 22:05:22 +1030111#ifndef ARRAY_SIZE
112#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
113#endif
114
115static uint32_t astlpc_packet_size_v1(uint32_t body)
116{
117 assert((body + 4) > body);
118
119 return body + 4;
120}
121
122static uint32_t astlpc_body_size_v1(uint32_t packet)
123{
124 assert((packet - 4) < packet);
125
126 return packet - 4;
127}
128
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030129void astlpc_pktbuf_protect_v1(struct mctp_pktbuf *pkt)
130{
131 (void)pkt;
132}
133
134bool astlpc_pktbuf_validate_v1(struct mctp_pktbuf *pkt)
135{
136 (void)pkt;
137 return true;
138}
139
140static uint32_t astlpc_packet_size_v3(uint32_t body)
141{
142 assert((body + 4 + 4) > body);
143
144 return body + 4 + 4;
145}
146
147static uint32_t astlpc_body_size_v3(uint32_t packet)
148{
149 assert((packet - 4 - 4) < packet);
150
151 return packet - 4 - 4;
152}
153
154void astlpc_pktbuf_protect_v3(struct mctp_pktbuf *pkt)
155{
156 uint32_t code;
157
158 code = htobe32(crc32(mctp_pktbuf_hdr(pkt), mctp_pktbuf_size(pkt)));
159 mctp_prdebug("%s: 0x%" PRIx32, __func__, code);
160 mctp_pktbuf_push(pkt, &code, 4);
161}
162
163bool astlpc_pktbuf_validate_v3(struct mctp_pktbuf *pkt)
164{
165 uint32_t code;
166 void *check;
167
168 code = be32toh(crc32(mctp_pktbuf_hdr(pkt), mctp_pktbuf_size(pkt) - 4));
169 mctp_prdebug("%s: 0x%" PRIx32, __func__, code);
170 check = mctp_pktbuf_pop(pkt, 4);
171 return check && !memcmp(&code, check, 4);
172}
173
Andrew Jeffery88412be2021-03-09 22:05:22 +1030174static const struct mctp_astlpc_protocol astlpc_protocol_version[] = {
175 [0] = {
176 .version = 0,
177 .packet_size = NULL,
178 .body_size = NULL,
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030179 .pktbuf_protect = NULL,
180 .pktbuf_validate = NULL,
Andrew Jeffery88412be2021-03-09 22:05:22 +1030181 },
182 [1] = {
183 .version = 1,
184 .packet_size = astlpc_packet_size_v1,
185 .body_size = astlpc_body_size_v1,
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030186 .pktbuf_protect = astlpc_pktbuf_protect_v1,
187 .pktbuf_validate = astlpc_pktbuf_validate_v1,
Andrew Jeffery88412be2021-03-09 22:05:22 +1030188 },
189 [2] = {
190 .version = 2,
191 .packet_size = astlpc_packet_size_v1,
192 .body_size = astlpc_body_size_v1,
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030193 .pktbuf_protect = astlpc_pktbuf_protect_v1,
194 .pktbuf_validate = astlpc_pktbuf_validate_v1,
195 },
196 [3] = {
197 .version = 3,
198 .packet_size = astlpc_packet_size_v3,
199 .body_size = astlpc_body_size_v3,
200 .pktbuf_protect = astlpc_pktbuf_protect_v3,
201 .pktbuf_validate = astlpc_pktbuf_validate_v3,
Andrew Jeffery88412be2021-03-09 22:05:22 +1030202 },
203};
204
Jeremy Kerr672c8852019-03-01 12:18:07 +0800205struct mctp_lpcmap_hdr {
Andrew Jeffery3a540662020-05-26 19:55:30 +0930206 uint32_t magic;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800207
Andrew Jeffery3a540662020-05-26 19:55:30 +0930208 uint16_t bmc_ver_min;
209 uint16_t bmc_ver_cur;
210 uint16_t host_ver_min;
211 uint16_t host_ver_cur;
212 uint16_t negotiated_ver;
213 uint16_t pad0;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800214
Andrew Jeffery3a540662020-05-26 19:55:30 +0930215 struct {
216 uint32_t rx_offset;
217 uint32_t rx_size;
218 uint32_t tx_offset;
219 uint32_t tx_size;
220 } layout;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800221} __attribute__((packed));
222
Andrew Jeffery3a540662020-05-26 19:55:30 +0930223static const uint32_t control_size = 0x100;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800224
Jeremy Kerr672c8852019-03-01 12:18:07 +0800225#define LPC_WIN_SIZE (1 * 1024 * 1024)
226
Jeremy Kerr672c8852019-03-01 12:18:07 +0800227#define KCS_STATUS_BMC_READY 0x80
228#define KCS_STATUS_CHANNEL_ACTIVE 0x40
229#define KCS_STATUS_IBF 0x02
230#define KCS_STATUS_OBF 0x01
231
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930232static inline int mctp_astlpc_kcs_write(struct mctp_binding_astlpc *astlpc,
233 enum mctp_binding_astlpc_kcs_reg reg,
234 uint8_t val)
235{
236 return astlpc->ops.kcs_write(astlpc->ops_data, reg, val);
237}
238
239static inline int mctp_astlpc_kcs_read(struct mctp_binding_astlpc *astlpc,
240 enum mctp_binding_astlpc_kcs_reg reg,
241 uint8_t *val)
242{
243 return astlpc->ops.kcs_read(astlpc->ops_data, reg, val);
244}
245
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930246static inline int mctp_astlpc_lpc_write(struct mctp_binding_astlpc *astlpc,
247 const void *buf, long offset,
248 size_t len)
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530249{
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930250 astlpc_prdebug(astlpc, "%s: %zu bytes to 0x%lx", __func__, len, offset);
251
252 assert(offset >= 0);
253
254 /* Indirect access */
255 if (astlpc->ops.lpc_write) {
256 void *data = astlpc->ops_data;
257
258 return astlpc->ops.lpc_write(data, buf, offset, len);
259 }
260
261 /* Direct mapping */
262 assert(astlpc->lpc_map);
263 memcpy(&((char *)astlpc->lpc_map)[offset], buf, len);
264
265 return 0;
266}
267
268static inline int mctp_astlpc_lpc_read(struct mctp_binding_astlpc *astlpc,
269 void *buf, long offset, size_t len)
270{
271 astlpc_prdebug(astlpc, "%s: %zu bytes from 0x%lx", __func__, len,
272 offset);
273
274 assert(offset >= 0);
275
276 /* Indirect access */
277 if (astlpc->ops.lpc_read) {
278 void *data = astlpc->ops_data;
279
280 return astlpc->ops.lpc_read(data, buf, offset, len);
281 }
282
283 /* Direct mapping */
284 assert(astlpc->lpc_map);
285 memcpy(buf, &((char *)astlpc->lpc_map)[offset], len);
286
287 return 0;
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530288}
289
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930290static int mctp_astlpc_kcs_set_status(struct mctp_binding_astlpc *astlpc,
291 uint8_t status)
292{
293 uint8_t data;
294 int rc;
295
296 /* Since we're setting the status register, we want the other endpoint
297 * to be interrupted. However, some hardware may only raise a host-side
298 * interrupt on an ODR event.
299 * So, write a dummy value of 0xff to ODR, which will ensure that an
300 * interrupt is triggered, and can be ignored by the host.
301 */
302 data = 0xff;
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930303
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930304 rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, status);
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930305 if (rc) {
306 astlpc_prwarn(astlpc, "KCS status write failed");
307 return -1;
308 }
309
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930310 rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, data);
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930311 if (rc) {
312 astlpc_prwarn(astlpc, "KCS dummy data write failed");
313 return -1;
314 }
315
316 return 0;
317}
318
Andrew Jeffery3a540662020-05-26 19:55:30 +0930319static int mctp_astlpc_layout_read(struct mctp_binding_astlpc *astlpc,
320 struct mctp_astlpc_layout *layout)
321{
322 struct mctp_lpcmap_hdr hdr;
323 int rc;
324
325 rc = mctp_astlpc_lpc_read(astlpc, &hdr, 0, sizeof(hdr));
326 if (rc < 0)
327 return rc;
328
329 /* Flip the buffers as the names are defined in terms of the host */
330 if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC) {
331 layout->rx.offset = be32toh(hdr.layout.tx_offset);
332 layout->rx.size = be32toh(hdr.layout.tx_size);
333 layout->tx.offset = be32toh(hdr.layout.rx_offset);
334 layout->tx.size = be32toh(hdr.layout.rx_size);
335 } else {
336 assert(astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST);
337
338 layout->rx.offset = be32toh(hdr.layout.rx_offset);
339 layout->rx.size = be32toh(hdr.layout.rx_size);
340 layout->tx.offset = be32toh(hdr.layout.tx_offset);
341 layout->tx.size = be32toh(hdr.layout.tx_size);
342 }
343
344 return 0;
345}
346
347static int mctp_astlpc_layout_write(struct mctp_binding_astlpc *astlpc,
348 struct mctp_astlpc_layout *layout)
349{
350 uint32_t rx_size_be;
351
352 if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC) {
353 struct mctp_lpcmap_hdr hdr;
354
355 /*
356 * Flip the buffers as the names are defined in terms of the
357 * host
358 */
359 hdr.layout.rx_offset = htobe32(layout->tx.offset);
360 hdr.layout.rx_size = htobe32(layout->tx.size);
361 hdr.layout.tx_offset = htobe32(layout->rx.offset);
362 hdr.layout.tx_size = htobe32(layout->rx.size);
363
364 return mctp_astlpc_lpc_write(astlpc, &hdr.layout,
365 offsetof(struct mctp_lpcmap_hdr, layout),
366 sizeof(hdr.layout));
367 }
368
369 assert(astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST);
370
371 /*
372 * As of v2 we only need to write rx_size - the offsets are controlled
373 * by the BMC, as is the BMC's rx_size (host tx_size).
374 */
375 rx_size_be = htobe32(layout->rx.size);
376 return mctp_astlpc_lpc_write(astlpc, &rx_size_be,
377 offsetof(struct mctp_lpcmap_hdr, layout.rx_size),
378 sizeof(rx_size_be));
379}
380
Andrew Jeffery88412be2021-03-09 22:05:22 +1030381static bool
382mctp_astlpc_buffer_validate(const struct mctp_binding_astlpc *astlpc,
383 const struct mctp_astlpc_buffer *buf,
384 const char *name)
Andrew Jeffery3a540662020-05-26 19:55:30 +0930385{
386 /* Check for overflow */
387 if (buf->offset + buf->size < buf->offset) {
388 mctp_prerr(
389 "%s packet buffer parameters overflow: offset: 0x%" PRIx32
390 ", size: %" PRIu32,
391 name, buf->offset, buf->size);
392 return false;
393 }
394
395 /* Check that the buffers are contained within the allocated space */
396 if (buf->offset + buf->size > LPC_WIN_SIZE) {
397 mctp_prerr(
398 "%s packet buffer parameters exceed %uM window size: offset: 0x%" PRIx32
399 ", size: %" PRIu32,
400 name, (LPC_WIN_SIZE / (1024 * 1024)), buf->offset,
401 buf->size);
402 return false;
403 }
404
405 /* Check that the baseline transmission unit is supported */
Andrew Jeffery88412be2021-03-09 22:05:22 +1030406 if (buf->size < astlpc->proto->packet_size(MCTP_PACKET_SIZE(MCTP_BTU))) {
Andrew Jeffery3a540662020-05-26 19:55:30 +0930407 mctp_prerr(
Andrew Jeffery88412be2021-03-09 22:05:22 +1030408 "%s packet buffer too small: Require %" PRIu32 " bytes to support the %u byte baseline transmission unit, found %" PRIu32,
409 name,
410 astlpc->proto->packet_size(MCTP_PACKET_SIZE(MCTP_BTU)),
Andrew Jeffery3a540662020-05-26 19:55:30 +0930411 MCTP_BTU, buf->size);
412 return false;
413 }
414
415 /* Check for overlap with the control space */
416 if (buf->offset < control_size) {
417 mctp_prerr(
418 "%s packet buffer overlaps control region {0x%" PRIx32
419 ", %" PRIu32 "}: Rx {0x%" PRIx32 ", %" PRIu32 "}",
420 name, 0U, control_size, buf->offset, buf->size);
421 return false;
422 }
423
424 return true;
425}
426
Andrew Jeffery88412be2021-03-09 22:05:22 +1030427static bool
428mctp_astlpc_layout_validate(const struct mctp_binding_astlpc *astlpc,
429 const struct mctp_astlpc_layout *layout)
Andrew Jeffery3a540662020-05-26 19:55:30 +0930430{
Andrew Jeffery88412be2021-03-09 22:05:22 +1030431 const struct mctp_astlpc_buffer *rx = &layout->rx;
432 const struct mctp_astlpc_buffer *tx = &layout->tx;
Andrew Jeffery3a540662020-05-26 19:55:30 +0930433 bool rx_valid, tx_valid;
434
Andrew Jeffery88412be2021-03-09 22:05:22 +1030435 rx_valid = mctp_astlpc_buffer_validate(astlpc, rx, "Rx");
436 tx_valid = mctp_astlpc_buffer_validate(astlpc, tx, "Tx");
Andrew Jeffery3a540662020-05-26 19:55:30 +0930437
438 if (!(rx_valid && tx_valid))
439 return false;
440
441 /* Check that the buffers are disjoint */
442 if ((rx->offset <= tx->offset && rx->offset + rx->size > tx->offset) ||
443 (tx->offset <= rx->offset && tx->offset + tx->size > rx->offset)) {
444 mctp_prerr("Rx and Tx packet buffers overlap: Rx {0x%" PRIx32
445 ", %" PRIu32 "}, Tx {0x%" PRIx32 ", %" PRIu32 "}",
446 rx->offset, rx->size, tx->offset, tx->size);
447 return false;
448 }
449
450 return true;
451}
452
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930453static int mctp_astlpc_init_bmc(struct mctp_binding_astlpc *astlpc)
454{
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930455 struct mctp_lpcmap_hdr hdr = { 0 };
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930456 uint8_t status;
Andrew Jeffery88412be2021-03-09 22:05:22 +1030457 uint32_t sz;
Andrew Jeffery3a540662020-05-26 19:55:30 +0930458
459 /*
460 * The largest buffer size is half of the allocated MCTP space
461 * excluding the control space.
462 */
463 sz = ((LPC_WIN_SIZE - control_size) / 2);
464
465 /*
466 * Trim the MTU to a multiple of 16 to meet the requirements of 12.17
467 * Query Hop in DSP0236 v1.3.0.
468 */
Andrew Jeffery88412be2021-03-09 22:05:22 +1030469 sz = MCTP_BODY_SIZE(astlpc->proto->body_size(sz));
Andrew Jeffery3a540662020-05-26 19:55:30 +0930470 sz &= ~0xfUL;
Andrew Jeffery88412be2021-03-09 22:05:22 +1030471 sz = astlpc->proto->packet_size(MCTP_PACKET_SIZE(sz));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930472
Andrew Jefferya9368982020-06-09 13:07:39 +0930473 if (astlpc->requested_mtu) {
Andrew Jeffery88412be2021-03-09 22:05:22 +1030474 uint32_t rpkt, rmtu;
Andrew Jefferya9368982020-06-09 13:07:39 +0930475
Andrew Jeffery88412be2021-03-09 22:05:22 +1030476 rmtu = astlpc->requested_mtu;
477 rpkt = astlpc->proto->packet_size(MCTP_PACKET_SIZE(rmtu));
478 sz = MIN(sz, rpkt);
Andrew Jefferya9368982020-06-09 13:07:39 +0930479 }
480
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930481 /* Flip the buffers as the names are defined in terms of the host */
Andrew Jeffery3a540662020-05-26 19:55:30 +0930482 astlpc->layout.tx.offset = control_size;
483 astlpc->layout.tx.size = sz;
484 astlpc->layout.rx.offset =
485 astlpc->layout.tx.offset + astlpc->layout.tx.size;
486 astlpc->layout.rx.size = sz;
487
Andrew Jeffery88412be2021-03-09 22:05:22 +1030488 if (!mctp_astlpc_layout_validate(astlpc, &astlpc->layout)) {
489 astlpc_prerr(astlpc, "Cannot support an MTU of %" PRIu32, sz);
Andrew Jefferya9368982020-06-09 13:07:39 +0930490 return -EINVAL;
491 }
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930492
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930493 hdr = (struct mctp_lpcmap_hdr){
494 .magic = htobe32(ASTLPC_MCTP_MAGIC),
495 .bmc_ver_min = htobe16(ASTLPC_VER_MIN),
496 .bmc_ver_cur = htobe16(ASTLPC_VER_CUR),
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930497
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930498 /* Flip the buffers back as we're now describing the host's
499 * configuration to the host */
Andrew Jeffery3a540662020-05-26 19:55:30 +0930500 .layout.rx_offset = htobe32(astlpc->layout.tx.offset),
501 .layout.rx_size = htobe32(astlpc->layout.tx.size),
502 .layout.tx_offset = htobe32(astlpc->layout.rx.offset),
503 .layout.tx_size = htobe32(astlpc->layout.rx.size),
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930504 };
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930505
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930506 mctp_astlpc_lpc_write(astlpc, &hdr, 0, sizeof(hdr));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930507
Andrew Jefferyb3b55a62020-07-06 13:34:18 +0930508 /*
509 * Set status indicating that the BMC is now active. Be explicit about
510 * clearing OBF; we're reinitialising the binding and so any previous
511 * buffer state is irrelevant.
512 */
513 status = KCS_STATUS_BMC_READY & ~KCS_STATUS_OBF;
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930514 return mctp_astlpc_kcs_set_status(astlpc, status);
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930515}
516
517static int mctp_binding_astlpc_start_bmc(struct mctp_binding *b)
518{
519 struct mctp_binding_astlpc *astlpc =
520 container_of(b, struct mctp_binding_astlpc, binding);
521
Andrew Jeffery88412be2021-03-09 22:05:22 +1030522 astlpc->proto = &astlpc_protocol_version[ASTLPC_VER_CUR];
523
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930524 return mctp_astlpc_init_bmc(astlpc);
525}
526
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930527static bool mctp_astlpc_validate_version(uint16_t bmc_ver_min,
528 uint16_t bmc_ver_cur,
529 uint16_t host_ver_min,
530 uint16_t host_ver_cur)
531{
532 if (!(bmc_ver_min && bmc_ver_cur && host_ver_min && host_ver_cur)) {
533 mctp_prerr("Invalid version present in [%" PRIu16 ", %" PRIu16
534 "], [%" PRIu16 ", %" PRIu16 "]",
535 bmc_ver_min, bmc_ver_cur, host_ver_min,
536 host_ver_cur);
537 return false;
538 } else if (bmc_ver_min > bmc_ver_cur) {
539 mctp_prerr("Invalid bmc version range [%" PRIu16 ", %" PRIu16
540 "]",
541 bmc_ver_min, bmc_ver_cur);
542 return false;
543 } else if (host_ver_min > host_ver_cur) {
544 mctp_prerr("Invalid host version range [%" PRIu16 ", %" PRIu16
545 "]",
546 host_ver_min, host_ver_cur);
547 return false;
548 } else if ((host_ver_cur < bmc_ver_min) ||
549 (host_ver_min > bmc_ver_cur)) {
550 mctp_prerr(
551 "Unable to satisfy version negotiation with ranges [%" PRIu16
552 ", %" PRIu16 "] and [%" PRIu16 ", %" PRIu16 "]",
553 bmc_ver_min, bmc_ver_cur, host_ver_min, host_ver_cur);
554 return false;
555 }
556
557 return true;
558}
559
Andrew Jeffery3a540662020-05-26 19:55:30 +0930560static int mctp_astlpc_negotiate_layout_host(struct mctp_binding_astlpc *astlpc)
561{
562 struct mctp_astlpc_layout layout;
Andrew Jeffery88412be2021-03-09 22:05:22 +1030563 uint32_t rmtu;
Andrew Jeffery3a540662020-05-26 19:55:30 +0930564 uint32_t sz;
565 int rc;
566
567 rc = mctp_astlpc_layout_read(astlpc, &layout);
568 if (rc < 0)
569 return rc;
570
Andrew Jeffery88412be2021-03-09 22:05:22 +1030571 if (!mctp_astlpc_layout_validate(astlpc, &layout)) {
Andrew Jeffery3a540662020-05-26 19:55:30 +0930572 astlpc_prerr(
573 astlpc,
574 "BMC provided invalid buffer layout: Rx {0x%" PRIx32
575 ", %" PRIu32 "}, Tx {0x%" PRIx32 ", %" PRIu32 "}",
576 layout.rx.offset, layout.rx.size, layout.tx.offset,
577 layout.tx.size);
578 return -EINVAL;
579 }
580
Andrew Jefferya9368982020-06-09 13:07:39 +0930581 astlpc_prinfo(astlpc, "Desire an MTU of %" PRIu32 " bytes",
582 astlpc->requested_mtu);
583
Andrew Jeffery88412be2021-03-09 22:05:22 +1030584 rmtu = astlpc->requested_mtu;
585 sz = astlpc->proto->packet_size(MCTP_PACKET_SIZE(rmtu));
Andrew Jeffery3a540662020-05-26 19:55:30 +0930586 layout.rx.size = sz;
587
Andrew Jeffery88412be2021-03-09 22:05:22 +1030588 if (!mctp_astlpc_layout_validate(astlpc, &layout)) {
Andrew Jeffery3a540662020-05-26 19:55:30 +0930589 astlpc_prerr(
590 astlpc,
591 "Generated invalid buffer layout with size %" PRIu32
592 ": Rx {0x%" PRIx32 ", %" PRIu32 "}, Tx {0x%" PRIx32
593 ", %" PRIu32 "}",
594 sz, layout.rx.offset, layout.rx.size, layout.tx.offset,
595 layout.tx.size);
596 return -EINVAL;
597 }
598
Andrew Jefferya9368982020-06-09 13:07:39 +0930599 astlpc_prinfo(astlpc, "Requesting MTU of %" PRIu32 " bytes",
600 astlpc->requested_mtu);
Andrew Jeffery3a540662020-05-26 19:55:30 +0930601
602 return mctp_astlpc_layout_write(astlpc, &layout);
603}
604
Andrew Jeffery88412be2021-03-09 22:05:22 +1030605static uint16_t mctp_astlpc_negotiate_version(uint16_t bmc_ver_min,
606 uint16_t bmc_ver_cur,
607 uint16_t host_ver_min,
608 uint16_t host_ver_cur)
609{
610 if (!mctp_astlpc_validate_version(bmc_ver_min, bmc_ver_cur,
611 host_ver_min, host_ver_cur))
612 return ASTLPC_VER_BAD;
613
614 if (bmc_ver_cur < host_ver_cur)
615 return bmc_ver_cur;
616
617 return host_ver_cur;
618}
619
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930620static int mctp_astlpc_init_host(struct mctp_binding_astlpc *astlpc)
621{
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930622 const uint16_t ver_min_be = htobe16(ASTLPC_VER_MIN);
623 const uint16_t ver_cur_be = htobe16(ASTLPC_VER_CUR);
Andrew Jeffery88412be2021-03-09 22:05:22 +1030624 uint16_t bmc_ver_min, bmc_ver_cur, negotiated;
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930625 struct mctp_lpcmap_hdr hdr;
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930626 uint8_t status;
627 int rc;
628
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930629 rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, &status);
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930630 if (rc) {
631 mctp_prwarn("KCS status read failed");
632 return rc;
633 }
634
635 astlpc->kcs_status = status;
636
637 if (!(status & KCS_STATUS_BMC_READY))
638 return -EHOSTDOWN;
639
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930640 mctp_astlpc_lpc_read(astlpc, &hdr, 0, sizeof(hdr));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930641
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930642 bmc_ver_min = be16toh(hdr.bmc_ver_min);
643 bmc_ver_cur = be16toh(hdr.bmc_ver_cur);
644
Andrew Jeffery88412be2021-03-09 22:05:22 +1030645 /* Calculate the expected value of negotiated_ver */
646 negotiated = mctp_astlpc_negotiate_version(bmc_ver_min, bmc_ver_cur,
647 ASTLPC_VER_MIN,
648 ASTLPC_VER_CUR);
649 if (!negotiated) {
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930650 astlpc_prerr(astlpc, "Cannot negotiate with invalid versions");
651 return -EINVAL;
652 }
653
Andrew Jeffery88412be2021-03-09 22:05:22 +1030654 /* Assign protocol ops so we can calculate the packet buffer sizes */
655 assert(negotiated < ARRAY_SIZE(astlpc_protocol_version));
656 astlpc->proto = &astlpc_protocol_version[negotiated];
657
658 /* Negotiate packet buffers in v2 style if the BMC supports it */
659 if (negotiated >= 2) {
Andrew Jeffery3a540662020-05-26 19:55:30 +0930660 rc = mctp_astlpc_negotiate_layout_host(astlpc);
661 if (rc < 0)
662 return rc;
663 }
664
Andrew Jeffery88412be2021-03-09 22:05:22 +1030665 /* Advertise the host's supported protocol versions */
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930666 mctp_astlpc_lpc_write(astlpc, &ver_min_be,
667 offsetof(struct mctp_lpcmap_hdr, host_ver_min),
668 sizeof(ver_min_be));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930669
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930670 mctp_astlpc_lpc_write(astlpc, &ver_cur_be,
671 offsetof(struct mctp_lpcmap_hdr, host_ver_cur),
672 sizeof(ver_cur_be));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930673
674 /* Send channel init command */
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930675 rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, 0x0);
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930676 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930677 astlpc_prwarn(astlpc, "KCS write failed");
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930678 }
679
Andrew Jeffery88412be2021-03-09 22:05:22 +1030680 /*
681 * Configure the host so `astlpc->proto->version == 0` holds until we
682 * receive a subsequent status update from the BMC. Until then,
683 * `astlpc->proto->version == 0` indicates that we're yet to complete
684 * the channel initialisation handshake.
685 *
686 * When the BMC provides a status update with KCS_STATUS_CHANNEL_ACTIVE
687 * set we will assign the appropriate protocol ops struct in accordance
688 * with `negotiated_ver`.
689 */
690 astlpc->proto = &astlpc_protocol_version[ASTLPC_VER_BAD];
691
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930692 return rc;
693}
694
695static int mctp_binding_astlpc_start_host(struct mctp_binding *b)
696{
697 struct mctp_binding_astlpc *astlpc =
698 container_of(b, struct mctp_binding_astlpc, binding);
699
700 return mctp_astlpc_init_host(astlpc);
701}
702
703static bool __mctp_astlpc_kcs_ready(struct mctp_binding_astlpc *astlpc,
704 uint8_t status, bool is_write)
705{
706 bool is_bmc;
707 bool ready_state;
708 uint8_t flag;
709
710 is_bmc = (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC);
711 flag = (is_bmc ^ is_write) ? KCS_STATUS_IBF : KCS_STATUS_OBF;
712 ready_state = is_write ? 0 : 1;
713
714 return !!(status & flag) == ready_state;
715}
716
717static inline bool
718mctp_astlpc_kcs_read_ready(struct mctp_binding_astlpc *astlpc, uint8_t status)
719{
720 return __mctp_astlpc_kcs_ready(astlpc, status, false);
721}
722
723static inline bool
724mctp_astlpc_kcs_write_ready(struct mctp_binding_astlpc *astlpc, uint8_t status)
725{
726 return __mctp_astlpc_kcs_ready(astlpc, status, true);
727}
728
Jeremy Kerr672c8852019-03-01 12:18:07 +0800729static int mctp_astlpc_kcs_send(struct mctp_binding_astlpc *astlpc,
730 uint8_t data)
731{
732 uint8_t status;
733 int rc;
734
735 for (;;) {
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930736 rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS,
737 &status);
Andrew Jeffery1b27fe82020-01-24 16:05:11 +1030738 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930739 astlpc_prwarn(astlpc, "KCS status read failed");
Jeremy Kerr672c8852019-03-01 12:18:07 +0800740 return -1;
741 }
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930742 if (mctp_astlpc_kcs_write_ready(astlpc, status))
Jeremy Kerr672c8852019-03-01 12:18:07 +0800743 break;
744 /* todo: timeout */
745 }
746
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930747 rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, data);
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530748 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930749 astlpc_prwarn(astlpc, "KCS data write failed");
Jeremy Kerr672c8852019-03-01 12:18:07 +0800750 return -1;
751 }
752
753 return 0;
754}
755
756static int mctp_binding_astlpc_tx(struct mctp_binding *b,
757 struct mctp_pktbuf *pkt)
758{
759 struct mctp_binding_astlpc *astlpc = binding_to_astlpc(b);
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930760 uint32_t len, len_be;
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030761 struct mctp_hdr *hdr;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800762
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030763 hdr = mctp_pktbuf_hdr(pkt);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800764 len = mctp_pktbuf_size(pkt);
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030765
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930766 astlpc_prdebug(astlpc,
767 "%s: Transmitting %" PRIu32
768 "-byte packet (%hhu, %hhu, 0x%hhx)",
769 __func__, len, hdr->src, hdr->dest, hdr->flags_seq_tag);
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030770
Andrew Jeffery88412be2021-03-09 22:05:22 +1030771 if (len > astlpc->proto->body_size(astlpc->layout.tx.size)) {
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030772 astlpc_prwarn(astlpc, "invalid TX len %" PRIu32 ": %" PRIu32, len,
773 astlpc->proto->body_size(astlpc->layout.tx.size));
Jeremy Kerr672c8852019-03-01 12:18:07 +0800774 return -1;
775 }
776
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930777 len_be = htobe32(len);
778 mctp_astlpc_lpc_write(astlpc, &len_be, astlpc->layout.tx.offset,
779 sizeof(len_be));
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030780
781 astlpc->proto->pktbuf_protect(pkt);
782 len = mctp_pktbuf_size(pkt);
783
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930784 mctp_astlpc_lpc_write(astlpc, hdr, astlpc->layout.tx.offset + 4, len);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800785
786 mctp_binding_set_tx_enabled(b, false);
787
788 mctp_astlpc_kcs_send(astlpc, 0x1);
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030789
Jeremy Kerr672c8852019-03-01 12:18:07 +0800790 return 0;
791}
792
Andrew Jeffery3a540662020-05-26 19:55:30 +0930793static uint32_t mctp_astlpc_calculate_mtu(struct mctp_binding_astlpc *astlpc,
794 struct mctp_astlpc_layout *layout)
795{
Andrew Jeffery88412be2021-03-09 22:05:22 +1030796 uint32_t low, high, limit, rpkt;
Andrew Jeffery3a540662020-05-26 19:55:30 +0930797
798 /* Derive the largest MTU the BMC _can_ support */
799 low = MIN(astlpc->layout.rx.offset, astlpc->layout.tx.offset);
800 high = MAX(astlpc->layout.rx.offset, astlpc->layout.tx.offset);
801 limit = high - low;
802
Andrew Jefferya9368982020-06-09 13:07:39 +0930803 /* Determine the largest MTU the BMC _wants_ to support */
804 if (astlpc->requested_mtu) {
Andrew Jeffery88412be2021-03-09 22:05:22 +1030805 uint32_t rmtu = astlpc->requested_mtu;
Andrew Jefferya9368982020-06-09 13:07:39 +0930806
Andrew Jeffery88412be2021-03-09 22:05:22 +1030807 rpkt = astlpc->proto->packet_size(MCTP_PACKET_SIZE(rmtu));
808 limit = MIN(limit, rpkt);
Andrew Jefferya9368982020-06-09 13:07:39 +0930809 }
Andrew Jeffery3a540662020-05-26 19:55:30 +0930810
811 /* Determine the accepted MTU, applied both directions by convention */
Andrew Jeffery88412be2021-03-09 22:05:22 +1030812 rpkt = MIN(limit, layout->tx.size);
813 return MCTP_BODY_SIZE(astlpc->proto->body_size(rpkt));
Andrew Jeffery3a540662020-05-26 19:55:30 +0930814}
815
Andrew Jeffery88412be2021-03-09 22:05:22 +1030816static int mctp_astlpc_negotiate_layout_bmc(struct mctp_binding_astlpc *astlpc)
Andrew Jeffery3a540662020-05-26 19:55:30 +0930817{
818 struct mctp_astlpc_layout proposed, pending;
819 uint32_t sz, mtu;
820 int rc;
821
Andrew Jeffery88412be2021-03-09 22:05:22 +1030822 /* Do we have a valid protocol version? */
823 if (!astlpc->proto->version)
824 return -EINVAL;
825
Andrew Jeffery3a540662020-05-26 19:55:30 +0930826 /* Extract the host's proposed layout */
827 rc = mctp_astlpc_layout_read(astlpc, &proposed);
828 if (rc < 0)
829 return rc;
830
Andrew Jeffery88412be2021-03-09 22:05:22 +1030831 /* Do we have a reasonable layout? */
832 if (!mctp_astlpc_layout_validate(astlpc, &proposed))
Andrew Jeffery3a540662020-05-26 19:55:30 +0930833 return -EINVAL;
834
835 /* Negotiate the MTU */
836 mtu = mctp_astlpc_calculate_mtu(astlpc, &proposed);
Andrew Jeffery88412be2021-03-09 22:05:22 +1030837 sz = astlpc->proto->packet_size(MCTP_PACKET_SIZE(mtu));
Andrew Jeffery3a540662020-05-26 19:55:30 +0930838
839 /*
840 * Use symmetric MTUs by convention and to pass constraints in rx/tx
841 * functions
842 */
843 pending = astlpc->layout;
844 pending.tx.size = sz;
845 pending.rx.size = sz;
846
Andrew Jeffery88412be2021-03-09 22:05:22 +1030847 if (mctp_astlpc_layout_validate(astlpc, &pending)) {
Andrew Jeffery3a540662020-05-26 19:55:30 +0930848 /* We found a sensible Rx MTU, so honour it */
849 astlpc->layout = pending;
850
851 /* Enforce the negotiated MTU */
852 rc = mctp_astlpc_layout_write(astlpc, &astlpc->layout);
853 if (rc < 0)
854 return rc;
855
856 astlpc_prinfo(astlpc, "Negotiated an MTU of %" PRIu32 " bytes",
857 mtu);
858 } else {
859 astlpc_prwarn(astlpc, "MTU negotiation failed");
860 return -EINVAL;
861 }
862
Andrew Jeffery88412be2021-03-09 22:05:22 +1030863 if (astlpc->proto->version >= 2)
Andrew Jeffery3a540662020-05-26 19:55:30 +0930864 astlpc->binding.pkt_size = MCTP_PACKET_SIZE(mtu);
865
866 return 0;
867}
868
Jeremy Kerr672c8852019-03-01 12:18:07 +0800869static void mctp_astlpc_init_channel(struct mctp_binding_astlpc *astlpc)
870{
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930871 uint16_t negotiated, negotiated_be;
872 struct mctp_lpcmap_hdr hdr;
873 uint8_t status;
Andrew Jeffery3a540662020-05-26 19:55:30 +0930874 int rc;
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930875
876 mctp_astlpc_lpc_read(astlpc, &hdr, 0, sizeof(hdr));
877
878 /* Version negotiation */
879 negotiated =
880 mctp_astlpc_negotiate_version(ASTLPC_VER_MIN, ASTLPC_VER_CUR,
881 be16toh(hdr.host_ver_min),
882 be16toh(hdr.host_ver_cur));
883
Andrew Jeffery88412be2021-03-09 22:05:22 +1030884 /* MTU negotiation requires knowing which protocol we'll use */
885 assert(negotiated < ARRAY_SIZE(astlpc_protocol_version));
886 astlpc->proto = &astlpc_protocol_version[negotiated];
887
Andrew Jeffery3a540662020-05-26 19:55:30 +0930888 /* Host Rx MTU negotiation: Failure terminates channel init */
Andrew Jeffery88412be2021-03-09 22:05:22 +1030889 rc = mctp_astlpc_negotiate_layout_bmc(astlpc);
Andrew Jeffery3a540662020-05-26 19:55:30 +0930890 if (rc < 0)
891 negotiated = ASTLPC_VER_BAD;
892
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930893 /* Populate the negotiated version */
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930894 negotiated_be = htobe16(negotiated);
895 mctp_astlpc_lpc_write(astlpc, &negotiated_be,
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930896 offsetof(struct mctp_lpcmap_hdr, negotiated_ver),
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930897 sizeof(negotiated_be));
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930898
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930899 /* Finalise the configuration */
900 status = KCS_STATUS_BMC_READY | KCS_STATUS_OBF;
901 if (negotiated > 0) {
902 astlpc_prinfo(astlpc, "Negotiated binding version %" PRIu16,
903 negotiated);
904 status |= KCS_STATUS_CHANNEL_ACTIVE;
905 } else {
Andrew Jeffery88412be2021-03-09 22:05:22 +1030906 astlpc_prerr(astlpc, "Failed to initialise channel");
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930907 }
Jeremy Kerr672c8852019-03-01 12:18:07 +0800908
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930909 mctp_astlpc_kcs_set_status(astlpc, status);
910
911 mctp_binding_set_tx_enabled(&astlpc->binding,
912 status & KCS_STATUS_CHANNEL_ACTIVE);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800913}
914
915static void mctp_astlpc_rx_start(struct mctp_binding_astlpc *astlpc)
916{
917 struct mctp_pktbuf *pkt;
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030918 uint32_t body, packet;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800919
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030920 mctp_astlpc_lpc_read(astlpc, &body, astlpc->layout.rx.offset,
921 sizeof(body));
922 body = be32toh(body);
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530923
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030924 if (body > astlpc->proto->body_size(astlpc->layout.rx.size)) {
925 astlpc_prwarn(astlpc, "invalid RX len 0x%x", body);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800926 return;
927 }
928
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930929 assert(astlpc->binding.pkt_size >= 0);
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030930 if (body > (uint32_t)astlpc->binding.pkt_size) {
931 astlpc_prwarn(astlpc, "invalid RX len 0x%x", body);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800932 return;
933 }
934
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030935 /* Eliminate the medium-specific header that we just read */
936 packet = astlpc->proto->packet_size(body) - 4;
937 pkt = mctp_pktbuf_alloc(&astlpc->binding, packet);
Christian Geddesae59f4f2021-09-01 09:54:25 -0500938 if (!pkt) {
939 astlpc_prwarn(astlpc, "unable to allocate pktbuf len 0x%x", packet);
940 return;
941 }
Jeremy Kerr672c8852019-03-01 12:18:07 +0800942
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030943 /*
944 * Read payload and medium-specific trailer from immediately after the
945 * medium-specific header.
946 */
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930947 mctp_astlpc_lpc_read(astlpc, mctp_pktbuf_hdr(pkt),
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030948 astlpc->layout.rx.offset + 4, packet);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800949
Christian Geddesae59f4f2021-09-01 09:54:25 -0500950 /* Inform the other side of the MCTP interface that we have read
951 * the packet off the bus before handling the contents of the packet.
952 */
953 mctp_astlpc_kcs_send(astlpc, 0x2);
954
Andrew Jefferyeba19a32021-03-09 23:09:40 +1030955 /*
956 * v3 will validate the CRC32 in the medium-specific trailer and adjust
957 * the packet size accordingly. On older protocols validation is a no-op
958 * that always returns true.
959 */
960 if (astlpc->proto->pktbuf_validate(pkt)) {
961 mctp_bus_rx(&astlpc->binding, pkt);
962 } else {
963 /* TODO: Drop any associated assembly */
964 mctp_pktbuf_free(pkt);
965 astlpc_prdebug(astlpc, "Dropped corrupt packet");
966 }
Jeremy Kerr672c8852019-03-01 12:18:07 +0800967}
968
969static void mctp_astlpc_tx_complete(struct mctp_binding_astlpc *astlpc)
970{
971 mctp_binding_set_tx_enabled(&astlpc->binding, true);
972}
973
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930974static int mctp_astlpc_finalise_channel(struct mctp_binding_astlpc *astlpc)
975{
Andrew Jeffery3a540662020-05-26 19:55:30 +0930976 struct mctp_astlpc_layout layout;
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930977 uint16_t negotiated;
978 int rc;
979
980 rc = mctp_astlpc_lpc_read(astlpc, &negotiated,
981 offsetof(struct mctp_lpcmap_hdr,
982 negotiated_ver),
983 sizeof(negotiated));
984 if (rc < 0)
985 return rc;
986
987 negotiated = be16toh(negotiated);
Andrew Jeffery88412be2021-03-09 22:05:22 +1030988 astlpc_prerr(astlpc, "Version negotiation got: %u", negotiated);
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930989
990 if (negotiated == ASTLPC_VER_BAD || negotiated < ASTLPC_VER_MIN ||
991 negotiated > ASTLPC_VER_CUR) {
992 astlpc_prerr(astlpc, "Failed to negotiate version, got: %u\n",
993 negotiated);
994 return -EINVAL;
995 }
996
Andrew Jeffery88412be2021-03-09 22:05:22 +1030997 assert(negotiated < ARRAY_SIZE(astlpc_protocol_version));
998 astlpc->proto = &astlpc_protocol_version[negotiated];
Andrew Jeffery4e8264b2020-05-23 20:34:33 +0930999
Andrew Jeffery3a540662020-05-26 19:55:30 +09301000 rc = mctp_astlpc_layout_read(astlpc, &layout);
1001 if (rc < 0)
1002 return rc;
1003
Andrew Jeffery88412be2021-03-09 22:05:22 +10301004 if (!mctp_astlpc_layout_validate(astlpc, &layout)) {
Andrew Jeffery3a540662020-05-26 19:55:30 +09301005 mctp_prerr("BMC proposed invalid buffer parameters");
1006 return -EINVAL;
1007 }
1008
1009 astlpc->layout = layout;
1010
1011 if (negotiated >= 2)
1012 astlpc->binding.pkt_size =
Andrew Jeffery88412be2021-03-09 22:05:22 +10301013 astlpc->proto->body_size(astlpc->layout.tx.size);
Andrew Jeffery3a540662020-05-26 19:55:30 +09301014
Andrew Jeffery4e8264b2020-05-23 20:34:33 +09301015 return 0;
1016}
1017
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301018static int mctp_astlpc_update_channel(struct mctp_binding_astlpc *astlpc,
1019 uint8_t status)
1020{
1021 uint8_t updated;
1022 int rc = 0;
1023
1024 assert(astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST);
1025
1026 updated = astlpc->kcs_status ^ status;
1027
Andrew Jefferyd0f5da02020-05-28 09:12:55 +09301028 astlpc_prdebug(astlpc, "%s: status: 0x%x, update: 0x%x", __func__,
1029 status, updated);
1030
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301031 if (updated & KCS_STATUS_BMC_READY) {
Andrew Jefferyd0f5da02020-05-28 09:12:55 +09301032 if (status & KCS_STATUS_BMC_READY) {
1033 astlpc->kcs_status = status;
1034 return astlpc->binding.start(&astlpc->binding);
1035 } else {
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301036 mctp_binding_set_tx_enabled(&astlpc->binding, false);
Andrew Jefferyd0f5da02020-05-28 09:12:55 +09301037 }
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301038 }
1039
Andrew Jeffery88412be2021-03-09 22:05:22 +10301040 if (astlpc->proto->version == 0 ||
1041 updated & KCS_STATUS_CHANNEL_ACTIVE) {
Andrew Jeffery4e8264b2020-05-23 20:34:33 +09301042 bool enable;
1043
1044 rc = mctp_astlpc_finalise_channel(astlpc);
1045 enable = (status & KCS_STATUS_CHANNEL_ACTIVE) && rc == 0;
1046
1047 mctp_binding_set_tx_enabled(&astlpc->binding, enable);
1048 }
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301049
1050 astlpc->kcs_status = status;
1051
1052 return rc;
1053}
1054
Jeremy Kerr672c8852019-03-01 12:18:07 +08001055int mctp_astlpc_poll(struct mctp_binding_astlpc *astlpc)
1056{
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301057 uint8_t status, data;
Jeremy Kerr672c8852019-03-01 12:18:07 +08001058 int rc;
1059
Andrew Jefferyf13cb972020-05-28 09:30:09 +09301060 rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, &status);
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301061 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301062 astlpc_prwarn(astlpc, "KCS read error");
Jeremy Kerr672c8852019-03-01 12:18:07 +08001063 return -1;
Jeremy Kerr672c8852019-03-01 12:18:07 +08001064 }
1065
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301066 astlpc_prdebug(astlpc, "%s: status: 0x%hhx", __func__, status);
Andrew Jefferyedfe3832020-02-06 11:52:11 +10301067
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301068 if (!mctp_astlpc_kcs_read_ready(astlpc, status))
Jeremy Kerr672c8852019-03-01 12:18:07 +08001069 return 0;
1070
Andrew Jefferyf13cb972020-05-28 09:30:09 +09301071 rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_DATA, &data);
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301072 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301073 astlpc_prwarn(astlpc, "KCS data read error");
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301074 return -1;
1075 }
1076
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301077 astlpc_prdebug(astlpc, "%s: data: 0x%hhx", __func__, data);
Andrew Jefferyedfe3832020-02-06 11:52:11 +10301078
Andrew Jeffery88412be2021-03-09 22:05:22 +10301079 if (!astlpc->proto->version && !(data == 0x0 || data == 0xff)) {
Andrew Jefferyafcb7012021-01-28 17:00:36 +10301080 astlpc_prwarn(astlpc, "Invalid message for binding state: 0x%x",
1081 data);
1082 return 0;
1083 }
1084
Jeremy Kerr672c8852019-03-01 12:18:07 +08001085 switch (data) {
1086 case 0x0:
1087 mctp_astlpc_init_channel(astlpc);
1088 break;
1089 case 0x1:
1090 mctp_astlpc_rx_start(astlpc);
1091 break;
1092 case 0x2:
1093 mctp_astlpc_tx_complete(astlpc);
1094 break;
Jeremy Kerr1a4b55a2019-06-24 14:22:39 +08001095 case 0xff:
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301096 /* No responsibilities for the BMC on 0xff */
Andrew Jefferyd0f5da02020-05-28 09:12:55 +09301097 if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST) {
1098 rc = mctp_astlpc_update_channel(astlpc, status);
1099 if (rc < 0)
1100 return rc;
1101 }
1102 break;
Jeremy Kerr672c8852019-03-01 12:18:07 +08001103 default:
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301104 astlpc_prwarn(astlpc, "unknown message 0x%x", data);
Jeremy Kerr672c8852019-03-01 12:18:07 +08001105 }
Andrew Jefferyd0f5da02020-05-28 09:12:55 +09301106
1107 /* Handle silent loss of bmc-ready */
1108 if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST) {
1109 if (!(status & KCS_STATUS_BMC_READY && data == 0xff))
1110 return mctp_astlpc_update_channel(astlpc, status);
1111 }
1112
1113 return rc;
Jeremy Kerr672c8852019-03-01 12:18:07 +08001114}
1115
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301116/* allocate and basic initialisation */
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301117static struct mctp_binding_astlpc *__mctp_astlpc_init(uint8_t mode,
1118 uint32_t mtu)
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301119{
1120 struct mctp_binding_astlpc *astlpc;
1121
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301122 assert((mode == MCTP_BINDING_ASTLPC_MODE_BMC) ||
1123 (mode == MCTP_BINDING_ASTLPC_MODE_HOST));
1124
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301125 astlpc = __mctp_alloc(sizeof(*astlpc));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301126 if (!astlpc)
1127 return NULL;
1128
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301129 memset(astlpc, 0, sizeof(*astlpc));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301130 astlpc->mode = mode;
1131 astlpc->lpc_map = NULL;
Andrew Jefferya9368982020-06-09 13:07:39 +09301132 astlpc->requested_mtu = mtu;
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301133 astlpc->binding.name = "astlpc";
1134 astlpc->binding.version = 1;
Andrew Jeffery1a4f4412021-01-28 13:42:02 +10301135 astlpc->binding.pkt_size =
1136 MCTP_PACKET_SIZE(mtu > MCTP_BTU ? mtu : MCTP_BTU);
Andrew Jefferyeba19a32021-03-09 23:09:40 +10301137 astlpc->binding.pkt_header = 4;
1138 astlpc->binding.pkt_trailer = 4;
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301139 astlpc->binding.tx = mctp_binding_astlpc_tx;
1140 if (mode == MCTP_BINDING_ASTLPC_MODE_BMC)
1141 astlpc->binding.start = mctp_binding_astlpc_start_bmc;
1142 else if (mode == MCTP_BINDING_ASTLPC_MODE_HOST)
1143 astlpc->binding.start = mctp_binding_astlpc_start_host;
1144 else {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301145 astlpc_prerr(astlpc, "%s: Invalid mode: %d\n", __func__, mode);
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301146 __mctp_free(astlpc);
1147 return NULL;
1148 }
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301149
1150 return astlpc;
1151}
1152
Jeremy Kerr3b36d172019-09-04 11:56:09 +08001153struct mctp_binding *mctp_binding_astlpc_core(struct mctp_binding_astlpc *b)
1154{
1155 return &b->binding;
1156}
1157
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301158struct mctp_binding_astlpc *
1159mctp_astlpc_init(uint8_t mode, uint32_t mtu, void *lpc_map,
1160 const struct mctp_binding_astlpc_ops *ops, void *ops_data)
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301161{
1162 struct mctp_binding_astlpc *astlpc;
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301163
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301164 if (!(mode == MCTP_BINDING_ASTLPC_MODE_BMC ||
1165 mode == MCTP_BINDING_ASTLPC_MODE_HOST)) {
1166 mctp_prerr("Unknown binding mode: %u", mode);
1167 return NULL;
1168 }
1169
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301170 astlpc = __mctp_astlpc_init(mode, mtu);
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301171 if (!astlpc)
1172 return NULL;
1173
1174 memcpy(&astlpc->ops, ops, sizeof(astlpc->ops));
1175 astlpc->ops_data = ops_data;
1176 astlpc->lpc_map = lpc_map;
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301177 astlpc->mode = mode;
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301178
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301179 return astlpc;
1180}
1181
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301182struct mctp_binding_astlpc *
1183mctp_astlpc_init_ops(const struct mctp_binding_astlpc_ops *ops, void *ops_data,
1184 void *lpc_map)
1185{
1186 return mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, lpc_map,
1187 ops, ops_data);
1188}
1189
Andrew Jeffery4663f672020-03-10 23:36:24 +10301190void mctp_astlpc_destroy(struct mctp_binding_astlpc *astlpc)
1191{
Andrew Jefferyd0f5da02020-05-28 09:12:55 +09301192 /* Clear channel-active and bmc-ready */
1193 if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC)
Andrew Jeffery7c4509a2021-08-26 14:56:16 +09301194 mctp_astlpc_kcs_set_status(astlpc, 0);
Andrew Jeffery4663f672020-03-10 23:36:24 +10301195 __mctp_free(astlpc);
1196}
1197
Jeremy Kerrb214c642019-11-27 11:34:00 +08001198#ifdef MCTP_HAVE_FILEIO
Andrew Jeffery55fb90b2020-05-12 13:54:37 +09301199
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301200static int mctp_astlpc_init_fileio_lpc(struct mctp_binding_astlpc *astlpc)
Jeremy Kerr672c8852019-03-01 12:18:07 +08001201{
1202 struct aspeed_lpc_ctrl_mapping map = {
1203 .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY,
1204 .window_id = 0, /* There's only one */
1205 .flags = 0,
1206 .addr = 0,
1207 .offset = 0,
1208 .size = 0
1209 };
Andrew Jeffery979c6a12020-05-23 20:04:49 +09301210 void *lpc_map_base;
Jeremy Kerr672c8852019-03-01 12:18:07 +08001211 int fd, rc;
1212
1213 fd = open(lpc_path, O_RDWR | O_SYNC);
1214 if (fd < 0) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301215 astlpc_prwarn(astlpc, "LPC open (%s) failed", lpc_path);
Jeremy Kerr672c8852019-03-01 12:18:07 +08001216 return -1;
1217 }
1218
1219 rc = ioctl(fd, ASPEED_LPC_CTRL_IOCTL_GET_SIZE, &map);
1220 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301221 astlpc_prwarn(astlpc, "LPC GET_SIZE failed");
Jeremy Kerr672c8852019-03-01 12:18:07 +08001222 close(fd);
1223 return -1;
1224 }
1225
Andrew Jefferyc1d5c542021-10-27 15:25:48 +10301226 /*
1227 * 🚨🚨🚨
1228 *
1229 * Decouple ourselves from hiomapd[1] (another user of the FW2AHB) by
1230 * mapping the FW2AHB to the reserved memory here as well.
1231 *
1232 * It's not possible to use the MCTP ASTLPC binding on machines that
1233 * need the FW2AHB bridge mapped anywhere except to the reserved memory
1234 * (e.g. the host SPI NOR).
1235 *
1236 * [1] https://github.com/openbmc/hiomapd/
1237 *
1238 * 🚨🚨🚨
1239 *
1240 * The following calculation must align with what's going on in
1241 * hiomapd's lpc.c so as not to disrupt its behaviour:
1242 *
1243 * https://github.com/openbmc/hiomapd/blob/5ff50e3cbd7702aefc185264e4adfb9952040575/lpc.c#L68
1244 *
1245 * 🚨🚨🚨
1246 */
1247
1248 /* Map the reserved memory at the top of the 28-bit LPC firmware address space */
1249 map.addr = 0x0FFFFFFF & -map.size;
1250 astlpc_prinfo(astlpc,
1251 "Configuring FW2AHB to map reserved memory at 0x%08x for 0x%x in the LPC FW cycle address-space",
1252 map.addr, map.size);
1253
1254 rc = ioctl(fd, ASPEED_LPC_CTRL_IOCTL_MAP, &map);
1255 if (rc) {
1256 astlpc_prwarn(astlpc, "Failed to map FW2AHB to reserved memory");
1257 close(fd);
1258 return -1;
1259 }
1260
1261 /* Map the reserved memory into our address space */
Andrew Jeffery979c6a12020-05-23 20:04:49 +09301262 lpc_map_base =
1263 mmap(NULL, map.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1264 if (lpc_map_base == MAP_FAILED) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301265 astlpc_prwarn(astlpc, "LPC mmap failed");
Jeremy Kerr672c8852019-03-01 12:18:07 +08001266 rc = -1;
1267 } else {
Andrew Jeffery979c6a12020-05-23 20:04:49 +09301268 astlpc->lpc_map = lpc_map_base + map.size - LPC_WIN_SIZE;
Jeremy Kerr672c8852019-03-01 12:18:07 +08001269 }
1270
1271 close(fd);
1272
1273 return rc;
1274}
1275
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301276static int mctp_astlpc_init_fileio_kcs(struct mctp_binding_astlpc *astlpc)
Jeremy Kerr672c8852019-03-01 12:18:07 +08001277{
1278 astlpc->kcs_fd = open(kcs_path, O_RDWR);
1279 if (astlpc->kcs_fd < 0)
1280 return -1;
1281
1282 return 0;
1283}
1284
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301285static int __mctp_astlpc_fileio_kcs_read(void *arg,
1286 enum mctp_binding_astlpc_kcs_reg reg, uint8_t *val)
1287{
1288 struct mctp_binding_astlpc *astlpc = arg;
1289 off_t offset = reg;
1290 int rc;
1291
1292 rc = pread(astlpc->kcs_fd, val, 1, offset);
1293
1294 return rc == 1 ? 0 : -1;
1295}
1296
1297static int __mctp_astlpc_fileio_kcs_write(void *arg,
1298 enum mctp_binding_astlpc_kcs_reg reg, uint8_t val)
1299{
1300 struct mctp_binding_astlpc *astlpc = arg;
1301 off_t offset = reg;
1302 int rc;
1303
1304 rc = pwrite(astlpc->kcs_fd, &val, 1, offset);
1305
1306 return rc == 1 ? 0 : -1;
1307}
1308
1309int mctp_astlpc_get_fd(struct mctp_binding_astlpc *astlpc)
1310{
1311 return astlpc->kcs_fd;
1312}
1313
1314struct mctp_binding_astlpc *mctp_astlpc_init_fileio(void)
Jeremy Kerr672c8852019-03-01 12:18:07 +08001315{
1316 struct mctp_binding_astlpc *astlpc;
1317 int rc;
1318
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301319 /*
1320 * If we're doing file IO then we're very likely not running
Andrew Jeffery8877c462020-06-15 12:22:53 +09301321 * freestanding, so lets assume that we're on the BMC side.
1322 *
1323 * Requesting an MTU of 0 requests the largest possible MTU, whatever
1324 * value that might take.
Andrew Jeffery7cd72f12020-05-12 20:27:59 +09301325 */
Andrew Jeffery8877c462020-06-15 12:22:53 +09301326 astlpc = __mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_BMC, 0);
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301327 if (!astlpc)
1328 return NULL;
Jeremy Kerr672c8852019-03-01 12:18:07 +08001329
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301330 /* Set internal operations for kcs. We use direct accesses to the lpc
1331 * map area */
1332 astlpc->ops.kcs_read = __mctp_astlpc_fileio_kcs_read;
1333 astlpc->ops.kcs_write = __mctp_astlpc_fileio_kcs_write;
1334 astlpc->ops_data = astlpc;
1335
1336 rc = mctp_astlpc_init_fileio_lpc(astlpc);
Jeremy Kerr672c8852019-03-01 12:18:07 +08001337 if (rc) {
1338 free(astlpc);
1339 return NULL;
1340 }
1341
Jeremy Kerrbc53d352019-08-28 14:26:14 +05301342 rc = mctp_astlpc_init_fileio_kcs(astlpc);
Jeremy Kerr672c8852019-03-01 12:18:07 +08001343 if (rc) {
1344 free(astlpc);
1345 return NULL;
1346 }
1347
Jeremy Kerr672c8852019-03-01 12:18:07 +08001348 return astlpc;
1349}
Jeremy Kerr92a10a62019-08-28 16:55:54 +05301350#else
1351struct mctp_binding_astlpc * __attribute__((const))
1352 mctp_astlpc_init_fileio(void)
1353{
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301354 astlpc_prerr(astlpc, "Missing support for file IO");
Jeremy Kerr92a10a62019-08-28 16:55:54 +05301355 return NULL;
1356}
Jeremy Kerr672c8852019-03-01 12:18:07 +08001357
Jeremy Kerr92a10a62019-08-28 16:55:54 +05301358int __attribute__((const)) mctp_astlpc_get_fd(
1359 struct mctp_binding_astlpc *astlpc __attribute__((unused)))
1360{
Andrew Jeffery9101a2a2020-05-22 16:08:03 +09301361 astlpc_prerr(astlpc, "Missing support for file IO");
Jeremy Kerr92a10a62019-08-28 16:55:54 +05301362 return -1;
1363}
1364#endif