blob: 1a757420c71dcc0ba2cf189d88b28ecbecc67862 [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
3#include <assert.h>
Jeremy Kerr92a10a62019-08-28 16:55:54 +05304#include <endian.h>
Andrew Jeffery59c6a5c2020-01-17 15:52:51 +10305#include <err.h>
Andrew Jefferyedfe3832020-02-06 11:52:11 +10306#include <inttypes.h>
Jeremy Kerr672c8852019-03-01 12:18:07 +08007#include <stdbool.h>
8#include <stdlib.h>
9#include <string.h>
Jeremy Kerr672c8852019-03-01 12:18:07 +080010
Jeremy Kerr672c8852019-03-01 12:18:07 +080011#define pr_fmt(x) "astlpc: " x
12
Andrew Jeffery59c6a5c2020-01-17 15:52:51 +103013#if HAVE_CONFIG_H
14#include "config.h"
15#endif
16
Jeremy Kerr672c8852019-03-01 12:18:07 +080017#include "libmctp.h"
18#include "libmctp-alloc.h"
19#include "libmctp-log.h"
20#include "libmctp-astlpc.h"
21
Jeremy Kerrb214c642019-11-27 11:34:00 +080022#ifdef MCTP_HAVE_FILEIO
Jeremy Kerr92a10a62019-08-28 16:55:54 +053023
Jeremy Kerrc6f676d2019-12-19 09:24:06 +080024#include <unistd.h>
Jeremy Kerr92a10a62019-08-28 16:55:54 +053025#include <fcntl.h>
26#include <sys/ioctl.h>
27#include <sys/mman.h>
28#include <linux/aspeed-lpc-ctrl.h>
29
30/* kernel interface */
31static const char *kcs_path = "/dev/mctp0";
32static const char *lpc_path = "/dev/aspeed-lpc-ctrl";
33
34#endif
35
Jeremy Kerr672c8852019-03-01 12:18:07 +080036struct mctp_binding_astlpc {
37 struct mctp_binding binding;
Jeremy Kerrbc53d352019-08-28 14:26:14 +053038
Jeremy Kerr672c8852019-03-01 12:18:07 +080039 union {
40 void *lpc_map;
41 struct mctp_lpcmap_hdr *lpc_hdr;
42 };
Jeremy Kerrbc53d352019-08-28 14:26:14 +053043
44 /* direct ops data */
45 struct mctp_binding_astlpc_ops ops;
46 void *ops_data;
47 struct mctp_lpcmap_hdr *priv_hdr;
48
49 /* fileio ops data */
50 void *lpc_map_base;
Jeremy Kerr672c8852019-03-01 12:18:07 +080051 int kcs_fd;
52 uint8_t kcs_status;
53
54 bool running;
55
56 /* temporary transmit buffer */
57 uint8_t txbuf[256];
58};
59
60#ifndef container_of
61#define container_of(ptr, type, member) \
Andrew Jeffery1e0af042020-01-10 15:58:28 +103062 (type *)((char *)(ptr) - (char *)&((type *)0)->member)
Jeremy Kerr672c8852019-03-01 12:18:07 +080063#endif
64
65#define binding_to_astlpc(b) \
66 container_of(b, struct mctp_binding_astlpc, binding)
67
68#define MCTP_MAGIC 0x4d435450
69#define BMC_VER_MIN 1
70#define BMC_VER_CUR 1
71
72struct mctp_lpcmap_hdr {
73 uint32_t magic;
74
75 uint16_t bmc_ver_min;
76 uint16_t bmc_ver_cur;
77 uint16_t host_ver_min;
78 uint16_t host_ver_cur;
79 uint16_t negotiated_ver;
80 uint16_t pad0;
81
82 uint32_t rx_offset;
83 uint32_t rx_size;
84 uint32_t tx_offset;
85 uint32_t tx_size;
86} __attribute__((packed));
87
88/* layout of TX/RX areas */
89static const uint32_t rx_offset = 0x100;
90static const uint32_t rx_size = 0x100;
91static const uint32_t tx_offset = 0x200;
92static const uint32_t tx_size = 0x100;
93
Jeremy Kerr672c8852019-03-01 12:18:07 +080094#define LPC_WIN_SIZE (1 * 1024 * 1024)
95
96enum {
97 KCS_REG_DATA = 0,
98 KCS_REG_STATUS = 1,
99};
100
101#define KCS_STATUS_BMC_READY 0x80
102#define KCS_STATUS_CHANNEL_ACTIVE 0x40
103#define KCS_STATUS_IBF 0x02
104#define KCS_STATUS_OBF 0x01
105
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530106static bool lpc_direct(struct mctp_binding_astlpc *astlpc)
107{
108 return astlpc->lpc_map != NULL;
109}
110
Jeremy Kerr672c8852019-03-01 12:18:07 +0800111static int mctp_astlpc_kcs_set_status(struct mctp_binding_astlpc *astlpc,
112 uint8_t status)
113{
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530114 uint8_t data;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800115 int rc;
116
Jeremy Kerr1a4b55a2019-06-24 14:22:39 +0800117 /* Since we're setting the status register, we want the other endpoint
118 * to be interrupted. However, some hardware may only raise a host-side
119 * interrupt on an ODR event.
120 * So, write a dummy value of 0xff to ODR, which will ensure that an
121 * interrupt is triggered, and can be ignored by the host.
122 */
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530123 data = 0xff;
124 status |= KCS_STATUS_OBF;
Jeremy Kerr1a4b55a2019-06-24 14:22:39 +0800125
Andrew Jefferyc84fd562020-01-30 21:18:16 +1030126 rc = astlpc->ops.kcs_write(astlpc->ops_data, MCTP_ASTLPC_KCS_REG_STATUS,
127 status);
128 if (rc) {
129 mctp_prwarn("KCS status write failed");
130 return -1;
131 }
132
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530133 rc = astlpc->ops.kcs_write(astlpc->ops_data, MCTP_ASTLPC_KCS_REG_DATA,
134 data);
135 if (rc) {
136 mctp_prwarn("KCS dummy data write failed");
137 return -1;
138 }
139
Jeremy Kerr672c8852019-03-01 12:18:07 +0800140 return 0;
141}
142
143static int mctp_astlpc_kcs_send(struct mctp_binding_astlpc *astlpc,
144 uint8_t data)
145{
146 uint8_t status;
147 int rc;
148
149 for (;;) {
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530150 rc = astlpc->ops.kcs_read(astlpc->ops_data,
151 MCTP_ASTLPC_KCS_REG_STATUS, &status);
Andrew Jeffery1b27fe82020-01-24 16:05:11 +1030152 if (rc) {
Andrew Jeffery182204e2020-01-23 17:02:38 +1030153 mctp_prwarn("KCS status read failed");
Jeremy Kerr672c8852019-03-01 12:18:07 +0800154 return -1;
155 }
156 if (!(status & KCS_STATUS_OBF))
157 break;
158 /* todo: timeout */
159 }
160
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530161 rc = astlpc->ops.kcs_write(astlpc->ops_data, MCTP_ASTLPC_KCS_REG_DATA,
162 data);
163 if (rc) {
Jeremy Kerr672c8852019-03-01 12:18:07 +0800164 mctp_prwarn("KCS data write failed");
165 return -1;
166 }
167
168 return 0;
169}
170
171static int mctp_binding_astlpc_tx(struct mctp_binding *b,
172 struct mctp_pktbuf *pkt)
173{
174 struct mctp_binding_astlpc *astlpc = binding_to_astlpc(b);
175 uint32_t len;
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030176 struct mctp_hdr *hdr;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800177
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030178 hdr = mctp_pktbuf_hdr(pkt);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800179 len = mctp_pktbuf_size(pkt);
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030180
181 mctp_prdebug("%s: Transmitting %"PRIu32"-byte packet (%hhu, %hhu, 0x%hhx)",
182 __func__, len, hdr->src, hdr->dest, hdr->flags_seq_tag);
183
Jeremy Kerr672c8852019-03-01 12:18:07 +0800184 if (len > rx_size - 4) {
185 mctp_prwarn("invalid TX len 0x%x", len);
186 return -1;
187 }
188
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530189 if (lpc_direct(astlpc)) {
190 *(uint32_t *)(astlpc->lpc_map + rx_offset) = htobe32(len);
191 memcpy(astlpc->lpc_map + rx_offset + 4, mctp_pktbuf_hdr(pkt),
192 len);
193 } else {
194 uint32_t tmp = htobe32(len);
195 astlpc->ops.lpc_write(astlpc->ops_data, &tmp, rx_offset,
196 sizeof(tmp));
197 astlpc->ops.lpc_write(astlpc->ops_data, mctp_pktbuf_hdr(pkt),
198 rx_offset + 4, len);
199 }
Jeremy Kerr672c8852019-03-01 12:18:07 +0800200
201 mctp_binding_set_tx_enabled(b, false);
202
203 mctp_astlpc_kcs_send(astlpc, 0x1);
204 return 0;
205}
206
207static void mctp_astlpc_init_channel(struct mctp_binding_astlpc *astlpc)
208{
209 /* todo: actual version negotiation */
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530210 if (lpc_direct(astlpc)) {
211 astlpc->lpc_hdr->negotiated_ver = htobe16(1);
212 } else {
213 uint16_t ver = htobe16(1);
214 astlpc->ops.lpc_write(astlpc->ops_data, &ver,
215 offsetof(struct mctp_lpcmap_hdr,
216 negotiated_ver),
217 sizeof(ver));
218 }
Jeremy Kerr672c8852019-03-01 12:18:07 +0800219 mctp_astlpc_kcs_set_status(astlpc,
220 KCS_STATUS_BMC_READY | KCS_STATUS_CHANNEL_ACTIVE |
221 KCS_STATUS_OBF);
222
223 mctp_binding_set_tx_enabled(&astlpc->binding, true);
224}
225
226static void mctp_astlpc_rx_start(struct mctp_binding_astlpc *astlpc)
227{
228 struct mctp_pktbuf *pkt;
229 uint32_t len;
230
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530231 if (lpc_direct(astlpc)) {
232 len = *(uint32_t *)(astlpc->lpc_map + tx_offset);
233 } else {
234 astlpc->ops.lpc_read(astlpc->ops_data, &len,
235 tx_offset, sizeof(len));
236 }
237 len = be32toh(len);
238
Jeremy Kerr672c8852019-03-01 12:18:07 +0800239 if (len > tx_size - 4) {
240 mctp_prwarn("invalid RX len 0x%x", len);
241 return;
242 }
243
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800244 if (len > astlpc->binding.pkt_size) {
Jeremy Kerr672c8852019-03-01 12:18:07 +0800245 mctp_prwarn("invalid RX len 0x%x", len);
246 return;
247 }
248
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800249 pkt = mctp_pktbuf_alloc(&astlpc->binding, len);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800250 if (!pkt)
251 goto out_complete;
252
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530253 if (lpc_direct(astlpc)) {
254 memcpy(mctp_pktbuf_hdr(pkt),
255 astlpc->lpc_map + tx_offset + 4, len);
256 } else {
257 astlpc->ops.lpc_read(astlpc->ops_data, mctp_pktbuf_hdr(pkt),
258 tx_offset + 4, len);
259 }
Jeremy Kerr672c8852019-03-01 12:18:07 +0800260
261 mctp_bus_rx(&astlpc->binding, pkt);
262
263out_complete:
264 mctp_astlpc_kcs_send(astlpc, 0x2);
265}
266
267static void mctp_astlpc_tx_complete(struct mctp_binding_astlpc *astlpc)
268{
269 mctp_binding_set_tx_enabled(&astlpc->binding, true);
270}
271
272int mctp_astlpc_poll(struct mctp_binding_astlpc *astlpc)
273{
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530274 uint8_t status, data;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800275 int rc;
276
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530277 rc = astlpc->ops.kcs_read(astlpc->ops_data, MCTP_ASTLPC_KCS_REG_STATUS,
278 &status);
279 if (rc) {
Jeremy Kerr672c8852019-03-01 12:18:07 +0800280 mctp_prwarn("KCS read error");
281 return -1;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800282 }
283
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030284 mctp_prdebug("%s: status: 0x%hhx", __func__, status);
285
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530286 if (!(status & KCS_STATUS_IBF))
Jeremy Kerr672c8852019-03-01 12:18:07 +0800287 return 0;
288
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530289 rc = astlpc->ops.kcs_read(astlpc->ops_data, MCTP_ASTLPC_KCS_REG_DATA,
290 &data);
291 if (rc) {
292 mctp_prwarn("KCS data read error");
293 return -1;
294 }
295
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030296 mctp_prdebug("%s: data: 0x%hhx", __func__, data);
297
Jeremy Kerr672c8852019-03-01 12:18:07 +0800298 switch (data) {
299 case 0x0:
300 mctp_astlpc_init_channel(astlpc);
301 break;
302 case 0x1:
303 mctp_astlpc_rx_start(astlpc);
304 break;
305 case 0x2:
306 mctp_astlpc_tx_complete(astlpc);
307 break;
Jeremy Kerr1a4b55a2019-06-24 14:22:39 +0800308 case 0xff:
309 /* reserved value for dummy data writes; do nothing */
310 break;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800311 default:
312 mctp_prwarn("unknown message 0x%x", data);
313 }
314 return 0;
315}
316
Jeremy Kerr672c8852019-03-01 12:18:07 +0800317static int mctp_astlpc_init_bmc(struct mctp_binding_astlpc *astlpc)
318{
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530319 struct mctp_lpcmap_hdr *hdr;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800320 uint8_t status;
321 int rc;
322
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530323 if (lpc_direct(astlpc))
324 hdr = astlpc->lpc_hdr;
325 else
326 hdr = astlpc->priv_hdr;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800327
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530328 hdr->magic = htobe32(MCTP_MAGIC);
329 hdr->bmc_ver_min = htobe16(BMC_VER_MIN);
330 hdr->bmc_ver_cur = htobe16(BMC_VER_CUR);
331
332 hdr->rx_offset = htobe32(rx_offset);
333 hdr->rx_size = htobe32(rx_size);
334 hdr->tx_offset = htobe32(tx_offset);
335 hdr->tx_size = htobe32(tx_size);
336
337 if (!lpc_direct(astlpc))
338 astlpc->ops.lpc_write(astlpc->ops_data, hdr, 0, sizeof(*hdr));
Jeremy Kerr672c8852019-03-01 12:18:07 +0800339
340 /* set status indicating that the BMC is now active */
341 status = KCS_STATUS_BMC_READY | KCS_STATUS_OBF;
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530342 rc = astlpc->ops.kcs_write(astlpc->ops_data,
343 MCTP_ASTLPC_KCS_REG_STATUS, status);
344 if (rc) {
Jeremy Kerr672c8852019-03-01 12:18:07 +0800345 mctp_prwarn("KCS write failed");
Jeremy Kerr672c8852019-03-01 12:18:07 +0800346 }
347
348 return rc;
349}
350
Jeremy Kerr8081beb2019-09-04 12:33:00 +0800351static int mctp_binding_astlpc_start(struct mctp_binding *b)
352{
353 struct mctp_binding_astlpc *astlpc = container_of(b,
354 struct mctp_binding_astlpc, binding);
355
356 return mctp_astlpc_init_bmc(astlpc);
357}
358
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530359/* allocate and basic initialisation */
360static struct mctp_binding_astlpc *__mctp_astlpc_init(void)
361{
362 struct mctp_binding_astlpc *astlpc;
363
364 astlpc = __mctp_alloc(sizeof(*astlpc));
365 memset(astlpc, 0, sizeof(*astlpc));
366 astlpc->binding.name = "astlpc";
367 astlpc->binding.version = 1;
368 astlpc->binding.tx = mctp_binding_astlpc_tx;
Jeremy Kerr8081beb2019-09-04 12:33:00 +0800369 astlpc->binding.start = mctp_binding_astlpc_start;
Andrew Jeffery73c268e2020-01-30 10:16:09 +1030370 astlpc->binding.pkt_size = MCTP_PACKET_SIZE(MCTP_BTU);
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530371 astlpc->binding.pkt_pad = 0;
372 astlpc->lpc_map = NULL;
373
374 return astlpc;
375}
376
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800377struct mctp_binding *mctp_binding_astlpc_core(struct mctp_binding_astlpc *b)
378{
379 return &b->binding;
380}
381
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530382struct mctp_binding_astlpc *mctp_astlpc_init_ops(
Andrew Jefferya0452492020-02-06 11:47:39 +1030383 const struct mctp_binding_astlpc_ops *ops,
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530384 void *ops_data, void *lpc_map)
385{
386 struct mctp_binding_astlpc *astlpc;
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530387
388 astlpc = __mctp_astlpc_init();
389 if (!astlpc)
390 return NULL;
391
392 memcpy(&astlpc->ops, ops, sizeof(astlpc->ops));
393 astlpc->ops_data = ops_data;
394 astlpc->lpc_map = lpc_map;
395
396 /* In indirect mode, we keep a separate buffer of header data.
397 * We need to sync this through the lpc_read/lpc_write ops.
398 */
399 if (!astlpc->lpc_map)
400 astlpc->priv_hdr = __mctp_alloc(sizeof(*astlpc->priv_hdr));
401
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530402 return astlpc;
403}
404
Jeremy Kerrb214c642019-11-27 11:34:00 +0800405#ifdef MCTP_HAVE_FILEIO
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530406static int mctp_astlpc_init_fileio_lpc(struct mctp_binding_astlpc *astlpc)
Jeremy Kerr672c8852019-03-01 12:18:07 +0800407{
408 struct aspeed_lpc_ctrl_mapping map = {
409 .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY,
410 .window_id = 0, /* There's only one */
411 .flags = 0,
412 .addr = 0,
413 .offset = 0,
414 .size = 0
415 };
416 int fd, rc;
417
418 fd = open(lpc_path, O_RDWR | O_SYNC);
419 if (fd < 0) {
420 mctp_prwarn("LPC open (%s) failed", lpc_path);
421 return -1;
422 }
423
424 rc = ioctl(fd, ASPEED_LPC_CTRL_IOCTL_GET_SIZE, &map);
425 if (rc) {
426 mctp_prwarn("LPC GET_SIZE failed");
427 close(fd);
428 return -1;
429 }
430
431 astlpc->lpc_map_base = mmap(NULL, map.size, PROT_READ | PROT_WRITE,
432 MAP_SHARED, fd, 0);
433 if (astlpc->lpc_map_base == MAP_FAILED) {
434 mctp_prwarn("LPC mmap failed");
435 rc = -1;
436 } else {
437 astlpc->lpc_map = astlpc->lpc_map_base +
438 map.size - LPC_WIN_SIZE;
439 }
440
441 close(fd);
442
443 return rc;
444}
445
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530446static int mctp_astlpc_init_fileio_kcs(struct mctp_binding_astlpc *astlpc)
Jeremy Kerr672c8852019-03-01 12:18:07 +0800447{
448 astlpc->kcs_fd = open(kcs_path, O_RDWR);
449 if (astlpc->kcs_fd < 0)
450 return -1;
451
452 return 0;
453}
454
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530455static int __mctp_astlpc_fileio_kcs_read(void *arg,
456 enum mctp_binding_astlpc_kcs_reg reg, uint8_t *val)
457{
458 struct mctp_binding_astlpc *astlpc = arg;
459 off_t offset = reg;
460 int rc;
461
462 rc = pread(astlpc->kcs_fd, val, 1, offset);
463
464 return rc == 1 ? 0 : -1;
465}
466
467static int __mctp_astlpc_fileio_kcs_write(void *arg,
468 enum mctp_binding_astlpc_kcs_reg reg, uint8_t val)
469{
470 struct mctp_binding_astlpc *astlpc = arg;
471 off_t offset = reg;
472 int rc;
473
474 rc = pwrite(astlpc->kcs_fd, &val, 1, offset);
475
476 return rc == 1 ? 0 : -1;
477}
478
479int mctp_astlpc_get_fd(struct mctp_binding_astlpc *astlpc)
480{
481 return astlpc->kcs_fd;
482}
483
484struct mctp_binding_astlpc *mctp_astlpc_init_fileio(void)
Jeremy Kerr672c8852019-03-01 12:18:07 +0800485{
486 struct mctp_binding_astlpc *astlpc;
487 int rc;
488
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530489 astlpc = __mctp_astlpc_init();
490 if (!astlpc)
491 return NULL;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800492
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530493 /* Set internal operations for kcs. We use direct accesses to the lpc
494 * map area */
495 astlpc->ops.kcs_read = __mctp_astlpc_fileio_kcs_read;
496 astlpc->ops.kcs_write = __mctp_astlpc_fileio_kcs_write;
497 astlpc->ops_data = astlpc;
498
499 rc = mctp_astlpc_init_fileio_lpc(astlpc);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800500 if (rc) {
501 free(astlpc);
502 return NULL;
503 }
504
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530505 rc = mctp_astlpc_init_fileio_kcs(astlpc);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800506 if (rc) {
507 free(astlpc);
508 return NULL;
509 }
510
Jeremy Kerr672c8852019-03-01 12:18:07 +0800511 return astlpc;
512}
Jeremy Kerr92a10a62019-08-28 16:55:54 +0530513#else
514struct mctp_binding_astlpc * __attribute__((const))
515 mctp_astlpc_init_fileio(void)
516{
Andrew Jeffery59c6a5c2020-01-17 15:52:51 +1030517 warnx("Missing support for file IO");
Jeremy Kerr92a10a62019-08-28 16:55:54 +0530518 return NULL;
519}
Jeremy Kerr672c8852019-03-01 12:18:07 +0800520
Jeremy Kerr92a10a62019-08-28 16:55:54 +0530521int __attribute__((const)) mctp_astlpc_get_fd(
522 struct mctp_binding_astlpc *astlpc __attribute__((unused)))
523{
Andrew Jeffery59c6a5c2020-01-17 15:52:51 +1030524 warnx("Missing support for file IO");
Jeremy Kerr92a10a62019-08-28 16:55:54 +0530525 return -1;
526}
527#endif