All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jonathan Cameron via <qemu-arm@nongnu.org>
To: Klaus Jensen <its@irrelevant.dk>
Cc: qemu-devel@nongnu.org, "Corey Minyard" <cminyard@mvista.com>,
	"Keith Busch" <kbusch@kernel.org>,
	"Jason Wang" <jasowang@redhat.com>,
	"Lior Weintraub" <liorw@pliops.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Jeremy Kerr" <jk@codeconstruct.com.au>,
	qemu-arm@nongnu.org, "Matt Johnston" <matt@codeconstruct.com.au>,
	"Peter Delevoryas" <peter@pjd.dev>,
	qemu-block@nongnu.org, "Cédric Le Goater" <clg@kaod.org>,
	"Klaus Jensen" <k.jensen@samsung.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	gost.dev@samsung.com
Subject: Re: [PATCH v3 3/3] hw/nvme: add nvme management interface model
Date: Wed, 31 May 2023 16:39:57 +0100	[thread overview]
Message-ID: <20230531163957.0000494e@Huawei.com> (raw)
In-Reply-To: <20230531114744.9946-4-its@irrelevant.dk>

On Wed, 31 May 2023 13:47:44 +0200
Klaus Jensen <its@irrelevant.dk> wrote:

> From: Klaus Jensen <k.jensen@samsung.com>
> 
> Add the 'nmi-i2c' device that emulates an NVMe Management Interface
> controller.
> 
> Initial support is very basic (Read NMI DS, Configuration Get).
> 
> This is based on previously posted code by Padmakar Kalghatgi, Arun
> Kumar Agasar and Saurav Kumar.
> 
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>

A few comments inline - I dug into the specs this time so some
new questions.

Jonathan

> diff --git a/hw/nvme/nmi-i2c.c b/hw/nvme/nmi-i2c.c
> new file mode 100644
> index 000000000000..38e43e48fa51
> --- /dev/null
> +++ b/hw/nvme/nmi-i2c.c
> @@ -0,0 +1,367 @@
> +/*
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * SPDX-FileCopyrightText: Copyright (c) 2022 Samsung Electronics Co., Ltd.

Update to 2023?

> +typedef struct NMIRequest {
> +   uint8_t opc;
> +   uint8_t rsvd1[3];
> +   uint32_t dw0;
> +   uint32_t dw1;
> +   uint32_t mic;
> +} NMIRequest;
> +
> +typedef struct NMIResponse {
> +    uint8_t status;
> +    uint8_t response[3];
> +    uint8_t payload[]; /* includes the Message Integrity Check */
> +} NMIResponse;

Not used.

> +
> +typedef enum NMIReadDSType {
> +    NMI_CMD_READ_NMI_DS_SUBSYSTEM       = 0x0,
> +    NMI_CMD_READ_NMI_DS_PORTS           = 0x1,
> +    NMI_CMD_READ_NMI_DS_CTRL_LIST       = 0x2,
> +    NMI_CMD_READ_NMI_DS_CTRL_INFO       = 0x3,
> +    NMI_CMD_READ_NMI_DS_CMD_SUPPORT     = 0x4,
> +    NMI_CMD_READ_NMI_DS_MEB_CMD_SUPPORT = 0x5,
> +} NMIReadDSType;
> +
> +static void nmi_set_parameter_error(NMIDevice *nmi, uint8_t bit, uint16_t byte)
> +{
> +    nmi->scratch[nmi->pos++] = 0x4;
> +    nmi->scratch[nmi->pos++] = bit;

Mask bit to only 3 bits?

> +    nmi->scratch[nmi->pos++] = (byte >> 4) & 0xf;
> +    nmi->scratch[nmi->pos++] = byte & 0xf;

Not following how byte is split up.  Figure 29 in 1.1d suggests it should be
in bits 23:08 and this doesn't match that.  Perhaps a reference given I guess
I'm looking at wrong thing.

> +}

