* [PATCH] i2c: virtio: add a virtio i2c frontend driver
@ 2020-09-03 5:34 Jie Deng
2020-09-03 6:12 ` Jason Wang
` (4 more replies)
0 siblings, 5 replies; 14+ messages in thread
From: Jie Deng @ 2020-09-03 5:34 UTC (permalink / raw)
To: linux-i2c, virtualization, linux-kernel
Cc: mst, jasowang, wsa+renesas, wsa, andriy.shevchenko,
jarkko.nikula, jdelvare, Sergey.Semin, krzk, rppt, jie.deng,
loic.poulain, tali.perry1, bjorn.andersson, shuo.a.liu,
conghui.chen, yu1.wang
Add an I2C bus driver for virtio para-virtualization.
The controller can be emulated by the backend driver in
any device model software by following the virtio protocol.
This driver communicates with the backend driver through a
virtio I2C message structure which includes following parts:
- Header: i2c_msg addr, flags, len.
- Data buffer: the pointer to the i2c msg data.
- Status: the processing result from the backend.
People may implement different backend drivers to emulate
different controllers according to their needs. A backend
example can be found in the device model of the open source
project ACRN. For more information, please refer to
https://projectacrn.org.
The virtio device ID 34 is used for this I2C adpter since IDs
before 34 have been reserved by other virtio devices.
Co-developed-by: Conghui Chen <conghui.chen@intel.com>
Signed-off-by: Conghui Chen <conghui.chen@intel.com>
Signed-off-by: Jie Deng <jie.deng@intel.com>
Reviewed-by: Shuo Liu <shuo.a.liu@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/i2c/busses/Kconfig | 11 ++
drivers/i2c/busses/Makefile | 3 +
drivers/i2c/busses/i2c-virtio.c | 276 ++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/virtio_ids.h | 1 +
4 files changed, 291 insertions(+)
create mode 100644 drivers/i2c/busses/i2c-virtio.c
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 293e7a0..70c8e30 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -21,6 +21,17 @@ config I2C_ALI1535
This driver can also be built as a module. If so, the module
will be called i2c-ali1535.
+config I2C_VIRTIO
+ tristate "Virtio I2C Adapter"
+ depends on VIRTIO
+ help
+ If you say yes to this option, support will be included for the virtio
+ i2c adapter driver. The hardware can be emulated by any device model
+ software according to the virtio protocol.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-virtio.
+
config I2C_ALI1563
tristate "ALI 1563"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 19aff0e..821acfa 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -6,6 +6,9 @@
# ACPI drivers
obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
+# VIRTIO I2C host controller driver
+obj-$(CONFIG_I2C_VIRTIO) += i2c-virtio.o
+
# PC SMBus host controller drivers
obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
diff --git a/drivers/i2c/busses/i2c-virtio.c b/drivers/i2c/busses/i2c-virtio.c
new file mode 100644
index 0000000..47f9fd1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-virtio.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Virtio I2C Bus Driver
+ *
+ * Copyright (c) 2020 Intel Corporation. All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+
+#define VIRTIO_I2C_MSG_OK 0
+#define VIRTIO_I2C_MSG_ERR 1
+
+/**
+ * struct virtio_i2c_hdr - the virtio I2C message header structure
+ * @addr: i2c_msg addr, the slave address
+ * @flags: i2c_msg flags
+ * @len: i2c_msg len
+ */
+struct virtio_i2c_hdr {
+ __virtio16 addr;
+ __virtio16 flags;
+ __virtio16 len;
+} __packed;
+
+/**
+ * struct virtio_i2c_msg - the virtio I2C message structure
+ * @hdr: the virtio I2C message header
+ * @buf: virtio I2C message data buffer
+ * @status: the processing result from the backend
+ */
+struct virtio_i2c_msg {
+ struct virtio_i2c_hdr hdr;
+ char *buf;
+ u8 status;
+};
+
+/**
+ * struct virtio_i2c - virtio I2C data
+ * @vdev: virtio device for this controller
+ * @completion: completion of virtio I2C message
+ * @adap: I2C adapter for this controller
+ * @i2c_lock: lock for virtqueue processing
+ * @vq: the virtio virtqueue for communication
+ */
+struct virtio_i2c {
+ struct virtio_device *vdev;
+ struct completion completion;
+ struct i2c_adapter adap;
+ struct mutex i2c_lock;
+ struct virtqueue *vq;
+};
+
+static void virtio_i2c_msg_done(struct virtqueue *vq)
+{
+ struct virtio_i2c *vi = vq->vdev->priv;
+
+ complete(&vi->completion);
+}
+
+static int virtio_i2c_add_msg(struct virtqueue *vq,
+ struct virtio_i2c_msg *vmsg,
+ struct i2c_msg *msg)
+{
+ struct scatterlist *sgs[3], hdr, bout, bin, status;
+ int outcnt = 0, incnt = 0;
+
+ if (!msg->len)
+ return -EINVAL;
+
+ vmsg->hdr.addr = msg->addr;
+ vmsg->hdr.flags = msg->flags;
+ vmsg->hdr.len = msg->len;
+
+ vmsg->buf = kzalloc(vmsg->hdr.len, GFP_KERNEL);
+ if (!vmsg->buf)
+ return -ENOMEM;
+
+ sg_init_one(&hdr, &vmsg->hdr, sizeof(struct virtio_i2c_hdr));
+ sgs[outcnt++] = &hdr;
+ if (vmsg->hdr.flags & I2C_M_RD) {
+ sg_init_one(&bin, vmsg->buf, msg->len);
+ sgs[outcnt + incnt++] = &bin;
+ } else {
+ memcpy(vmsg->buf, msg->buf, msg->len);
+ sg_init_one(&bout, vmsg->buf, msg->len);
+ sgs[outcnt++] = &bout;
+ }
+ sg_init_one(&status, &vmsg->status, sizeof(vmsg->status));
+ sgs[outcnt + incnt++] = &status;
+
+ return virtqueue_add_sgs(vq, sgs, outcnt, incnt, vmsg, GFP_KERNEL);
+}
+
+static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct virtio_i2c *vi = i2c_get_adapdata(adap);
+ struct virtio_i2c_msg *vmsg_o, *vmsg_i;
+ struct virtqueue *vq = vi->vq;
+ unsigned long time_left;
+ int len, i, ret = 0;
+
+ vmsg_o = kzalloc(sizeof(*vmsg_o), GFP_KERNEL);
+ if (!vmsg_o)
+ return -ENOMEM;
+
+ mutex_lock(&vi->i2c_lock);
+ vmsg_o->buf = NULL;
+ for (i = 0; i < num; i++) {
+ ret = virtio_i2c_add_msg(vq, vmsg_o, &msgs[i]);
+ if (ret) {
+ dev_err(&adap->dev, "failed to add msg[%d] to virtqueue.\n", i);
+ goto err_unlock_free;
+ }
+
+ virtqueue_kick(vq);
+
+ time_left = wait_for_completion_timeout(&vi->completion, adap->timeout);
+ if (!time_left) {
+ dev_err(&adap->dev, "msg[%d]: addr=0x%x timeout.\n", i, msgs[i].addr);
+ ret = i;
+ goto err_unlock_free;
+ }
+
+ vmsg_i = (struct virtio_i2c_msg *)virtqueue_get_buf(vq, &len);
+ if (vmsg_i) {
+ /* vmsg_i should point to the same address with vmsg_o */
+ if (vmsg_i != vmsg_o) {
+ dev_err(&adap->dev, "msg[%d]: addr=0x%x virtqueue error.\n",
+ i, vmsg_i->hdr.addr);
+ ret = i;
+ goto err_unlock_free;
+ }
+ if (vmsg_i->status != VIRTIO_I2C_MSG_OK) {
+ dev_err(&adap->dev, "msg[%d]: addr=0x%x error=%d.\n",
+ i, vmsg_i->hdr.addr, vmsg_i->status);
+ ret = i;
+ goto err_unlock_free;
+ }
+ if ((vmsg_i->hdr.flags & I2C_M_RD) && vmsg_i->hdr.len)
+ memcpy(msgs[i].buf, vmsg_i->buf, vmsg_i->hdr.len);
+
+ kfree(vmsg_i->buf);
+ vmsg_i->buf = NULL;
+ }
+ reinit_completion(&vi->completion);
+ }
+ if (i == num)
+ ret = num;
+
+err_unlock_free:
+ mutex_unlock(&vi->i2c_lock);
+ kfree(vmsg_o->buf);
+ kfree(vmsg_o);
+ return ret;
+}
+
+static void virtio_i2c_del_vqs(struct virtio_device *vdev)
+{
+ vdev->config->reset(vdev);
+ vdev->config->del_vqs(vdev);
+}
+
+static int virtio_i2c_setup_vqs(struct virtio_i2c *vi)
+{
+ struct virtio_device *vdev = vi->vdev;
+
+ vi->vq = virtio_find_single_vq(vdev, virtio_i2c_msg_done, "i2c-msg");
+ return PTR_ERR_OR_ZERO(vi->vq);
+}
+
+static u32 virtio_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm virtio_algorithm = {
+ .master_xfer = virtio_i2c_xfer,
+ .functionality = virtio_i2c_func,
+};
+
+static struct i2c_adapter virtio_adapter = {
+ .owner = THIS_MODULE,
+ .name = "Virtio I2C Adapter",
+ .class = I2C_CLASS_DEPRECATED,
+ .algo = &virtio_algorithm,
+};
+
+static int virtio_i2c_probe(struct virtio_device *vdev)
+{
+ struct device *pdev = vdev->dev.parent;
+ struct virtio_i2c *vi;
+ int ret;
+
+ vi = devm_kzalloc(&vdev->dev, sizeof(*vi), GFP_KERNEL);
+ if (!vi)
+ return -ENOMEM;
+
+ vdev->priv = vi;
+ vi->vdev = vdev;
+
+ mutex_init(&vi->i2c_lock);
+ init_completion(&vi->completion);
+
+ ret = virtio_i2c_setup_vqs(vi);
+ if (ret)
+ return ret;
+
+ vi->adap = virtio_adapter;
+ i2c_set_adapdata(&vi->adap, vi);
+ vi->adap.dev.parent = &vdev->dev;
+ /* Setup ACPI node for slave devices which will be probed through ACPI */
+ ACPI_COMPANION_SET(&vi->adap.dev, ACPI_COMPANION(pdev));
+ vi->adap.timeout = HZ / 10;
+ ret = i2c_add_adapter(&vi->adap);
+ if (ret) {
+ dev_err(&vdev->dev, "failed to add virtio-i2c adapter.\n");
+ virtio_i2c_del_vqs(vdev);
+ }
+
+ return ret;
+}
+
+static void virtio_i2c_remove(struct virtio_device *vdev)
+{
+ struct virtio_i2c *vi = vdev->priv;
+
+ i2c_del_adapter(&vi->adap);
+ virtio_i2c_del_vqs(vdev);
+}
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_I2C_ADPTER, VIRTIO_DEV_ANY_ID },
+ {}
+};
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+static int __maybe_unused virtio_i2c_freeze(struct virtio_device *vdev)
+{
+ virtio_i2c_del_vqs(vdev);
+ return 0;
+}
+
+static int __maybe_unused virtio_i2c_restore(struct virtio_device *vdev)
+{
+ return virtio_i2c_setup_vqs(vdev->priv);
+}
+
+static struct virtio_driver virtio_i2c_driver = {
+ .id_table = id_table,
+ .probe = virtio_i2c_probe,
+ .remove = virtio_i2c_remove,
+ .driver = {
+ .name = "i2c_virtio",
+ },
+#ifdef CONFIG_PM_SLEEP
+ .freeze = virtio_i2c_freeze,
+ .restore = virtio_i2c_restore,
+#endif
+};
+module_virtio_driver(virtio_i2c_driver);
+
+MODULE_DESCRIPTION("Virtio i2c bus driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
index b052355..398ef2d 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -48,5 +48,6 @@
#define VIRTIO_ID_FS 26 /* virtio filesystem */
#define VIRTIO_ID_PMEM 27 /* virtio pmem */
#define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
+#define VIRTIO_ID_I2C_ADPTER 34 /* virtio i2c adpter */
#endif /* _LINUX_VIRTIO_IDS_H */
--
2.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-03 5:34 [PATCH] i2c: virtio: add a virtio i2c frontend driver Jie Deng
@ 2020-09-03 6:12 ` Jason Wang
2020-09-03 7:19 ` Jie Deng
2020-09-03 9:58 ` Michael S. Tsirkin
` (3 subsequent siblings)
4 siblings, 1 reply; 14+ messages in thread
From: Jason Wang @ 2020-09-03 6:12 UTC (permalink / raw)
To: Jie Deng, linux-i2c, virtualization, linux-kernel
Cc: mst, wsa+renesas, wsa, andriy.shevchenko, jarkko.nikula,
jdelvare, Sergey.Semin, krzk, rppt, loic.poulain, tali.perry1,
bjorn.andersson, shuo.a.liu, conghui.chen, yu1.wang
On 2020/9/3 下午1:34, Jie Deng wrote:
> Add an I2C bus driver for virtio para-virtualization.
>
> The controller can be emulated by the backend driver in
> any device model software by following the virtio protocol.
>
> This driver communicates with the backend driver through a
> virtio I2C message structure which includes following parts:
>
> - Header: i2c_msg addr, flags, len.
> - Data buffer: the pointer to the i2c msg data.
> - Status: the processing result from the backend.
>
> People may implement different backend drivers to emulate
> different controllers according to their needs. A backend
> example can be found in the device model of the open source
> project ACRN. For more information, please refer to
> https://projectacrn.org.
May I know the reason why don't you use i2c or virtio directly?
>
> The virtio device ID 34 is used for this I2C adpter since IDs
> before 34 have been reserved by other virtio devices.
Is there a link to the spec patch?
Thanks
>
> Co-developed-by: Conghui Chen <conghui.chen@intel.com>
> Signed-off-by: Conghui Chen <conghui.chen@intel.com>
> Signed-off-by: Jie Deng <jie.deng@intel.com>
> Reviewed-by: Shuo Liu <shuo.a.liu@intel.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> drivers/i2c/busses/Kconfig | 11 ++
> drivers/i2c/busses/Makefile | 3 +
> drivers/i2c/busses/i2c-virtio.c | 276 ++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/virtio_ids.h | 1 +
> 4 files changed, 291 insertions(+)
> create mode 100644 drivers/i2c/busses/i2c-virtio.c
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 293e7a0..70c8e30 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -21,6 +21,17 @@ config I2C_ALI1535
> This driver can also be built as a module. If so, the module
> will be called i2c-ali1535.
>
> +config I2C_VIRTIO
> + tristate "Virtio I2C Adapter"
> + depends on VIRTIO
> + help
> + If you say yes to this option, support will be included for the virtio
> + i2c adapter driver. The hardware can be emulated by any device model
> + software according to the virtio protocol.
> +
> + This driver can also be built as a module. If so, the module
> + will be called i2c-virtio.
> +
> config I2C_ALI1563
> tristate "ALI 1563"
> depends on PCI
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 19aff0e..821acfa 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -6,6 +6,9 @@
> # ACPI drivers
> obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
>
> +# VIRTIO I2C host controller driver
> +obj-$(CONFIG_I2C_VIRTIO) += i2c-virtio.o
> +
> # PC SMBus host controller drivers
> obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
> obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
> diff --git a/drivers/i2c/busses/i2c-virtio.c b/drivers/i2c/busses/i2c-virtio.c
> new file mode 100644
> index 0000000..47f9fd1
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-virtio.c
> @@ -0,0 +1,276 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Virtio I2C Bus Driver
> + *
> + * Copyright (c) 2020 Intel Corporation. All rights reserved.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/completion.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/io.h>
> +#include <linux/jiffies.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/wait.h>
> +
> +#include <linux/virtio.h>
> +#include <linux/virtio_ids.h>
> +#include <linux/virtio_config.h>
> +
> +#define VIRTIO_I2C_MSG_OK 0
> +#define VIRTIO_I2C_MSG_ERR 1
> +
> +/**
> + * struct virtio_i2c_hdr - the virtio I2C message header structure
> + * @addr: i2c_msg addr, the slave address
> + * @flags: i2c_msg flags
> + * @len: i2c_msg len
> + */
> +struct virtio_i2c_hdr {
> + __virtio16 addr;
> + __virtio16 flags;
> + __virtio16 len;
> +} __packed;
> +
> +/**
> + * struct virtio_i2c_msg - the virtio I2C message structure
> + * @hdr: the virtio I2C message header
> + * @buf: virtio I2C message data buffer
> + * @status: the processing result from the backend
> + */
> +struct virtio_i2c_msg {
> + struct virtio_i2c_hdr hdr;
> + char *buf;
> + u8 status;
> +};
> +
> +/**
> + * struct virtio_i2c - virtio I2C data
> + * @vdev: virtio device for this controller
> + * @completion: completion of virtio I2C message
> + * @adap: I2C adapter for this controller
> + * @i2c_lock: lock for virtqueue processing
> + * @vq: the virtio virtqueue for communication
> + */
> +struct virtio_i2c {
> + struct virtio_device *vdev;
> + struct completion completion;
> + struct i2c_adapter adap;
> + struct mutex i2c_lock;
> + struct virtqueue *vq;
> +};
> +
> +static void virtio_i2c_msg_done(struct virtqueue *vq)
> +{
> + struct virtio_i2c *vi = vq->vdev->priv;
> +
> + complete(&vi->completion);
> +}
> +
> +static int virtio_i2c_add_msg(struct virtqueue *vq,
> + struct virtio_i2c_msg *vmsg,
> + struct i2c_msg *msg)
> +{
> + struct scatterlist *sgs[3], hdr, bout, bin, status;
> + int outcnt = 0, incnt = 0;
> +
> + if (!msg->len)
> + return -EINVAL;
> +
> + vmsg->hdr.addr = msg->addr;
> + vmsg->hdr.flags = msg->flags;
> + vmsg->hdr.len = msg->len;
> +
> + vmsg->buf = kzalloc(vmsg->hdr.len, GFP_KERNEL);
> + if (!vmsg->buf)
> + return -ENOMEM;
> +
> + sg_init_one(&hdr, &vmsg->hdr, sizeof(struct virtio_i2c_hdr));
> + sgs[outcnt++] = &hdr;
> + if (vmsg->hdr.flags & I2C_M_RD) {
> + sg_init_one(&bin, vmsg->buf, msg->len);
> + sgs[outcnt + incnt++] = &bin;
> + } else {
> + memcpy(vmsg->buf, msg->buf, msg->len);
> + sg_init_one(&bout, vmsg->buf, msg->len);
> + sgs[outcnt++] = &bout;
> + }
> + sg_init_one(&status, &vmsg->status, sizeof(vmsg->status));
> + sgs[outcnt + incnt++] = &status;
> +
> + return virtqueue_add_sgs(vq, sgs, outcnt, incnt, vmsg, GFP_KERNEL);
> +}
> +
> +static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> +{
> + struct virtio_i2c *vi = i2c_get_adapdata(adap);
> + struct virtio_i2c_msg *vmsg_o, *vmsg_i;
> + struct virtqueue *vq = vi->vq;
> + unsigned long time_left;
> + int len, i, ret = 0;
> +
> + vmsg_o = kzalloc(sizeof(*vmsg_o), GFP_KERNEL);
> + if (!vmsg_o)
> + return -ENOMEM;
> +
> + mutex_lock(&vi->i2c_lock);
> + vmsg_o->buf = NULL;
> + for (i = 0; i < num; i++) {
> + ret = virtio_i2c_add_msg(vq, vmsg_o, &msgs[i]);
> + if (ret) {
> + dev_err(&adap->dev, "failed to add msg[%d] to virtqueue.\n", i);
> + goto err_unlock_free;
> + }
> +
> + virtqueue_kick(vq);
> +
> + time_left = wait_for_completion_timeout(&vi->completion, adap->timeout);
> + if (!time_left) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x timeout.\n", i, msgs[i].addr);
> + ret = i;
> + goto err_unlock_free;
> + }
> +
> + vmsg_i = (struct virtio_i2c_msg *)virtqueue_get_buf(vq, &len);
> + if (vmsg_i) {
> + /* vmsg_i should point to the same address with vmsg_o */
> + if (vmsg_i != vmsg_o) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x virtqueue error.\n",
> + i, vmsg_i->hdr.addr);
> + ret = i;
> + goto err_unlock_free;
> + }
> + if (vmsg_i->status != VIRTIO_I2C_MSG_OK) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x error=%d.\n",
> + i, vmsg_i->hdr.addr, vmsg_i->status);
> + ret = i;
> + goto err_unlock_free;
> + }
> + if ((vmsg_i->hdr.flags & I2C_M_RD) && vmsg_i->hdr.len)
> + memcpy(msgs[i].buf, vmsg_i->buf, vmsg_i->hdr.len);
> +
> + kfree(vmsg_i->buf);
> + vmsg_i->buf = NULL;
> + }
> + reinit_completion(&vi->completion);
> + }
> + if (i == num)
> + ret = num;
> +
> +err_unlock_free:
> + mutex_unlock(&vi->i2c_lock);
> + kfree(vmsg_o->buf);
> + kfree(vmsg_o);
> + return ret;
> +}
> +
> +static void virtio_i2c_del_vqs(struct virtio_device *vdev)
> +{
> + vdev->config->reset(vdev);
> + vdev->config->del_vqs(vdev);
> +}
> +
> +static int virtio_i2c_setup_vqs(struct virtio_i2c *vi)
> +{
> + struct virtio_device *vdev = vi->vdev;
> +
> + vi->vq = virtio_find_single_vq(vdev, virtio_i2c_msg_done, "i2c-msg");
> + return PTR_ERR_OR_ZERO(vi->vq);
> +}
> +
> +static u32 virtio_i2c_func(struct i2c_adapter *adap)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +static struct i2c_algorithm virtio_algorithm = {
> + .master_xfer = virtio_i2c_xfer,
> + .functionality = virtio_i2c_func,
> +};
> +
> +static struct i2c_adapter virtio_adapter = {
> + .owner = THIS_MODULE,
> + .name = "Virtio I2C Adapter",
> + .class = I2C_CLASS_DEPRECATED,
> + .algo = &virtio_algorithm,
> +};
> +
> +static int virtio_i2c_probe(struct virtio_device *vdev)
> +{
> + struct device *pdev = vdev->dev.parent;
> + struct virtio_i2c *vi;
> + int ret;
> +
> + vi = devm_kzalloc(&vdev->dev, sizeof(*vi), GFP_KERNEL);
> + if (!vi)
> + return -ENOMEM;
> +
> + vdev->priv = vi;
> + vi->vdev = vdev;
> +
> + mutex_init(&vi->i2c_lock);
> + init_completion(&vi->completion);
> +
> + ret = virtio_i2c_setup_vqs(vi);
> + if (ret)
> + return ret;
> +
> + vi->adap = virtio_adapter;
> + i2c_set_adapdata(&vi->adap, vi);
> + vi->adap.dev.parent = &vdev->dev;
> + /* Setup ACPI node for slave devices which will be probed through ACPI */
> + ACPI_COMPANION_SET(&vi->adap.dev, ACPI_COMPANION(pdev));
> + vi->adap.timeout = HZ / 10;
> + ret = i2c_add_adapter(&vi->adap);
> + if (ret) {
> + dev_err(&vdev->dev, "failed to add virtio-i2c adapter.\n");
> + virtio_i2c_del_vqs(vdev);
> + }
> +
> + return ret;
> +}
> +
> +static void virtio_i2c_remove(struct virtio_device *vdev)
> +{
> + struct virtio_i2c *vi = vdev->priv;
> +
> + i2c_del_adapter(&vi->adap);
> + virtio_i2c_del_vqs(vdev);
> +}
> +
> +static struct virtio_device_id id_table[] = {
> + { VIRTIO_ID_I2C_ADPTER, VIRTIO_DEV_ANY_ID },
> + {}
> +};
> +MODULE_DEVICE_TABLE(virtio, id_table);
> +
> +static int __maybe_unused virtio_i2c_freeze(struct virtio_device *vdev)
> +{
> + virtio_i2c_del_vqs(vdev);
> + return 0;
> +}
> +
> +static int __maybe_unused virtio_i2c_restore(struct virtio_device *vdev)
> +{
> + return virtio_i2c_setup_vqs(vdev->priv);
> +}
> +
> +static struct virtio_driver virtio_i2c_driver = {
> + .id_table = id_table,
> + .probe = virtio_i2c_probe,
> + .remove = virtio_i2c_remove,
> + .driver = {
> + .name = "i2c_virtio",
> + },
> +#ifdef CONFIG_PM_SLEEP
> + .freeze = virtio_i2c_freeze,
> + .restore = virtio_i2c_restore,
> +#endif
> +};
> +module_virtio_driver(virtio_i2c_driver);
> +
> +MODULE_DESCRIPTION("Virtio i2c bus driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
> index b052355..398ef2d 100644
> --- a/include/uapi/linux/virtio_ids.h
> +++ b/include/uapi/linux/virtio_ids.h
> @@ -48,5 +48,6 @@
> #define VIRTIO_ID_FS 26 /* virtio filesystem */
> #define VIRTIO_ID_PMEM 27 /* virtio pmem */
> #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
> +#define VIRTIO_ID_I2C_ADPTER 34 /* virtio i2c adpter */
>
> #endif /* _LINUX_VIRTIO_IDS_H */
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-03 6:12 ` Jason Wang
@ 2020-09-03 7:19 ` Jie Deng
2020-09-03 9:14 ` Loic Poulain
2020-09-04 3:38 ` Jason Wang
0 siblings, 2 replies; 14+ messages in thread
From: Jie Deng @ 2020-09-03 7:19 UTC (permalink / raw)
To: Jason Wang, linux-i2c, virtualization, linux-kernel
Cc: mst, wsa+renesas, wsa, andriy.shevchenko, jarkko.nikula,
jdelvare, Sergey.Semin, krzk, rppt, loic.poulain, tali.perry1,
bjorn.andersson, shuo.a.liu, conghui.chen, yu1.wang
On 2020/9/3 14:12, Jason Wang wrote:
>
> On 2020/9/3 下午1:34, Jie Deng wrote:
>> Add an I2C bus driver for virtio para-virtualization.
>>
>> The controller can be emulated by the backend driver in
>> any device model software by following the virtio protocol.
>>
>> This driver communicates with the backend driver through a
>> virtio I2C message structure which includes following parts:
>>
>> - Header: i2c_msg addr, flags, len.
>> - Data buffer: the pointer to the i2c msg data.
>> - Status: the processing result from the backend.
>>
>> People may implement different backend drivers to emulate
>> different controllers according to their needs. A backend
>> example can be found in the device model of the open source
>> project ACRN. For more information, please refer to
>> https://projectacrn.org.
>
>
> May I know the reason why don't you use i2c or virtio directly?
>
We don't want to add virtio drivers for every I2C devices in the guests.
This bus driver is designed to provide a way to flexibly expose the
physical
I2C slave devices to the guest without adding or changing the drivers of
the
I2C slave devices in the guest OS.
>
>>
>> The virtio device ID 34 is used for this I2C adpter since IDs
>> before 34 have been reserved by other virtio devices.
>
>
> Is there a link to the spec patch?
>
> Thanks
>
I haven't submitted the patch to reserve the ID in spec yet.
I write the ID here because I want to see your opinions first.
Thanks
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-03 7:19 ` Jie Deng
@ 2020-09-03 9:14 ` Loic Poulain
2020-09-04 3:38 ` Jason Wang
1 sibling, 0 replies; 14+ messages in thread
From: Loic Poulain @ 2020-09-03 9:14 UTC (permalink / raw)
To: Jie Deng
Cc: Jason Wang, linux-i2c, virtualization, open list, mst,
wsa+renesas, wsa, Andy Shevchenko, jarkko.nikula, jdelvare,
Sergey.Semin, krzk, rppt, tali.perry1, Bjorn Andersson,
shuo.a.liu, conghui.chen, yu1.wang
On Thu, 3 Sep 2020 at 09:19, Jie Deng <jie.deng@intel.com> wrote:
>
>
> On 2020/9/3 14:12, Jason Wang wrote:
> >
> > On 2020/9/3 下午1:34, Jie Deng wrote:
> >> Add an I2C bus driver for virtio para-virtualization.
> >>
> >> The controller can be emulated by the backend driver in
> >> any device model software by following the virtio protocol.
> >>
> >> This driver communicates with the backend driver through a
> >> virtio I2C message structure which includes following parts:
> >>
> >> - Header: i2c_msg addr, flags, len.
> >> - Data buffer: the pointer to the i2c msg data.
> >> - Status: the processing result from the backend.
> >>
> >> People may implement different backend drivers to emulate
> >> different controllers according to their needs. A backend
> >> example can be found in the device model of the open source
> >> project ACRN. For more information, please refer to
> >> https://projectacrn.org.
> >
> >
> > May I know the reason why don't you use i2c or virtio directly?
> >
> We don't want to add virtio drivers for every I2C devices in the guests.
> This bus driver is designed to provide a way to flexibly expose the
> physical
> I2C slave devices to the guest without adding or changing the drivers of
> the
> I2C slave devices in the guest OS.
So AFAIU, what you're trying to do here is "I2C slave passthrough over
para-virtualized I2C bus"? While not totally crazy, that looks a bit weird since
a straightforward way would be to directly assign the I2C bus controller as a
passthrough device (vfio?), though I assume your goal is also having per slave
VM assignment control (and not exposing the whole bus)...
>
>
> >
> >>
> >> The virtio device ID 34 is used for this I2C adpter since IDs
> >> before 34 have been reserved by other virtio devices.
> >
> >
> > Is there a link to the spec patch?
> >
> > Thanks
> >
> I haven't submitted the patch to reserve the ID in spec yet.
> I write the ID here because I want to see your opinions first.
>
> Thanks
>
>
Regards,
Loic
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-03 5:34 [PATCH] i2c: virtio: add a virtio i2c frontend driver Jie Deng
2020-09-03 6:12 ` Jason Wang
@ 2020-09-03 9:58 ` Michael S. Tsirkin
2020-09-04 5:28 ` Jie Deng
2020-09-03 10:20 ` Andy Shevchenko
` (2 subsequent siblings)
4 siblings, 1 reply; 14+ messages in thread
From: Michael S. Tsirkin @ 2020-09-03 9:58 UTC (permalink / raw)
To: Jie Deng
Cc: linux-i2c, virtualization, linux-kernel, jasowang, wsa+renesas,
wsa, andriy.shevchenko, jarkko.nikula, jdelvare, Sergey.Semin,
krzk, rppt, loic.poulain, tali.perry1, bjorn.andersson,
shuo.a.liu, conghui.chen, yu1.wang
On Thu, Sep 03, 2020 at 01:34:45PM +0800, Jie Deng wrote:
> Add an I2C bus driver for virtio para-virtualization.
>
> The controller can be emulated by the backend driver in
> any device model software by following the virtio protocol.
>
> This driver communicates with the backend driver through a
> virtio I2C message structure which includes following parts:
>
> - Header: i2c_msg addr, flags, len.
> - Data buffer: the pointer to the i2c msg data.
> - Status: the processing result from the backend.
>
> People may implement different backend drivers to emulate
> different controllers according to their needs. A backend
> example can be found in the device model of the open source
> project ACRN. For more information, please refer to
> https://projectacrn.org.
>
> The virtio device ID 34 is used for this I2C adpter since IDs
> before 34 have been reserved by other virtio devices.
Please reserve the ID with the virtio tc so no one conflicts.
> Co-developed-by: Conghui Chen <conghui.chen@intel.com>
> Signed-off-by: Conghui Chen <conghui.chen@intel.com>
> Signed-off-by: Jie Deng <jie.deng@intel.com>
> Reviewed-by: Shuo Liu <shuo.a.liu@intel.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> drivers/i2c/busses/Kconfig | 11 ++
> drivers/i2c/busses/Makefile | 3 +
> drivers/i2c/busses/i2c-virtio.c | 276 ++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/virtio_ids.h | 1 +
> 4 files changed, 291 insertions(+)
> create mode 100644 drivers/i2c/busses/i2c-virtio.c
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 293e7a0..70c8e30 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -21,6 +21,17 @@ config I2C_ALI1535
> This driver can also be built as a module. If so, the module
> will be called i2c-ali1535.
>
> +config I2C_VIRTIO
> + tristate "Virtio I2C Adapter"
> + depends on VIRTIO
> + help
> + If you say yes to this option, support will be included for the virtio
> + i2c adapter driver. The hardware can be emulated by any device model
> + software according to the virtio protocol.
> +
> + This driver can also be built as a module. If so, the module
> + will be called i2c-virtio.
> +
> config I2C_ALI1563
> tristate "ALI 1563"
> depends on PCI
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 19aff0e..821acfa 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -6,6 +6,9 @@
> # ACPI drivers
> obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
>
> +# VIRTIO I2C host controller driver
> +obj-$(CONFIG_I2C_VIRTIO) += i2c-virtio.o
> +
> # PC SMBus host controller drivers
> obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
> obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
> diff --git a/drivers/i2c/busses/i2c-virtio.c b/drivers/i2c/busses/i2c-virtio.c
> new file mode 100644
> index 0000000..47f9fd1
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-virtio.c
> @@ -0,0 +1,276 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Virtio I2C Bus Driver
> + *
> + * Copyright (c) 2020 Intel Corporation. All rights reserved.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/completion.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/io.h>
> +#include <linux/jiffies.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/wait.h>
> +
> +#include <linux/virtio.h>
> +#include <linux/virtio_ids.h>
> +#include <linux/virtio_config.h>
> +
> +#define VIRTIO_I2C_MSG_OK 0
> +#define VIRTIO_I2C_MSG_ERR 1
> +
> +/**
> + * struct virtio_i2c_hdr - the virtio I2C message header structure
> + * @addr: i2c_msg addr, the slave address
> + * @flags: i2c_msg flags
> + * @len: i2c_msg len
> + */
> +struct virtio_i2c_hdr {
> + __virtio16 addr;
> + __virtio16 flags;
> + __virtio16 len;
> +} __packed;
virtio16 is for legacy devices, modern ones should be __le.
and we don't really need to pack it I think.
> +
> +/**
> + * struct virtio_i2c_msg - the virtio I2C message structure
> + * @hdr: the virtio I2C message header
> + * @buf: virtio I2C message data buffer
> + * @status: the processing result from the backend
> + */
> +struct virtio_i2c_msg {
> + struct virtio_i2c_hdr hdr;
> + char *buf;
> + u8 status;
> +};
> +
> +/**
> + * struct virtio_i2c - virtio I2C data
> + * @vdev: virtio device for this controller
> + * @completion: completion of virtio I2C message
> + * @adap: I2C adapter for this controller
> + * @i2c_lock: lock for virtqueue processing
> + * @vq: the virtio virtqueue for communication
> + */
> +struct virtio_i2c {
> + struct virtio_device *vdev;
> + struct completion completion;
> + struct i2c_adapter adap;
> + struct mutex i2c_lock;
> + struct virtqueue *vq;
> +};
> +
> +static void virtio_i2c_msg_done(struct virtqueue *vq)
> +{
> + struct virtio_i2c *vi = vq->vdev->priv;
> +
> + complete(&vi->completion);
> +}
> +
> +static int virtio_i2c_add_msg(struct virtqueue *vq,
> + struct virtio_i2c_msg *vmsg,
> + struct i2c_msg *msg)
> +{
> + struct scatterlist *sgs[3], hdr, bout, bin, status;
> + int outcnt = 0, incnt = 0;
> +
> + if (!msg->len)
> + return -EINVAL;
> +
> + vmsg->hdr.addr = msg->addr;
> + vmsg->hdr.flags = msg->flags;
> + vmsg->hdr.len = msg->len;
> +
> + vmsg->buf = kzalloc(vmsg->hdr.len, GFP_KERNEL);
> + if (!vmsg->buf)
> + return -ENOMEM;
> +
> + sg_init_one(&hdr, &vmsg->hdr, sizeof(struct virtio_i2c_hdr));
> + sgs[outcnt++] = &hdr;
> + if (vmsg->hdr.flags & I2C_M_RD) {
> + sg_init_one(&bin, vmsg->buf, msg->len);
> + sgs[outcnt + incnt++] = &bin;
> + } else {
> + memcpy(vmsg->buf, msg->buf, msg->len);
> + sg_init_one(&bout, vmsg->buf, msg->len);
> + sgs[outcnt++] = &bout;
> + }
> + sg_init_one(&status, &vmsg->status, sizeof(vmsg->status));
> + sgs[outcnt + incnt++] = &status;
> +
> + return virtqueue_add_sgs(vq, sgs, outcnt, incnt, vmsg, GFP_KERNEL);
> +}
> +
> +static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> +{
> + struct virtio_i2c *vi = i2c_get_adapdata(adap);
> + struct virtio_i2c_msg *vmsg_o, *vmsg_i;
> + struct virtqueue *vq = vi->vq;
> + unsigned long time_left;
> + int len, i, ret = 0;
> +
> + vmsg_o = kzalloc(sizeof(*vmsg_o), GFP_KERNEL);
> + if (!vmsg_o)
> + return -ENOMEM;
> +
> + mutex_lock(&vi->i2c_lock);
> + vmsg_o->buf = NULL;
> + for (i = 0; i < num; i++) {
> + ret = virtio_i2c_add_msg(vq, vmsg_o, &msgs[i]);
> + if (ret) {
> + dev_err(&adap->dev, "failed to add msg[%d] to virtqueue.\n", i);
> + goto err_unlock_free;
> + }
> +
> + virtqueue_kick(vq);
> +
> + time_left = wait_for_completion_timeout(&vi->completion, adap->timeout);
> + if (!time_left) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x timeout.\n", i, msgs[i].addr);
> + ret = i;
> + goto err_unlock_free;
> + }
> +
> + vmsg_i = (struct virtio_i2c_msg *)virtqueue_get_buf(vq, &len);
> + if (vmsg_i) {
> + /* vmsg_i should point to the same address with vmsg_o */
> + if (vmsg_i != vmsg_o) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x virtqueue error.\n",
> + i, vmsg_i->hdr.addr);
> + ret = i;
> + goto err_unlock_free;
> + }
> + if (vmsg_i->status != VIRTIO_I2C_MSG_OK) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x error=%d.\n",
> + i, vmsg_i->hdr.addr, vmsg_i->status);
> + ret = i;
> + goto err_unlock_free;
> + }
> + if ((vmsg_i->hdr.flags & I2C_M_RD) && vmsg_i->hdr.len)
> + memcpy(msgs[i].buf, vmsg_i->buf, vmsg_i->hdr.len);
> +
> + kfree(vmsg_i->buf);
> + vmsg_i->buf = NULL;
> + }
> + reinit_completion(&vi->completion);
> + }
> + if (i == num)
> + ret = num;
> +
> +err_unlock_free:
> + mutex_unlock(&vi->i2c_lock);
> + kfree(vmsg_o->buf);
> + kfree(vmsg_o);
> + return ret;
> +}
> +
> +static void virtio_i2c_del_vqs(struct virtio_device *vdev)
> +{
> + vdev->config->reset(vdev);
> + vdev->config->del_vqs(vdev);
> +}
> +
> +static int virtio_i2c_setup_vqs(struct virtio_i2c *vi)
> +{
> + struct virtio_device *vdev = vi->vdev;
> +
> + vi->vq = virtio_find_single_vq(vdev, virtio_i2c_msg_done, "i2c-msg");
> + return PTR_ERR_OR_ZERO(vi->vq);
> +}
> +
> +static u32 virtio_i2c_func(struct i2c_adapter *adap)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +static struct i2c_algorithm virtio_algorithm = {
> + .master_xfer = virtio_i2c_xfer,
> + .functionality = virtio_i2c_func,
> +};
> +
> +static struct i2c_adapter virtio_adapter = {
> + .owner = THIS_MODULE,
> + .name = "Virtio I2C Adapter",
> + .class = I2C_CLASS_DEPRECATED,
> + .algo = &virtio_algorithm,
> +};
> +
> +static int virtio_i2c_probe(struct virtio_device *vdev)
> +{
> + struct device *pdev = vdev->dev.parent;
> + struct virtio_i2c *vi;
> + int ret;
> +
> + vi = devm_kzalloc(&vdev->dev, sizeof(*vi), GFP_KERNEL);
> + if (!vi)
> + return -ENOMEM;
> +
> + vdev->priv = vi;
> + vi->vdev = vdev;
> +
> + mutex_init(&vi->i2c_lock);
> + init_completion(&vi->completion);
> +
> + ret = virtio_i2c_setup_vqs(vi);
> + if (ret)
> + return ret;
> +
> + vi->adap = virtio_adapter;
> + i2c_set_adapdata(&vi->adap, vi);
> + vi->adap.dev.parent = &vdev->dev;
> + /* Setup ACPI node for slave devices which will be probed through ACPI */
> + ACPI_COMPANION_SET(&vi->adap.dev, ACPI_COMPANION(pdev));
> + vi->adap.timeout = HZ / 10;
> + ret = i2c_add_adapter(&vi->adap);
> + if (ret) {
> + dev_err(&vdev->dev, "failed to add virtio-i2c adapter.\n");
> + virtio_i2c_del_vqs(vdev);
> + }
> +
> + return ret;
> +}
> +
> +static void virtio_i2c_remove(struct virtio_device *vdev)
> +{
> + struct virtio_i2c *vi = vdev->priv;
> +
> + i2c_del_adapter(&vi->adap);
> + virtio_i2c_del_vqs(vdev);
> +}
> +
> +static struct virtio_device_id id_table[] = {
> + { VIRTIO_ID_I2C_ADPTER, VIRTIO_DEV_ANY_ID },
> + {}
> +};
> +MODULE_DEVICE_TABLE(virtio, id_table);
> +
> +static int __maybe_unused virtio_i2c_freeze(struct virtio_device *vdev)
> +{
> + virtio_i2c_del_vqs(vdev);
> + return 0;
> +}
> +
> +static int __maybe_unused virtio_i2c_restore(struct virtio_device *vdev)
> +{
> + return virtio_i2c_setup_vqs(vdev->priv);
> +}
> +
> +static struct virtio_driver virtio_i2c_driver = {
> + .id_table = id_table,
> + .probe = virtio_i2c_probe,
> + .remove = virtio_i2c_remove,
> + .driver = {
> + .name = "i2c_virtio",
> + },
> +#ifdef CONFIG_PM_SLEEP
> + .freeze = virtio_i2c_freeze,
> + .restore = virtio_i2c_restore,
> +#endif
> +};
> +module_virtio_driver(virtio_i2c_driver);
> +
> +MODULE_DESCRIPTION("Virtio i2c bus driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
> index b052355..398ef2d 100644
> --- a/include/uapi/linux/virtio_ids.h
> +++ b/include/uapi/linux/virtio_ids.h
> @@ -48,5 +48,6 @@
> #define VIRTIO_ID_FS 26 /* virtio filesystem */
> #define VIRTIO_ID_PMEM 27 /* virtio pmem */
> #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
> +#define VIRTIO_ID_I2C_ADPTER 34 /* virtio i2c adpter */
>
> #endif /* _LINUX_VIRTIO_IDS_H */
> --
> 2.7.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-03 5:34 [PATCH] i2c: virtio: add a virtio i2c frontend driver Jie Deng
2020-09-03 6:12 ` Jason Wang
2020-09-03 9:58 ` Michael S. Tsirkin
@ 2020-09-03 10:20 ` Andy Shevchenko
2020-09-04 6:08 ` Jie Deng
2020-09-04 4:06 ` Jason Wang
2020-09-09 9:02 ` Jason Wang
4 siblings, 1 reply; 14+ messages in thread
From: Andy Shevchenko @ 2020-09-03 10:20 UTC (permalink / raw)
To: Jie Deng
Cc: linux-i2c, virtualization, linux-kernel, mst, jasowang,
wsa+renesas, wsa, jarkko.nikula, jdelvare, Sergey.Semin, krzk,
rppt, loic.poulain, tali.perry1, bjorn.andersson, shuo.a.liu,
conghui.chen, yu1.wang
On Thu, Sep 03, 2020 at 01:34:45PM +0800, Jie Deng wrote:
> Add an I2C bus driver for virtio para-virtualization.
>
> The controller can be emulated by the backend driver in
> any device model software by following the virtio protocol.
>
> This driver communicates with the backend driver through a
> virtio I2C message structure which includes following parts:
>
> - Header: i2c_msg addr, flags, len.
> - Data buffer: the pointer to the i2c msg data.
> - Status: the processing result from the backend.
>
> People may implement different backend drivers to emulate
> different controllers according to their needs. A backend
> example can be found in the device model of the open source
> project ACRN. For more information, please refer to
> https://projectacrn.org.
>
> The virtio device ID 34 is used for this I2C adpter since IDs
> before 34 have been reserved by other virtio devices.
Seems it's slightly different version to what I have reviewed internally.
My comments below. (I admit that some of them maybe new)
...
> +/**
> + * struct virtio_i2c_hdr - the virtio I2C message header structure
> + * @addr: i2c_msg addr, the slave address
> + * @flags: i2c_msg flags
> + * @len: i2c_msg len
> + */
> +struct virtio_i2c_hdr {
> + __virtio16 addr;
> + __virtio16 flags;
> + __virtio16 len;
> +} __packed;
As Misha noticed and somewhere I saw 0-day reports these should be carefully
taken care of.
...
> +static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> +{
> + struct virtio_i2c *vi = i2c_get_adapdata(adap);
> + struct virtio_i2c_msg *vmsg_o, *vmsg_i;
> + struct virtqueue *vq = vi->vq;
> + unsigned long time_left;
> + int len, i, ret = 0;
> +
> + vmsg_o = kzalloc(sizeof(*vmsg_o), GFP_KERNEL);
> + if (!vmsg_o)
> + return -ENOMEM;
> +
> + mutex_lock(&vi->i2c_lock);
> + vmsg_o->buf = NULL;
> + for (i = 0; i < num; i++) {
> + ret = virtio_i2c_add_msg(vq, vmsg_o, &msgs[i]);
> + if (ret) {
> + dev_err(&adap->dev, "failed to add msg[%d] to virtqueue.\n", i);
> + goto err_unlock_free;
break;
> + }
> +
> + virtqueue_kick(vq);
> +
> + time_left = wait_for_completion_timeout(&vi->completion, adap->timeout);
> + if (!time_left) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x timeout.\n", i, msgs[i].addr);
> + ret = i;
> + goto err_unlock_free;
break;
And so on.
> + }
> +
> + vmsg_i = (struct virtio_i2c_msg *)virtqueue_get_buf(vq, &len);
> + if (vmsg_i) {
> + /* vmsg_i should point to the same address with vmsg_o */
> + if (vmsg_i != vmsg_o) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x virtqueue error.\n",
> + i, vmsg_i->hdr.addr);
> + ret = i;
> + goto err_unlock_free;
> + }
> + if (vmsg_i->status != VIRTIO_I2C_MSG_OK) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x error=%d.\n",
> + i, vmsg_i->hdr.addr, vmsg_i->status);
> + ret = i;
> + goto err_unlock_free;
> + }
> + if ((vmsg_i->hdr.flags & I2C_M_RD) && vmsg_i->hdr.len)
> + memcpy(msgs[i].buf, vmsg_i->buf, vmsg_i->hdr.len);
> +
> + kfree(vmsg_i->buf);
> + vmsg_i->buf = NULL;
> + }
> + reinit_completion(&vi->completion);
> + }
> + if (i == num)
> + ret = num;
And this conditional seems a dup of the for-loop successfully iterating over
entire queue.
> +err_unlock_free:
Redundant.
> + mutex_unlock(&vi->i2c_lock);
> + kfree(vmsg_o->buf);
> + kfree(vmsg_o);
> + return ret;
> +}
...
> + vi->adap.timeout = HZ / 10;
+ Blank line.
> + ret = i2c_add_adapter(&vi->adap);
> + if (ret) {
> + dev_err(&vdev->dev, "failed to add virtio-i2c adapter.\n");
> + virtio_i2c_del_vqs(vdev);
Usually we do clean up followed by message.
> + }
> +
> + return ret;
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-03 7:19 ` Jie Deng
2020-09-03 9:14 ` Loic Poulain
@ 2020-09-04 3:38 ` Jason Wang
1 sibling, 0 replies; 14+ messages in thread
From: Jason Wang @ 2020-09-04 3:38 UTC (permalink / raw)
To: Jie Deng, linux-i2c, virtualization, linux-kernel
Cc: mst, wsa+renesas, wsa, andriy.shevchenko, jarkko.nikula,
jdelvare, Sergey.Semin, krzk, rppt, loic.poulain, tali.perry1,
bjorn.andersson, shuo.a.liu, conghui.chen, yu1.wang
On 2020/9/3 下午3:19, Jie Deng wrote:
>
> On 2020/9/3 14:12, Jason Wang wrote:
>>
>> On 2020/9/3 下午1:34, Jie Deng wrote:
>>> Add an I2C bus driver for virtio para-virtualization.
>>>
>>> The controller can be emulated by the backend driver in
>>> any device model software by following the virtio protocol.
>>>
>>> This driver communicates with the backend driver through a
>>> virtio I2C message structure which includes following parts:
>>>
>>> - Header: i2c_msg addr, flags, len.
>>> - Data buffer: the pointer to the i2c msg data.
>>> - Status: the processing result from the backend.
>>>
>>> People may implement different backend drivers to emulate
>>> different controllers according to their needs. A backend
>>> example can be found in the device model of the open source
>>> project ACRN. For more information, please refer to
>>> https://projectacrn.org.
>>
>>
>> May I know the reason why don't you use i2c or virtio directly?
>>
> We don't want to add virtio drivers for every I2C devices in the guests.
> This bus driver is designed to provide a way to flexibly expose the
> physical
> I2C slave devices to the guest without adding or changing the drivers
> of the
> I2C slave devices in the guest OS.
Ok, if I understand this correctly, this is virtio transport of i2c
message (similar to virtio-scsi).
>
>
>>
>>>
>>> The virtio device ID 34 is used for this I2C adpter since IDs
>>> before 34 have been reserved by other virtio devices.
>>
>>
>> Is there a link to the spec patch?
>>
>> Thanks
>>
> I haven't submitted the patch to reserve the ID in spec yet.
> I write the ID here because I want to see your opinions first.
It would be helpful to send a spec draft for early review.
Thanks
>
> Thanks
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-03 5:34 [PATCH] i2c: virtio: add a virtio i2c frontend driver Jie Deng
` (2 preceding siblings ...)
2020-09-03 10:20 ` Andy Shevchenko
@ 2020-09-04 4:06 ` Jason Wang
2020-09-04 13:21 ` Jie Deng
2020-09-09 9:02 ` Jason Wang
4 siblings, 1 reply; 14+ messages in thread
From: Jason Wang @ 2020-09-04 4:06 UTC (permalink / raw)
To: Jie Deng, linux-i2c, virtualization, linux-kernel
Cc: mst, wsa+renesas, wsa, andriy.shevchenko, jarkko.nikula,
jdelvare, Sergey.Semin, krzk, rppt, loic.poulain, tali.perry1,
bjorn.andersson, shuo.a.liu, conghui.chen, yu1.wang
On 2020/9/3 下午1:34, Jie Deng wrote:
> Add an I2C bus driver for virtio para-virtualization.
>
> The controller can be emulated by the backend driver in
> any device model software by following the virtio protocol.
>
> This driver communicates with the backend driver through a
> virtio I2C message structure which includes following parts:
>
> - Header: i2c_msg addr, flags, len.
> - Data buffer: the pointer to the i2c msg data.
> - Status: the processing result from the backend.
>
> People may implement different backend drivers to emulate
> different controllers according to their needs. A backend
> example can be found in the device model of the open source
> project ACRN. For more information, please refer to
> https://projectacrn.org.
>
> The virtio device ID 34 is used for this I2C adpter since IDs
> before 34 have been reserved by other virtio devices.
>
> Co-developed-by: Conghui Chen <conghui.chen@intel.com>
> Signed-off-by: Conghui Chen <conghui.chen@intel.com>
> Signed-off-by: Jie Deng <jie.deng@intel.com>
> Reviewed-by: Shuo Liu <shuo.a.liu@intel.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> drivers/i2c/busses/Kconfig | 11 ++
> drivers/i2c/busses/Makefile | 3 +
> drivers/i2c/busses/i2c-virtio.c | 276 ++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/virtio_ids.h | 1 +
> 4 files changed, 291 insertions(+)
> create mode 100644 drivers/i2c/busses/i2c-virtio.c
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 293e7a0..70c8e30 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -21,6 +21,17 @@ config I2C_ALI1535
> This driver can also be built as a module. If so, the module
> will be called i2c-ali1535.
>
> +config I2C_VIRTIO
> + tristate "Virtio I2C Adapter"
> + depends on VIRTIO
I guess it should depend on some I2C module here.
> + help
> + If you say yes to this option, support will be included for the virtio
> + i2c adapter driver. The hardware can be emulated by any device model
> + software according to the virtio protocol.
> +
> + This driver can also be built as a module. If so, the module
> + will be called i2c-virtio.
> +
> config I2C_ALI1563
> tristate "ALI 1563"
> depends on PCI
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 19aff0e..821acfa 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -6,6 +6,9 @@
> # ACPI drivers
> obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
>
> +# VIRTIO I2C host controller driver
> +obj-$(CONFIG_I2C_VIRTIO) += i2c-virtio.o
> +
> # PC SMBus host controller drivers
> obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
> obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
> diff --git a/drivers/i2c/busses/i2c-virtio.c b/drivers/i2c/busses/i2c-virtio.c
> new file mode 100644
> index 0000000..47f9fd1
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-virtio.c
> @@ -0,0 +1,276 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Virtio I2C Bus Driver
> + *
> + * Copyright (c) 2020 Intel Corporation. All rights reserved.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/completion.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/io.h>
> +#include <linux/jiffies.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/wait.h>
> +
> +#include <linux/virtio.h>
> +#include <linux/virtio_ids.h>
> +#include <linux/virtio_config.h>
> +
> +#define VIRTIO_I2C_MSG_OK 0
> +#define VIRTIO_I2C_MSG_ERR 1
> +
> +/**
> + * struct virtio_i2c_hdr - the virtio I2C message header structure
> + * @addr: i2c_msg addr, the slave address
> + * @flags: i2c_msg flags
> + * @len: i2c_msg len
> + */
> +struct virtio_i2c_hdr {
> + __virtio16 addr;
> + __virtio16 flags;
> + __virtio16 len;
> +} __packed;
> +
> +/**
> + * struct virtio_i2c_msg - the virtio I2C message structure
> + * @hdr: the virtio I2C message header
> + * @buf: virtio I2C message data buffer
> + * @status: the processing result from the backend
> + */
> +struct virtio_i2c_msg {
> + struct virtio_i2c_hdr hdr;
> + char *buf;
> + u8 status;
Any reason for separating status out of virtio_i2c_hdr?
> +};
> +
> +/**
> + * struct virtio_i2c - virtio I2C data
> + * @vdev: virtio device for this controller
> + * @completion: completion of virtio I2C message
> + * @adap: I2C adapter for this controller
> + * @i2c_lock: lock for virtqueue processing
> + * @vq: the virtio virtqueue for communication
> + */
> +struct virtio_i2c {
> + struct virtio_device *vdev;
> + struct completion completion;
> + struct i2c_adapter adap;
> + struct mutex i2c_lock;
> + struct virtqueue *vq;
> +};
> +
> +static void virtio_i2c_msg_done(struct virtqueue *vq)
> +{
> + struct virtio_i2c *vi = vq->vdev->priv;
> +
> + complete(&vi->completion);
> +}
> +
> +static int virtio_i2c_add_msg(struct virtqueue *vq,
> + struct virtio_i2c_msg *vmsg,
> + struct i2c_msg *msg)
> +{
> + struct scatterlist *sgs[3], hdr, bout, bin, status;
> + int outcnt = 0, incnt = 0;
> +
> + if (!msg->len)
> + return -EINVAL;
> +
> + vmsg->hdr.addr = msg->addr;
> + vmsg->hdr.flags = msg->flags;
> + vmsg->hdr.len = msg->len;
Missing endian conversion?
> +
> + vmsg->buf = kzalloc(vmsg->hdr.len, GFP_KERNEL);
> + if (!vmsg->buf)
> + return -ENOMEM;
> +
> + sg_init_one(&hdr, &vmsg->hdr, sizeof(struct virtio_i2c_hdr));
> + sgs[outcnt++] = &hdr;
> + if (vmsg->hdr.flags & I2C_M_RD) {
> + sg_init_one(&bin, vmsg->buf, msg->len);
> + sgs[outcnt + incnt++] = &bin;
> + } else {
> + memcpy(vmsg->buf, msg->buf, msg->len);
> + sg_init_one(&bout, vmsg->buf, msg->len);
> + sgs[outcnt++] = &bout;
> + }
> + sg_init_one(&status, &vmsg->status, sizeof(vmsg->status));
> + sgs[outcnt + incnt++] = &status;
> +
> + return virtqueue_add_sgs(vq, sgs, outcnt, incnt, vmsg, GFP_KERNEL);
> +}
> +
> +static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> +{
> + struct virtio_i2c *vi = i2c_get_adapdata(adap);
> + struct virtio_i2c_msg *vmsg_o, *vmsg_i;
> + struct virtqueue *vq = vi->vq;
> + unsigned long time_left;
> + int len, i, ret = 0;
> +
> + vmsg_o = kzalloc(sizeof(*vmsg_o), GFP_KERNEL);
> + if (!vmsg_o)
> + return -ENOMEM;
It looks to me we can avoid the allocation by embedding virtio_i2c_msg
into struct virtio_i2c;
> +
> + mutex_lock(&vi->i2c_lock);
> + vmsg_o->buf = NULL;
> + for (i = 0; i < num; i++) {
> + ret = virtio_i2c_add_msg(vq, vmsg_o, &msgs[i]);
> + if (ret) {
> + dev_err(&adap->dev, "failed to add msg[%d] to virtqueue.\n", i);
> + goto err_unlock_free;
> + }
> +
> + virtqueue_kick(vq);
> +
> + time_left = wait_for_completion_timeout(&vi->completion, adap->timeout);
> + if (!time_left) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x timeout.\n", i, msgs[i].addr);
> + ret = i;
> + goto err_unlock_free;
> + }
> +
> + vmsg_i = (struct virtio_i2c_msg *)virtqueue_get_buf(vq, &len);
> + if (vmsg_i) {
> + /* vmsg_i should point to the same address with vmsg_o */
> + if (vmsg_i != vmsg_o) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x virtqueue error.\n",
> + i, vmsg_i->hdr.addr);
> + ret = i;
> + goto err_unlock_free;
> + }
Does this imply in order completion of i2c device? (E.g what happens if
multiple virtio i2c requests are submitted)
Btw, this always use a single descriptor once a time which makes me
suspect if a virtqueue(virtio) is really needed. It looks to me we can
utilize the virtqueue by submit the request in a batch.
> + if (vmsg_i->status != VIRTIO_I2C_MSG_OK) {
> + dev_err(&adap->dev, "msg[%d]: addr=0x%x error=%d.\n",
> + i, vmsg_i->hdr.addr, vmsg_i->status);
> + ret = i;
> + goto err_unlock_free;
> + }
> + if ((vmsg_i->hdr.flags & I2C_M_RD) && vmsg_i->hdr.len)
> + memcpy(msgs[i].buf, vmsg_i->buf, vmsg_i->hdr.len);
> +
> + kfree(vmsg_i->buf);
> + vmsg_i->buf = NULL;
> + }
> + reinit_completion(&vi->completion);
> + }
> + if (i == num)
> + ret = num;
> +
> +err_unlock_free:
> + mutex_unlock(&vi->i2c_lock);
> + kfree(vmsg_o->buf);
> + kfree(vmsg_o);
> + return ret;
> +}
> +
> +static void virtio_i2c_del_vqs(struct virtio_device *vdev)
> +{
> + vdev->config->reset(vdev);
Why need reset here?
Thanks
> + vdev->config->del_vqs(vdev);
> +}
> +
> +static int virtio_i2c_setup_vqs(struct virtio_i2c *vi)
> +{
> + struct virtio_device *vdev = vi->vdev;
> +
> + vi->vq = virtio_find_single_vq(vdev, virtio_i2c_msg_done, "i2c-msg");
We've in the scope of ic2, so "msg" should be sufficient.
> + return PTR_ERR_OR_ZERO(vi->vq);
> +}
> +
> +static u32 virtio_i2c_func(struct i2c_adapter *adap)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +static struct i2c_algorithm virtio_algorithm = {
> + .master_xfer = virtio_i2c_xfer,
> + .functionality = virtio_i2c_func,
> +};
> +
> +static struct i2c_adapter virtio_adapter = {
> + .owner = THIS_MODULE,
> + .name = "Virtio I2C Adapter",
> + .class = I2C_CLASS_DEPRECATED,
> + .algo = &virtio_algorithm,
> +};
> +
> +static int virtio_i2c_probe(struct virtio_device *vdev)
> +{
> + struct device *pdev = vdev->dev.parent;
> + struct virtio_i2c *vi;
> + int ret;
> +
> + vi = devm_kzalloc(&vdev->dev, sizeof(*vi), GFP_KERNEL);
> + if (!vi)
> + return -ENOMEM;
> +
> + vdev->priv = vi;
> + vi->vdev = vdev;
> +
> + mutex_init(&vi->i2c_lock);
> + init_completion(&vi->completion);
> +
> + ret = virtio_i2c_setup_vqs(vi);
> + if (ret)
> + return ret;
> +
> + vi->adap = virtio_adapter;
> + i2c_set_adapdata(&vi->adap, vi);
> + vi->adap.dev.parent = &vdev->dev;
> + /* Setup ACPI node for slave devices which will be probed through ACPI */
> + ACPI_COMPANION_SET(&vi->adap.dev, ACPI_COMPANION(pdev));
> + vi->adap.timeout = HZ / 10;
> + ret = i2c_add_adapter(&vi->adap);
> + if (ret) {
> + dev_err(&vdev->dev, "failed to add virtio-i2c adapter.\n");
> + virtio_i2c_del_vqs(vdev);
> + }
> +
> + return ret;
> +}
> +
> +static void virtio_i2c_remove(struct virtio_device *vdev)
> +{
> + struct virtio_i2c *vi = vdev->priv;
> +
> + i2c_del_adapter(&vi->adap);
> + virtio_i2c_del_vqs(vdev);
> +}
> +
> +static struct virtio_device_id id_table[] = {
> + { VIRTIO_ID_I2C_ADPTER, VIRTIO_DEV_ANY_ID },
> + {}
> +};
> +MODULE_DEVICE_TABLE(virtio, id_table);
> +
> +static int __maybe_unused virtio_i2c_freeze(struct virtio_device *vdev)
> +{
> + virtio_i2c_del_vqs(vdev);
> + return 0;
> +}
> +
> +static int __maybe_unused virtio_i2c_restore(struct virtio_device *vdev)
> +{
> + return virtio_i2c_setup_vqs(vdev->priv);
> +}
> +
> +static struct virtio_driver virtio_i2c_driver = {
> + .id_table = id_table,
> + .probe = virtio_i2c_probe,
> + .remove = virtio_i2c_remove,
> + .driver = {
> + .name = "i2c_virtio",
> + },
> +#ifdef CONFIG_PM_SLEEP
> + .freeze = virtio_i2c_freeze,
> + .restore = virtio_i2c_restore,
> +#endif
> +};
> +module_virtio_driver(virtio_i2c_driver);
> +
> +MODULE_DESCRIPTION("Virtio i2c bus driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
> index b052355..398ef2d 100644
> --- a/include/uapi/linux/virtio_ids.h
> +++ b/include/uapi/linux/virtio_ids.h
> @@ -48,5 +48,6 @@
> #define VIRTIO_ID_FS 26 /* virtio filesystem */
> #define VIRTIO_ID_PMEM 27 /* virtio pmem */
> #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
> +#define VIRTIO_ID_I2C_ADPTER 34 /* virtio i2c adpter */
>
> #endif /* _LINUX_VIRTIO_IDS_H */
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-03 9:58 ` Michael S. Tsirkin
@ 2020-09-04 5:28 ` Jie Deng
0 siblings, 0 replies; 14+ messages in thread
From: Jie Deng @ 2020-09-04 5:28 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: linux-i2c, virtualization, linux-kernel, jasowang, wsa+renesas,
wsa, andriy.shevchenko, jarkko.nikula, jdelvare, Sergey.Semin,
krzk, rppt, loic.poulain, tali.perry1, bjorn.andersson,
shuo.a.liu, conghui.chen, yu1.wang
On 2020/9/3 17:58, Michael S. Tsirkin wrote:
> On Thu, Sep 03, 2020 at 01:34:45PM +0800, Jie Deng wrote:
>> Add an I2C bus driver for virtio para-virtualization.
>>
>> The controller can be emulated by the backend driver in
>> any device model software by following the virtio protocol.
>>
>> This driver communicates with the backend driver through a
>> virtio I2C message structure which includes following parts:
>>
>> - Header: i2c_msg addr, flags, len.
>> - Data buffer: the pointer to the i2c msg data.
>> - Status: the processing result from the backend.
>>
>> People may implement different backend drivers to emulate
>> different controllers according to their needs. A backend
>> example can be found in the device model of the open source
>> project ACRN. For more information, please refer to
>> https://projectacrn.org.
>>
>> The virtio device ID 34 is used for this I2C adpter since IDs
>> before 34 have been reserved by other virtio devices.
> Please reserve the ID with the virtio tc so no one conflicts.
>
Sure. I will send a patch to request the ID.
>
> +
> +/**
> + * struct virtio_i2c_hdr - the virtio I2C message header structure
> + * @addr: i2c_msg addr, the slave address
> + * @flags: i2c_msg flags
> + * @len: i2c_msg len
> + */
> +struct virtio_i2c_hdr {
> + __virtio16 addr;
> + __virtio16 flags;
> + __virtio16 len;
> +} __packed;
> virtio16 is for legacy devices, modern ones should be __le.
> and we don't really need to pack it I think.
Right. I will fix these. Thanks.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-03 10:20 ` Andy Shevchenko
@ 2020-09-04 6:08 ` Jie Deng
0 siblings, 0 replies; 14+ messages in thread
From: Jie Deng @ 2020-09-04 6:08 UTC (permalink / raw)
To: Andy Shevchenko
Cc: linux-i2c, virtualization, linux-kernel, mst, jasowang,
wsa+renesas, wsa, jarkko.nikula, jdelvare, Sergey.Semin, krzk,
rppt, loic.poulain, tali.perry1, bjorn.andersson, shuo.a.liu,
conghui.chen, yu1.wang
On 2020/9/3 18:20, Andy Shevchenko wrote:
> On Thu, Sep 03, 2020 at 01:34:45PM +0800, Jie Deng wrote:
>> Add an I2C bus driver for virtio para-virtualization.
>>
>> The controller can be emulated by the backend driver in
>> any device model software by following the virtio protocol.
>>
>> This driver communicates with the backend driver through a
>> virtio I2C message structure which includes following parts:
>>
>> - Header: i2c_msg addr, flags, len.
>> - Data buffer: the pointer to the i2c msg data.
>> - Status: the processing result from the backend.
>>
>> People may implement different backend drivers to emulate
>> different controllers according to their needs. A backend
>> example can be found in the device model of the open source
>> project ACRN. For more information, please refer to
>> https://projectacrn.org.
>>
>> The virtio device ID 34 is used for this I2C adpter since IDs
>> before 34 have been reserved by other virtio devices.
> Seems it's slightly different version to what I have reviewed internally.
> My comments below. (I admit that some of them maybe new)
>
> ...
Yeah... Some new devices have been added into the virtio spec during
these days.
>> +/**
>> + * struct virtio_i2c_hdr - the virtio I2C message header structure
>> + * @addr: i2c_msg addr, the slave address
>> + * @flags: i2c_msg flags
>> + * @len: i2c_msg len
>> + */
>> +struct virtio_i2c_hdr {
>> + __virtio16 addr;
>> + __virtio16 flags;
>> + __virtio16 len;
>> +} __packed;
> As Misha noticed and somewhere I saw 0-day reports these should be carefully
> taken care of.
>
> ...
Sure. Will fix these.
>> +static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
>> +{
>> + struct virtio_i2c *vi = i2c_get_adapdata(adap);
>> + struct virtio_i2c_msg *vmsg_o, *vmsg_i;
>> + struct virtqueue *vq = vi->vq;
>> + unsigned long time_left;
>> + int len, i, ret = 0;
>> +
>> + vmsg_o = kzalloc(sizeof(*vmsg_o), GFP_KERNEL);
>> + if (!vmsg_o)
>> + return -ENOMEM;
>> +
>> + mutex_lock(&vi->i2c_lock);
>> + vmsg_o->buf = NULL;
>> + for (i = 0; i < num; i++) {
>> + ret = virtio_i2c_add_msg(vq, vmsg_o, &msgs[i]);
>> + if (ret) {
>> + dev_err(&adap->dev, "failed to add msg[%d] to virtqueue.\n", i);
>> + goto err_unlock_free;
> break;
OK.
>> + }
>> +
>> + virtqueue_kick(vq);
>> +
>> + time_left = wait_for_completion_timeout(&vi->completion, adap->timeout);
>> + if (!time_left) {
>> + dev_err(&adap->dev, "msg[%d]: addr=0x%x timeout.\n", i, msgs[i].addr);
>> + ret = i;
>> + goto err_unlock_free;
> break;
>
> And so on.
OK.
>> + }
>> +
>> + vmsg_i = (struct virtio_i2c_msg *)virtqueue_get_buf(vq, &len);
>> + if (vmsg_i) {
>> + /* vmsg_i should point to the same address with vmsg_o */
>> + if (vmsg_i != vmsg_o) {
>> + dev_err(&adap->dev, "msg[%d]: addr=0x%x virtqueue error.\n",
>> + i, vmsg_i->hdr.addr);
>> + ret = i;
>> + goto err_unlock_free;
>> + }
>> + if (vmsg_i->status != VIRTIO_I2C_MSG_OK) {
>> + dev_err(&adap->dev, "msg[%d]: addr=0x%x error=%d.\n",
>> + i, vmsg_i->hdr.addr, vmsg_i->status);
>> + ret = i;
>> + goto err_unlock_free;
>> + }
>> + if ((vmsg_i->hdr.flags & I2C_M_RD) && vmsg_i->hdr.len)
>> + memcpy(msgs[i].buf, vmsg_i->buf, vmsg_i->hdr.len);
>> +
>> + kfree(vmsg_i->buf);
>> + vmsg_i->buf = NULL;
>> + }
>> + reinit_completion(&vi->completion);
>> + }
>> + if (i == num)
>> + ret = num;
> And this conditional seems a dup of the for-loop successfully iterating over
> entire queue.
You are right.
We may save several lines of code by using "Return (ret<0) ? ret : i" at
the end.
>> +err_unlock_free:
> Redundant.
OK.
>> + mutex_unlock(&vi->i2c_lock);
>> + kfree(vmsg_o->buf);
>> + kfree(vmsg_o);
>> + return ret;
>> +}
> ...
>
>> + vi->adap.timeout = HZ / 10;
> + Blank line.
OK.
>> + ret = i2c_add_adapter(&vi->adap);
>> + if (ret) {
>> + dev_err(&vdev->dev, "failed to add virtio-i2c adapter.\n");
>> + virtio_i2c_del_vqs(vdev);
> Usually we do clean up followed by message.
I will change the order. Thank you.
>> + }
>> +
>> + return ret;
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-04 4:06 ` Jason Wang
@ 2020-09-04 13:21 ` Jie Deng
2020-09-07 5:40 ` Jason Wang
0 siblings, 1 reply; 14+ messages in thread
From: Jie Deng @ 2020-09-04 13:21 UTC (permalink / raw)
To: Jason Wang, linux-i2c, virtualization, linux-kernel
Cc: mst, wsa+renesas, wsa, andriy.shevchenko, jarkko.nikula,
jdelvare, Sergey.Semin, krzk, rppt, loic.poulain, tali.perry1,
bjorn.andersson, shuo.a.liu, conghui.chen, yu1.wang
On 2020/9/4 12:06, Jason Wang wrote:
>
>> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
>> index 293e7a0..70c8e30 100644
>> --- a/drivers/i2c/busses/Kconfig
>> +++ b/drivers/i2c/busses/Kconfig
>> @@ -21,6 +21,17 @@ config I2C_ALI1535
>> This driver can also be built as a module. If so, the module
>> will be called i2c-ali1535.
>> +config I2C_VIRTIO
>> + tristate "Virtio I2C Adapter"
>> + depends on VIRTIO
>
>
> I guess it should depend on some I2C module here.
>
The dependency of I2C is included in the Kconfig in its parent directory.
So there is nothing special to add here.
>
>>
>> +struct virtio_i2c_msg {
>> + struct virtio_i2c_hdr hdr;
>> + char *buf;
>> + u8 status;
>
>
> Any reason for separating status out of virtio_i2c_hdr?
>
The status is not from i2c_msg. So I put it out of virtio_i2c_hdr.
>
>> +};
>> +
>> +/**
>> + * struct virtio_i2c - virtio I2C data
>> + * @vdev: virtio device for this controller
>> + * @completion: completion of virtio I2C message
>> + * @adap: I2C adapter for this controller
>> + * @i2c_lock: lock for virtqueue processing
>> + * @vq: the virtio virtqueue for communication
>> + */
>> +struct virtio_i2c {
>> + struct virtio_device *vdev;
>> + struct completion completion;
>> + struct i2c_adapter adap;
>> + struct mutex i2c_lock;
>> + struct virtqueue *vq;
>> +};
>> +
>> +static void virtio_i2c_msg_done(struct virtqueue *vq)
>> +{
>> + struct virtio_i2c *vi = vq->vdev->priv;
>> +
>> + complete(&vi->completion);
>> +}
>> +
>> +static int virtio_i2c_add_msg(struct virtqueue *vq,
>> + struct virtio_i2c_msg *vmsg,
>> + struct i2c_msg *msg)
>> +{
>> + struct scatterlist *sgs[3], hdr, bout, bin, status;
>> + int outcnt = 0, incnt = 0;
>> +
>> + if (!msg->len)
>> + return -EINVAL;
>> +
>> + vmsg->hdr.addr = msg->addr;
>> + vmsg->hdr.flags = msg->flags;
>> + vmsg->hdr.len = msg->len;
>
>
> Missing endian conversion?
>
You are right. Need conversion here.
>
>> +
>> + vmsg->buf = kzalloc(vmsg->hdr.len, GFP_KERNEL);
>> + if (!vmsg->buf)
>> + return -ENOMEM;
>> +
>> + sg_init_one(&hdr, &vmsg->hdr, sizeof(struct virtio_i2c_hdr));
>> + sgs[outcnt++] = &hdr;
>> + if (vmsg->hdr.flags & I2C_M_RD) {
>> + sg_init_one(&bin, vmsg->buf, msg->len);
>> + sgs[outcnt + incnt++] = &bin;
>> + } else {
>> + memcpy(vmsg->buf, msg->buf, msg->len);
>> + sg_init_one(&bout, vmsg->buf, msg->len);
>> + sgs[outcnt++] = &bout;
>> + }
>> + sg_init_one(&status, &vmsg->status, sizeof(vmsg->status));
>> + sgs[outcnt + incnt++] = &status;
>> +
>> + return virtqueue_add_sgs(vq, sgs, outcnt, incnt, vmsg, GFP_KERNEL);
>> +}
>> +
>> +static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg
>> *msgs, int num)
>> +{
>> + struct virtio_i2c *vi = i2c_get_adapdata(adap);
>> + struct virtio_i2c_msg *vmsg_o, *vmsg_i;
>> + struct virtqueue *vq = vi->vq;
>> + unsigned long time_left;
>> + int len, i, ret = 0;
>> +
>> + vmsg_o = kzalloc(sizeof(*vmsg_o), GFP_KERNEL);
>> + if (!vmsg_o)
>> + return -ENOMEM;
>
>
> It looks to me we can avoid the allocation by embedding virtio_i2c_msg
> into struct virtio_i2c;
>
Yeah... That's better. Thanks.
>
>> +
>> + mutex_lock(&vi->i2c_lock);
>> + vmsg_o->buf = NULL;
>> + for (i = 0; i < num; i++) {
>> + ret = virtio_i2c_add_msg(vq, vmsg_o, &msgs[i]);
>> + if (ret) {
>> + dev_err(&adap->dev, "failed to add msg[%d] to
>> virtqueue.\n", i);
>> + goto err_unlock_free;
>> + }
>> +
>> + virtqueue_kick(vq);
>> +
>> + time_left = wait_for_completion_timeout(&vi->completion,
>> adap->timeout);
>> + if (!time_left) {
>> + dev_err(&adap->dev, "msg[%d]: addr=0x%x timeout.\n", i,
>> msgs[i].addr);
>> + ret = i;
>> + goto err_unlock_free;
>> + }
>> +
>> + vmsg_i = (struct virtio_i2c_msg *)virtqueue_get_buf(vq, &len);
>> + if (vmsg_i) {
>> + /* vmsg_i should point to the same address with vmsg_o */
>> + if (vmsg_i != vmsg_o) {
>> + dev_err(&adap->dev, "msg[%d]: addr=0x%x virtqueue
>> error.\n",
>> + i, vmsg_i->hdr.addr);
>> + ret = i;
>> + goto err_unlock_free;
>> + }
>
>
> Does this imply in order completion of i2c device? (E.g what happens
> if multiple virtio i2c requests are submitted)
>
> Btw, this always use a single descriptor once a time which makes me
> suspect if a virtqueue(virtio) is really needed. It looks to me we can
> utilize the virtqueue by submit the request in a batch.
>
I'm afraid not all physical devices support batch. I'd like to keep the
current design and consider
your suggestion as a possible optimization in the future.
Thanks.
>>
>> +}
>> +
>> +static void virtio_i2c_del_vqs(struct virtio_device *vdev)
>> +{
>> + vdev->config->reset(vdev);
>
>
> Why need reset here?
>
> Thanks
>
I'm following what other virtio drivers do.
They reset the devices before they clean up the queues.
>
>> + vdev->config->del_vqs(vdev);
>> +}
>> +
>> +static int virtio_i2c_setup_vqs(struct virtio_i2c *vi)
>> +{
>> + struct virtio_device *vdev = vi->vdev;
>> +
>> + vi->vq = virtio_find_single_vq(vdev, virtio_i2c_msg_done,
>> "i2c-msg");
>
>
> We've in the scope of ic2, so "msg" should be sufficient.
>
>
OK. Will change this name. Thanks.
>> + return PTR_ERR_OR_ZERO(vi->vq);
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-04 13:21 ` Jie Deng
@ 2020-09-07 5:40 ` Jason Wang
[not found] ` <c9be298b-c51b-f7f3-994b-b7bd9ae53b99@intel.com>
0 siblings, 1 reply; 14+ messages in thread
From: Jason Wang @ 2020-09-07 5:40 UTC (permalink / raw)
To: Jie Deng, linux-i2c, virtualization, linux-kernel
Cc: mst, wsa+renesas, wsa, andriy.shevchenko, jarkko.nikula,
jdelvare, Sergey.Semin, krzk, rppt, loic.poulain, tali.perry1,
bjorn.andersson, shuo.a.liu, conghui.chen, yu1.wang
On 2020/9/4 下午9:21, Jie Deng wrote:
>
> On 2020/9/4 12:06, Jason Wang wrote:
>>
>>> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
>>> index 293e7a0..70c8e30 100644
>>> --- a/drivers/i2c/busses/Kconfig
>>> +++ b/drivers/i2c/busses/Kconfig
>>> @@ -21,6 +21,17 @@ config I2C_ALI1535
>>> This driver can also be built as a module. If so, the module
>>> will be called i2c-ali1535.
>>> +config I2C_VIRTIO
>>> + tristate "Virtio I2C Adapter"
>>> + depends on VIRTIO
>>
>>
>> I guess it should depend on some I2C module here.
>>
> The dependency of I2C is included in the Kconfig in its parent directory.
> So there is nothing special to add here.
Ok.
>
>
>>
>>>
>>> +struct virtio_i2c_msg {
>>> + struct virtio_i2c_hdr hdr;
>>> + char *buf;
>>> + u8 status;
>>
>>
>> Any reason for separating status out of virtio_i2c_hdr?
>>
> The status is not from i2c_msg.
You meant ic2_hdr? You embed status in virtio_i2c_msg anyway.
> So I put it out of virtio_i2c_hdr.
Something like status or response is pretty common in virtio request
(e.g net or scsi), if no special reason, it's better to keep it in the hdr.
>
>>
>>> +};
>>> +
>>> +/**
>>> + * struct virtio_i2c - virtio I2C data
>>> + * @vdev: virtio device for this controller
>>> + * @completion: completion of virtio I2C message
>>> + * @adap: I2C adapter for this controller
>>> + * @i2c_lock: lock for virtqueue processing
>>> + * @vq: the virtio virtqueue for communication
>>> + */
>>> +struct virtio_i2c {
>>> + struct virtio_device *vdev;
>>> + struct completion completion;
>>> + struct i2c_adapter adap;
>>> + struct mutex i2c_lock;
>>> + struct virtqueue *vq;
>>> +};
>>> +
>>> +static void virtio_i2c_msg_done(struct virtqueue *vq)
>>> +{
>>> + struct virtio_i2c *vi = vq->vdev->priv;
>>> +
>>> + complete(&vi->completion);
>>> +}
>>> +
>>> +static int virtio_i2c_add_msg(struct virtqueue *vq,
>>> + struct virtio_i2c_msg *vmsg,
>>> + struct i2c_msg *msg)
>>> +{
>>> + struct scatterlist *sgs[3], hdr, bout, bin, status;
>>> + int outcnt = 0, incnt = 0;
>>> +
>>> + if (!msg->len)
>>> + return -EINVAL;
>>> +
>>> + vmsg->hdr.addr = msg->addr;
>>> + vmsg->hdr.flags = msg->flags;
>>> + vmsg->hdr.len = msg->len;
>>
>>
>> Missing endian conversion?
>>
> You are right. Need conversion here.
>>
>>> +
>>> + vmsg->buf = kzalloc(vmsg->hdr.len, GFP_KERNEL);
>>> + if (!vmsg->buf)
>>> + return -ENOMEM;
>>> +
>>> + sg_init_one(&hdr, &vmsg->hdr, sizeof(struct virtio_i2c_hdr));
>>> + sgs[outcnt++] = &hdr;
>>> + if (vmsg->hdr.flags & I2C_M_RD) {
>>> + sg_init_one(&bin, vmsg->buf, msg->len);
>>> + sgs[outcnt + incnt++] = &bin;
>>> + } else {
>>> + memcpy(vmsg->buf, msg->buf, msg->len);
>>> + sg_init_one(&bout, vmsg->buf, msg->len);
>>> + sgs[outcnt++] = &bout;
>>> + }
>>> + sg_init_one(&status, &vmsg->status, sizeof(vmsg->status));
>>> + sgs[outcnt + incnt++] = &status;
>>> +
>>> + return virtqueue_add_sgs(vq, sgs, outcnt, incnt, vmsg,
>>> GFP_KERNEL);
>>> +}
>>> +
>>> +static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg
>>> *msgs, int num)
>>> +{
>>> + struct virtio_i2c *vi = i2c_get_adapdata(adap);
>>> + struct virtio_i2c_msg *vmsg_o, *vmsg_i;
>>> + struct virtqueue *vq = vi->vq;
>>> + unsigned long time_left;
>>> + int len, i, ret = 0;
>>> +
>>> + vmsg_o = kzalloc(sizeof(*vmsg_o), GFP_KERNEL);
>>> + if (!vmsg_o)
>>> + return -ENOMEM;
>>
>>
>> It looks to me we can avoid the allocation by embedding
>> virtio_i2c_msg into struct virtio_i2c;
>>
> Yeah... That's better. Thanks.
>
>
>>
>>> +
>>> + mutex_lock(&vi->i2c_lock);
>>> + vmsg_o->buf = NULL;
>>> + for (i = 0; i < num; i++) {
>>> + ret = virtio_i2c_add_msg(vq, vmsg_o, &msgs[i]);
>>> + if (ret) {
>>> + dev_err(&adap->dev, "failed to add msg[%d] to
>>> virtqueue.\n", i);
>>> + goto err_unlock_free;
>>> + }
>>> +
>>> + virtqueue_kick(vq);
>>> +
>>> + time_left = wait_for_completion_timeout(&vi->completion,
>>> adap->timeout);
>>> + if (!time_left) {
>>> + dev_err(&adap->dev, "msg[%d]: addr=0x%x timeout.\n", i,
>>> msgs[i].addr);
>>> + ret = i;
>>> + goto err_unlock_free;
>>> + }
>>> +
>>> + vmsg_i = (struct virtio_i2c_msg *)virtqueue_get_buf(vq, &len);
>>> + if (vmsg_i) {
>>> + /* vmsg_i should point to the same address with vmsg_o */
>>> + if (vmsg_i != vmsg_o) {
>>> + dev_err(&adap->dev, "msg[%d]: addr=0x%x virtqueue
>>> error.\n",
>>> + i, vmsg_i->hdr.addr);
>>> + ret = i;
>>> + goto err_unlock_free;
>>> + }
>>
>>
>> Does this imply in order completion of i2c device? (E.g what happens
>> if multiple virtio i2c requests are submitted)
>>
>> Btw, this always use a single descriptor once a time which makes me
>> suspect if a virtqueue(virtio) is really needed. It looks to me we
>> can utilize the virtqueue by submit the request in a batch.
>>
> I'm afraid not all physical devices support batch.
Yes but I think I meant for the virtio device not the physical one. It's
impossible to forbid batching if you have a queue anyway ...
> I'd like to keep the current design and consider
> your suggestion as a possible optimization in the future.
>
> Thanks.
>
>
>>>
>>> +}
>>> +
>>> +static void virtio_i2c_del_vqs(struct virtio_device *vdev)
>>> +{
>>> + vdev->config->reset(vdev);
>>
>>
>> Why need reset here?
>>
>> Thanks
>>
> I'm following what other virtio drivers do.
> They reset the devices before they clean up the queues.
You're ring.
Thanks
>
>
>>
>>> + vdev->config->del_vqs(vdev);
>>> +}
>>> +
>>> +static int virtio_i2c_setup_vqs(struct virtio_i2c *vi)
>>> +{
>>> + struct virtio_device *vdev = vi->vdev;
>>> +
>>> + vi->vq = virtio_find_single_vq(vdev, virtio_i2c_msg_done,
>>> "i2c-msg");
>>
>>
>> We've in the scope of ic2, so "msg" should be sufficient.
>>
>>
> OK. Will change this name. Thanks.
>
>
>>> + return PTR_ERR_OR_ZERO(vi->vq);
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
[not found] ` <c9be298b-c51b-f7f3-994b-b7bd9ae53b99@intel.com>
@ 2020-09-09 8:54 ` Jason Wang
0 siblings, 0 replies; 14+ messages in thread
From: Jason Wang @ 2020-09-09 8:54 UTC (permalink / raw)
To: Jie Deng, linux-i2c, virtualization, linux-kernel
Cc: mst, wsa+renesas, wsa, andriy.shevchenko, jarkko.nikula,
jdelvare, Sergey.Semin, krzk, rppt, loic.poulain, tali.perry1,
bjorn.andersson, shuo.a.liu, conghui.chen, yu1.wang
On 2020/9/8 上午9:40, Jie Deng wrote:
>
>
> On 2020/9/7 13:40, Jason Wang wrote:
>>
>>>
>>>
>>>>
>>>>>
>>>>> +struct virtio_i2c_msg {
>>>>> + struct virtio_i2c_hdr hdr;
>>>>> + char *buf;
>>>>> + u8 status;
>>>>
>>>>
>>>> Any reason for separating status out of virtio_i2c_hdr?
>>>>
>>> The status is not from i2c_msg.
>>
>>
>> You meant ic2_hdr? You embed status in virtio_i2c_msg anyway.
>>
>>
> The "i2c_msg" structure defined in i2c.h.
>
>>> So I put it out of virtio_i2c_hdr.
>>
>>
>> Something like status or response is pretty common in virtio request
>> (e.g net or scsi), if no special reason, it's better to keep it in
>> the hdr.
>>
> Mainly based on IN or OUT.
>
> The addr, flags and len are from "i2c_msg". They are put in one
> structure as an OUT**scatterlist.
> The buf can be an OUT**or an IN scatterlist depending on write or read.
> The status is a result from the backend which is defined as an IN
> scatterlis.
Ok. I get this.
Thanks
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] i2c: virtio: add a virtio i2c frontend driver
2020-09-03 5:34 [PATCH] i2c: virtio: add a virtio i2c frontend driver Jie Deng
` (3 preceding siblings ...)
2020-09-04 4:06 ` Jason Wang
@ 2020-09-09 9:02 ` Jason Wang
4 siblings, 0 replies; 14+ messages in thread
From: Jason Wang @ 2020-09-09 9:02 UTC (permalink / raw)
To: Jie Deng, linux-i2c, virtualization, linux-kernel
Cc: mst, wsa+renesas, wsa, andriy.shevchenko, jarkko.nikula,
jdelvare, Sergey.Semin, krzk, rppt, loic.poulain, tali.perry1,
bjorn.andersson, shuo.a.liu, conghui.chen, yu1.wang
On 2020/9/3 下午1:34, Jie Deng wrote:
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -6,6 +6,9 @@
> # ACPI drivers
> obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
>
> +# VIRTIO I2C host controller driver
> +obj-$(CONFIG_I2C_VIRTIO) += i2c-virtio.o
> +
> # PC SMBus host controller drivers
> obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
> obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
> diff --git a/drivers/i2c/busses/i2c-virtio.c b/drivers/i2c/busses/i2c-virtio.c
> new file mode 100644
> index 0000000..47f9fd1
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-virtio.c
> @@ -0,0 +1,276 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Virtio I2C Bus Driver
> + *
> + * Copyright (c) 2020 Intel Corporation. All rights reserved.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/completion.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/io.h>
> +#include <linux/jiffies.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/wait.h>
> +
> +#include <linux/virtio.h>
> +#include <linux/virtio_ids.h>
> +#include <linux/virtio_config.h>
> +
> +#define VIRTIO_I2C_MSG_OK 0
> +#define VIRTIO_I2C_MSG_ERR 1
> +
> +/**
> + * struct virtio_i2c_hdr - the virtio I2C message header structure
> + * @addr: i2c_msg addr, the slave address
> + * @flags: i2c_msg flags
> + * @len: i2c_msg len
> + */
> +struct virtio_i2c_hdr {
> + __virtio16 addr;
> + __virtio16 flags;
> + __virtio16 len;
> +} __packed;
Btw, this part should belong to uAPI, and you need to define the status
in uAPI.
Thanks
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2020-09-09 9:02 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-03 5:34 [PATCH] i2c: virtio: add a virtio i2c frontend driver Jie Deng
2020-09-03 6:12 ` Jason Wang
2020-09-03 7:19 ` Jie Deng
2020-09-03 9:14 ` Loic Poulain
2020-09-04 3:38 ` Jason Wang
2020-09-03 9:58 ` Michael S. Tsirkin
2020-09-04 5:28 ` Jie Deng
2020-09-03 10:20 ` Andy Shevchenko
2020-09-04 6:08 ` Jie Deng
2020-09-04 4:06 ` Jason Wang
2020-09-04 13:21 ` Jie Deng
2020-09-07 5:40 ` Jason Wang
[not found] ` <c9be298b-c51b-f7f3-994b-b7bd9ae53b99@intel.com>
2020-09-09 8:54 ` Jason Wang
2020-09-09 9:02 ` Jason Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).