[PATCH RFC v4] virtio: Implement Virtio Backend for SD/MMC in QEMU
From: Mi Add a Virtio backend for SD/MMC devices. Confirmed interoperability with Linux. Linux patch link: https://lore.kernel.org/linux-mmc/20240701120642.30001-1-krashmi...@gmail.com/ Signed-off-by: Mikhail Krasheninnikov CC: Matwey Kornilov CC: qemu-bl...@nongnu.org CC: Michael S. Tsirkin CC: Kevin Wolf CC: Stefan Hajnoczi --- Changes from v3: - Many structs were moved to uapi in kernel patch (new link would be sent as response to this letter). This patch integrates them. - Since there's no corresponding patch to Virtio specification yet, this patch is marked as RFC. hw/block/Kconfig | 6 + hw/block/meson.build | 1 + hw/block/virtio-sdhci.c | 142 ++ hw/virtio/meson.build | 1 + hw/virtio/virtio-sdhci-pci.c | 86 +++ hw/virtio/virtio.c| 3 +- include/hw/virtio/virtio-sdhci.h | 22 +++ include/standard-headers/linux/virtio_ids.h | 1 + include/standard-headers/linux/virtio_sdhci.h | 39 + 9 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 hw/block/virtio-sdhci.c create mode 100644 hw/virtio/virtio-sdhci-pci.c create mode 100644 include/hw/virtio/virtio-sdhci.h create mode 100644 include/standard-headers/linux/virtio_sdhci.h diff --git a/hw/block/Kconfig b/hw/block/Kconfig index 9e8f28f982..5b5363da01 100644 --- a/hw/block/Kconfig +++ b/hw/block/Kconfig @@ -44,3 +44,9 @@ config VHOST_USER_BLK config SWIM bool + +config VIRTIO_SDHCI +bool +default y +select SD +depends on VIRTIO diff --git a/hw/block/meson.build b/hw/block/meson.build index 8aa4dc3893..82356c264e 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -19,5 +19,6 @@ system_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c')) specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', 'virtio-blk-common.c')) specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c', 'virtio-blk-common.c')) +specific_ss.add(when: 'CONFIG_VIRTIO_SDHCI', if_true: files('virtio-sdhci.c')) subdir('dataplane') diff --git a/hw/block/virtio-sdhci.c b/hw/block/virtio-sdhci.c new file mode 100644 index 00..d3a90f7b5a --- /dev/null +++ b/hw/block/virtio-sdhci.c @@ -0,0 +1,142 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" + +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-sdhci.h" +#include "qemu/typedefs.h" +#include "sysemu/blockdev.h" +#include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/linux/virtio_sdhci.h" + +static void send_command(SDBus *sdbus, struct mmc_req *mmc_request, uint8_t *response, + struct virtio_mmc_response *virtio_resp) +{ +SDRequest sdreq; +int resp_len; + +sdreq.cmd = (uint8_t)mmc_request->opcode; +sdreq.arg = mmc_request->arg; +resp_len = sdbus_do_command(sdbus, &sdreq, response); +virtio_resp->cmd_resp_len = resp_len; + +for (int i = 0; i < resp_len / sizeof(__le32); i++) { +virtio_resp->cmd_resp[i] = ldl_be_p(&virtio_resp->cmd_resp[i]); +} +} + +static void send_command_without_response(SDBus *sdbus, struct mmc_req *mmc_request) +{ +SDRequest sdreq; +uint8_t response[4]; + +sdreq.cmd = (uint8_t)mmc_request->opcode; +sdreq.arg = mmc_request->arg; +sdbus_do_command(sdbus, &sdreq, response); +} + +static void handle_mmc_request(VirtIODevice *vdev, struct virtio_mmc_request *virtio_req, + struct virtio_mmc_response *virtio_resp) +{ +VirtIOSDHCI *vsd = VIRTIO_SDHCI(vdev); +SDBus *sdbus = &vsd->sdbus; + +if (virtio_req->flags & VIRTIO_MMC_REQUEST_SBC) { +send_command_without_response(sdbus, &virtio_req->sbc_req); +} + +send_command(sdbus, &virtio_req->request, +(uint8_t *)virtio_resp->cmd_resp, virtio_resp); + +if (virtio_req->flags & VIRTIO_MMC_REQUEST_DATA) { +if (virtio_req->flags & VIRTIO_MMC_REQUEST_WRITE) { +sdbus_write_data(sdbus, virtio_req->buf, virtio_req->buf_len); +} else { +sdbus_read_data(sdbus, virtio_resp->buf, virtio_req->buf_len); +} +} + +if (virtio_req->flags & VIRTIO_MMC_REQUEST_STOP) { +send_command_without_response(sdbus, &virtio_req->stop_req); +} +} + +static void handle_request(VirtIODevice *vdev, VirtQueue *vq) +{ +VirtQueueElement *elem; +struct virtio_mmc_request virtio_req; +struct virtio_mmc_response virtio_resp; + +elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + +iov_to_buf(elem->out_sg, elem->out_
Re: [PATCH v3] virtio: Implement Virtio Backend for SD/MMC in QEMU
On Wed, 3 Jul 2024, Michael S. Tsirkin wrote: > On Wed, Jul 03, 2024 at 10:55:17PM +0300, Mikhail Krasheninnikov wrote: > > > > Hello, Alex! > > > > No, there's no patch to the VirtIO specification yet. This is > > proof-of-concept solution since I'm not sure that I did everything > > correct with the design (and as folks' reviews show, for a good reason). > > As soon as most obvious issues would be out of the way, I think I'll > > submit a patch. > > > Mikhail, if you want people to review your patches but not merge > them yet, pls use an RFC tag in the subject to avoid confusion. > > Thanks, > > -- > MST > > Hello, Michael! I was planning to submit three patches: to the kernel, emulator and Virtio specification around the same time - as soon as the obvious bugs are fixed, I'll submit a patch to the specification. I thought it wasn't necessary to use the RFC tag in that case, but if you think it is, I'll include it with the next version of the patch.
Re: [PATCH v3] virtio: Implement Virtio Backend for SD/MMC in QEMU
Hello, Alex! No, there's no patch to the VirtIO specification yet. This is proof-of-concept solution since I'm not sure that I did everything correct with the design (and as folks' reviews show, for a good reason). As soon as most obvious issues would be out of the way, I think I'll submit a patch.
[PATCH v3] virtio: Implement Virtio Backend for SD/MMC in QEMU
From: Mi Add a Virtio backend for SD/MMC devices. Confirmed interoperability with Linux. Linux patch link: https://lore.kernel.org/linux-mmc/20240701120642.30001-1-krashmi...@gmail.com/ Signed-off-by: Mikhail Krasheninnikov CC: Matwey Kornilov CC: qemu-bl...@nongnu.org CC: Michael S. Tsirkin CC: Kevin Wolf CC: Stefan Hajnoczi --- Thanks for the feedback! Changes from v2: - Renamed virtio-mmc to virtio-sdhci - Added a link to linux patch with corresponding driver in commit message - Moved variable declaration to function prologue - Removed duplicate defines - Changed #pragma once Michael, I couldn't find any simular structs to those in virtio-sdhci.c in Linux uapi, I'll be very grateful if you could point them out to me! hw/block/Kconfig| 6 + hw/block/meson.build| 1 + hw/block/virtio-sdhci.c | 169 hw/virtio/meson.build | 1 + hw/virtio/virtio-sdhci-pci.c| 86 ++ hw/virtio/virtio.c | 3 +- include/hw/virtio/virtio-sdhci.h| 22 +++ include/standard-headers/linux/virtio_ids.h | 1 + 8 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 hw/block/virtio-sdhci.c create mode 100644 hw/virtio/virtio-sdhci-pci.c create mode 100644 include/hw/virtio/virtio-sdhci.h diff --git a/hw/block/Kconfig b/hw/block/Kconfig index 9e8f28f982..5b5363da01 100644 --- a/hw/block/Kconfig +++ b/hw/block/Kconfig @@ -44,3 +44,9 @@ config VHOST_USER_BLK config SWIM bool + +config VIRTIO_SDHCI +bool +default y +select SD +depends on VIRTIO diff --git a/hw/block/meson.build b/hw/block/meson.build index 8aa4dc3893..82356c264e 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -19,5 +19,6 @@ system_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c')) specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', 'virtio-blk-common.c')) specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c', 'virtio-blk-common.c')) +specific_ss.add(when: 'CONFIG_VIRTIO_SDHCI', if_true: files('virtio-sdhci.c')) subdir('dataplane') diff --git a/hw/block/virtio-sdhci.c b/hw/block/virtio-sdhci.c new file mode 100644 index 00..8b7105229f --- /dev/null +++ b/hw/block/virtio-sdhci.c @@ -0,0 +1,169 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" + +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-sdhci.h" +#include "qemu/typedefs.h" +#include "sysemu/blockdev.h" +#include "standard-headers/linux/virtio_ids.h" + +typedef struct sd_req { +uint32_t opcode; +uint32_t arg; +} sd_req; + +typedef struct virtio_sdhci_req { +uint8_t flags; + +#define VIRTIO_SDHCI_REQUEST_DATA BIT(1) +#define VIRTIO_SDHCI_REQUEST_WRITE BIT(2) +#define VIRTIO_SDHCI_REQUEST_STOP BIT(3) +#define VIRTIO_SDHCI_REQUEST_SBC BIT(4) + +sd_req request; + +uint8_t buf[4096]; +size_t buf_len; + +sd_req stop_req; +sd_req sbc_req; +} virtio_sdhci_req; + +typedef struct virtio_sdhci_resp { +uint32_t response[4]; +int resp_len; +uint8_t buf[4096]; +} virtio_sdhci_resp; + +static void send_command(SDBus *sdbus, sd_req *mmc_request, uint8_t *response, + virtio_sdhci_resp *virtio_resp) +{ +SDRequest sdreq; +int resp_len; + +sdreq.cmd = (uint8_t)mmc_request->opcode; +sdreq.arg = mmc_request->arg; +resp_len = sdbus_do_command(sdbus, &sdreq, response); +virtio_resp->resp_len = resp_len; + +for (int i = 0; i < resp_len / sizeof(uint32_t); i++) { +virtio_resp->response[i] = ldl_be_p(&virtio_resp->response[i]); +} +} + +static void send_command_without_response(SDBus *sdbus, sd_req *mmc_request) +{ +SDRequest sdreq; +uint8_t response[4]; + +sdreq.cmd = (uint8_t)mmc_request->opcode; +sdreq.arg = mmc_request->arg; +sdbus_do_command(sdbus, &sdreq, response); +} + +static void handle_mmc_request(VirtIODevice *vdev, virtio_sdhci_req *virtio_req, + virtio_sdhci_resp *virtio_resp) +{ +VirtIOSDHCI *vsd = VIRTIO_SDHCI(vdev); +SDBus *sdbus = &vsd->sdbus; + +if (virtio_req->flags & VIRTIO_SDHCI_REQUEST_SBC) { +send_command_without_response(sdbus, &virtio_req->sbc_req); +} + +send_command(sdbus, &virtio_req->request, +(uint8_t *)virtio_resp->response, virtio_resp); + +if (virtio_req->flags & VIRTIO_SDHCI_REQUEST_DATA) { +if (virtio_req->flags & VIRTIO_SDHCI_REQUEST_WRITE) { +sdbus_write_data(sdbus, virtio_req->buf, virtio_req->buf_len); +} else { +sdbus_read_data(sdbus, virtio_resp->
[PATCH v2] virtio: Implement Virtio Backend for SD/MMC in QEMU
From: Mi Add a Virtio backend for SD/MMC devices. Confirmed interoperability with Linux. Signed-off-by: Mikhail Krasheninnikov CC: Matwey Kornilov CC: qemu-bl...@nongnu.org CC: Michael S. Tsirkin CC: Kevin Wolf CC: Stefan Hajnoczi --- After a feedback, moved virtio.c from virtio core directory to hw/block. >From what I see from the examples of virtio drivers, other files should be where they are now. Correct me if I'm wrong. hw/block/Kconfig| 5 + hw/block/meson.build| 1 + hw/block/virtio-mmc.c | 165 hw/virtio/meson.build | 1 + hw/virtio/virtio-mmc-pci.c | 85 ++ hw/virtio/virtio.c | 3 +- include/hw/virtio/virtio-mmc.h | 20 +++ include/standard-headers/linux/virtio_ids.h | 1 + 8 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 hw/block/virtio-mmc.c create mode 100644 hw/virtio/virtio-mmc-pci.c create mode 100644 include/hw/virtio/virtio-mmc.h diff --git a/hw/block/Kconfig b/hw/block/Kconfig index 9e8f28f982..a3059261fa 100644 --- a/hw/block/Kconfig +++ b/hw/block/Kconfig @@ -44,3 +44,8 @@ config VHOST_USER_BLK config SWIM bool + +config VIRTIO_MMC +bool +default y +depends on VIRTIO diff --git a/hw/block/meson.build b/hw/block/meson.build index 8aa4dc3893..4fa6e90b5f 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -19,5 +19,6 @@ system_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c')) specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', 'virtio-blk-common.c')) specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c', 'virtio-blk-common.c')) +specific_ss.add(when: 'CONFIG_VIRTIO_MMC', if_true: files('virtio-mmc.c')) subdir('dataplane') diff --git a/hw/block/virtio-mmc.c b/hw/block/virtio-mmc.c new file mode 100644 index 00..50bd7113c5 --- /dev/null +++ b/hw/block/virtio-mmc.c @@ -0,0 +1,165 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" + +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-mmc.h" +#include "qemu/typedefs.h" +#include "sysemu/blockdev.h" + +typedef struct mmc_req { +uint32_t opcode; +uint32_t arg; +} mmc_req; + +typedef struct virtio_mmc_req { +uint8_t flags; + +#define VIRTIO_MMC_REQUEST_DATA BIT(1) +#define VIRTIO_MMC_REQUEST_WRITE BIT(2) +#define VIRTIO_MMC_REQUEST_STOP BIT(3) +#define VIRTIO_MMC_REQUEST_SBC BIT(4) + +mmc_req request; + +uint8_t buf[4096]; +size_t buf_len; + +mmc_req stop_req; +mmc_req sbc_req; +} virtio_mmc_req; + +typedef struct virtio_mmc_resp { +uint32_t response[4]; +int resp_len; +uint8_t buf[4096]; +} virtio_mmc_resp; + +static void send_command(SDBus *sdbus, mmc_req *mmc_request, uint8_t *response, + virtio_mmc_resp *virtio_resp) +{ +SDRequest sdreq; +sdreq.cmd = (uint8_t)mmc_request->opcode; +sdreq.arg = mmc_request->arg; +int resp_len = sdbus_do_command(sdbus, &sdreq, response); +virtio_resp->resp_len = resp_len; + +for (int i = 0; i < resp_len / sizeof(uint32_t); i++) { +virtio_resp->response[i] = ldl_be_p(&virtio_resp->response[i]); +} +} + +static void send_command_without_response(SDBus *sdbus, mmc_req *mmc_request) +{ +SDRequest sdreq; +sdreq.cmd = (uint8_t)mmc_request->opcode; +sdreq.arg = mmc_request->arg; +uint8_t response[4]; +sdbus_do_command(sdbus, &sdreq, response); +} + +static void handle_mmc_request(VirtIODevice *vdev, virtio_mmc_req *virtio_req, + virtio_mmc_resp *virtio_resp) +{ +VirtIOMMC *vmmc = VIRTIO_MMC(vdev); +SDBus *sdbus = &vmmc->sdbus; + +if (virtio_req->flags & VIRTIO_MMC_REQUEST_SBC) { +send_command_without_response(sdbus, &virtio_req->sbc_req); +} + +send_command(sdbus, &virtio_req->request, +(uint8_t *)virtio_resp->response, virtio_resp); + +if (virtio_req->flags & VIRTIO_MMC_REQUEST_DATA) { +if (virtio_req->flags & VIRTIO_MMC_REQUEST_WRITE) { +sdbus_write_data(sdbus, virtio_req->buf, virtio_req->buf_len); +} else { +sdbus_read_data(sdbus, virtio_resp->buf, virtio_req->buf_len); +} +} + +if (virtio_req->flags & VIRTIO_MMC_REQUEST_STOP) { +send_command_without_response(sdbus, &virtio_req->stop_req); +} +} + +static void handle_request(VirtIODevice *vdev, VirtQueue *vq) +{ +VirtQueueElement *elem; +virtio_mmc_req virtio_req; +virtio_mmc_resp virtio_resp; + +elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + +iov_to_buf(elem->o
[PATCH] virtio: Implement Virtio Backend for SD/MMC in QEMU
Add a Virtio backend for SD/MMC devices. Confirmed interoperability with Linux. Signed-off-by: Mikhail Krasheninnikov CC: Matwey Kornilov CC: qemu-bl...@nongnu.org CC: Michael S. Tsirkin --- hw/virtio/Kconfig | 5 + hw/virtio/meson.build | 2 + hw/virtio/virtio-mmc-pci.c | 85 ++ hw/virtio/virtio-mmc.c | 165 hw/virtio/virtio.c | 3 +- include/hw/virtio/virtio-mmc.h | 20 +++ include/standard-headers/linux/virtio_ids.h | 1 + 7 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 hw/virtio/virtio-mmc-pci.c create mode 100644 hw/virtio/virtio-mmc.c create mode 100644 include/hw/virtio/virtio-mmc.h diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index 92c9cf6c96..e5fa7607c4 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -105,3 +105,8 @@ config VHOST_USER_SCMI bool default y depends on VIRTIO && VHOST_USER + +config VIRTIO_MMC +bool +default y +depends on VIRTIO \ No newline at end of file diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index 47baf00366..1ff095c5bc 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -41,6 +41,7 @@ specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_GPIO', if_true: files('vhost-use specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_GPIO'], if_true: files('vhost-user-gpio-pci.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi.c')) specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SCMI'], if_true: files('vhost-user-scmi-pci.c')) +specific_virtio_ss.add(when: 'CONFIG_VIRTIO_MMC', if_true: files('virtio-mmc.c')) virtio_pci_ss = ss.source_set() virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) @@ -68,6 +69,7 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu-pci. virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-md-pci.c')) +virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MMC', if_true: files('virtio-mmc-pci.c')) specific_virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss) diff --git a/hw/virtio/virtio-mmc-pci.c b/hw/virtio/virtio-mmc-pci.c new file mode 100644 index 00..f0ed17d03b --- /dev/null +++ b/hw/virtio/virtio-mmc-pci.c @@ -0,0 +1,85 @@ +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-pci.h" +#include "hw/virtio/virtio-mmc.h" +#include "hw/qdev-properties-system.h" +#include "qemu/typedefs.h" +#include "qapi/error.h" +#include "sysemu/block-backend-global-state.h" + +typedef struct VirtIOMMCPCI VirtIOMMCPCI; + +/* + * virtio-mmc-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_MMC_PCI "virtio-mmc-pci-base" +DECLARE_INSTANCE_CHECKER(VirtIOMMCPCI, VIRTIO_MMC_PCI, + TYPE_VIRTIO_MMC_PCI) + +struct VirtIOMMCPCI { +VirtIOPCIProxy parent_obj; +VirtIOMMC vdev; +BlockBackend *blk; +}; + +static void virtio_mmc_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ +VirtIOMMCPCI *vmmc = VIRTIO_MMC_PCI(vpci_dev); +DeviceState *dev = DEVICE(&vmmc->vdev); + +if (!vmmc->blk) { +error_setg(errp, "Drive property not set"); +return; +} +VirtIOMMC *vmmc_dev = &vmmc->vdev; +vmmc_dev->blk = vmmc->blk; +blk_detach_dev(vmmc->blk, DEVICE(vpci_dev)); + +qdev_set_parent_bus(dev, BUS(&vpci_dev->bus), errp); + +virtio_pci_force_virtio_1(vpci_dev); +object_property_set_bool(OBJECT(dev), "realized", true, errp); +} + +static Property virtio_mmc_properties[] = { +DEFINE_PROP_DRIVE("drive", VirtIOMMCPCI, blk), +DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_mmc_pci_class_init(ObjectClass *oc, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(oc); +VirtioPCIClass *virtio_pci_class = VIRTIO_PCI_CLASS(oc); +PCIDeviceClass *pci_device_class = PCI_DEVICE_CLASS(oc); + +device_class_set_props(dc, virtio_mmc_properties); +set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + +virtio_pci_class->realize = virtio_mmc_pci_realize; + +pci_device_class->revision = VIRTIO_PCI_ABI_VERSION; +pci_device_class->class_id = PCI_CLASS_MEMORY_FLASH; +} + +static void virtio_mmc_pci_instance_init(Object *obj) +{ +VirtIOMMCPCI *dev = VIRTIO_MMC_PCI(obj); + +virtio_instance_init