> +static void nmi_handle_mi_read_nmi_ds(NMIDevice *nmi, NMIRequest *request)
> +{
> +    I2CSlave *i2c = I2C_SLAVE(nmi);
> +
> +    uint32_t dw0 = le32_to_cpu(request->dw0);
> +    uint8_t dtyp = (dw0 >> 24) & 0xf;
> +    uint8_t *buf;
> +    size_t len;
> +
> +    trace_nmi_handle_mi_read_nmi_ds(dtyp);
> +
> +    static uint8_t nmi_ds_subsystem[36] = {
> +        0x00,       /* success */
> +        0x20,       /* response data length */

Not the easiest datasheet to read, but I think length is 2 bytes.
Figure 93 in the 1.2b NMI spec has it as bits 15:00 in
a 24 bit field. Ah. I see this is 1.1 definition, in that it's
the same but in figure 89.


> +        0x00, 0x00, /* reserved */
> +        0x00,       /* number of ports */
> +        0x01,       /* major version */
> +        0x01,       /* minor version */
> +    };
> +
> +    static uint8_t nmi_ds_ports[36] = {
> +        0x00,       /* success */
> +        0x20,       /* response data length */

As above - this is 2 bytes.

> +        0x00, 0x00, /* reserved */
> +        0x02,       /* port type (smbus) */
> +        0x00,       /* reserved */
> +        0x40, 0x00, /* maximum mctp transission unit size (64 bytes) */
> +        0x00, 0x00, 0x00, 0x00, /* management endpoint buffer size */
> +        0x00, 0x00, /* vpd i2c address/freq */

Give separate bytes for the two things, why not just have two lines and
a comment for each one?

> +        0x00, 0x01, /* management endpoint i2c address/freq */

Same here though second byte isn't anything to do with frequency. Documnted
as NVMe Basic Management and indicates if that command is supported.

> +    };
> +
> +    static uint8_t nmi_ds_empty[8] = {
> +        0x00,       /* success */
> +        0x02,       /* response data length */
> +        0x00, 0x00, /* reserved */
> +        0x00, 0x00, /* number of controllers */
A reference for this would be good as I'm not sure it's defined in the NMI spec.
Is it the controller list from 4.4.1 in the main NVME 2.0 spec?


> +        0x00, 0x00, /* padding */
> +    };
> +
> +    switch (dtyp) {
> +    case NMI_CMD_READ_NMI_DS_SUBSYSTEM:
> +        len = 36;
sizeof(nmi_ds_subsystem)  Might as well keep that 36 in just one place.
> +        buf = nmi_ds_subsystem;
> +
> +        break;
> +
> +    case NMI_CMD_READ_NMI_DS_PORTS:
> +        len = 36;
> +        buf = nmi_ds_ports;
same here?
> +
> +        /* patch in the i2c address of the endpoint */
> +        buf[14] = i2c->address;

If you have multiple instances of this as they will
race over the static buffer.  Just make it non static and add
a comment on why.

> +
> +        break;
> +
> +    case NMI_CMD_READ_NMI_DS_CTRL_LIST:
> +    case NMI_CMD_READ_NMI_DS_CMD_SUPPORT:
> +    case NMI_CMD_READ_NMI_DS_MEB_CMD_SUPPORT:
> +        len = 8;
> +        buf = nmi_ds_empty;
> +
> +        break;
> +
> +    default:
> +        nmi_set_parameter_error(nmi, offsetof(NMIRequest, dw0) + 4, 0);
> +
> +        return;
> +    }
> +
> +    memcpy(nmi->scratch + nmi->pos, buf, len);
> +    nmi->pos += len;
> +}
> +
> +enum {
> +    NMI_CMD_CONFIGURATION_GET_SMBUS_FREQ                = 0x1,
> +    NMI_CMD_CONFIGURATION_GET_HEALTH_STATUS_CHANGE      = 0x2,
> +    NMI_CMD_CONFIGURATION_GET_MCTP_TRANSMISSION_UNIT    = 0x3,
> +};
> +
> +static void nmi_handle_mi_config_get(NMIDevice *nmi, NMIRequest *request)
> +{
> +    uint32_t dw0 = le32_to_cpu(request->dw0);
> +    uint8_t identifier = dw0 & 0xff;
> +    uint8_t *buf;
> +
> +    static uint8_t smbus_freq[4] = {
> +        0x00,               /* success */
> +        0x01, 0x00, 0x00,   /* 100 kHz */
> +    };
> +
> +    static uint8_t mtu[4] = {
> +        0x00,               /* success */
> +        0x40, 0x00, 0x00,   /* 64 */

2 bytes only I think with another reserved.
Figure 66 in 1.1d

> +    };
> +
> +    trace_nmi_handle_mi_config_get(identifier);
> +
> +    switch (identifier) {
> +    case NMI_CMD_CONFIGURATION_GET_SMBUS_FREQ:
> +        buf = smbus_freq;
> +        break;
> +
> +    case NMI_CMD_CONFIGURATION_GET_MCTP_TRANSMISSION_UNIT:
> +        buf = mtu;
> +        break;
> +
> +    default:
> +        nmi_set_parameter_error(nmi, 0x0, offsetof(NMIRequest, dw0));
> +        return;
> +    }
> +
> +    memcpy(nmi->scratch + nmi->pos, buf, 4);
> +    nmi->pos += 4;
> +}
> +
> +enum {
> +    NMI_CMD_READ_NMI_DS         = 0x0,
> +    NMI_CMD_CONFIGURATION_GET   = 0x4,
> +};
> +
> +static void nmi_handle_mi(NMIDevice *nmi, NMIMessage *msg)
> +{
> +    NMIRequest *request = (NMIRequest *)msg->payload;
> +
> +    trace_nmi_handle_mi(request->opc);
> +
> +    switch (request->opc) {
> +    case NMI_CMD_READ_NMI_DS:
> +        nmi_handle_mi_read_nmi_ds(nmi, request);
> +        break;
> +
> +    case NMI_CMD_CONFIGURATION_GET:
> +        nmi_handle_mi_config_get(nmi, request);
> +        break;
> +
> +    default:
> +        nmi_set_parameter_error(nmi, 0x0, 0x0);
> +        fprintf(stderr, "nmi command 0x%x not handled\n", request->opc);
> +
> +        break;
> +    }
> +}
> +
> +enum {
> +    NMI_MESSAGE_TYPE_NMI = 0x1,
> +};
> +



