From nobody Wed Nov 13 07:15:18 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1689614479; cv=none; d=zohomail.com; s=zohoarc; b=dXuYNm9pjC6rrLb8KlSN2SNGpKEiCAXiTF0LZivDhvlptjzjD6jRCqzYv1VM9Z177riMc3b7HNjAfOIN/pUGEoZBWfsI5c5e8RMuuOxi38Nuz9v88svXT+hMswqCuSWfs7GFn0d/+eC1mQu2J9gdPAL2N86qZfxQaIkYykcgJZE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1689614479; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=w4A13EzEHYoHuUP4FxcoSb83kCtkoca9gbJ27AOpVf0=; b=NbbiC1KTCgnUSQcfavxwdCW4xRhox1igeqO+clzv/hgMESsjh0CHwNBb8K00drfaPqtaBDDpEBBV1rKeq/L+0bdEaBIxXtXmamjJY9ri0izlzVicyTahx4BhWqMSkbKb27PSv3UcHrkasu+9HiDHn7M+NheorKMrTGV3kyGRRN4= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 168961447941196.77526543490012; Mon, 17 Jul 2023 10:21:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qLRu3-0002mw-Re; Mon, 17 Jul 2023 13:20:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qLRu2-0002if-33 for qemu-devel@nongnu.org; Mon, 17 Jul 2023 13:20:54 -0400 Received: from frasgout.his.huawei.com ([185.176.79.56]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qLRtz-000541-B0 for qemu-devel@nongnu.org; Mon, 17 Jul 2023 13:20:53 -0400 Received: from lhrpeml500005.china.huawei.com (unknown [172.18.147.226]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4R4TKn6nPGz67T1b; Tue, 18 Jul 2023 01:17:33 +0800 (CST) Received: from SecurePC-101-06.china.huawei.com (10.122.247.231) by lhrpeml500005.china.huawei.com (7.191.163.240) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 17 Jul 2023 18:20:48 +0100 To: , Dan Williams , CC: , Alison Schofield , Ira Weiny , Dave Jiang , Davidlohr Bueso , Viacheslav Dubeyko , Shesha Bhushan Sreenivasamurthy , Fan Ni , Michael Tsirkin , Jonathan Zhang , Klaus Jensen Subject: [RFC PATCH 08/17] hw/i2c: add mctp core Date: Mon, 17 Jul 2023 18:16:37 +0100 Message-ID: <20230717171646.8972-9-Jonathan.Cameron@huawei.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230717171646.8972-1-Jonathan.Cameron@huawei.com> References: <20230717171646.8972-1-Jonathan.Cameron@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Originating-IP: [10.122.247.231] X-ClientProxiedBy: lhrpeml100001.china.huawei.com (7.191.160.183) To lhrpeml500005.china.huawei.com (7.191.163.240) X-CFilter-Loop: Reflected Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=185.176.79.56; envelope-from=jonathan.cameron@huawei.com; helo=frasgout.his.huawei.com X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Jonathan Cameron From: Jonathan Cameron via Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1689614480530100001 From: Klaus Jensen Add an abstract MCTP over I2C endpoint model. This implements MCTP control message handling as well as handling the actual I2C transport (packetization). Devices are intended to derive from this and implement the class methods. Parts of this implementation is inspired by code[1] previously posted by Jonathan Cameron. [1]: https://lore.kernel.org/qemu-devel/20220520170128.4436-1-Jonathan.Ca= meron@huawei.com/ Signed-off-by: Klaus Jensen Signed-off-by: Jonathan Cameron --- MAINTAINERS | 7 + include/hw/i2c/mctp.h | 114 +++++++++++ include/hw/i2c/smbus_master.h | 3 + include/net/mctp.h | 43 +++++ hw/i2c/mctp.c | 352 ++++++++++++++++++++++++++++++++++ hw/i2c/smbus_master.c | 28 +++ hw/arm/Kconfig | 1 + hw/i2c/Kconfig | 4 + hw/i2c/meson.build | 1 + hw/i2c/trace-events | 12 ++ 10 files changed, 565 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 12e59b6b27..02a5bce814 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3386,6 +3386,13 @@ F: tests/qtest/adm1272-test.c F: tests/qtest/max34451-test.c F: tests/qtest/isl_pmbus_vr-test.c =20 +MCTP I2C Transport +M: Klaus Jensen +S: Maintained +F: hw/i2c/mctp.c +F: include/hw/i2c/mctp.h +F: include/net/mctp.h + Firmware schema specifications M: Philippe Mathieu-Daud=C3=A9 R: Daniel P. Berrange diff --git a/include/hw/i2c/mctp.h b/include/hw/i2c/mctp.h new file mode 100644 index 0000000000..c53ee6a3b6 --- /dev/null +++ b/include/hw/i2c/mctp.h @@ -0,0 +1,114 @@ +#ifndef QEMU_I2C_MCTP_H +#define QEMU_I2C_MCTP_H + +#include "qom/object.h" +#include "hw/qdev-core.h" +#include "net/mctp.h" + +typedef struct MCTPI2CPacketHeader { + uint8_t dest; + uint8_t prot; + uint8_t byte_count; + uint8_t source; +} MCTPI2CPacketHeader; + +typedef struct MCTPI2CPacket { + MCTPI2CPacketHeader i2c; + MCTPPacket mctp; +} MCTPI2CPacket; + +#define i2c_mctp_payload(buf) (buf + offsetof(MCTPI2CPacket, mctp.payload)) + +#define TYPE_MCTP_I2C_ENDPOINT "mctp-i2c-endpoint" +OBJECT_DECLARE_TYPE(MCTPI2CEndpoint, MCTPI2CEndpointClass, MCTP_I2C_ENDPOI= NT) + +struct MCTPI2CEndpointClass { + I2CSlaveClass parent_class; + + int (*put_message_bytes)(MCTPI2CEndpoint *mctp, uint8_t *buf, size_t l= en); + size_t (*get_message_bytes)(MCTPI2CEndpoint *mctp, uint8_t *buf, + size_t maxlen, uint8_t *mctp_flags); + + void (*handle_message)(MCTPI2CEndpoint *mctp); + void (*reset_message)(MCTPI2CEndpoint *mctp); + + size_t (*get_message_types)(MCTPI2CEndpoint *mctp, uint8_t *data, + size_t maxlen); +}; + +/* + * Maximum value of the SMBus Block Write "Byte Count" field (8 bits). + * + * This is the count of bytes that follow the Byte Count field and up to, = but + * not including, the PEC byte. + */ +#define I2C_MCTP_MAXBLOCK 255 + +/* + * Maximum Transmission Unit under I2C. + * + * This is for the MCTP Packet Payload (255, subtracting the 4 byte MCTP P= acket + * Header or the 1 byte MCTP/I2C piggy-backed source address). + */ +#define I2C_MCTP_MAXMTU (I2C_MCTP_MAXBLOCK - (sizeof(MCTPPacketHeader) + 1= )) + +/* + * Maximum length of an MCTP/I2C packet. + * + * This is the sum of the three I2C header bytes (Destination target addre= ss, + * Command Code and Byte Count), the maximum number of bytes in a message = (255) + * and the 1 byte Packet Error Code. + */ +#define I2C_MCTP_MAX_LENGTH (3 + I2C_MCTP_MAXBLOCK + 1) + +/* + * Maximum length of an MCTP/I2C Control Message. + * + * This is the 64 byte MCTP Baseline Maximum Transmission Unit, adding the + * combined MCTP/I2C headers and the trailing 1 byte PEC. + */ +#define I2C_MCTP_CONTROL_MAX_LENGTH \ + (sizeof(MCTPI2CPacket) + MCTP_BASELINE_MTU + 1) + +typedef enum { + I2C_MCTP_STATE_IDLE, + I2C_MCTP_STATE_RX_STARTED, + I2C_MCTP_STATE_RX, + I2C_MCTP_STATE_WAIT_TX, + I2C_MCTP_STATE_TX, +} MCTPState; + +typedef enum { + I2C_MCTP_STATE_TX_START_SEND, + I2C_MCTP_STATE_TX_SEND_BYTE, +} MCTPTxState; + +typedef struct MCTPI2CEndpoint { + I2CSlave parent_obj; + I2CBus *i2c; + + MCTPState state; + + /* mctp endpoint identifier */ + uint8_t my_eid; + + uint8_t buffer[I2C_MCTP_MAX_LENGTH]; + uint64_t pos; + size_t len; + + struct { + MCTPTxState state; + bool is_control; + + uint8_t eid; + uint8_t addr; + uint8_t pktseq; + uint8_t flags; + + QEMUBH *bh; + } tx; +} MCTPI2CEndpoint; + +void i2c_mctp_schedule_send(MCTPI2CEndpoint *mctp); + +#endif /* QEMU_I2C_MCTP_H */ diff --git a/include/hw/i2c/smbus_master.h b/include/hw/i2c/smbus_master.h index bb13bc423c..ea5eff3a2c 100644 --- a/include/hw/i2c/smbus_master.h +++ b/include/hw/i2c/smbus_master.h @@ -27,6 +27,9 @@ =20 #include "hw/i2c/i2c.h" =20 +/* SMBus PEC */ +uint8_t i2c_smbus_pec(uint8_t crc, uint8_t *buf, size_t len); + /* Master device commands. */ int smbus_quick_command(I2CBus *bus, uint8_t addr, int read); int smbus_receive_byte(I2CBus *bus, uint8_t addr); diff --git a/include/net/mctp.h b/include/net/mctp.h new file mode 100644 index 0000000000..c936224ecf --- /dev/null +++ b/include/net/mctp.h @@ -0,0 +1,43 @@ +#ifndef QEMU_MCTP_H +#define QEMU_MCTP_H + +#define MCTP_BASELINE_MTU 64 + +enum { + MCTP_H_FLAGS_EOM =3D 1 << 6, + MCTP_H_FLAGS_SOM =3D 1 << 7, +}; + +enum { + MCTP_MESSAGE_TYPE_CONTROL =3D 0x0, + MCTP_MESSAGE_TYPE_NMI =3D 0x4, + + MCTP_MESSAGE_IC =3D 1 << 7, +}; + +typedef struct MCTPPacketHeader { + uint8_t version; + struct { + uint8_t dest; + uint8_t source; + } eid; + uint8_t flags; +} MCTPPacketHeader; + +typedef struct MCTPPacket { + MCTPPacketHeader hdr; + uint8_t payload[]; +} MCTPPacket; + +typedef struct MCTPControlMessage { + uint8_t type; + uint8_t flags; + uint8_t command; + uint8_t data[]; +} MCTPControlMessage; + +enum { + MCTP_CONTROL_ERROR_UNSUPPORTED_CMD =3D 0x5, +}; + +#endif /* QEMU_MCTP_H */ diff --git a/hw/i2c/mctp.c b/hw/i2c/mctp.c new file mode 100644 index 0000000000..0f4045d0d6 --- /dev/null +++ b/hw/i2c/mctp.c @@ -0,0 +1,352 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * SPDX-FileCopyrightText: Copyright (c) 2022 Samsung Electronics Co., Ltd. + * SPDX-FileContributor: Klaus Jensen + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" + +#include "hw/qdev-properties.h" +#include "hw/i2c/i2c.h" +#include "hw/i2c/smbus_master.h" +#include "hw/i2c/mctp.h" + +#include "trace.h" + +void i2c_mctp_schedule_send(MCTPI2CEndpoint *mctp) +{ + I2CBus *i2c =3D I2C_BUS(qdev_get_parent_bus(DEVICE(mctp))); + + mctp->tx.state =3D I2C_MCTP_STATE_TX_START_SEND; + + i2c_bus_master(i2c, mctp->tx.bh); +} + +static void i2c_mctp_tx(void *opaque) +{ + DeviceState *dev =3D DEVICE(opaque); + I2CBus *i2c =3D I2C_BUS(qdev_get_parent_bus(dev)); + I2CSlave *slave =3D I2C_SLAVE(dev); + MCTPI2CEndpoint *mctp =3D MCTP_I2C_ENDPOINT(dev); + MCTPI2CEndpointClass *mc =3D MCTP_I2C_ENDPOINT_GET_CLASS(mctp); + MCTPI2CPacket *pkt =3D (MCTPI2CPacket *)mctp->buffer; + uint8_t flags =3D 0; + + switch (mctp->tx.state) { + case I2C_MCTP_STATE_TX_SEND_BYTE: + if (mctp->pos < mctp->len) { + uint8_t byte =3D mctp->buffer[mctp->pos]; + + trace_i2c_mctp_tx_send_byte(mctp->pos, byte); + + /* send next byte */ + i2c_send_async(i2c, byte); + + mctp->pos++; + + break; + } + + /* packet sent */ + i2c_end_transfer(i2c); + + /* end of any control data */ + mctp->len =3D 0; + + /* fall through */ + + case I2C_MCTP_STATE_TX_START_SEND: + if (mctp->tx.is_control) { + /* packet payload is already in buffer */ + flags |=3D MCTP_H_FLAGS_SOM | MCTP_H_FLAGS_EOM; + } else { + /* get message bytes from derived device */ + mctp->len =3D mc->get_message_bytes(mctp, pkt->mctp.payload, + I2C_MCTP_MAXMTU, &flags); + } + + if (!mctp->len) { + trace_i2c_mctp_tx_done(); + + /* no more packets needed; release the bus */ + i2c_bus_release(i2c); + + mctp->state =3D I2C_MCTP_STATE_IDLE; + mctp->tx.is_control =3D false; + + break; + } + + mctp->state =3D I2C_MCTP_STATE_TX; + + pkt->i2c =3D (MCTPI2CPacketHeader) { + .dest =3D mctp->tx.addr & ~0x1, + .prot =3D 0xf, + .byte_count =3D 5 + mctp->len, + .source =3D slave->address << 1 | 0x1, + }; + + pkt->mctp.hdr =3D (MCTPPacketHeader) { + .version =3D 0x1, + .eid.dest =3D mctp->tx.eid, + .eid.source =3D mctp->my_eid, + .flags =3D flags | (mctp->tx.pktseq++ & 0x3) << 4 | mctp->tx.f= lags, + }; + + mctp->len +=3D sizeof(MCTPI2CPacket); + assert(mctp->len < I2C_MCTP_MAX_LENGTH); + + mctp->buffer[mctp->len] =3D i2c_smbus_pec(0, mctp->buffer, mctp->l= en); + mctp->len++; + + trace_i2c_mctp_tx_start_send(mctp->len); + + i2c_start_send_async(i2c, pkt->i2c.dest >> 1); + + /* already "sent" the destination slave address */ + mctp->pos =3D 1; + + mctp->tx.state =3D I2C_MCTP_STATE_TX_SEND_BYTE; + + break; + } +} + +#define i2c_mctp_control_data(buf) \ + (i2c_mctp_payload(buf) + offsetof(MCTPControlMessage, data)) + +static void i2c_mctp_handle_control_set_eid(MCTPI2CEndpoint *mctp, uint8_t= eid) +{ + mctp->my_eid =3D eid; + + uint8_t buf[] =3D { + 0x0, 0x0, eid, 0x0, + }; + + memcpy(i2c_mctp_control_data(mctp->buffer), buf, sizeof(buf)); + mctp->len +=3D sizeof(buf); +} + +static void i2c_mctp_handle_control_get_eid(MCTPI2CEndpoint *mctp) +{ + uint8_t buf[] =3D { + 0x0, mctp->my_eid, 0x0, 0x0, + }; + + memcpy(i2c_mctp_control_data(mctp->buffer), buf, sizeof(buf)); + mctp->len +=3D sizeof(buf); +} + +static void i2c_mctp_handle_control_get_version(MCTPI2CEndpoint *mctp) +{ + uint8_t buf[] =3D { + 0x0, 0x1, 0x0, 0x1, 0x3, 0x1, + }; + + memcpy(i2c_mctp_control_data(mctp->buffer), buf, sizeof(buf)); + mctp->len +=3D sizeof(buf); +} + +enum { + MCTP_CONTROL_SET_EID =3D 0x01, + MCTP_CONTROL_GET_EID =3D 0x02, + MCTP_CONTROL_GET_VERSION =3D 0x04, + MCTP_CONTROL_GET_MESSAGE_TYPE_SUPPORT =3D 0x05, +}; + +static void i2c_mctp_handle_control(MCTPI2CEndpoint *mctp) +{ + MCTPI2CEndpointClass *mc =3D MCTP_I2C_ENDPOINT_GET_CLASS(mctp); + MCTPControlMessage *msg =3D (MCTPControlMessage *)i2c_mctp_payload(mct= p->buffer); + + /* clear Rq/D */ + msg->flags &=3D 0x1f; + + mctp->len =3D sizeof(MCTPControlMessage); + + trace_i2c_mctp_handle_control(msg->command); + + switch (msg->command) { + case MCTP_CONTROL_SET_EID: + i2c_mctp_handle_control_set_eid(mctp, msg->data[1]); + break; + + case MCTP_CONTROL_GET_EID: + i2c_mctp_handle_control_get_eid(mctp); + break; + + case MCTP_CONTROL_GET_VERSION: + i2c_mctp_handle_control_get_version(mctp); + break; + + case MCTP_CONTROL_GET_MESSAGE_TYPE_SUPPORT: + mctp->len +=3D mc->get_message_types(mctp, i2c_mctp_control_data(m= ctp->buffer), + MCTP_BASELINE_MTU - mctp->len); + break; + + default: + trace_i2c_mctp_unhandled_control(msg->command); + + msg->data[0] =3D MCTP_CONTROL_ERROR_UNSUPPORTED_CMD; + mctp->len++; + + break; + } + + assert(mctp->len <=3D MCTP_BASELINE_MTU); + + i2c_mctp_schedule_send(mctp); +} + +static int i2c_mctp_event_cb(I2CSlave *i2c, enum i2c_event event) +{ + MCTPI2CEndpoint *mctp =3D MCTP_I2C_ENDPOINT(i2c); + MCTPI2CEndpointClass *mc =3D MCTP_I2C_ENDPOINT_GET_CLASS(mctp); + MCTPI2CPacket *pkt =3D (MCTPI2CPacket *)mctp->buffer; + size_t payload_len; + uint8_t pec; + + switch (event) { + case I2C_START_SEND: + if (mctp->state =3D=3D I2C_MCTP_STATE_IDLE) { + mctp->state =3D I2C_MCTP_STATE_RX_STARTED; + } else if (mctp->state !=3D I2C_MCTP_STATE_RX) { + return -1; + } + + /* the i2c core eats the slave address, so put it back in */ + pkt->i2c.dest =3D i2c->address << 1; + mctp->len =3D 1; + + return 0; + + case I2C_FINISH: + if (mctp->len < sizeof(MCTPI2CPacket) + 1) { + trace_i2c_mctp_drop("short packet"); + goto drop; + } + + payload_len =3D mctp->len - (1 + offsetof(MCTPI2CPacket, mctp.payl= oad)); + + if (pkt->i2c.byte_count + 3 !=3D mctp->len - 1) { + trace_i2c_mctp_drop_invalid_length(pkt->i2c.byte_count + 3, + mctp->len - 1); + goto drop; + } + + pec =3D i2c_smbus_pec(0, mctp->buffer, mctp->len - 1); + if (mctp->buffer[mctp->len - 1] !=3D pec) { + trace_i2c_mctp_drop_invalid_pec(mctp->buffer[mctp->len - 1], p= ec); + goto drop; + } + + if (pkt->mctp.hdr.eid.dest !=3D mctp->my_eid) { + trace_i2c_mctp_drop_invalid_eid(pkt->mctp.hdr.eid.dest, + mctp->my_eid); + goto drop; + } + + if (pkt->mctp.hdr.flags & MCTP_H_FLAGS_SOM) { + mctp->tx.is_control =3D false; + + if (mctp->state =3D=3D I2C_MCTP_STATE_RX) { + mc->reset_message(mctp); + } + + mctp->state =3D I2C_MCTP_STATE_RX; + + mctp->tx.addr =3D pkt->i2c.source; + mctp->tx.eid =3D pkt->mctp.hdr.eid.source; + mctp->tx.flags =3D pkt->mctp.hdr.flags & 0x7; + mctp->tx.pktseq =3D (pkt->mctp.hdr.flags >> 4) & 0x3; + + if ((pkt->mctp.payload[0] & 0x7f) =3D=3D MCTP_MESSAGE_TYPE_CON= TROL) { + mctp->tx.is_control =3D true; + + i2c_mctp_handle_control(mctp); + + return 0; + } + } else if (mctp->state =3D=3D I2C_MCTP_STATE_RX_STARTED) { + trace_i2c_mctp_drop("expected SOM"); + goto drop; + } else if (((pkt->mctp.hdr.flags >> 4) & 0x3) !=3D (++mctp->tx.pkt= seq & 0x3)) { + trace_i2c_mctp_drop_invalid_pktseq((pkt->mctp.hdr.flags >> 4) = & 0x3, + mctp->tx.pktseq & 0x3); + goto drop; + } + + mc->put_message_bytes(mctp, i2c_mctp_payload(mctp->buffer), payloa= d_len); + + if (pkt->mctp.hdr.flags & MCTP_H_FLAGS_EOM) { + mc->handle_message(mctp); + mctp->state =3D I2C_MCTP_STATE_WAIT_TX; + } + + return 0; + + default: + return -1; + } + +drop: + mc->reset_message(mctp); + + mctp->state =3D I2C_MCTP_STATE_IDLE; + + return 0; +} + +static int i2c_mctp_send_cb(I2CSlave *i2c, uint8_t data) +{ + MCTPI2CEndpoint *mctp =3D MCTP_I2C_ENDPOINT(i2c); + + if (mctp->len < I2C_MCTP_MAX_LENGTH) { + mctp->buffer[mctp->len++] =3D data; + return 0; + } + + return -1; +} + +static void i2c_mctp_instance_init(Object *obj) +{ + MCTPI2CEndpoint *mctp =3D MCTP_I2C_ENDPOINT(obj); + + mctp->tx.bh =3D qemu_bh_new(i2c_mctp_tx, mctp); +} + +static Property mctp_i2c_props[] =3D { + DEFINE_PROP_UINT8("eid", MCTPI2CEndpoint, my_eid, 0x9), + DEFINE_PROP_END_OF_LIST(), +}; + +static void i2c_mctp_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(oc); + I2CSlaveClass *k =3D I2C_SLAVE_CLASS(oc); + + k->event =3D i2c_mctp_event_cb; + k->send =3D i2c_mctp_send_cb; + + device_class_set_props(dc, mctp_i2c_props); +} + +static const TypeInfo i2c_mctp_info =3D { + .name =3D TYPE_MCTP_I2C_ENDPOINT, + .parent =3D TYPE_I2C_SLAVE, + .abstract =3D true, + .instance_init =3D i2c_mctp_instance_init, + .instance_size =3D sizeof(MCTPI2CEndpoint), + .class_init =3D i2c_mctp_class_init, + .class_size =3D sizeof(MCTPI2CEndpointClass), +}; + +static void register_types(void) +{ + type_register_static(&i2c_mctp_info); +} + +type_init(register_types) diff --git a/hw/i2c/smbus_master.c b/hw/i2c/smbus_master.c index 6a53c34e70..47f9eb24e0 100644 --- a/hw/i2c/smbus_master.c +++ b/hw/i2c/smbus_master.c @@ -15,6 +15,34 @@ #include "hw/i2c/i2c.h" #include "hw/i2c/smbus_master.h" =20 +static uint8_t crc8(uint16_t data) +{ +#define POLY (0x1070U << 3) + int i; + + for (i =3D 0; i < 8; i++) { + if (data & 0x8000) { + data =3D data ^ POLY; + } + + data =3D data << 1; + } + + return (uint8_t)(data >> 8); +#undef POLY +} + +uint8_t i2c_smbus_pec(uint8_t crc, uint8_t *buf, size_t len) +{ + int i; + + for (i =3D 0; i < len; i++) { + crc =3D crc8((crc ^ buf[i]) << 8); + } + + return crc; +} + /* Master device commands. */ int smbus_quick_command(I2CBus *bus, uint8_t addr, int read) { diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 7e68348440..3308d9e0bd 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -541,6 +541,7 @@ config ASPEED_SOC select DS1338 select FTGMAC100 select I2C + select MCTP_I2C select DPS310 select PCA9552 select SERIAL diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index 14886b35da..3415e8421a 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -45,3 +45,7 @@ config PCA954X config PMBUS bool select SMBUS + +config MCTP_I2C + bool + select I2C diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index b58bc167db..d707ec58f7 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -1,5 +1,6 @@ i2c_ss =3D ss.source_set() i2c_ss.add(when: 'CONFIG_I2C', if_true: files('core.c')) +i2c_ss.add(when: 'CONFIG_MCTP_I2C', if_true: files('mctp.c')) i2c_ss.add(when: 'CONFIG_SMBUS', if_true: files('smbus_slave.c', 'smbus_ma= ster.c')) i2c_ss.add(when: 'CONFIG_ACPI_SMBUS', if_true: files('pm_smbus.c')) i2c_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('smbus_ich9.c')) diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index 8e88aa24c1..2e3065a998 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -45,3 +45,15 @@ npcm7xx_smbus_recv_fifo(const char *id, uint8_t received= , uint8_t expected) "%s =20 pca954x_write_bytes(uint8_t value) "PCA954X write data: 0x%02x" pca954x_read_data(uint8_t value) "PCA954X read data: 0x%02x" + +# mctp.c +i2c_mctp_tx_start_send(size_t len) "len %zu" +i2c_mctp_tx_send_byte(size_t pos, uint8_t byte) "pos %zu byte 0x%"PRIx8"" +i2c_mctp_tx_done(void) "packet sent" +i2c_mctp_handle_control(uint8_t command) "command 0x%"PRIx8"" +i2c_mctp_unhandled_control(uint8_t command) "command 0x%"PRIx8"" +i2c_mctp_drop(const char *reason) "%s" +i2c_mctp_drop_invalid_length(unsigned byte_count, size_t expected) "byte_c= ount %u expected %zu" +i2c_mctp_drop_invalid_pec(uint8_t pec, uint8_t expected) "pec 0x%"PRIx8" e= xpected 0x%"PRIx8"" +i2c_mctp_drop_invalid_eid(uint8_t eid, uint8_t expected) "eid 0x%"PRIx8" e= xpected 0x%"PRIx8"" +i2c_mctp_drop_invalid_pktseq(uint8_t pktseq, uint8_t expected) "pktseq 0x%= "PRIx8" expected 0x%"PRIx8"" --=20 2.39.2