13d36ee2eSJeremy Kerr /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2672c8852SJeremy Kerr 3672c8852SJeremy Kerr #include <assert.h> 4*92a10a6bSJeremy Kerr #include <endian.h> 5672c8852SJeremy Kerr #include <stdbool.h> 6672c8852SJeremy Kerr #include <stdlib.h> 7672c8852SJeremy Kerr #include <string.h> 8672c8852SJeremy Kerr #include <unistd.h> 9672c8852SJeremy Kerr 10672c8852SJeremy Kerr #define pr_fmt(x) "astlpc: " x 11672c8852SJeremy Kerr 12672c8852SJeremy Kerr #include "libmctp.h" 13672c8852SJeremy Kerr #include "libmctp-alloc.h" 14672c8852SJeremy Kerr #include "libmctp-log.h" 15672c8852SJeremy Kerr #include "libmctp-astlpc.h" 16672c8852SJeremy Kerr 17*92a10a6bSJeremy Kerr #ifndef MCTP_WITHOUT_FILEIO 18*92a10a6bSJeremy Kerr 19*92a10a6bSJeremy Kerr #include <fcntl.h> 20*92a10a6bSJeremy Kerr #include <sys/ioctl.h> 21*92a10a6bSJeremy Kerr #include <sys/mman.h> 22*92a10a6bSJeremy Kerr #include <linux/aspeed-lpc-ctrl.h> 23*92a10a6bSJeremy Kerr 24*92a10a6bSJeremy Kerr /* kernel interface */ 25*92a10a6bSJeremy Kerr static const char *kcs_path = "/dev/mctp0"; 26*92a10a6bSJeremy Kerr static const char *lpc_path = "/dev/aspeed-lpc-ctrl"; 27*92a10a6bSJeremy Kerr 28*92a10a6bSJeremy Kerr #endif 29*92a10a6bSJeremy Kerr 30672c8852SJeremy Kerr struct mctp_binding_astlpc { 31672c8852SJeremy Kerr struct mctp_binding binding; 32bc53d35aSJeremy Kerr 33672c8852SJeremy Kerr union { 34672c8852SJeremy Kerr void *lpc_map; 35672c8852SJeremy Kerr struct mctp_lpcmap_hdr *lpc_hdr; 36672c8852SJeremy Kerr }; 37bc53d35aSJeremy Kerr 38bc53d35aSJeremy Kerr /* direct ops data */ 39bc53d35aSJeremy Kerr struct mctp_binding_astlpc_ops ops; 40bc53d35aSJeremy Kerr void *ops_data; 41bc53d35aSJeremy Kerr struct mctp_lpcmap_hdr *priv_hdr; 42bc53d35aSJeremy Kerr 43bc53d35aSJeremy Kerr /* fileio ops data */ 44bc53d35aSJeremy Kerr void *lpc_map_base; 45672c8852SJeremy Kerr int kcs_fd; 46672c8852SJeremy Kerr uint8_t kcs_status; 47672c8852SJeremy Kerr 48672c8852SJeremy Kerr bool running; 49672c8852SJeremy Kerr 50672c8852SJeremy Kerr /* temporary transmit buffer */ 51672c8852SJeremy Kerr uint8_t txbuf[256]; 52672c8852SJeremy Kerr }; 53672c8852SJeremy Kerr 54672c8852SJeremy Kerr #ifndef container_of 55672c8852SJeremy Kerr #define container_of(ptr, type, member) \ 56672c8852SJeremy Kerr (type *)((char *)(ptr) - (char *)&((type *)0)->member) 57672c8852SJeremy Kerr #endif 58672c8852SJeremy Kerr 59672c8852SJeremy Kerr #define binding_to_astlpc(b) \ 60672c8852SJeremy Kerr container_of(b, struct mctp_binding_astlpc, binding) 61672c8852SJeremy Kerr 62672c8852SJeremy Kerr #define MCTP_MAGIC 0x4d435450 63672c8852SJeremy Kerr #define BMC_VER_MIN 1 64672c8852SJeremy Kerr #define BMC_VER_CUR 1 65672c8852SJeremy Kerr 66672c8852SJeremy Kerr struct mctp_lpcmap_hdr { 67672c8852SJeremy Kerr uint32_t magic; 68672c8852SJeremy Kerr 69672c8852SJeremy Kerr uint16_t bmc_ver_min; 70672c8852SJeremy Kerr uint16_t bmc_ver_cur; 71672c8852SJeremy Kerr uint16_t host_ver_min; 72672c8852SJeremy Kerr uint16_t host_ver_cur; 73672c8852SJeremy Kerr uint16_t negotiated_ver; 74672c8852SJeremy Kerr uint16_t pad0; 75672c8852SJeremy Kerr 76672c8852SJeremy Kerr uint32_t rx_offset; 77672c8852SJeremy Kerr uint32_t rx_size; 78672c8852SJeremy Kerr uint32_t tx_offset; 79672c8852SJeremy Kerr uint32_t tx_size; 80672c8852SJeremy Kerr } __attribute__((packed)); 81672c8852SJeremy Kerr 82672c8852SJeremy Kerr /* layout of TX/RX areas */ 83672c8852SJeremy Kerr static const uint32_t rx_offset = 0x100; 84672c8852SJeremy Kerr static const uint32_t rx_size = 0x100; 85672c8852SJeremy Kerr static const uint32_t tx_offset = 0x200; 86672c8852SJeremy Kerr static const uint32_t tx_size = 0x100; 87672c8852SJeremy Kerr 88672c8852SJeremy Kerr #define LPC_WIN_SIZE (1 * 1024 * 1024) 89672c8852SJeremy Kerr 90672c8852SJeremy Kerr enum { 91672c8852SJeremy Kerr KCS_REG_DATA = 0, 92672c8852SJeremy Kerr KCS_REG_STATUS = 1, 93672c8852SJeremy Kerr }; 94672c8852SJeremy Kerr 95672c8852SJeremy Kerr #define KCS_STATUS_BMC_READY 0x80 96672c8852SJeremy Kerr #define KCS_STATUS_CHANNEL_ACTIVE 0x40 97672c8852SJeremy Kerr #define KCS_STATUS_IBF 0x02 98672c8852SJeremy Kerr #define KCS_STATUS_OBF 0x01 99672c8852SJeremy Kerr 100bc53d35aSJeremy Kerr static bool lpc_direct(struct mctp_binding_astlpc *astlpc) 101bc53d35aSJeremy Kerr { 102bc53d35aSJeremy Kerr return astlpc->lpc_map != NULL; 103bc53d35aSJeremy Kerr } 104bc53d35aSJeremy Kerr 105672c8852SJeremy Kerr static int mctp_astlpc_kcs_set_status(struct mctp_binding_astlpc *astlpc, 106672c8852SJeremy Kerr uint8_t status) 107672c8852SJeremy Kerr { 108bc53d35aSJeremy Kerr uint8_t data; 109672c8852SJeremy Kerr int rc; 110672c8852SJeremy Kerr 1111a4b55acSJeremy Kerr /* Since we're setting the status register, we want the other endpoint 1121a4b55acSJeremy Kerr * to be interrupted. However, some hardware may only raise a host-side 1131a4b55acSJeremy Kerr * interrupt on an ODR event. 1141a4b55acSJeremy Kerr * So, write a dummy value of 0xff to ODR, which will ensure that an 1151a4b55acSJeremy Kerr * interrupt is triggered, and can be ignored by the host. 1161a4b55acSJeremy Kerr */ 117bc53d35aSJeremy Kerr data = 0xff; 118bc53d35aSJeremy Kerr status |= KCS_STATUS_OBF; 1191a4b55acSJeremy Kerr 120bc53d35aSJeremy Kerr rc = astlpc->ops.kcs_write(astlpc->ops_data, MCTP_ASTLPC_KCS_REG_DATA, 121bc53d35aSJeremy Kerr data); 122bc53d35aSJeremy Kerr if (rc) { 123bc53d35aSJeremy Kerr mctp_prwarn("KCS dummy data write failed"); 124bc53d35aSJeremy Kerr return -1; 125bc53d35aSJeremy Kerr } 126bc53d35aSJeremy Kerr 127bc53d35aSJeremy Kerr 128bc53d35aSJeremy Kerr rc = astlpc->ops.kcs_write(astlpc->ops_data, MCTP_ASTLPC_KCS_REG_STATUS, 129bc53d35aSJeremy Kerr status); 130bc53d35aSJeremy Kerr if (rc) { 131672c8852SJeremy Kerr mctp_prwarn("KCS status write failed"); 132672c8852SJeremy Kerr return -1; 133672c8852SJeremy Kerr } 134672c8852SJeremy Kerr return 0; 135672c8852SJeremy Kerr } 136672c8852SJeremy Kerr 137672c8852SJeremy Kerr static int mctp_astlpc_kcs_send(struct mctp_binding_astlpc *astlpc, 138672c8852SJeremy Kerr uint8_t data) 139672c8852SJeremy Kerr { 140672c8852SJeremy Kerr uint8_t status; 141672c8852SJeremy Kerr int rc; 142672c8852SJeremy Kerr 143672c8852SJeremy Kerr for (;;) { 144bc53d35aSJeremy Kerr rc = astlpc->ops.kcs_read(astlpc->ops_data, 145bc53d35aSJeremy Kerr MCTP_ASTLPC_KCS_REG_STATUS, &status); 146672c8852SJeremy Kerr if (rc != 1) { 147672c8852SJeremy Kerr mctp_prwarn("KCE status read failed"); 148672c8852SJeremy Kerr return -1; 149672c8852SJeremy Kerr } 150672c8852SJeremy Kerr if (!(status & KCS_STATUS_OBF)) 151672c8852SJeremy Kerr break; 152672c8852SJeremy Kerr /* todo: timeout */ 153672c8852SJeremy Kerr } 154672c8852SJeremy Kerr 155bc53d35aSJeremy Kerr rc = astlpc->ops.kcs_write(astlpc->ops_data, MCTP_ASTLPC_KCS_REG_DATA, 156bc53d35aSJeremy Kerr data); 157bc53d35aSJeremy Kerr if (rc) { 158672c8852SJeremy Kerr mctp_prwarn("KCS data write failed"); 159672c8852SJeremy Kerr return -1; 160672c8852SJeremy Kerr } 161672c8852SJeremy Kerr 162672c8852SJeremy Kerr return 0; 163672c8852SJeremy Kerr } 164672c8852SJeremy Kerr 165672c8852SJeremy Kerr static int mctp_binding_astlpc_tx(struct mctp_binding *b, 166672c8852SJeremy Kerr struct mctp_pktbuf *pkt) 167672c8852SJeremy Kerr { 168672c8852SJeremy Kerr struct mctp_binding_astlpc *astlpc = binding_to_astlpc(b); 169672c8852SJeremy Kerr uint32_t len; 170672c8852SJeremy Kerr 171672c8852SJeremy Kerr len = mctp_pktbuf_size(pkt); 172672c8852SJeremy Kerr if (len > rx_size - 4) { 173672c8852SJeremy Kerr mctp_prwarn("invalid TX len 0x%x", len); 174672c8852SJeremy Kerr return -1; 175672c8852SJeremy Kerr } 176672c8852SJeremy Kerr 177bc53d35aSJeremy Kerr if (lpc_direct(astlpc)) { 178672c8852SJeremy Kerr *(uint32_t *)(astlpc->lpc_map + rx_offset) = htobe32(len); 179bc53d35aSJeremy Kerr memcpy(astlpc->lpc_map + rx_offset + 4, mctp_pktbuf_hdr(pkt), 180bc53d35aSJeremy Kerr len); 181bc53d35aSJeremy Kerr } else { 182bc53d35aSJeremy Kerr uint32_t tmp = htobe32(len); 183bc53d35aSJeremy Kerr astlpc->ops.lpc_write(astlpc->ops_data, &tmp, rx_offset, 184bc53d35aSJeremy Kerr sizeof(tmp)); 185bc53d35aSJeremy Kerr astlpc->ops.lpc_write(astlpc->ops_data, mctp_pktbuf_hdr(pkt), 186bc53d35aSJeremy Kerr rx_offset + 4, len); 187bc53d35aSJeremy Kerr } 188672c8852SJeremy Kerr 189672c8852SJeremy Kerr mctp_binding_set_tx_enabled(b, false); 190672c8852SJeremy Kerr 191672c8852SJeremy Kerr mctp_astlpc_kcs_send(astlpc, 0x1); 192672c8852SJeremy Kerr return 0; 193672c8852SJeremy Kerr } 194672c8852SJeremy Kerr 195672c8852SJeremy Kerr static void mctp_astlpc_init_channel(struct mctp_binding_astlpc *astlpc) 196672c8852SJeremy Kerr { 197672c8852SJeremy Kerr /* todo: actual version negotiation */ 198bc53d35aSJeremy Kerr if (lpc_direct(astlpc)) { 199672c8852SJeremy Kerr astlpc->lpc_hdr->negotiated_ver = htobe16(1); 200bc53d35aSJeremy Kerr } else { 201bc53d35aSJeremy Kerr uint16_t ver = htobe16(1); 202bc53d35aSJeremy Kerr astlpc->ops.lpc_write(astlpc->ops_data, &ver, 203bc53d35aSJeremy Kerr offsetof(struct mctp_lpcmap_hdr, 204bc53d35aSJeremy Kerr negotiated_ver), 205bc53d35aSJeremy Kerr sizeof(ver)); 206bc53d35aSJeremy Kerr } 207672c8852SJeremy Kerr mctp_astlpc_kcs_set_status(astlpc, 208672c8852SJeremy Kerr KCS_STATUS_BMC_READY | KCS_STATUS_CHANNEL_ACTIVE | 209672c8852SJeremy Kerr KCS_STATUS_OBF); 210672c8852SJeremy Kerr 211672c8852SJeremy Kerr mctp_binding_set_tx_enabled(&astlpc->binding, true); 212672c8852SJeremy Kerr } 213672c8852SJeremy Kerr 214672c8852SJeremy Kerr static void mctp_astlpc_rx_start(struct mctp_binding_astlpc *astlpc) 215672c8852SJeremy Kerr { 216672c8852SJeremy Kerr struct mctp_pktbuf *pkt; 217672c8852SJeremy Kerr uint32_t len; 218672c8852SJeremy Kerr 219bc53d35aSJeremy Kerr if (lpc_direct(astlpc)) { 220bc53d35aSJeremy Kerr len = *(uint32_t *)(astlpc->lpc_map + tx_offset); 221bc53d35aSJeremy Kerr } else { 222bc53d35aSJeremy Kerr astlpc->ops.lpc_read(astlpc->ops_data, &len, 223bc53d35aSJeremy Kerr tx_offset, sizeof(len)); 224bc53d35aSJeremy Kerr } 225bc53d35aSJeremy Kerr len = be32toh(len); 226bc53d35aSJeremy Kerr 227672c8852SJeremy Kerr if (len > tx_size - 4) { 228672c8852SJeremy Kerr mctp_prwarn("invalid RX len 0x%x", len); 229672c8852SJeremy Kerr return; 230672c8852SJeremy Kerr } 231672c8852SJeremy Kerr 232df15f7e9SJeremy Kerr if (len > astlpc->binding.pkt_size) { 233672c8852SJeremy Kerr mctp_prwarn("invalid RX len 0x%x", len); 234672c8852SJeremy Kerr return; 235672c8852SJeremy Kerr } 236672c8852SJeremy Kerr 237df15f7e9SJeremy Kerr pkt = mctp_pktbuf_alloc(&astlpc->binding, len); 238672c8852SJeremy Kerr if (!pkt) 239672c8852SJeremy Kerr goto out_complete; 240672c8852SJeremy Kerr 241bc53d35aSJeremy Kerr if (lpc_direct(astlpc)) { 242bc53d35aSJeremy Kerr memcpy(mctp_pktbuf_hdr(pkt), 243bc53d35aSJeremy Kerr astlpc->lpc_map + tx_offset + 4, len); 244bc53d35aSJeremy Kerr } else { 245bc53d35aSJeremy Kerr astlpc->ops.lpc_read(astlpc->ops_data, mctp_pktbuf_hdr(pkt), 246bc53d35aSJeremy Kerr tx_offset + 4, len); 247bc53d35aSJeremy Kerr } 248672c8852SJeremy Kerr 249672c8852SJeremy Kerr mctp_bus_rx(&astlpc->binding, pkt); 250672c8852SJeremy Kerr 251672c8852SJeremy Kerr out_complete: 252672c8852SJeremy Kerr mctp_astlpc_kcs_send(astlpc, 0x2); 253672c8852SJeremy Kerr } 254672c8852SJeremy Kerr 255672c8852SJeremy Kerr static void mctp_astlpc_tx_complete(struct mctp_binding_astlpc *astlpc) 256672c8852SJeremy Kerr { 257672c8852SJeremy Kerr mctp_binding_set_tx_enabled(&astlpc->binding, true); 258672c8852SJeremy Kerr } 259672c8852SJeremy Kerr 260672c8852SJeremy Kerr int mctp_astlpc_poll(struct mctp_binding_astlpc *astlpc) 261672c8852SJeremy Kerr { 262bc53d35aSJeremy Kerr uint8_t status, data; 263672c8852SJeremy Kerr int rc; 264672c8852SJeremy Kerr 265bc53d35aSJeremy Kerr rc = astlpc->ops.kcs_read(astlpc->ops_data, MCTP_ASTLPC_KCS_REG_STATUS, 266bc53d35aSJeremy Kerr &status); 267bc53d35aSJeremy Kerr if (rc) { 268672c8852SJeremy Kerr mctp_prwarn("KCS read error"); 269672c8852SJeremy Kerr return -1; 270672c8852SJeremy Kerr } 271672c8852SJeremy Kerr 272bc53d35aSJeremy Kerr if (!(status & KCS_STATUS_IBF)) 273672c8852SJeremy Kerr return 0; 274672c8852SJeremy Kerr 275bc53d35aSJeremy Kerr rc = astlpc->ops.kcs_read(astlpc->ops_data, MCTP_ASTLPC_KCS_REG_DATA, 276bc53d35aSJeremy Kerr &data); 277bc53d35aSJeremy Kerr if (rc) { 278bc53d35aSJeremy Kerr mctp_prwarn("KCS data read error"); 279bc53d35aSJeremy Kerr return -1; 280bc53d35aSJeremy Kerr } 281bc53d35aSJeremy Kerr 282672c8852SJeremy Kerr switch (data) { 283672c8852SJeremy Kerr case 0x0: 284672c8852SJeremy Kerr mctp_astlpc_init_channel(astlpc); 285672c8852SJeremy Kerr break; 286672c8852SJeremy Kerr case 0x1: 287672c8852SJeremy Kerr mctp_astlpc_rx_start(astlpc); 288672c8852SJeremy Kerr break; 289672c8852SJeremy Kerr case 0x2: 290672c8852SJeremy Kerr mctp_astlpc_tx_complete(astlpc); 291672c8852SJeremy Kerr break; 2921a4b55acSJeremy Kerr case 0xff: 2931a4b55acSJeremy Kerr /* reserved value for dummy data writes; do nothing */ 2941a4b55acSJeremy Kerr break; 295672c8852SJeremy Kerr default: 296672c8852SJeremy Kerr mctp_prwarn("unknown message 0x%x", data); 297672c8852SJeremy Kerr } 298672c8852SJeremy Kerr return 0; 299672c8852SJeremy Kerr } 300672c8852SJeremy Kerr 301672c8852SJeremy Kerr void mctp_astlpc_register_bus(struct mctp_binding_astlpc *astlpc, 302672c8852SJeremy Kerr struct mctp *mctp, mctp_eid_t eid) 303672c8852SJeremy Kerr { 304672c8852SJeremy Kerr mctp_register_bus(mctp, &astlpc->binding, eid); 305672c8852SJeremy Kerr } 306672c8852SJeremy Kerr 307672c8852SJeremy Kerr static int mctp_astlpc_init_bmc(struct mctp_binding_astlpc *astlpc) 308672c8852SJeremy Kerr { 309bc53d35aSJeremy Kerr struct mctp_lpcmap_hdr *hdr; 310672c8852SJeremy Kerr uint8_t status; 311672c8852SJeremy Kerr int rc; 312672c8852SJeremy Kerr 313bc53d35aSJeremy Kerr if (lpc_direct(astlpc)) 314bc53d35aSJeremy Kerr hdr = astlpc->lpc_hdr; 315bc53d35aSJeremy Kerr else 316bc53d35aSJeremy Kerr hdr = astlpc->priv_hdr; 317672c8852SJeremy Kerr 318bc53d35aSJeremy Kerr hdr->magic = htobe32(MCTP_MAGIC); 319bc53d35aSJeremy Kerr hdr->bmc_ver_min = htobe16(BMC_VER_MIN); 320bc53d35aSJeremy Kerr hdr->bmc_ver_cur = htobe16(BMC_VER_CUR); 321bc53d35aSJeremy Kerr 322bc53d35aSJeremy Kerr hdr->rx_offset = htobe32(rx_offset); 323bc53d35aSJeremy Kerr hdr->rx_size = htobe32(rx_size); 324bc53d35aSJeremy Kerr hdr->tx_offset = htobe32(tx_offset); 325bc53d35aSJeremy Kerr hdr->tx_size = htobe32(tx_size); 326bc53d35aSJeremy Kerr 327bc53d35aSJeremy Kerr if (!lpc_direct(astlpc)) 328bc53d35aSJeremy Kerr astlpc->ops.lpc_write(astlpc->ops_data, hdr, 0, sizeof(*hdr)); 329672c8852SJeremy Kerr 330672c8852SJeremy Kerr /* set status indicating that the BMC is now active */ 331672c8852SJeremy Kerr status = KCS_STATUS_BMC_READY | KCS_STATUS_OBF; 332bc53d35aSJeremy Kerr rc = astlpc->ops.kcs_write(astlpc->ops_data, 333bc53d35aSJeremy Kerr MCTP_ASTLPC_KCS_REG_STATUS, status); 334bc53d35aSJeremy Kerr if (rc) { 335672c8852SJeremy Kerr mctp_prwarn("KCS write failed"); 336672c8852SJeremy Kerr } 337672c8852SJeremy Kerr 338672c8852SJeremy Kerr return rc; 339672c8852SJeremy Kerr } 340672c8852SJeremy Kerr 341bc53d35aSJeremy Kerr /* allocate and basic initialisation */ 342bc53d35aSJeremy Kerr static struct mctp_binding_astlpc *__mctp_astlpc_init(void) 343bc53d35aSJeremy Kerr { 344bc53d35aSJeremy Kerr struct mctp_binding_astlpc *astlpc; 345bc53d35aSJeremy Kerr 346bc53d35aSJeremy Kerr astlpc = __mctp_alloc(sizeof(*astlpc)); 347bc53d35aSJeremy Kerr memset(astlpc, 0, sizeof(*astlpc)); 348bc53d35aSJeremy Kerr astlpc->binding.name = "astlpc"; 349bc53d35aSJeremy Kerr astlpc->binding.version = 1; 350bc53d35aSJeremy Kerr astlpc->binding.tx = mctp_binding_astlpc_tx; 351bc53d35aSJeremy Kerr astlpc->binding.pkt_size = MCTP_BMTU; 352bc53d35aSJeremy Kerr astlpc->binding.pkt_pad = 0; 353bc53d35aSJeremy Kerr astlpc->lpc_map = NULL; 354bc53d35aSJeremy Kerr 355bc53d35aSJeremy Kerr return astlpc; 356bc53d35aSJeremy Kerr } 357bc53d35aSJeremy Kerr 358bc53d35aSJeremy Kerr struct mctp_binding_astlpc *mctp_astlpc_init_ops( 359bc53d35aSJeremy Kerr struct mctp_binding_astlpc_ops *ops, 360bc53d35aSJeremy Kerr void *ops_data, void *lpc_map) 361bc53d35aSJeremy Kerr { 362bc53d35aSJeremy Kerr struct mctp_binding_astlpc *astlpc; 363bc53d35aSJeremy Kerr int rc; 364bc53d35aSJeremy Kerr 365bc53d35aSJeremy Kerr astlpc = __mctp_astlpc_init(); 366bc53d35aSJeremy Kerr if (!astlpc) 367bc53d35aSJeremy Kerr return NULL; 368bc53d35aSJeremy Kerr 369bc53d35aSJeremy Kerr memcpy(&astlpc->ops, ops, sizeof(astlpc->ops)); 370bc53d35aSJeremy Kerr astlpc->ops_data = ops_data; 371bc53d35aSJeremy Kerr astlpc->lpc_map = lpc_map; 372bc53d35aSJeremy Kerr 373bc53d35aSJeremy Kerr /* In indirect mode, we keep a separate buffer of header data. 374bc53d35aSJeremy Kerr * We need to sync this through the lpc_read/lpc_write ops. 375bc53d35aSJeremy Kerr */ 376bc53d35aSJeremy Kerr if (!astlpc->lpc_map) 377bc53d35aSJeremy Kerr astlpc->priv_hdr = __mctp_alloc(sizeof(*astlpc->priv_hdr)); 378bc53d35aSJeremy Kerr 379bc53d35aSJeremy Kerr rc = mctp_astlpc_init_bmc(astlpc); 380bc53d35aSJeremy Kerr if (rc) { 381bc53d35aSJeremy Kerr free(astlpc); 382bc53d35aSJeremy Kerr return NULL; 383bc53d35aSJeremy Kerr } 384bc53d35aSJeremy Kerr 385bc53d35aSJeremy Kerr return astlpc; 386bc53d35aSJeremy Kerr } 387bc53d35aSJeremy Kerr 388*92a10a6bSJeremy Kerr #ifndef MCTP_WITHOUT_FILEIO 389bc53d35aSJeremy Kerr static int mctp_astlpc_init_fileio_lpc(struct mctp_binding_astlpc *astlpc) 390672c8852SJeremy Kerr { 391672c8852SJeremy Kerr struct aspeed_lpc_ctrl_mapping map = { 392672c8852SJeremy Kerr .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY, 393672c8852SJeremy Kerr .window_id = 0, /* There's only one */ 394672c8852SJeremy Kerr .flags = 0, 395672c8852SJeremy Kerr .addr = 0, 396672c8852SJeremy Kerr .offset = 0, 397672c8852SJeremy Kerr .size = 0 398672c8852SJeremy Kerr }; 399672c8852SJeremy Kerr int fd, rc; 400672c8852SJeremy Kerr 401672c8852SJeremy Kerr fd = open(lpc_path, O_RDWR | O_SYNC); 402672c8852SJeremy Kerr if (fd < 0) { 403672c8852SJeremy Kerr mctp_prwarn("LPC open (%s) failed", lpc_path); 404672c8852SJeremy Kerr return -1; 405672c8852SJeremy Kerr } 406672c8852SJeremy Kerr 407672c8852SJeremy Kerr rc = ioctl(fd, ASPEED_LPC_CTRL_IOCTL_GET_SIZE, &map); 408672c8852SJeremy Kerr if (rc) { 409672c8852SJeremy Kerr mctp_prwarn("LPC GET_SIZE failed"); 410672c8852SJeremy Kerr close(fd); 411672c8852SJeremy Kerr return -1; 412672c8852SJeremy Kerr } 413672c8852SJeremy Kerr 414672c8852SJeremy Kerr astlpc->lpc_map_base = mmap(NULL, map.size, PROT_READ | PROT_WRITE, 415672c8852SJeremy Kerr MAP_SHARED, fd, 0); 416672c8852SJeremy Kerr if (astlpc->lpc_map_base == MAP_FAILED) { 417672c8852SJeremy Kerr mctp_prwarn("LPC mmap failed"); 418672c8852SJeremy Kerr rc = -1; 419672c8852SJeremy Kerr } else { 420672c8852SJeremy Kerr astlpc->lpc_map = astlpc->lpc_map_base + 421672c8852SJeremy Kerr map.size - LPC_WIN_SIZE; 422672c8852SJeremy Kerr } 423672c8852SJeremy Kerr 424672c8852SJeremy Kerr close(fd); 425672c8852SJeremy Kerr 426672c8852SJeremy Kerr return rc; 427672c8852SJeremy Kerr } 428672c8852SJeremy Kerr 429bc53d35aSJeremy Kerr static int mctp_astlpc_init_fileio_kcs(struct mctp_binding_astlpc *astlpc) 430672c8852SJeremy Kerr { 431672c8852SJeremy Kerr astlpc->kcs_fd = open(kcs_path, O_RDWR); 432672c8852SJeremy Kerr if (astlpc->kcs_fd < 0) 433672c8852SJeremy Kerr return -1; 434672c8852SJeremy Kerr 435672c8852SJeremy Kerr return 0; 436672c8852SJeremy Kerr } 437672c8852SJeremy Kerr 438bc53d35aSJeremy Kerr static int __mctp_astlpc_fileio_kcs_read(void *arg, 439bc53d35aSJeremy Kerr enum mctp_binding_astlpc_kcs_reg reg, uint8_t *val) 440bc53d35aSJeremy Kerr { 441bc53d35aSJeremy Kerr struct mctp_binding_astlpc *astlpc = arg; 442bc53d35aSJeremy Kerr off_t offset = reg; 443bc53d35aSJeremy Kerr int rc; 444bc53d35aSJeremy Kerr 445bc53d35aSJeremy Kerr rc = pread(astlpc->kcs_fd, val, 1, offset); 446bc53d35aSJeremy Kerr 447bc53d35aSJeremy Kerr return rc == 1 ? 0 : -1; 448bc53d35aSJeremy Kerr } 449bc53d35aSJeremy Kerr 450bc53d35aSJeremy Kerr static int __mctp_astlpc_fileio_kcs_write(void *arg, 451bc53d35aSJeremy Kerr enum mctp_binding_astlpc_kcs_reg reg, uint8_t val) 452bc53d35aSJeremy Kerr { 453bc53d35aSJeremy Kerr struct mctp_binding_astlpc *astlpc = arg; 454bc53d35aSJeremy Kerr off_t offset = reg; 455bc53d35aSJeremy Kerr int rc; 456bc53d35aSJeremy Kerr 457bc53d35aSJeremy Kerr rc = pwrite(astlpc->kcs_fd, &val, 1, offset); 458bc53d35aSJeremy Kerr 459bc53d35aSJeremy Kerr return rc == 1 ? 0 : -1; 460bc53d35aSJeremy Kerr } 461bc53d35aSJeremy Kerr 462bc53d35aSJeremy Kerr int mctp_astlpc_get_fd(struct mctp_binding_astlpc *astlpc) 463bc53d35aSJeremy Kerr { 464bc53d35aSJeremy Kerr return astlpc->kcs_fd; 465bc53d35aSJeremy Kerr } 466bc53d35aSJeremy Kerr 467bc53d35aSJeremy Kerr struct mctp_binding_astlpc *mctp_astlpc_init_fileio(void) 468672c8852SJeremy Kerr { 469672c8852SJeremy Kerr struct mctp_binding_astlpc *astlpc; 470672c8852SJeremy Kerr int rc; 471672c8852SJeremy Kerr 472bc53d35aSJeremy Kerr astlpc = __mctp_astlpc_init(); 473bc53d35aSJeremy Kerr if (!astlpc) 474bc53d35aSJeremy Kerr return NULL; 475672c8852SJeremy Kerr 476bc53d35aSJeremy Kerr /* Set internal operations for kcs. We use direct accesses to the lpc 477bc53d35aSJeremy Kerr * map area */ 478bc53d35aSJeremy Kerr astlpc->ops.kcs_read = __mctp_astlpc_fileio_kcs_read; 479bc53d35aSJeremy Kerr astlpc->ops.kcs_write = __mctp_astlpc_fileio_kcs_write; 480bc53d35aSJeremy Kerr astlpc->ops_data = astlpc; 481bc53d35aSJeremy Kerr 482bc53d35aSJeremy Kerr rc = mctp_astlpc_init_fileio_lpc(astlpc); 483672c8852SJeremy Kerr if (rc) { 484672c8852SJeremy Kerr free(astlpc); 485672c8852SJeremy Kerr return NULL; 486672c8852SJeremy Kerr } 487672c8852SJeremy Kerr 488bc53d35aSJeremy Kerr rc = mctp_astlpc_init_fileio_kcs(astlpc); 489672c8852SJeremy Kerr if (rc) { 490672c8852SJeremy Kerr free(astlpc); 491672c8852SJeremy Kerr return NULL; 492672c8852SJeremy Kerr } 493672c8852SJeremy Kerr 494672c8852SJeremy Kerr rc = mctp_astlpc_init_bmc(astlpc); 495672c8852SJeremy Kerr if (rc) { 496672c8852SJeremy Kerr free(astlpc); 497672c8852SJeremy Kerr return NULL; 498672c8852SJeremy Kerr } 499672c8852SJeremy Kerr 500672c8852SJeremy Kerr return astlpc; 501672c8852SJeremy Kerr } 502*92a10a6bSJeremy Kerr #else 503*92a10a6bSJeremy Kerr struct mctp_binding_astlpc * __attribute__((const)) 504*92a10a6bSJeremy Kerr mctp_astlpc_init_fileio(void) 505*92a10a6bSJeremy Kerr { 506*92a10a6bSJeremy Kerr return NULL; 507*92a10a6bSJeremy Kerr } 508672c8852SJeremy Kerr 509*92a10a6bSJeremy Kerr int __attribute__((const)) mctp_astlpc_get_fd( 510*92a10a6bSJeremy Kerr struct mctp_binding_astlpc *astlpc __attribute__((unused))) 511*92a10a6bSJeremy Kerr { 512*92a10a6bSJeremy Kerr return -1; 513*92a10a6bSJeremy Kerr } 514*92a10a6bSJeremy Kerr #endif 515