> +static size_t nmi_get_types(MCTPI2CEndpoint *mctp, const uint8_t **data)
> +{
> +    static const uint8_t buf[] = {
> +        0x0, 0x1, MCTP_MESSAGE_TYPE_NMI,
> +    };

Perhaps a comment that the 0x1 is the length.  Or you could define
a structure for this with a variable length final field?

Also, should the control type be reported?  I couldn't find a statement
that it shouldn't and it has a message ID.

> +
> +    *data = buf;
> +
> +    return sizeof(buf);
> +}
> +

WARNING: multiple messages have this Message-ID (diff)
From: Jonathan Cameron via <qemu-devel@nongnu.org>
To: Klaus Jensen <its@irrelevant.dk>
Cc: qemu-devel@nongnu.org, "Corey Minyard" <cminyard@mvista.com>,
	"Keith Busch" <kbusch@kernel.org>,
	"Jason Wang" <jasowang@redhat.com>,
	"Lior Weintraub" <liorw@pliops.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Jeremy Kerr" <jk@codeconstruct.com.au>,
	qemu-arm@nongnu.org, "Matt Johnston" <matt@codeconstruct.com.au>,
	"Peter Delevoryas" <peter@pjd.dev>,
	qemu-block@nongnu.org, "Cédric Le Goater" <clg@kaod.org>,
	"Klaus Jensen" <k.jensen@samsung.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	gost.dev@samsung.com
