From: Jeremy Kerr <jk@codeconstruct.com.au>
To: Klaus Jensen <its@irrelevant.dk>, qemu-devel@nongnu.org
Cc: "Andrew Jeffery" <andrew@aj.id.au>,
"Keith Busch" <kbusch@kernel.org>,
"Corey Minyard" <cminyard@mvista.com>,
"Peter Delevoryas" <peter@pjd.dev>,
qemu-arm@nongnu.org, "Peter Maydell" <peter.maydell@linaro.org>,
qemu-block@nongnu.org, "Joel Stanley" <joel@jms.id.au>,
"Cédric Le Goater" <clg@kaod.org>,
"Klaus Jensen" <k.jensen@samsung.com>,
"Matt Johnston" <matt@codeconstruct.com.au>
Subject: Re: [PATCH RFC 2/3] hw/i2c: add mctp core
Date: Fri, 18 Nov 2022 13:56:50 +0800 [thread overview]
Message-ID: <d8a8549c6fc29650131046ee00b7968ebedf886b.camel@codeconstruct.com.au> (raw)
In-Reply-To: <20221116084312.35808-3-its@irrelevant.dk>
Hi Klaus,
> 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.
Looks good, nice to see how it's used by the nmi device later too.
A couple of issues with the state machine though, comments inline, and
a bit of a patch below.
> +static void i2c_mctp_tx(void *opaque)
> +{
> + DeviceState *dev = DEVICE(opaque);
> + I2CBus *i2c = I2C_BUS(qdev_get_parent_bus(dev));
> + I2CSlave *slave = I2C_SLAVE(dev);
> + MCTPI2CEndpoint *mctp = MCTP_I2C_ENDPOINT(dev);
> + MCTPI2CEndpointClass *mc = MCTP_I2C_ENDPOINT_GET_CLASS(mctp);
> + MCTPI2CPacket *pkt = (MCTPI2CPacket *)mctp->buffer;
> + uint8_t flags = 0;
> +
> + switch (mctp->tx.state) {
> + case I2C_MCTP_STATE_TX_SEND_BYTE:
> + if (mctp->pos < mctp->len) {
> + uint8_t byte = 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);
If we're sending a control message, mctp->len will be set to the control
msg len here, then:
> +
> + /* fall through */
> +
> + case I2C_MCTP_STATE_TX_START_SEND:
> + if (mctp->tx.is_control) {
> + /* packet payload is already in buffer */
> + flags |= MCTP_H_FLAGS_SOM | MCTP_H_FLAGS_EOM;
> + } else {
> + /* get message bytes from derived device */
> + mctp->len = mc->get_message_bytes(mctp, pkt->mctp.payload,
> + I2C_MCTP_MAXMTU, &flags);
> + }
... it doesn't get cleared above, so:
> +
> + if (!mctp->len) {
... we don't hit this conditional, and hence keep sending unlimited
bytes. This presents as continuous interrupts to the aspeed i2c driver
when replying to any control message.
I think we need a mctp->len = 0 with the i2c_end_transfer(). With that,
I can get control protocol communication working with mctpd.
> +static int i2c_mctp_event_cb(I2CSlave *i2c, enum i2c_event event)
> +{
> + MCTPI2CEndpoint *mctp = MCTP_I2C_ENDPOINT(i2c);
> + MCTPI2CEndpointClass *mc = MCTP_I2C_ENDPOINT_GET_CLASS(mctp);
> + MCTPI2CPacket *pkt = (MCTPI2CPacket *)mctp->buffer;
> + size_t payload_len;
> + uint8_t pec;
> +
> + switch (event) {
> + case I2C_START_SEND:
> + if (mctp->state != I2C_MCTP_STATE_IDLE) {
> + return -1;
mctp->state may (validly) be I2C_MCTP_STATE_RX here, if we're receiving
the start event for the second packet of a multi-packet message.
> + }
> +
> + /* the i2c core eats the slave address, so put it back in */
> + pkt->i2c.dest = i2c->address << 1;
> + mctp->len = 1;
> +
> + mctp->state = I2C_MCTP_STATE_RX_STARTED;
> +
> + return 0;
> +
> + case I2C_FINISH:
> + payload_len = mctp->len - (1 + offsetof(MCTPI2CPacket, mctp.payload));
> +
> + if (pkt->i2c.byte_count + 3 != mctp->len - 1) {
> + trace_i2c_mctp_drop_invalid_length(pkt->i2c.byte_count +
> 3,
> + mctp->len - 1);
> + goto drop;
> + }
> +
> + pec = i2c_smbus_pec(0, mctp->buffer, mctp->len - 1);
> + if (mctp->buffer[mctp->len - 1] != pec) {
> + trace_i2c_mctp_drop_invalid_pec(mctp->buffer[mctp->len - 1], pec);
> + goto drop;
> + }
> +
> + if (pkt->mctp.hdr.eid.dest != 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 = false;
> +
> + if (mctp->state == I2C_MCTP_STATE_RX) {
> + mc->reset_message(mctp);
> + }
> +
> + mctp->state = I2C_MCTP_STATE_RX;
> +
> + mctp->tx.addr = pkt->i2c.source;
> + mctp->tx.eid = pkt->mctp.hdr.eid.source;
> + mctp->tx.flags = pkt->mctp.hdr.flags & 0x7;
> + mctp->tx.pktseq = (pkt->mctp.hdr.flags >> 4) & 0x3;
> +
> + if ((pkt->mctp.payload[0] & 0x7f) == MCTP_MESSAGE_TYPE_CONTROL) {
> + mctp->tx.is_control = true;
> +
> + i2c_mctp_handle_control(mctp);
> +
> + return 0;
> + }
> + } else if (mctp->state == I2C_MCTP_STATE_RX_STARTED) {
> + trace_i2c_mctp_drop("expected SOM");
> + goto drop;
> + } else if (((pkt->mctp.hdr.flags >> 4) & 0x3) != (mctp->tx.pktseq++ & 0x3)) {
The pktseq is the sequence number of the last packet seen, so you want a
pre-increment there: ++mctp->tx.pktseq & 0x3
} else if (((pkt->mctp.hdr.flags >> 4) & 0x3) != (++mctp->tx.pktseq & 0x3)) {
With those changes, I can get control protocol going, and multi-packet
messages work. There's a couple of failures from unsupported commands,
but otherwise looks good:
# mctp addr add 8 dev mctpi2c6
# mctp link set mctpi2c6 up
# mctp link set mctpi2c6 mtu 254
# systemctl restart mctpd
# busctl --no-pager call xyz.openbmc_project.MCTP \
/xyz/openbmc_project/mctp au.com.CodeConstruct.MCTP \
SetupEndpoint say mctpi2c6 1 0x1d
yisb 9 1 "/xyz/openbmc_project/mctp/1/9" true
# mctp route del 9 via mctpi2c6
# mctp route add 9 via mctpi2c6 mtu 68
# mi-mctp 1 9 info
nmi message type 0x2 not handled
Identify Controller failed, no quirks applied
NVMe MI subsys info:
num ports: 1
major ver: 1
minor ver: 1
NVMe MI port info:
port 0
type SMBus[2]
MCTP MTU: 64
MEB size: 0
SMBus address: 0x00
VPD access freq: 0x00
MCTP address: 0x1d
MCTP access freq: 0x01
NVMe basic management: disabled
nmi command 0x1 not handled
mi-mctp: can't perform Health Status Poll operation: Success
# mi-mctp 1 9 get-config 0
nmi message type 0x2 not handled
Identify Controller failed, no quirks applied
SMBus access frequency (port 0): 100k [0x1]
MCTP MTU (port 0): 64
I've included a patch below, with some fixes for the above, in case that
helps.
Cheers,
Jeremy
diff --git a/hw/i2c/mctp.c b/hw/i2c/mctp.c
index 46376de95a..1775deb46f 100644
--- a/hw/i2c/mctp.c
+++ b/hw/i2c/mctp.c
@@ -78,6 +78,9 @@ static void i2c_mctp_tx(void *opaque)
/* packet sent */
i2c_end_transfer(i2c);
+ /* end of any control data */
+ mctp->len = 0;
+
/* fall through */
case I2C_MCTP_STATE_TX_START_SEND:
@@ -228,7 +231,9 @@ static int i2c_mctp_event_cb(I2CSlave *i2c, enum i2c_event event)
switch (event) {
case I2C_START_SEND:
- if (mctp->state != I2C_MCTP_STATE_IDLE) {
+ if (mctp->state == I2C_MCTP_STATE_IDLE) {
+ mctp->state = I2C_MCTP_STATE_RX_STARTED;
+ } else if (mctp->state != I2C_MCTP_STATE_RX) {
return -1;
}
@@ -236,8 +241,6 @@ static int i2c_mctp_event_cb(I2CSlave *i2c, enum i2c_event event)
pkt->i2c.dest = i2c->address << 1;
mctp->len = 1;
- mctp->state = I2C_MCTP_STATE_RX_STARTED;
-
return 0;
case I2C_FINISH:
@@ -285,7 +288,7 @@ static int i2c_mctp_event_cb(I2CSlave *i2c, enum i2c_event event)
} else if (mctp->state == I2C_MCTP_STATE_RX_STARTED) {
trace_i2c_mctp_drop("expected SOM");
goto drop;
- } else if (((pkt->mctp.hdr.flags >> 4) & 0x3) != (mctp->tx.pktseq++ & 0x3)) {
+ } else if (((pkt->mctp.hdr.flags >> 4) & 0x3) != (++mctp->tx.pktseq & 0x3)) {
trace_i2c_mctp_drop_invalid_pktseq((pkt->mctp.hdr.flags >> 4) & 0x3,
mctp->tx.pktseq & 0x3);
goto drop;
next prev parent reply other threads:[~2022-11-18 5:57 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-16 8:43 [PATCH 0/3] hw/{i2c, nvme}: mctp endpoint, nvme management interface model Klaus Jensen
2022-11-16 8:43 ` [PATCH maybe-7.2 1/3] hw/i2c: only schedule pending master when bus is idle Klaus Jensen
2022-11-16 13:16 ` Peter Maydell
2022-11-16 13:43 ` Corey Minyard
2022-11-16 15:58 ` Cédric Le Goater
2022-11-17 6:40 ` Klaus Jensen
2022-11-17 6:56 ` Cédric Le Goater
2022-11-17 7:37 ` Klaus Jensen
2022-11-17 8:01 ` Cédric Le Goater
2022-11-17 11:58 ` Klaus Jensen
2022-11-17 13:40 ` Cédric Le Goater
2022-11-18 6:59 ` Klaus Jensen
2022-11-22 8:45 ` Klaus Jensen
2022-11-16 8:43 ` [PATCH RFC 2/3] hw/i2c: add mctp core Klaus Jensen
2022-11-16 14:27 ` Corey Minyard
2022-11-17 6:51 ` Klaus Jensen
2022-11-18 5:56 ` Jeremy Kerr [this message]
2022-11-18 6:15 ` Jeremy Kerr
2022-11-18 7:03 ` Klaus Jensen
2022-11-18 7:09 ` Jeremy Kerr
2022-11-18 7:01 ` Klaus Jensen
2022-11-21 8:04 ` Matt Johnston
2022-11-16 8:43 ` [PATCH RFC 3/3] hw/nvme: add nvme management interface model Klaus Jensen
2022-11-18 7:56 ` Philippe Mathieu-Daudé
2022-11-18 7:58 ` Klaus Jensen
2022-11-16 9:18 ` [PATCH 0/3] hw/{i2c,nvme}: mctp endpoint, " Jeremy Kerr
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=d8a8549c6fc29650131046ee00b7968ebedf886b.camel@codeconstruct.com.au \
--to=jk@codeconstruct.com.au \
--cc=andrew@aj.id.au \
--cc=clg@kaod.org \
--cc=cminyard@mvista.com \
--cc=its@irrelevant.dk \
--cc=joel@jms.id.au \
--cc=k.jensen@samsung.com \
--cc=kbusch@kernel.org \
--cc=matt@codeconstruct.com.au \
--cc=peter.maydell@linaro.org \
--cc=peter@pjd.dev \
--cc=qemu-arm@nongnu.org \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.