blob: 6abb123961a2c0ed32e56463dc94d16afc99cb26 [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
21#include "libmctp.h"
22#include "libmctp-alloc.h"
23#include "libmctp-log.h"
24#include "libmctp-astlpc.h"
Przemyslaw Czarnowskiff25d7e2020-03-26 11:39:37 +010025#include "container_of.h"
Jeremy Kerr672c8852019-03-01 12:18:07 +080026
Jeremy Kerrb214c642019-11-27 11:34:00 +080027#ifdef MCTP_HAVE_FILEIO
Jeremy Kerr92a10a62019-08-28 16:55:54 +053028
Jeremy Kerrc6f676d2019-12-19 09:24:06 +080029#include <unistd.h>
Jeremy Kerr92a10a62019-08-28 16:55:54 +053030#include <fcntl.h>
31#include <sys/ioctl.h>
32#include <sys/mman.h>
33#include <linux/aspeed-lpc-ctrl.h>
34
35/* kernel interface */
36static const char *kcs_path = "/dev/mctp0";
37static const char *lpc_path = "/dev/aspeed-lpc-ctrl";
38
39#endif
40
Andrew Jeffery7cd72f12020-05-12 20:27:59 +093041struct mctp_astlpc_buffer {
42 uint32_t offset;
43 uint32_t size;
44};
45
46struct mctp_astlpc_layout {
47 struct mctp_astlpc_buffer rx;
48 struct mctp_astlpc_buffer tx;
49};
50
Jeremy Kerr672c8852019-03-01 12:18:07 +080051struct mctp_binding_astlpc {
52 struct mctp_binding binding;
Jeremy Kerrbc53d352019-08-28 14:26:14 +053053
Andrew Jeffery55fb90b2020-05-12 13:54:37 +093054 void *lpc_map;
Andrew Jeffery7cd72f12020-05-12 20:27:59 +093055 struct mctp_astlpc_layout layout;
56
57 uint8_t mode;
Jeremy Kerrbc53d352019-08-28 14:26:14 +053058
59 /* direct ops data */
Andrew Jeffery55fb90b2020-05-12 13:54:37 +093060 struct mctp_binding_astlpc_ops ops;
61 void *ops_data;
Jeremy Kerrbc53d352019-08-28 14:26:14 +053062
63 /* fileio ops data */
Andrew Jeffery979c6a12020-05-23 20:04:49 +093064 int kcs_fd;
65 uint8_t kcs_status;
Jeremy Kerr672c8852019-03-01 12:18:07 +080066
67 bool running;
Jeremy Kerr672c8852019-03-01 12:18:07 +080068};
69
Jeremy Kerr672c8852019-03-01 12:18:07 +080070#define binding_to_astlpc(b) \
71 container_of(b, struct mctp_binding_astlpc, binding)
72
Andrew Jeffery9101a2a2020-05-22 16:08:03 +093073#define astlpc_prlog(ctx, lvl, fmt, ...) \
74 do { \
75 bool __bmc = ((ctx)->mode == MCTP_BINDING_ASTLPC_MODE_BMC); \
76 mctp_prlog(lvl, pr_fmt("%s: " fmt), __bmc ? "bmc" : "host", \
77 ##__VA_ARGS__); \
78 } while (0)
79
80#define astlpc_prerr(ctx, fmt, ...) \
81 astlpc_prlog(ctx, MCTP_LOG_ERR, fmt, ##__VA_ARGS__)
82#define astlpc_prwarn(ctx, fmt, ...) \
83 astlpc_prlog(ctx, MCTP_LOG_WARNING, fmt, ##__VA_ARGS__)
84#define astlpc_prinfo(ctx, fmt, ...) \
85 astlpc_prlog(ctx, MCTP_LOG_INFO, fmt, ##__VA_ARGS__)
86#define astlpc_prdebug(ctx, fmt, ...) \
87 astlpc_prlog(ctx, MCTP_LOG_DEBUG, fmt, ##__VA_ARGS__)
88
Andrew Jeffery7cd72f12020-05-12 20:27:59 +093089/* clang-format off */
90#define ASTLPC_MCTP_MAGIC 0x4d435450
91#define ASTLPC_VER_MIN 1
92#define ASTLPC_VER_CUR 1
93
94#define ASTLPC_BODY_SIZE(sz) ((sz) - 4)
95/* clang-format on */
Jeremy Kerr672c8852019-03-01 12:18:07 +080096
97struct mctp_lpcmap_hdr {
98 uint32_t magic;
99
100 uint16_t bmc_ver_min;
101 uint16_t bmc_ver_cur;
102 uint16_t host_ver_min;
103 uint16_t host_ver_cur;
104 uint16_t negotiated_ver;
105 uint16_t pad0;
106
107 uint32_t rx_offset;
108 uint32_t rx_size;
109 uint32_t tx_offset;
110 uint32_t tx_size;
111} __attribute__((packed));
112
113/* layout of TX/RX areas */
114static const uint32_t rx_offset = 0x100;
115static const uint32_t rx_size = 0x100;
116static const uint32_t tx_offset = 0x200;
117static const uint32_t tx_size = 0x100;
118
Jeremy Kerr672c8852019-03-01 12:18:07 +0800119#define LPC_WIN_SIZE (1 * 1024 * 1024)
120
Jeremy Kerr672c8852019-03-01 12:18:07 +0800121#define KCS_STATUS_BMC_READY 0x80
122#define KCS_STATUS_CHANNEL_ACTIVE 0x40
123#define KCS_STATUS_IBF 0x02
124#define KCS_STATUS_OBF 0x01
125
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930126static inline int mctp_astlpc_kcs_write(struct mctp_binding_astlpc *astlpc,
127 enum mctp_binding_astlpc_kcs_reg reg,
128 uint8_t val)
129{
130 return astlpc->ops.kcs_write(astlpc->ops_data, reg, val);
131}
132
133static inline int mctp_astlpc_kcs_read(struct mctp_binding_astlpc *astlpc,
134 enum mctp_binding_astlpc_kcs_reg reg,
135 uint8_t *val)
136{
137 return astlpc->ops.kcs_read(astlpc->ops_data, reg, val);
138}
139
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930140static inline int mctp_astlpc_lpc_write(struct mctp_binding_astlpc *astlpc,
141 const void *buf, long offset,
142 size_t len)
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530143{
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930144 astlpc_prdebug(astlpc, "%s: %zu bytes to 0x%lx", __func__, len, offset);
145
146 assert(offset >= 0);
147
148 /* Indirect access */
149 if (astlpc->ops.lpc_write) {
150 void *data = astlpc->ops_data;
151
152 return astlpc->ops.lpc_write(data, buf, offset, len);
153 }
154
155 /* Direct mapping */
156 assert(astlpc->lpc_map);
157 memcpy(&((char *)astlpc->lpc_map)[offset], buf, len);
158
159 return 0;
160}
161
162static inline int mctp_astlpc_lpc_read(struct mctp_binding_astlpc *astlpc,
163 void *buf, long offset, size_t len)
164{
165 astlpc_prdebug(astlpc, "%s: %zu bytes from 0x%lx", __func__, len,
166 offset);
167
168 assert(offset >= 0);
169
170 /* Indirect access */
171 if (astlpc->ops.lpc_read) {
172 void *data = astlpc->ops_data;
173
174 return astlpc->ops.lpc_read(data, buf, offset, len);
175 }
176
177 /* Direct mapping */
178 assert(astlpc->lpc_map);
179 memcpy(buf, &((char *)astlpc->lpc_map)[offset], len);
180
181 return 0;
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530182}
183
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930184static int mctp_astlpc_kcs_set_status(struct mctp_binding_astlpc *astlpc,
185 uint8_t status)
186{
187 uint8_t data;
188 int rc;
189
190 /* Since we're setting the status register, we want the other endpoint
191 * to be interrupted. However, some hardware may only raise a host-side
192 * interrupt on an ODR event.
193 * So, write a dummy value of 0xff to ODR, which will ensure that an
194 * interrupt is triggered, and can be ignored by the host.
195 */
196 data = 0xff;
197 status |= KCS_STATUS_OBF;
198
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930199 rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, status);
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930200 if (rc) {
201 astlpc_prwarn(astlpc, "KCS status write failed");
202 return -1;
203 }
204
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930205 rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, data);
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930206 if (rc) {
207 astlpc_prwarn(astlpc, "KCS dummy data write failed");
208 return -1;
209 }
210
211 return 0;
212}
213
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930214static int mctp_astlpc_init_bmc(struct mctp_binding_astlpc *astlpc)
215{
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930216 struct mctp_lpcmap_hdr hdr = { 0 };
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930217 uint8_t status;
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930218
219 /* Flip the buffers as the names are defined in terms of the host */
220 astlpc->layout.rx.offset = tx_offset;
221 astlpc->layout.rx.size = tx_size;
222 astlpc->layout.tx.offset = rx_offset;
223 astlpc->layout.tx.size = rx_size;
224
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930225 hdr = (struct mctp_lpcmap_hdr){
226 .magic = htobe32(ASTLPC_MCTP_MAGIC),
227 .bmc_ver_min = htobe16(ASTLPC_VER_MIN),
228 .bmc_ver_cur = htobe16(ASTLPC_VER_CUR),
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930229
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930230 /* Flip the buffers back as we're now describing the host's
231 * configuration to the host */
232 .rx_offset = htobe32(astlpc->layout.tx.offset),
233 .rx_size = htobe32(astlpc->layout.tx.size),
234 .tx_offset = htobe32(astlpc->layout.rx.offset),
235 .tx_size = htobe32(astlpc->layout.rx.size),
236 };
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930237
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930238 mctp_astlpc_lpc_write(astlpc, &hdr, 0, sizeof(hdr));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930239
240 /* set status indicating that the BMC is now active */
241 status = KCS_STATUS_BMC_READY | KCS_STATUS_OBF;
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930242 return mctp_astlpc_kcs_set_status(astlpc, status);
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930243}
244
245static int mctp_binding_astlpc_start_bmc(struct mctp_binding *b)
246{
247 struct mctp_binding_astlpc *astlpc =
248 container_of(b, struct mctp_binding_astlpc, binding);
249
250 return mctp_astlpc_init_bmc(astlpc);
251}
252
253static int mctp_astlpc_init_host(struct mctp_binding_astlpc *astlpc)
254{
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930255 const uint16_t ver_min_be = htobe16(ASTLPC_VER_MIN);
256 const uint16_t ver_cur_be = htobe16(ASTLPC_VER_CUR);
257 struct mctp_lpcmap_hdr hdr;
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930258 uint8_t status;
259 int rc;
260
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930261 rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, &status);
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930262 if (rc) {
263 mctp_prwarn("KCS status read failed");
264 return rc;
265 }
266
267 astlpc->kcs_status = status;
268
269 if (!(status & KCS_STATUS_BMC_READY))
270 return -EHOSTDOWN;
271
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930272 mctp_astlpc_lpc_read(astlpc, &hdr, 0, sizeof(hdr));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930273
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930274 astlpc->layout.rx.offset = be32toh(hdr.rx_offset);
275 astlpc->layout.rx.size = be32toh(hdr.rx_size);
276 astlpc->layout.tx.offset = be32toh(hdr.tx_offset);
277 astlpc->layout.tx.size = be32toh(hdr.tx_size);
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930278
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930279 mctp_astlpc_lpc_write(astlpc, &ver_min_be,
280 offsetof(struct mctp_lpcmap_hdr, host_ver_min),
281 sizeof(ver_min_be));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930282
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930283 mctp_astlpc_lpc_write(astlpc, &ver_cur_be,
284 offsetof(struct mctp_lpcmap_hdr, host_ver_cur),
285 sizeof(ver_cur_be));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930286
287 /* Send channel init command */
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930288 rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, 0x0);
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930289 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930290 astlpc_prwarn(astlpc, "KCS write failed");
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930291 }
292
293 return rc;
294}
295
296static int mctp_binding_astlpc_start_host(struct mctp_binding *b)
297{
298 struct mctp_binding_astlpc *astlpc =
299 container_of(b, struct mctp_binding_astlpc, binding);
300
301 return mctp_astlpc_init_host(astlpc);
302}
303
304static bool __mctp_astlpc_kcs_ready(struct mctp_binding_astlpc *astlpc,
305 uint8_t status, bool is_write)
306{
307 bool is_bmc;
308 bool ready_state;
309 uint8_t flag;
310
311 is_bmc = (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC);
312 flag = (is_bmc ^ is_write) ? KCS_STATUS_IBF : KCS_STATUS_OBF;
313 ready_state = is_write ? 0 : 1;
314
315 return !!(status & flag) == ready_state;
316}
317
318static inline bool
319mctp_astlpc_kcs_read_ready(struct mctp_binding_astlpc *astlpc, uint8_t status)
320{
321 return __mctp_astlpc_kcs_ready(astlpc, status, false);
322}
323
324static inline bool
325mctp_astlpc_kcs_write_ready(struct mctp_binding_astlpc *astlpc, uint8_t status)
326{
327 return __mctp_astlpc_kcs_ready(astlpc, status, true);
328}
329
Jeremy Kerr672c8852019-03-01 12:18:07 +0800330static int mctp_astlpc_kcs_send(struct mctp_binding_astlpc *astlpc,
331 uint8_t data)
332{
333 uint8_t status;
334 int rc;
335
336 for (;;) {
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930337 rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS,
338 &status);
Andrew Jeffery1b27fe82020-01-24 16:05:11 +1030339 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930340 astlpc_prwarn(astlpc, "KCS status read failed");
Jeremy Kerr672c8852019-03-01 12:18:07 +0800341 return -1;
342 }
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930343 if (mctp_astlpc_kcs_write_ready(astlpc, status))
Jeremy Kerr672c8852019-03-01 12:18:07 +0800344 break;
345 /* todo: timeout */
346 }
347
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930348 rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, data);
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530349 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930350 astlpc_prwarn(astlpc, "KCS data write failed");
Jeremy Kerr672c8852019-03-01 12:18:07 +0800351 return -1;
352 }
353
354 return 0;
355}
356
357static int mctp_binding_astlpc_tx(struct mctp_binding *b,
358 struct mctp_pktbuf *pkt)
359{
360 struct mctp_binding_astlpc *astlpc = binding_to_astlpc(b);
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930361 uint32_t len, len_be;
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030362 struct mctp_hdr *hdr;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800363
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030364 hdr = mctp_pktbuf_hdr(pkt);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800365 len = mctp_pktbuf_size(pkt);
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030366
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930367 astlpc_prdebug(astlpc,
368 "%s: Transmitting %" PRIu32
369 "-byte packet (%hhu, %hhu, 0x%hhx)",
370 __func__, len, hdr->src, hdr->dest, hdr->flags_seq_tag);
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030371
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930372 if (len > ASTLPC_BODY_SIZE(astlpc->layout.tx.size)) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930373 astlpc_prwarn(astlpc, "invalid TX len 0x%x", len);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800374 return -1;
375 }
376
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930377 len_be = htobe32(len);
378 mctp_astlpc_lpc_write(astlpc, &len_be, astlpc->layout.tx.offset,
379 sizeof(len_be));
380 mctp_astlpc_lpc_write(astlpc, hdr, astlpc->layout.tx.offset + 4, len);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800381
382 mctp_binding_set_tx_enabled(b, false);
383
384 mctp_astlpc_kcs_send(astlpc, 0x1);
385 return 0;
386}
387
388static void mctp_astlpc_init_channel(struct mctp_binding_astlpc *astlpc)
389{
390 /* todo: actual version negotiation */
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930391 uint16_t negotiated = htobe16(1);
392 mctp_astlpc_lpc_write(astlpc, &negotiated,
393 offsetof(struct mctp_lpcmap_hdr, negotiated_ver),
394 sizeof(negotiated));
395
396 mctp_astlpc_kcs_set_status(astlpc, KCS_STATUS_BMC_READY |
397 KCS_STATUS_CHANNEL_ACTIVE |
398 KCS_STATUS_OBF);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800399
400 mctp_binding_set_tx_enabled(&astlpc->binding, true);
401}
402
403static void mctp_astlpc_rx_start(struct mctp_binding_astlpc *astlpc)
404{
405 struct mctp_pktbuf *pkt;
406 uint32_t len;
407
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930408 mctp_astlpc_lpc_read(astlpc, &len, astlpc->layout.rx.offset,
409 sizeof(len));
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530410 len = be32toh(len);
411
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930412 if (len > ASTLPC_BODY_SIZE(astlpc->layout.rx.size)) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930413 astlpc_prwarn(astlpc, "invalid RX len 0x%x", len);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800414 return;
415 }
416
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930417 assert(astlpc->binding.pkt_size >= 0);
418 if (len > (uint32_t)astlpc->binding.pkt_size) {
Jeremy Kerr672c8852019-03-01 12:18:07 +0800419 mctp_prwarn("invalid RX len 0x%x", len);
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930420 astlpc_prwarn(astlpc, "invalid RX len 0x%x", len);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800421 return;
422 }
423
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800424 pkt = mctp_pktbuf_alloc(&astlpc->binding, len);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800425 if (!pkt)
426 goto out_complete;
427
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930428 mctp_astlpc_lpc_read(astlpc, mctp_pktbuf_hdr(pkt),
429 astlpc->layout.rx.offset + 4, len);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800430
431 mctp_bus_rx(&astlpc->binding, pkt);
432
433out_complete:
434 mctp_astlpc_kcs_send(astlpc, 0x2);
435}
436
437static void mctp_astlpc_tx_complete(struct mctp_binding_astlpc *astlpc)
438{
439 mctp_binding_set_tx_enabled(&astlpc->binding, true);
440}
441
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930442static int mctp_astlpc_update_channel(struct mctp_binding_astlpc *astlpc,
443 uint8_t status)
444{
445 uint8_t updated;
446 int rc = 0;
447
448 assert(astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST);
449
450 updated = astlpc->kcs_status ^ status;
451
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930452 astlpc_prdebug(astlpc, "%s: status: 0x%x, update: 0x%x", __func__,
453 status, updated);
454
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930455 if (updated & KCS_STATUS_BMC_READY) {
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930456 if (status & KCS_STATUS_BMC_READY) {
457 astlpc->kcs_status = status;
458 return astlpc->binding.start(&astlpc->binding);
459 } else {
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930460 mctp_binding_set_tx_enabled(&astlpc->binding, false);
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930461 }
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930462 }
463
464 if (updated & KCS_STATUS_CHANNEL_ACTIVE)
465 mctp_binding_set_tx_enabled(&astlpc->binding,
466 status & KCS_STATUS_CHANNEL_ACTIVE);
467
468 astlpc->kcs_status = status;
469
470 return rc;
471}
472
Jeremy Kerr672c8852019-03-01 12:18:07 +0800473int mctp_astlpc_poll(struct mctp_binding_astlpc *astlpc)
474{
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530475 uint8_t status, data;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800476 int rc;
477
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930478 rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, &status);
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530479 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930480 astlpc_prwarn(astlpc, "KCS read error");
Jeremy Kerr672c8852019-03-01 12:18:07 +0800481 return -1;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800482 }
483
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930484 astlpc_prdebug(astlpc, "%s: status: 0x%hhx", __func__, status);
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030485
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930486 if (!mctp_astlpc_kcs_read_ready(astlpc, status))
Jeremy Kerr672c8852019-03-01 12:18:07 +0800487 return 0;
488
Andrew Jefferyf13cb972020-05-28 09:30:09 +0930489 rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_DATA, &data);
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530490 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930491 astlpc_prwarn(astlpc, "KCS data read error");
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530492 return -1;
493 }
494
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930495 astlpc_prdebug(astlpc, "%s: data: 0x%hhx", __func__, data);
Andrew Jefferyedfe3832020-02-06 11:52:11 +1030496
Jeremy Kerr672c8852019-03-01 12:18:07 +0800497 switch (data) {
498 case 0x0:
499 mctp_astlpc_init_channel(astlpc);
500 break;
501 case 0x1:
502 mctp_astlpc_rx_start(astlpc);
503 break;
504 case 0x2:
505 mctp_astlpc_tx_complete(astlpc);
506 break;
Jeremy Kerr1a4b55a2019-06-24 14:22:39 +0800507 case 0xff:
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930508 /* No responsibilities for the BMC on 0xff */
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930509 if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST) {
510 rc = mctp_astlpc_update_channel(astlpc, status);
511 if (rc < 0)
512 return rc;
513 }
514 break;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800515 default:
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930516 astlpc_prwarn(astlpc, "unknown message 0x%x", data);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800517 }
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930518
519 /* Handle silent loss of bmc-ready */
520 if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST) {
521 if (!(status & KCS_STATUS_BMC_READY && data == 0xff))
522 return mctp_astlpc_update_channel(astlpc, status);
523 }
524
525 return rc;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800526}
527
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530528/* allocate and basic initialisation */
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930529static struct mctp_binding_astlpc *__mctp_astlpc_init(uint8_t mode,
530 uint32_t mtu)
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530531{
532 struct mctp_binding_astlpc *astlpc;
533
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930534 assert((mode == MCTP_BINDING_ASTLPC_MODE_BMC) ||
535 (mode == MCTP_BINDING_ASTLPC_MODE_HOST));
536
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530537 astlpc = __mctp_alloc(sizeof(*astlpc));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930538 if (!astlpc)
539 return NULL;
540
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530541 memset(astlpc, 0, sizeof(*astlpc));
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930542 astlpc->mode = mode;
543 astlpc->lpc_map = NULL;
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530544 astlpc->binding.name = "astlpc";
545 astlpc->binding.version = 1;
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930546 astlpc->binding.pkt_size = MCTP_PACKET_SIZE(mtu);
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530547 astlpc->binding.pkt_pad = 0;
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930548 astlpc->binding.tx = mctp_binding_astlpc_tx;
549 if (mode == MCTP_BINDING_ASTLPC_MODE_BMC)
550 astlpc->binding.start = mctp_binding_astlpc_start_bmc;
551 else if (mode == MCTP_BINDING_ASTLPC_MODE_HOST)
552 astlpc->binding.start = mctp_binding_astlpc_start_host;
553 else {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930554 astlpc_prerr(astlpc, "%s: Invalid mode: %d\n", __func__, mode);
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930555 __mctp_free(astlpc);
556 return NULL;
557 }
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530558
559 return astlpc;
560}
561
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800562struct mctp_binding *mctp_binding_astlpc_core(struct mctp_binding_astlpc *b)
563{
564 return &b->binding;
565}
566
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930567struct mctp_binding_astlpc *
568mctp_astlpc_init(uint8_t mode, uint32_t mtu, void *lpc_map,
569 const struct mctp_binding_astlpc_ops *ops, void *ops_data)
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530570{
571 struct mctp_binding_astlpc *astlpc;
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530572
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930573 if (!(mode == MCTP_BINDING_ASTLPC_MODE_BMC ||
574 mode == MCTP_BINDING_ASTLPC_MODE_HOST)) {
575 mctp_prerr("Unknown binding mode: %u", mode);
576 return NULL;
577 }
578
579 if (mtu != MCTP_BTU) {
580 mctp_prwarn("Unable to negotiate the MTU, using %u instead",
581 MCTP_BTU);
582 mtu = MCTP_BTU;
583 }
584
585 astlpc = __mctp_astlpc_init(mode, mtu);
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530586 if (!astlpc)
587 return NULL;
588
589 memcpy(&astlpc->ops, ops, sizeof(astlpc->ops));
590 astlpc->ops_data = ops_data;
591 astlpc->lpc_map = lpc_map;
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930592 astlpc->mode = mode;
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530593
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530594 return astlpc;
595}
596
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930597struct mctp_binding_astlpc *
598mctp_astlpc_init_ops(const struct mctp_binding_astlpc_ops *ops, void *ops_data,
599 void *lpc_map)
600{
601 return mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, lpc_map,
602 ops, ops_data);
603}
604
Andrew Jeffery4663f672020-03-10 23:36:24 +1030605void mctp_astlpc_destroy(struct mctp_binding_astlpc *astlpc)
606{
Andrew Jefferyd0f5da02020-05-28 09:12:55 +0930607 /* Clear channel-active and bmc-ready */
608 if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC)
609 mctp_astlpc_kcs_set_status(astlpc, KCS_STATUS_OBF);
Andrew Jeffery4663f672020-03-10 23:36:24 +1030610 __mctp_free(astlpc);
611}
612
Jeremy Kerrb214c642019-11-27 11:34:00 +0800613#ifdef MCTP_HAVE_FILEIO
Andrew Jeffery55fb90b2020-05-12 13:54:37 +0930614
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530615static int mctp_astlpc_init_fileio_lpc(struct mctp_binding_astlpc *astlpc)
Jeremy Kerr672c8852019-03-01 12:18:07 +0800616{
617 struct aspeed_lpc_ctrl_mapping map = {
618 .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY,
619 .window_id = 0, /* There's only one */
620 .flags = 0,
621 .addr = 0,
622 .offset = 0,
623 .size = 0
624 };
Andrew Jeffery979c6a12020-05-23 20:04:49 +0930625 void *lpc_map_base;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800626 int fd, rc;
627
628 fd = open(lpc_path, O_RDWR | O_SYNC);
629 if (fd < 0) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930630 astlpc_prwarn(astlpc, "LPC open (%s) failed", lpc_path);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800631 return -1;
632 }
633
634 rc = ioctl(fd, ASPEED_LPC_CTRL_IOCTL_GET_SIZE, &map);
635 if (rc) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930636 astlpc_prwarn(astlpc, "LPC GET_SIZE failed");
Jeremy Kerr672c8852019-03-01 12:18:07 +0800637 close(fd);
638 return -1;
639 }
640
Andrew Jeffery979c6a12020-05-23 20:04:49 +0930641 lpc_map_base =
642 mmap(NULL, map.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
643 if (lpc_map_base == MAP_FAILED) {
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930644 astlpc_prwarn(astlpc, "LPC mmap failed");
Jeremy Kerr672c8852019-03-01 12:18:07 +0800645 rc = -1;
646 } else {
Andrew Jeffery979c6a12020-05-23 20:04:49 +0930647 astlpc->lpc_map = lpc_map_base + map.size - LPC_WIN_SIZE;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800648 }
649
650 close(fd);
651
652 return rc;
653}
654
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530655static int mctp_astlpc_init_fileio_kcs(struct mctp_binding_astlpc *astlpc)
Jeremy Kerr672c8852019-03-01 12:18:07 +0800656{
657 astlpc->kcs_fd = open(kcs_path, O_RDWR);
658 if (astlpc->kcs_fd < 0)
659 return -1;
660
661 return 0;
662}
663
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530664static int __mctp_astlpc_fileio_kcs_read(void *arg,
665 enum mctp_binding_astlpc_kcs_reg reg, uint8_t *val)
666{
667 struct mctp_binding_astlpc *astlpc = arg;
668 off_t offset = reg;
669 int rc;
670
671 rc = pread(astlpc->kcs_fd, val, 1, offset);
672
673 return rc == 1 ? 0 : -1;
674}
675
676static int __mctp_astlpc_fileio_kcs_write(void *arg,
677 enum mctp_binding_astlpc_kcs_reg reg, uint8_t val)
678{
679 struct mctp_binding_astlpc *astlpc = arg;
680 off_t offset = reg;
681 int rc;
682
683 rc = pwrite(astlpc->kcs_fd, &val, 1, offset);
684
685 return rc == 1 ? 0 : -1;
686}
687
688int mctp_astlpc_get_fd(struct mctp_binding_astlpc *astlpc)
689{
690 return astlpc->kcs_fd;
691}
692
693struct mctp_binding_astlpc *mctp_astlpc_init_fileio(void)
Jeremy Kerr672c8852019-03-01 12:18:07 +0800694{
695 struct mctp_binding_astlpc *astlpc;
696 int rc;
697
Andrew Jeffery7cd72f12020-05-12 20:27:59 +0930698 /*
699 * If we're doing file IO then we're very likely not running
700 * freestanding, so lets assume that we're on the BMC side
701 */
702 astlpc = __mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU);
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530703 if (!astlpc)
704 return NULL;
Jeremy Kerr672c8852019-03-01 12:18:07 +0800705
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530706 /* Set internal operations for kcs. We use direct accesses to the lpc
707 * map area */
708 astlpc->ops.kcs_read = __mctp_astlpc_fileio_kcs_read;
709 astlpc->ops.kcs_write = __mctp_astlpc_fileio_kcs_write;
710 astlpc->ops_data = astlpc;
711
712 rc = mctp_astlpc_init_fileio_lpc(astlpc);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800713 if (rc) {
714 free(astlpc);
715 return NULL;
716 }
717
Jeremy Kerrbc53d352019-08-28 14:26:14 +0530718 rc = mctp_astlpc_init_fileio_kcs(astlpc);
Jeremy Kerr672c8852019-03-01 12:18:07 +0800719 if (rc) {
720 free(astlpc);
721 return NULL;
722 }
723
Jeremy Kerr672c8852019-03-01 12:18:07 +0800724 return astlpc;
725}
Jeremy Kerr92a10a62019-08-28 16:55:54 +0530726#else
727struct mctp_binding_astlpc * __attribute__((const))
728 mctp_astlpc_init_fileio(void)
729{
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930730 astlpc_prerr(astlpc, "Missing support for file IO");
Jeremy Kerr92a10a62019-08-28 16:55:54 +0530731 return NULL;
732}
Jeremy Kerr672c8852019-03-01 12:18:07 +0800733
Jeremy Kerr92a10a62019-08-28 16:55:54 +0530734int __attribute__((const)) mctp_astlpc_get_fd(
735 struct mctp_binding_astlpc *astlpc __attribute__((unused)))
736{
Andrew Jeffery9101a2a2020-05-22 16:08:03 +0930737 astlpc_prerr(astlpc, "Missing support for file IO");
Jeremy Kerr92a10a62019-08-28 16:55:54 +0530738 return -1;
739}
740#endif