Subject: Re: [PATCH v3 3/3] hw/nvme: add nvme management interface model
Date: Wed, 31 May 2023 16:39:57 +0100	[thread overview]
Message-ID: <20230531163957.0000494e@Huawei.com> (raw)
In-Reply-To: <20230531114744.9946-4-its@irrelevant.dk>

On Wed, 31 May 2023 13:47:44 +0200
Klaus Jensen <its@irrelevant.dk> wrote:

> From: Klaus Jensen <k.jensen@samsung.com>
> 
> Add the 'nmi-i2c' device that emulates an NVMe Management Interface
> controller.
> 
> Initial support is very basic (Read NMI DS, Configuration Get).
> 
> This is based on previously posted code by Padmakar Kalghatgi, Arun
> Kumar Agasar and Saurav Kumar.
> 
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>

A few comments inline - I dug into the specs this time so some
new questions.

Jonathan

> diff --git a/hw/nvme/nmi-i2c.c b/hw/nvme/nmi-i2c.c
> new file mode 100644
> index 000000000000..38e43e48fa51
> --- /dev/null
> +++ b/hw/nvme/nmi-i2c.c
> @@ -0,0 +1,367 @@
> +/*
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * SPDX-FileCopyrightText: Copyright (c) 2022 Samsung Electronics Co., Ltd.

Update to 2023?

> +typedef struct NMIRequest {
> +   uint8_t opc;
> +   uint8_t rsvd1[3];
> +   uint32_t dw0;
> +   uint32_t dw1;
> +   uint32_t mic;
> +} NMIRequest;
> +
> +typedef struct NMIResponse {
> +    uint8_t status;
> +    uint8_t response[3];
> +    uint8_t payload[]; /* includes the Message Integrity Check */
> +} NMIResponse;

Not used.

> +
> +typedef enum NMIReadDSType {
> +    NMI_CMD_READ_NMI_DS_SUBSYSTEM       = 0x0,
> +    NMI_CMD_READ_NMI_DS_PORTS           = 0x1,
> +    NMI_CMD_READ_NMI_DS_CTRL_LIST       = 0x2,
> +    NMI_CMD_READ_NMI_DS_CTRL_INFO       = 0x3,
> +    NMI_CMD_READ_NMI_DS_CMD_SUPPORT     = 0x4,
> +    NMI_CMD_READ_NMI_DS_MEB_CMD_SUPPORT = 0x5,
> +} NMIReadDSType;
> +
> +static void nmi_set_parameter_error(NMIDevice *nmi, uint8_t bit, uint16_t byte)
> +{
> +    nmi->scratch[nmi->pos++] = 0x4;
> +    nmi->scratch[nmi->pos++] = bit;

Mask bit to only 3 bits?

> +    nmi->scratch[nmi->pos++] = (byte >> 4) & 0xf;
> +    nmi->scratch[nmi->pos++] = byte & 0xf;

Not following how byte is split up.  Figure 29 in 1.1d suggests it should be
in bits 23:08 and this doesn't match that.  Perhaps a reference given I guess
I'm looking at wrong thing.

> +}

