[RFC PATCH v2 1/2] Adding i2c interface for qemu
Padmakar
p.kalghatgi at samsung.com
Mon Aug 2 10:22:01 PDT 2021
From: padmakar <p.kalghatgi at samsung.com>
The changes here includes the interface for i2c/smbus
for nvme-mi protocol. We have used an address of 0x15
using which the guest VM can send and recieve the nvme-mi
commands. Since the nvme-mi device uses the I2C_SLAVE as
parent, we have used the send and recieve callbacks by
which the nvme-mi device will get the required notification.
With the callback approach, we have eliminated the use of
threads.
Please provide us with your valuable feedback on this patch.
---
hw/nvme/nvme-mi.c | 152 ++++++++++++++++++++++--------------------------------
hw/nvme/nvme-mi.h | 23 ++++++---
2 files changed, 79 insertions(+), 96 deletions(-)
diff --git a/hw/nvme/nvme-mi.c b/hw/nvme/nvme-mi.c
index 5e93417..a90ce90 100644
--- a/hw/nvme/nvme-mi.c
+++ b/hw/nvme/nvme-mi.c
@@ -4,7 +4,7 @@
* Copyright (c) 2021, Samsung Electronics co Ltd.
*
* Written by Padmakar Kalghatgi <p.kalghatgi at samsung.com>
- * Arun Kumar Agasar <arun.ag at partner.samsung.com>
+ * Arun Kumar Agasar <arun.kka at samsung.com>
* Saurav Kumar <saurav.29 at partner.samsung.com>
*
* This code is licensed under the GNU GPL v2 or later.
@@ -19,10 +19,8 @@
* The nvme-mi device has to be used along with nvme device only
*
* Add options:
- * -device nvme-mi,bus=<nvme bus number>
- * -device vhost-vsock-pci, guest-cid=<vsock cid>
+ * -device nvme-mi,nvme=<nvme id>,address=0x15",
*
- * the cid is used to connect to the vsock
*/
#include "qemu/osdep.h"
@@ -41,8 +39,8 @@ static void nvme_mi_send_resp(NvmeMiCtrl *ctrl_mi, uint8_t *resp, uint32_t size)
{
uint32_t crc_value = crc32c(0xFFFFFFFF, resp, size);
size += 4;
- uint32_t retries = 5;
uint32_t offset = 0;
+ uint32_t ofst = 0;
uint32_t som = 1;
uint32_t eom = 0;
uint32_t pktseq = 0;
@@ -51,24 +49,17 @@ static void nvme_mi_send_resp(NvmeMiCtrl *ctrl_mi, uint8_t *resp, uint32_t size)
uint32_t sizesent = size > mtus ? mtus : size;
size -= sizesent;
eom = size > 0 ? 0 : 1;
- g_autofree uint8_t *buf = (uint8_t *)g_malloc(sizesent + 8);
+ g_autofree uint8_t *buf = (uint8_t *)g_malloc0(sizesent + 8);
buf[2] = sizesent + 5;
buf[7] = (som << 7) | (eom << 6) | (pktseq << 5);
som = 0;
memcpy(buf + 8, resp + offset, sizesent);
offset += sizesent;
if (size <= 0) {
- memcpy(buf + 4 + offset , &crc_value, sizeof(crc_value));
- }
- retries = 5;
- while (retries > 0) {
- int32_t nsend = send(ctrl_mi->sock_desc, buf, sizesent + 8, 0);
- if (nsend < 0) {
- retries--;
- } else {
- break;
- }
+ memcpy(buf + 8 + offset , &crc_value, sizeof(crc_value));
}
+ memcpy(ctrl_mi->misendrecv.sendrecvbuf + ofst, buf, sizesent + 8);
+ ofst += sizesent + 8;
}
}
@@ -176,7 +167,6 @@ static void nvme_mi_controller_health_ds(NvmeMiCtrl *ctrl_mi,
(dword1 & 0x2)) {
nvme_mi_chds.cwarn.temp_above_or_under_thresh = 0x1;
}
- printf("size = %lu\n", sizeof(resp) + sizeof(NvmeMiCtrlHealthDs));
g_autofree uint8_t *resp_buf = (uint8_t *)g_malloc(sizeof(resp) +
sizeof(NvmeMiCtrlHealthDs));
resp.mgmt_resp = 1 << 0x10;
@@ -283,9 +273,8 @@ static void nvme_mi_vpd_read(NvmeMiCtrl *ctrl_mi, NvmeMIRequest *req)
nvme_mi_send_resp(ctrl_mi, resp_buf, dlen + sizeof(resp));
}
}
-
-static void nvme_mi_vpd_write(NvmeMiCtrl *ctrl_mi, NvmeMIRequest *req,
- uint8_t *buf)
+static void nvme_mi_vpd_write(NvmeMiCtrl *ctrl_mi,
+ NvmeMIRequest *req, uint8_t *buf)
{
uint16_t dofst = (req->dword0 & 0xFFFF);
uint16_t dlen = (req->dword1 & 0xFFFF);
@@ -308,7 +297,7 @@ static void nvme_mi_nvm_subsys_health_status_poll(NvmeMiCtrl *ctrl_mi,
NvmeMiNvmSubsysHspds nshds;
nvme_mi_resp_hdr_init(&resp, false);
for (uint32_t cntlid = 1; cntlid < ARRAY_SIZE(ctrl_mi->n->subsys->ctrls);
- cntlid++) {
+ cntlid++) {
NvmeCtrl *ctrl = nvme_subsys_ctrl(ctrl_mi->n->subsys, cntlid);
if (!ctrl) {
@@ -335,7 +324,8 @@ static void nvme_mi_nvm_subsys_health_status_poll(NvmeMiCtrl *ctrl_mi,
}
- g_autofree uint8_t *resp_buf = (uint8_t *)g_malloc(sizeof(resp) + sizeof(nshds));
+ g_autofree uint8_t *resp_buf = (uint8_t *)g_malloc(sizeof(resp) +
+ sizeof(nshds));
memcpy(resp_buf, &resp, sizeof(resp));
memcpy(resp_buf + sizeof(resp), &nshds, sizeof(nshds));
nvme_mi_send_resp(ctrl_mi, resp_buf, sizeof(resp_buf));
@@ -553,15 +543,12 @@ static void nvme_mi_admin_command(NvmeMiCtrl *ctrl_mi, void* req_arg)
NvmeAdminMIRequest *req = (NvmeAdminMIRequest *) (msg);
switch (req->opc) {
case NVME_ADM_MI_CMD_IDENTIFY:
- printf("identify\n");
nvme_mi_admin_identify(ctrl_mi, req);
break;
case NVME_ADM_MI_CMD_GET_LOG_PAGE:
- printf("get log page\n");
nvme_mi_admin_get_log_page(ctrl_mi, req);
break;
case NVME_ADM_MI_CMD_GET_FEATURES:
- printf("get features\n");
nvme_mi_admin_get_features(ctrl_mi, req);
break;
default:
@@ -578,92 +565,79 @@ static void nvme_mi_admin_command(NvmeMiCtrl *ctrl_mi, void* req_arg)
return;
}
-static void nvme_mi_init(NvmeMiCtrl *ctrl_mi)
+static uint8_t nvme_mi_i2c_recv(I2CSlave *s)
{
- pthread_t vsock_tid;
- pthread_create(&vsock_tid, NULL, vsock_server_start, ctrl_mi);
- pthread_detach(vsock_tid);
+ NvmeMiCtrl *mictrl = (NvmeMiCtrl *)s;
+ NvmeMiSendRecvStruct *misendrecv = &mictrl->misendrecv;
+ if (misendrecv->bsyncflag == true) {
+ return -1;
+ }
+ return misendrecv->sendrecvbuf[misendrecv->sendlen++];
}
-void *vsock_server_start(void *arg)
+static int nvme_mi_i2c_send(I2CSlave *s, uint8_t data)
{
- NvmeMiCtrl *ctrl_mi = (NvmeMiCtrl *)arg;
- int listenfd = 0, c = 0;
- struct sockaddr_vm sa = {
- .svm_family = AF_VSOCK,
- .svm_cid = VMADDR_CID_ANY,
- .svm_port = 1342,
- };
- struct sockaddr_vm client;
- listenfd = socket(AF_VSOCK, SOCK_STREAM, 0);
- if (listenfd == -1) {
- pthread_exit(NULL);
- }
- if (bind(listenfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
- pthread_exit(NULL);
+ NvmeMiCtrl *mictrl = (NvmeMiCtrl *)s;
+ NvmeMiSendRecvStruct *misendrecv = &mictrl->misendrecv;
+
+ misendrecv->bsyncflag = true;
+ misendrecv->sendlen = 0;
+ switch (misendrecv->len) {
+ case 1:
+ misendrecv->total_len = data;
+ break;
+ case 6:
+ misendrecv->eom = (data & 0x40) >> 6;
+ break;
}
- listen(listenfd, 1);
- puts("Waiting for incoming connections...");
- c = sizeof(struct sockaddr_vm);
- while (1) {
- ctrl_mi->sock_desc = accept(listenfd, (struct sockaddr *)&client,
- (socklen_t *)&c);
- if ((ctrl_mi->sock_desc) < 0) {
- continue;
- }
-
- NvmeMiMctpHeader mctp_hdr;
- uint32_t total_len = 0;
- uint8_t *getdata_buf = NULL;
- while (!mctp_hdr.EOM) {
- uint8_t buf[7];
- recv(ctrl_mi->sock_desc, buf, 7, 0);
- mctp_hdr.byte_count = buf[1];
- mctp_hdr.EOM = (buf[6] & 0x40) >> 6;
- mctp_hdr.SOM = (buf[6] & 0x80) >> 7;
- mctp_hdr.pckt_seq = (buf[6] & 0x20) >> 5;
-
- uint32_t curr_len = total_len;
- total_len = total_len + (mctp_hdr.byte_count - 5);
-
- getdata_buf = (uint8_t *)g_realloc(getdata_buf, total_len);
- recv(ctrl_mi->sock_desc, getdata_buf + curr_len,
- (mctp_hdr.byte_count - 5), 0);
+ misendrecv->sendrecvbuf[++misendrecv->len] = data;
+ if (misendrecv->len == misendrecv->total_len + 3) {
+ misendrecv->cmdbuffer = (uint8_t *)g_realloc(misendrecv->cmdbuffer,
+ misendrecv->len - 5);
+ memcpy(misendrecv->cmdbuffer + misendrecv->offset,
+ misendrecv->sendrecvbuf + 8, misendrecv->len - 5);
+
+ misendrecv->offset = misendrecv->len - 5;
+ misendrecv->total_len = 0;
+ misendrecv->len = 0;
+
+ if (misendrecv->eom == 1) {
+ nvme_mi_admin_command(mictrl, misendrecv->cmdbuffer);
+ misendrecv->offset = 0;
+ misendrecv->bsyncflag = false;
}
- NvmeMiMessageHeader msghdr;
- memcpy(&msghdr, getdata_buf, sizeof(NvmeMiMessageHeader));
- nvme_mi_admin_command(ctrl_mi, getdata_buf);
}
- pthread_exit(0);
+ return 0;
}
static void nvme_mi_realize(DeviceState *dev, Error **errp)
{
- NvmeMiCtrl *ctrl_mi = (NvmeMiCtrl *)malloc(sizeof(NvmeMiCtrl));
- BusState *s = qdev_get_parent_bus(dev);
- ctrl_mi->n = NVME(s->parent);
- ctrl_mi->mctp_unit_size = 64;
- ctrl_mi->smbus_freq = 0x01;
- ctrl_mi->sock_desc = 0;
- memset(&ctrl_mi->vpd_data, 0, sizeof(ctrl_mi->vpd_data));
-
- nvme_mi_init(ctrl_mi);
+ NvmeMiCtrl *s = (NvmeMiCtrl *)(dev);
+
+ s->smbus_freq = 100;
+ s->mctp_unit_size = 64;
}
+static Property nvme_mi_props[] = {
+ DEFINE_PROP_LINK("nvme", NvmeMiCtrl, n, TYPE_NVME,
+ NvmeCtrl *),
+ DEFINE_PROP_END_OF_LIST(),
+};
static void nvme_mi_class_init(ObjectClass *oc, void *data)
{
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-
- dc->bus_type = TYPE_NVME_BUS;
dc->realize = nvme_mi_realize;
- dc->desc = "nvme mi";
+ k->recv = nvme_mi_i2c_recv;
+ k->send = nvme_mi_i2c_send;
+
+ device_class_set_props(dc, nvme_mi_props);
}
static const TypeInfo nvme_mi = {
.name = TYPE_NVME_MI,
- .parent = TYPE_DEVICE,
+ .parent = TYPE_I2C_SLAVE,
.instance_size = sizeof(NvmeMiCtrl),
.class_init = nvme_mi_class_init,
};
diff --git a/hw/nvme/nvme-mi.h b/hw/nvme/nvme-mi.h
index 4c155a0..92a20e6 100644
--- a/hw/nvme/nvme-mi.h
+++ b/hw/nvme/nvme-mi.h
@@ -5,7 +5,7 @@
*
* Authors:
* Padmakar Kalghatgi <p.kalghatgi at samsung.com>
- * Arun Kumar Agasar <arun.ag at partner.samsung.com>
+ * Arun Kumar Agasar <arun.kka at samsung.com>
* Saurav Kumar <saurav.29 at partner.samsung.com>
*
* This code is licensed under the GNU GPL v2 or later.
@@ -14,14 +14,12 @@
#ifndef NVME_MI_H
#define NVME_MI_H
-#include <sys/socket.h>
-#include <linux/vm_sockets.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
-#include <pthread.h>
+#include "hw/i2c/i2c.h"
#define TYPE_NVME_MI "nvme-mi"
@@ -32,17 +30,28 @@
#define OPT_SUPP_CMD_LIST 4
#define MGMT_EPT_BUFF_CMD_SUPP_LIST 5
+
+typedef struct NvmeMiSendRecvStruct {
+ uint32_t sendlen;
+ uint8_t len;
+ uint8_t total_len;
+ uint32_t offset;
+ uint8_t eom;
+ bool bsyncflag;
+ u_char sendrecvbuf[5000];
+ uint8_t *cmdbuffer;
+} NvmeMiSendRecvStruct;
typedef struct NvmeMiVpdElements {
long common_header;
} NvmeMiVpdElements;
typedef struct NvmeMiCtrl {
- int32_t sock_desc;
+ I2CSlave parent_obj;
uint32_t mctp_unit_size;
uint32_t smbus_freq;
- NvmeCtrl *n;
NvmeMiVpdElements vpd_data;
- u_char dummy[1000];
+ NvmeMiSendRecvStruct misendrecv;
+ NvmeCtrl *n;
} NvmeMiCtrl;
enum NvmeMiMngmtInterfaceCmdSetsOpcodes {
--
2.7.0.windows.1
More information about the Linux-nvme
mailing list