> +static void nmi_handle_mi_read_nmi_ds(NMIDevice *nmi, NMIRequest *request)
> +{
> +    I2CSlave *i2c = I2C_SLAVE(nmi);
> +
> +    uint32_t dw0 = le32_to_cpu(request->dw0);
> +    uint8_t dtyp = (dw0 >> 24) & 0xf;
> +    uint8_t *buf;
> +    size_t len;
> +
> +    trace_nmi_handle_mi_read_nmi_ds(dtyp);
> +
> +    static uint8_t nmi_ds_subsystem[36] = {
> +        0x00,       /* success */
> +        0x20,       /* response data length */

Not the easiest datasheet to read, but I think length is 2 bytes.
Figure 93 in the 1.2b NMI spec has it as bits 15:00 in
a 24 bit field. Ah. I see this is 1.1 definition, in that it's
the same but in figure 89.


> +        0x00, 0x00, /* reserved */
> +        0x00,       /* number of ports */
> +        0x01,       /* major version */
> +        0x01,       /* minor version */
> +    };
> +
> +    static uint8_t nmi_ds_ports[36] = {
> +        0x00,       /* success */
> +        0x20,       /* response data length */

As above - this is 2 bytes.

> +        0x00, 0x00, /* reserved */
> +        0x02,       /* port type (smbus) */
> +        0x00,       /* reserved */
> +        0x40, 0x00, /* maximum mctp transission unit size (64 bytes) */
> +        0x00, 0x00, 0x00, 0x00, /* management endpoint buffer size */
> +        0x00, 0x00, /* vpd i2c address/freq */

Give separate bytes for the two things, why not just have two lines and
a comment for each one?

> +        0x00, 0x01, /* management endpoint i2c address/freq */

Same here though second byte isn't anything to do with frequency. Documnted
as NVMe Basic Management and indicates if that command is supported.

> +    };
> +
> +    static uint8_t nmi_ds_empty[8] = {
> +        0x00,       /* success */
> +        0x02,       /* response data length */
> +        0x00, 0x00, /* reserved */
> +        0x00, 0x00, /* number of controllers */
A reference for this would be good as I'm not sure it's defined in the NMI spec.
Is it the controller list from 4.4.1 in the main NVME 2.0 spec?


> +        0x00, 0x00, /* padding */
> +    };
> +
> +    switch (dtyp) {
> +    case NMI_CMD_READ_NMI_DS_SUBSYSTEM:
> +        len = 36;
sizeof(nmi_ds_subsystem)  Might as well keep that 36 in just one place.
> +        buf = nmi_ds_subsystem;
> +
> +        break;
> +
> +    case NMI_CMD_READ_NMI_DS_PORTS:
> +        len = 36;
> +        buf = nmi_ds_ports;
same here?
> +
> +        /* patch in the i2c address of the endpoint */
> +        buf[14] = i2c->address;

If you have multiple instances of this as they will
race over the static buffer.  Just make it non static and add
a comment on why.

> +
> +        break;
> +
> +    case NMI_CMD_READ_NMI_DS_CTRL_LIST:
> +    case NMI_CMD_READ_NMI_DS_CMD_SUPPORT:
> +    case NMI_CMD_READ_NMI_DS_MEB_CMD_SUPPORT:
> +        len = 8;
> +        buf = nmi_ds_empty;
> +
> +        break;
> +
> +    default:
> +        nmi_set_parameter_error(nmi, offsetof(NMIRequest, dw0) + 4, 0);
> +
> +        return;
> +    }
> +
> +    memcpy(nmi->scratch + nmi->pos, buf, len);
> +    nmi->pos += len;
> +}
> +
> +enum {
> +    NMI_CMD_CONFIGURATION_GET_SMBUS_FREQ                = 0x1,
> +    NMI_CMD_CONFIGURATION_GET_HEALTH_STATUS_CHANGE      = 0x2,
> +    NMI_CMD_CONFIGURATION_GET_MCTP_TRANSMISSION_UNIT    = 0x3,
> +};
> +
> +static void nmi_handle_mi_config_get(NMIDevice *nmi, NMIRequest *request)
> +{
> +    uint32_t dw0 = le32_to_cpu(request->dw0);
> +    uint8_t identifier = dw0 & 0xff;
> +    uint8_t *buf;
> +
> +    static uint8_t smbus_freq[4] = {
> +        0x00,               /* success */
> +        0x01, 0x00, 0x00,   /* 100 kHz */
> +    };
> +
> +    static uint8_t mtu[4] = {
> +        0x00,               /* success */
> +        0x40, 0x00, 0x00,   /* 64 */

2 bytes only I think with another reserved.
Figure 66 in 1.1d

> +    };
> +
> +    trace_nmi_handle_mi_config_get(identifier);
> +
> +    switch (identifier) {
> +    case NMI_CMD_CONFIGURATION_GET_SMBUS_FREQ:
> +        buf = smbus_freq;
> +        break;
> +
> +    case NMI_CMD_CONFIGURATION_GET_MCTP_TRANSMISSION_UNIT:
> +        buf = mtu;
> +        break;
> +
> +    default:
> +        nmi_set_parameter_error(nmi, 0x0, offsetof(NMIRequest, dw0));
> +        return;
> +    }
> +
> +    memcpy(nmi->scratch + nmi->pos, buf, 4);
> +    nmi->pos += 4;
> +}
> +
> +enum {
> +    NMI_CMD_READ_NMI_DS         = 0x0,
> +    NMI_CMD_CONFIGURATION_GET   = 0x4,
> +};
> +
> +static void nmi_handle_mi(NMIDevice *nmi, NMIMessage *msg)
> +{
> +    NMIRequest *request = (NMIRequest *)msg->payload;
> +
> +    trace_nmi_handle_mi(request->opc);
> +
> +    switch (request->opc) {
> +    case NMI_CMD_READ_NMI_DS:
> +        nmi_handle_mi_read_nmi_ds(nmi, request);
> +        break;
> +
> +    case NMI_CMD_CONFIGURATION_GET:
> +        nmi_handle_mi_config_get(nmi, request);
> +        break;
> +
> +    default:
> +        nmi_set_parameter_error(nmi, 0x0, 0x0);
> +        fprintf(stderr, "nmi command 0x%x not handled\n", request->opc);
> +
> +        break;
> +    }
> +}
> +
> +enum {
> +    NMI_MESSAGE_TYPE_NMI = 0x1,
> +};
> +



> +static size_t nmi_get_types(MCTPI2CEndpoint *mctp, const uint8_t **data)
> +{
> +    static const uint8_t buf[] = {
> +        0x0, 0x1, MCTP_MESSAGE_TYPE_NMI,
> +    };

Perhaps a comment that the 0x1 is the length.  Or you could define
a structure for this with a variable length final field?

Also, should the control type be reported?  I couldn't find a statement
that it shouldn't and it has a message ID.

> +
> +    *data = buf;
> +
> +    return sizeof(buf);
> +}
> +


  reply	other threads:[~2023-05-31 15:40 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-31 11:47 [PATCH v3 0/3] hw/{i2c, nvme}: mctp endpoint, nvme management interface model Klaus Jensen
2023-05-31 11:47 ` [PATCH v3 1/3] hw/i2c: add smbus pec utility function Klaus Jensen
2023-05-31 13:13   ` Jonathan Cameron via
2023-05-31 13:13     ` Jonathan Cameron via
2023-06-01 20:34   ` Philippe Mathieu-Daudé
2023-05-31 11:47 ` [PATCH v3 2/3] hw/i2c: add mctp core Klaus Jensen
2023-05-31 14:59   ` Jonathan Cameron via
2023-05-31 14:59     ` Jonathan Cameron via
2023-05-31 15:04     ` Jonathan Cameron via
2023-05-31 15:04       ` Jonathan Cameron via
2023-05-31 11:47 ` [PATCH v3 3/3] hw/nvme: add nvme management interface model Klaus Jensen
2023-05-31 15:39   ` Jonathan Cameron via [this message]
2023-05-31 15:39     ` Jonathan Cameron via
2023-06-01 19:42 ` [PATCH v3 0/3] hw/{i2c, nvme}: mctp endpoint, " Corey Minyard

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=20230531163957.0000494e@Huawei.com \
    --to=qemu-arm@nongnu.org \
    --cc=Jonathan.Cameron@Huawei.com \
    --cc=clg@kaod.org \
    --cc=cminyard@mvista.com \
    --cc=gost.dev@samsung.com \
    --cc=its@irrelevant.dk \
    --cc=jasowang@redhat.com \
    --cc=jk@codeconstruct.com.au \
    --cc=k.jensen@samsung.com \
    --cc=kbusch@kernel.org \
    --cc=liorw@pliops.com \
    --cc=matt@codeconstruct.com.au \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=peter@pjd.dev \
    --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.