[PATCH] Add vhost-user-spi and vhost-user-spi-pci devices

Haixu Cui posted 1 patch 4 months, 2 weeks ago
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, "Michael S. Tsirkin" <mst@redhat.com>, Cornelia Huck <cohuck@redhat.com>
hw/virtio/Kconfig                           |   5 +
hw/virtio/meson.build                       |   3 +
hw/virtio/vhost-user-spi-pci.c              |  69 ++++++++
hw/virtio/vhost-user-spi.c                  |  66 +++++++
hw/virtio/virtio.c                          |   4 +-
include/hw/virtio/vhost-user-spi.h          |  25 +++
include/standard-headers/linux/virtio_ids.h |   1 +
include/standard-headers/linux/virtio_spi.h | 186 ++++++++++++++++++++
8 files changed, 358 insertions(+), 1 deletion(-)
create mode 100644 hw/virtio/vhost-user-spi-pci.c
create mode 100644 hw/virtio/vhost-user-spi.c
create mode 100644 include/hw/virtio/vhost-user-spi.h
create mode 100644 include/standard-headers/linux/virtio_spi.h
[PATCH] Add vhost-user-spi and vhost-user-spi-pci devices
Posted by Haixu Cui 4 months, 2 weeks ago
This work is based on the virtio-spi spec, virtio-spi driver introduced by
the following patch series:
- https://github.com/oasis-tcs/virtio-spec/tree/virtio-1.4/device-types/spi
- https://lwn.net/Articles/966715/

To test with rust-vmm vhost-user-spi daemon, start the vhost-daemon firstly:
    vhost-device-spi --socket-path=vspi.sock --socket-count=1 --device "/dev/spidev0.0"

Then invoke qemu with the following parameters:
    qemu-system-aarch64 -m 1G \
        -chardev socket,path=/home/root/vspi.sock0,id=vspi \
        -device vhost-user-spi-pci,chardev=vspi,id=spi \
        -object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on \
        -numa node,memdev=mem
        ...

Signed-off-by: Haixu Cui <quic_haixcui@quicinc.com>
---
 hw/virtio/Kconfig                           |   5 +
 hw/virtio/meson.build                       |   3 +
 hw/virtio/vhost-user-spi-pci.c              |  69 ++++++++
 hw/virtio/vhost-user-spi.c                  |  66 +++++++
 hw/virtio/virtio.c                          |   4 +-
 include/hw/virtio/vhost-user-spi.h          |  25 +++
 include/standard-headers/linux/virtio_ids.h |   1 +
 include/standard-headers/linux/virtio_spi.h | 186 ++++++++++++++++++++
 8 files changed, 358 insertions(+), 1 deletion(-)
 create mode 100644 hw/virtio/vhost-user-spi-pci.c
 create mode 100644 hw/virtio/vhost-user-spi.c
 create mode 100644 include/hw/virtio/vhost-user-spi.h
 create mode 100644 include/standard-headers/linux/virtio_spi.h

diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
index aa63ff7fd4..d5857651e5 100644
--- a/hw/virtio/Kconfig
+++ b/hw/virtio/Kconfig
@@ -110,3 +110,8 @@ config VHOST_USER_SCMI
     bool
     default y
     depends on VIRTIO && VHOST_USER
+
+config VHOST_USER_SPI
+    bool
+    default y
+    depends on VIRTIO && VHOST_USER
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index 621fc65454..42296219e5 100644
--- a/hw/virtio/meson.build
+++ b/hw/virtio/meson.build
@@ -26,6 +26,7 @@ if have_vhost
     system_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
     system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SND', if_true: files('vhost-user-snd.c'))
     system_virtio_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c'))
+    system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SPI', if_true: files('vhost-user-spi.c'))
 
     # PCI Stubs
     system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('vhost-user-device-pci.c'))
@@ -39,6 +40,8 @@ if have_vhost
                          if_true: files('vhost-user-snd-pci.c'))
     system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_INPUT'],
                          if_true: files('vhost-user-input-pci.c'))
+    system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SPI'],
+                         if_true: files('vhost-user-spi-pci.c'))
   endif
   if have_vhost_vdpa
     system_virtio_ss.add(files('vhost-vdpa.c'))
diff --git a/hw/virtio/vhost-user-spi-pci.c b/hw/virtio/vhost-user-spi-pci.c
new file mode 100644
index 0000000000..3565d526af
--- /dev/null
+++ b/hw/virtio/vhost-user-spi-pci.c
@@ -0,0 +1,69 @@
+/*
+ * Vhost-user spi virtio device PCI glue
+ *
+ * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/vhost-user-spi.h"
+#include "hw/virtio/virtio-pci.h"
+
+struct VHostUserSPIPCI {
+    VirtIOPCIProxy parent_obj;
+    VHostUserSPI vdev;
+};
+
+typedef struct VHostUserSPIPCI VHostUserSPIPCI;
+
+#define TYPE_VHOST_USER_SPI_PCI "vhost-user-spi-pci-base"
+
+DECLARE_INSTANCE_CHECKER(VHostUserSPIPCI, VHOST_USER_SPI_PCI,
+                         TYPE_VHOST_USER_SPI_PCI)
+
+static void vhost_user_spi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
+
+    vpci_dev->nvectors = 1;
+    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
+}
+
+static void vhost_user_spi_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+    k->realize = vhost_user_spi_pci_realize;
+    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
+    pcidev_k->revision = 0x00;
+    pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+}
+
+static void vhost_user_spi_pci_instance_init(Object *obj)
+{
+    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(obj);
+
+    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+                                TYPE_VHOST_USER_SPI);
+}
+
+static const VirtioPCIDeviceTypeInfo vhost_user_spi_pci_info = {
+    .base_name = TYPE_VHOST_USER_SPI_PCI,
+    .non_transitional_name = "vhost-user-spi-pci",
+    .instance_size = sizeof(VHostUserSPIPCI),
+    .instance_init = vhost_user_spi_pci_instance_init,
+    .class_init = vhost_user_spi_pci_class_init,
+};
+
+static void vhost_user_spi_pci_register(void)
+{
+    virtio_pci_types_register(&vhost_user_spi_pci_info);
+}
+
+type_init(vhost_user_spi_pci_register);
diff --git a/hw/virtio/vhost-user-spi.c b/hw/virtio/vhost-user-spi.c
new file mode 100644
index 0000000000..e138b8b53b
--- /dev/null
+++ b/hw/virtio/vhost-user-spi.c
@@ -0,0 +1,66 @@
+/*
+ * Vhost-user spi virtio device
+ *
+ * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/vhost-user-spi.h"
+#include "qemu/error-report.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_spi.h"
+
+static Property vspi_properties[] = {
+    DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vspi_realize(DeviceState *dev, Error **errp)
+{
+    VHostUserBase *vub = VHOST_USER_BASE(dev);
+    VHostUserBaseClass *vubc = VHOST_USER_BASE_GET_CLASS(dev);
+
+    /* Fixed for SPI */
+    vub->virtio_id = VIRTIO_ID_SPI;
+    vub->num_vqs = 1;
+    vub->vq_size = 4;
+    vub->config_size = sizeof(struct virtio_spi_config);
+
+    vubc->parent_realize(dev, errp);
+}
+
+static const VMStateDescription vu_spi_vmstate = {
+    .name = "vhost-user-spi",
+    .unmigratable = 1,
+};
+
+static void vu_spi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
+
+    dc->vmsd = &vu_spi_vmstate;
+    device_class_set_props(dc, vspi_properties);
+    device_class_set_parent_realize(dc, vspi_realize,
+                                    &vubc->parent_realize);
+    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+}
+
+static const TypeInfo vu_spi_info = {
+    .name = TYPE_VHOST_USER_SPI,
+    .parent = TYPE_VHOST_USER_BASE,
+    .instance_size = sizeof(VHostUserSPI),
+    .class_init = vu_spi_class_init,
+};
+
+static void vu_spi_register_types(void)
+{
+    type_register_static(&vu_spi_info);
+}
+
+type_init(vu_spi_register_types)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 583a224163..689e2e21e7 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -46,6 +46,7 @@
 #include "standard-headers/linux/virtio_iommu.h"
 #include "standard-headers/linux/virtio_mem.h"
 #include "standard-headers/linux/virtio_vsock.h"
+#include "standard-headers/linux/virtio_spi.h"
 
 /*
  * Maximum size of virtio device config space
@@ -194,7 +195,8 @@ const char *virtio_device_names[] = {
     [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv",
     [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol",
     [VIRTIO_ID_BT] = "virtio-bluetooth",
-    [VIRTIO_ID_GPIO] = "virtio-gpio"
+    [VIRTIO_ID_GPIO] = "virtio-gpio",
+    [VIRTIO_ID_SPI] = "virtio-spi"
 };
 
 static const char *virtio_id_to_name(uint16_t device_id)
diff --git a/include/hw/virtio/vhost-user-spi.h b/include/hw/virtio/vhost-user-spi.h
new file mode 100644
index 0000000000..d6967d8431
--- /dev/null
+++ b/include/hw/virtio/vhost-user-spi.h
@@ -0,0 +1,25 @@
+/*
+ * Vhost-user spi virtio device
+ *
+ * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_VHOST_USER_SPI_H
+#define QEMU_VHOST_USER_SPI_H
+
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/vhost.h"
+#include "hw/virtio/vhost-user.h"
+#include "hw/virtio/vhost-user-base.h"
+
+#define TYPE_VHOST_USER_SPI "vhost-user-spi-device"
+
+OBJECT_DECLARE_SIMPLE_TYPE(VHostUserSPI, VHOST_USER_SPI)
+
+struct VHostUserSPI {
+    VHostUserBase parent_obj;
+};
+
+#endif /* QEMU_VHOST_USER_SPI_H */
diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h
index 7aa2eb7662..601d387c5a 100644
--- a/include/standard-headers/linux/virtio_ids.h
+++ b/include/standard-headers/linux/virtio_ids.h
@@ -68,6 +68,7 @@
 #define VIRTIO_ID_AUDIO_POLICY		39 /* virtio audio policy */
 #define VIRTIO_ID_BT			40 /* virtio bluetooth */
 #define VIRTIO_ID_GPIO			41 /* virtio gpio */
+#define VIRTIO_ID_SPI                   45 /* virtio spi */
 
 /*
  * Virtio Transitional IDs
diff --git a/include/standard-headers/linux/virtio_spi.h b/include/standard-headers/linux/virtio_spi.h
new file mode 100644
index 0000000000..6631827bfa
--- /dev/null
+++ b/include/standard-headers/linux/virtio_spi.h
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
+/*
+ * Definitions for virtio SPI Controller
+ *
+ * Copyright (c) 2021 Intel Corporation. All rights reserved.
+ */
+
+#ifndef _LINUX_VIRTIO_SPI_H
+#define _LINUX_VIRTIO_SPI_H
+
+#include "standard-headers/linux/const.h"
+#include "standard-headers/linux/types.h"
+
+/* Sample data on trailing clock edge */
+#define VIRTIO_SPI_CPHA (1 << 0)
+/* Clock is high when IDLE */
+#define VIRTIO_SPI_CPOL (1 << 1)
+/* Chip Select is active high */
+#define VIRTIO_SPI_CS_HIGH (1 << 2)
+/* Transmit LSB first */
+#define VIRTIO_SPI_MODE_LSB_FIRST (1 << 3)
+/* Loopback mode */
+#define VIRTIO_SPI_MODE_LOOP (1 << 4)
+
+/*
+ * All config fields are read-only for the Virtio SPI driver
+ *
+ * @cs_max_number: maximum number of chipselect the host SPI controller
+ *   supports.
+ * @cs_change_supported: indicates if the host SPI controller supports to toggle
+ * chipselect after each transfer in one message:
+ *   0: unsupported, chipselect will be kept in active state throughout the
+ *      message transaction;
+ *   1: supported.
+ *   Note: Message here contains a sequence of SPI transfers.
+ * @tx_nbits_supported: indicates the supported number of bit for writing:
+ *   bit 0: DUAL (2-bit transfer), 1 for supported
+ *   bit 1: QUAD (4-bit transfer), 1 for supported
+ *   bit 2: OCTAL (8-bit transfer), 1 for supported
+ *   other bits are reserved as 0, 1-bit transfer is always supported.
+ * @rx_nbits_supported: indicates the supported number of bit for reading:
+ *   bit 0: DUAL (2-bit transfer), 1 for supported
+ *   bit 1: QUAD (4-bit transfer), 1 for supported
+ *   bit 2: OCTAL (8-bit transfer), 1 for supported
+ *   other bits are reserved as 0, 1-bit transfer is always supported.
+ * @bits_per_word_mask: mask indicating which values of bits_per_word are
+ *   supported. If not set, no limitation for bits_per_word.
+ * @mode_func_supported: indicates the following features are supported or not:
+ *   bit 0-1: CPHA feature
+ *     0b00: invalid, should support as least one CPHA setting
+ *     0b01: supports CPHA=0 only
+ *     0b10: supports CPHA=1 only
+ *     0b11: supports CPHA=0 and CPHA=1.
+ *   bit 2-3: CPOL feature
+ *     0b00: invalid, should support as least one CPOL setting
+ *     0b01: supports CPOL=0 only
+ *     0b10: supports CPOL=1 only
+ *     0b11: supports CPOL=0 and CPOL=1.
+ *   bit 4: chipselect active high feature, 0 for unsupported and 1 for
+ *     supported, chipselect active low should always be supported.
+ *   bit 5: LSB first feature, 0 for unsupported and 1 for supported,
+ *     MSB first should always be supported.
+ *   bit 6: loopback mode feature, 0 for unsupported and 1 for supported,
+ *     normal mode should always be supported.
+ * @max_freq_hz: the maximum clock rate supported in Hz unit, 0 means no
+ *   limitation for transfer speed.
+ * @max_word_delay_ns: the maximum word delay supported in ns unit,
+ *   0 means word delay feature is unsupported.
+ *   Note: Just as one message contains a sequence of transfers,
+ *         one transfer may contain a sequence of words.
+ * @max_cs_setup_ns: the maximum delay supported after chipselect is asserted,
+ *   in ns unit, 0 means delay is not supported to introduce after chipselect is
+ *   asserted.
+ * @max_cs_hold_ns: the maximum delay supported before chipselect is deasserted,
+ *   in ns unit, 0 means delay is not supported to introduce before chipselect
+ *   is deasserted.
+ * @max_cs_incative_ns: maximum delay supported after chipselect is deasserted,
+ *   in ns unit, 0 means delay is not supported to introduce after chipselect is
+ *   deasserted.
+ */
+struct virtio_spi_config {
+	/* # of /dev/spidev<bus_num>.CS with CS=0..chip_select_max_number -1 */
+        uint8_t cs_max_number;
+        uint8_t cs_change_supported;
+#define VIRTIO_SPI_RX_TX_SUPPORT_DUAL (1 << 0)
+#define VIRTIO_SPI_RX_TX_SUPPORT_QUAD (1 << 1)
+#define VIRTIO_SPI_RX_TX_SUPPORT_OCTAL (1 << 2)
+        uint8_t tx_nbits_supported;
+        uint8_t rx_nbits_supported;
+        uint32_t bits_per_word_mask;
+#define VIRTIO_SPI_MF_SUPPORT_CPHA_0 (1 << 0)
+#define VIRTIO_SPI_MF_SUPPORT_CPHA_1 (1 << 1)
+#define VIRTIO_SPI_MF_SUPPORT_CPOL_0 (1 << 2)
+#define VIRTIO_SPI_MF_SUPPORT_CPOL_1 (1 << 3)
+#define VIRTIO_SPI_MF_SUPPORT_CS_HIGH (1 << 4)
+#define VIRTIO_SPI_MF_SUPPORT_LSB_FIRST (1 << 5)
+#define VIRTIO_SPI_MF_SUPPORT_LOOPBACK (1 << 6)
+        uint32_t mode_func_supported;
+        uint32_t max_freq_hz;
+        uint32_t max_word_delay_ns;
+        uint32_t max_cs_setup_ns;
+        uint32_t max_cs_hold_ns;
+        uint32_t max_cs_inactive_ns;
+};
+
+/*
+ * @chip_select_id: chipselect index the SPI transfer used.
+ *
+ * @bits_per_word: the number of bits in each SPI transfer word.
+ *
+ * @cs_change: whether to deselect device after finishing this transfer
+ *     before starting the next transfer, 0 means cs keep asserted and
+ *     1 means cs deasserted then asserted again.
+ *
+ * @tx_nbits: bus width for write transfer.
+ *     0,1: bus width is 1, also known as SINGLE
+ *     2  : bus width is 2, also known as DUAL
+ *     4  : bus width is 4, also known as QUAD
+ *     8  : bus width is 8, also known as OCTAL
+ *     other values are invalid.
+ *
+ * @rx_nbits: bus width for read transfer.
+ *     0,1: bus width is 1, also known as SINGLE
+ *     2  : bus width is 2, also known as DUAL
+ *     4  : bus width is 4, also known as QUAD
+ *     8  : bus width is 8, also known as OCTAL
+ *     other values are invalid.
+ *
+ * @reserved: for future use.
+ *
+ * @mode: SPI transfer mode.
+ *     bit 0: CPHA, determines the timing (i.e. phase) of the data
+ *         bits relative to the clock pulses.For CPHA=0, the
+ *         "out" side changes the data on the trailing edge of the
+ *         preceding clock cycle, while the "in" side captures the data
+ *         on (or shortly after) the leading edge of the clock cycle.
+ *         For CPHA=1, the "out" side changes the data on the leading
+ *         edge of the current clock cycle, while the "in" side
+ *         captures the data on (or shortly after) the trailing edge of
+ *         the clock cycle.
+ *     bit 1: CPOL, determines the polarity of the clock. CPOL=0 is a
+ *         clock which idles at 0, and each cycle consists of a pulse
+ *         of 1. CPOL=1 is a clock which idles at 1, and each cycle
+ *         consists of a pulse of 0.
+ *     bit 2: CS_HIGH, if 1, chip select active high, else active low.
+ *     bit 3: LSB_FIRST, determines per-word bits-on-wire, if 0, MSB
+ *         first, else LSB first.
+ *     bit 4: LOOP, loopback mode.
+ *
+ * @freq: the transfer speed in Hz.
+ *
+ * @word_delay_ns: delay to be inserted between consecutive words of a
+ *     transfer, in ns unit.
+ *
+ * @cs_setup_ns: delay to be introduced after CS is asserted, in ns
+ *     unit.
+ *
+ * @cs_delay_hold_ns: delay to be introduced before CS is deasserted
+ *     for each transfer, in ns unit.
+ *
+ * @cs_change_delay_inactive_ns: delay to be introduced after CS is
+ *     deasserted and before next asserted, in ns unit.
+ */
+struct spi_transfer_head {
+        uint8_t chip_select_id;
+        uint8_t bits_per_word;
+        uint8_t cs_change;
+        uint8_t tx_nbits;
+        uint8_t rx_nbits;
+        uint8_t reserved[3];
+        uint32_t mode;
+        uint32_t freq;
+        uint32_t word_delay_ns;
+        uint32_t cs_setup_ns;
+        uint32_t cs_delay_hold_ns;
+        uint32_t cs_change_delay_inactive_ns;
+};
+
+struct spi_transfer_result {
+#define VIRTIO_SPI_TRANS_OK 0
+#define VIRTIO_SPI_PARAM_ERR 1
+#define VIRTIO_SPI_TRANS_ERR 2
+	uint8_t status;
+};
+
+#endif /* _LINUX_VIRTIO_SPI_H */
-- 
2.34.1
Re: [PATCH] Add vhost-user-spi and vhost-user-spi-pci devices
Posted by Alex Bennée 2 months, 4 weeks ago
Haixu Cui <quic_haixcui@quicinc.com> writes:


Apologies for the delay in getting to this. 

> This work is based on the virtio-spi spec, virtio-spi driver introduced by
> the following patch series:
> - https://github.com/oasis-tcs/virtio-spec/tree/virtio-1.4/device-types/spi
> - https://lwn.net/Articles/966715/
>
> To test with rust-vmm vhost-user-spi daemon, start the vhost-daemon firstly:
>     vhost-device-spi --socket-path=vspi.sock --socket-count=1 --device "/dev/spidev0.0"

I'm struggling to test this on my main dev box. Are there any dummy SPI
modules for the kernel for testing? Otherwise we could consider
implementing something similar to "mock_gpio" for the rust-vmm
vhost-user-spi backend?


> Then invoke qemu with the following parameters:
>     qemu-system-aarch64 -m 1G \
>         -chardev socket,path=/home/root/vspi.sock0,id=vspi \
>         -device vhost-user-spi-pci,chardev=vspi,id=spi \
>         -object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on \
>         -numa node,memdev=mem
>         ...

>
> Signed-off-by: Haixu Cui <quic_haixcui@quicinc.com>
> ---
>  hw/virtio/Kconfig                           |   5 +
>  hw/virtio/meson.build                       |   3 +
>  hw/virtio/vhost-user-spi-pci.c              |  69 ++++++++
>  hw/virtio/vhost-user-spi.c                  |  66 +++++++
>  hw/virtio/virtio.c                          |   4 +-
>  include/hw/virtio/vhost-user-spi.h          |  25 +++
>  include/standard-headers/linux/virtio_ids.h |   1 +
>  include/standard-headers/linux/virtio_spi.h | 186 ++++++++++++++++++++
>  8 files changed, 358 insertions(+), 1 deletion(-)
>  create mode 100644 hw/virtio/vhost-user-spi-pci.c
>  create mode 100644 hw/virtio/vhost-user-spi.c
>  create mode 100644 include/hw/virtio/vhost-user-spi.h
>  create mode 100644 include/standard-headers/linux/virtio_spi.h

Generally we want separate headers patches for the importing of headers.
Doubly so in this case because I can't see the SPI definitions in the
current Linux master. So:

  - 1/2 - Import headers for SPI (!merge until upstream)
  - 2/2 - Implement vhost-user stub for virtio-spi



>
> diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
> index aa63ff7fd4..d5857651e5 100644
> --- a/hw/virtio/Kconfig
> +++ b/hw/virtio/Kconfig
> @@ -110,3 +110,8 @@ config VHOST_USER_SCMI
>      bool
>      default y
>      depends on VIRTIO && VHOST_USER
> +
> +config VHOST_USER_SPI
> +    bool
> +    default y
> +    depends on VIRTIO && VHOST_USER
> diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
> index 621fc65454..42296219e5 100644
> --- a/hw/virtio/meson.build
> +++ b/hw/virtio/meson.build
> @@ -26,6 +26,7 @@ if have_vhost
>      system_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
>      system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SND', if_true: files('vhost-user-snd.c'))
>      system_virtio_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c'))
> +    system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SPI', if_true: files('vhost-user-spi.c'))
>  
>      # PCI Stubs
>      system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('vhost-user-device-pci.c'))
> @@ -39,6 +40,8 @@ if have_vhost
>                           if_true: files('vhost-user-snd-pci.c'))
>      system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_INPUT'],
>                           if_true: files('vhost-user-input-pci.c'))
> +    system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SPI'],
> +                         if_true: files('vhost-user-spi-pci.c'))
>    endif
>    if have_vhost_vdpa
>      system_virtio_ss.add(files('vhost-vdpa.c'))
> diff --git a/hw/virtio/vhost-user-spi-pci.c b/hw/virtio/vhost-user-spi-pci.c
> new file mode 100644
> index 0000000000..3565d526af
> --- /dev/null
> +++ b/hw/virtio/vhost-user-spi-pci.c
> @@ -0,0 +1,69 @@
> +/*
> + * Vhost-user spi virtio device PCI glue
> + *
> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/virtio/vhost-user-spi.h"
> +#include "hw/virtio/virtio-pci.h"
> +
> +struct VHostUserSPIPCI {
> +    VirtIOPCIProxy parent_obj;
> +    VHostUserSPI vdev;
> +};
> +
> +typedef struct VHostUserSPIPCI VHostUserSPIPCI;
> +
> +#define TYPE_VHOST_USER_SPI_PCI "vhost-user-spi-pci-base"
> +
> +DECLARE_INSTANCE_CHECKER(VHostUserSPIPCI, VHOST_USER_SPI_PCI,
> +                         TYPE_VHOST_USER_SPI_PCI)
> +
> +static void vhost_user_spi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
> +{
> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(vpci_dev);
> +    DeviceState *vdev = DEVICE(&dev->vdev);
> +
> +    vpci_dev->nvectors = 1;
> +    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
> +}
> +
> +static void vhost_user_spi_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
> +    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
> +    k->realize = vhost_user_spi_pci_realize;
> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
> +    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
> +    pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
> +    pcidev_k->revision = 0x00;
> +    pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
> +}
> +
> +static void vhost_user_spi_pci_instance_init(Object *obj)
> +{
> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(obj);
> +
> +    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
> +                                TYPE_VHOST_USER_SPI);
> +}
> +
> +static const VirtioPCIDeviceTypeInfo vhost_user_spi_pci_info = {
> +    .base_name = TYPE_VHOST_USER_SPI_PCI,
> +    .non_transitional_name = "vhost-user-spi-pci",
> +    .instance_size = sizeof(VHostUserSPIPCI),
> +    .instance_init = vhost_user_spi_pci_instance_init,
> +    .class_init = vhost_user_spi_pci_class_init,
> +};
> +
> +static void vhost_user_spi_pci_register(void)
> +{
> +    virtio_pci_types_register(&vhost_user_spi_pci_info);
> +}
> +
> +type_init(vhost_user_spi_pci_register);
> diff --git a/hw/virtio/vhost-user-spi.c b/hw/virtio/vhost-user-spi.c
> new file mode 100644
> index 0000000000..e138b8b53b
> --- /dev/null
> +++ b/hw/virtio/vhost-user-spi.c
> @@ -0,0 +1,66 @@
> +/*
> + * Vhost-user spi virtio device
> + *
> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/virtio/virtio-bus.h"
> +#include "hw/virtio/vhost-user-spi.h"
> +#include "qemu/error-report.h"
> +#include "standard-headers/linux/virtio_ids.h"
> +#include "standard-headers/linux/virtio_spi.h"
> +
> +static Property vspi_properties[] = {
> +    DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void vspi_realize(DeviceState *dev, Error **errp)
> +{
> +    VHostUserBase *vub = VHOST_USER_BASE(dev);
> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_GET_CLASS(dev);
> +
> +    /* Fixed for SPI */
> +    vub->virtio_id = VIRTIO_ID_SPI;
> +    vub->num_vqs = 1;
> +    vub->vq_size = 4;
> +    vub->config_size = sizeof(struct virtio_spi_config);
> +
> +    vubc->parent_realize(dev, errp);
> +}
> +
> +static const VMStateDescription vu_spi_vmstate = {
> +    .name = "vhost-user-spi",
> +    .unmigratable = 1,
> +};
> +
> +static void vu_spi_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
> +
> +    dc->vmsd = &vu_spi_vmstate;
> +    device_class_set_props(dc, vspi_properties);
> +    device_class_set_parent_realize(dc, vspi_realize,
> +                                    &vubc->parent_realize);
> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
> +}
> +
> +static const TypeInfo vu_spi_info = {
> +    .name = TYPE_VHOST_USER_SPI,
> +    .parent = TYPE_VHOST_USER_BASE,
> +    .instance_size = sizeof(VHostUserSPI),
> +    .class_init = vu_spi_class_init,
> +};
> +
> +static void vu_spi_register_types(void)
> +{
> +    type_register_static(&vu_spi_info);
> +}
> +
> +type_init(vu_spi_register_types)
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 583a224163..689e2e21e7 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -46,6 +46,7 @@
>  #include "standard-headers/linux/virtio_iommu.h"
>  #include "standard-headers/linux/virtio_mem.h"
>  #include "standard-headers/linux/virtio_vsock.h"
> +#include "standard-headers/linux/virtio_spi.h"
>  
>  /*
>   * Maximum size of virtio device config space
> @@ -194,7 +195,8 @@ const char *virtio_device_names[] = {
>      [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv",
>      [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol",
>      [VIRTIO_ID_BT] = "virtio-bluetooth",
> -    [VIRTIO_ID_GPIO] = "virtio-gpio"
> +    [VIRTIO_ID_GPIO] = "virtio-gpio",
> +    [VIRTIO_ID_SPI] = "virtio-spi"
>  };


For the vhost-user-stub bits when split from the headers:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro
Re: [PATCH] Add vhost-user-spi and vhost-user-spi-pci devices
Posted by Haixu Cui 2 months, 3 weeks ago
Hi Alex,
     Thanks a lot for your comments, please refer to my response below.

On 8/28/2024 1:14 AM, Alex Bennée wrote:
> Haixu Cui <quic_haixcui@quicinc.com> writes:
> 
> 
> Apologies for the delay in getting to this.
> 
>> This work is based on the virtio-spi spec, virtio-spi driver introduced by
>> the following patch series:
>> - https://github.com/oasis-tcs/virtio-spec/tree/virtio-1.4/device-types/spi
>> - https://lwn.net/Articles/966715/
>>
>> To test with rust-vmm vhost-user-spi daemon, start the vhost-daemon firstly:
>>      vhost-device-spi --socket-path=vspi.sock --socket-count=1 --device "/dev/spidev0.0"
> 
> I'm struggling to test this on my main dev box. Are there any dummy SPI
> modules for the kernel for testing? Otherwise we could consider
> implementing something similar to "mock_gpio" for the rust-vmm
> vhost-user-spi backend?

I verified this on my board with physical SPI interface, and I don't 
know if these is dummy SPI module available in kernel. I'll look into this.
> 
> 
>> Then invoke qemu with the following parameters:
>>      qemu-system-aarch64 -m 1G \
>>          -chardev socket,path=/home/root/vspi.sock0,id=vspi \
>>          -device vhost-user-spi-pci,chardev=vspi,id=spi \
>>          -object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on \
>>          -numa node,memdev=mem
>>          ...
> 
>>
>> Signed-off-by: Haixu Cui <quic_haixcui@quicinc.com>
>> ---
>>   hw/virtio/Kconfig                           |   5 +
>>   hw/virtio/meson.build                       |   3 +
>>   hw/virtio/vhost-user-spi-pci.c              |  69 ++++++++
>>   hw/virtio/vhost-user-spi.c                  |  66 +++++++
>>   hw/virtio/virtio.c                          |   4 +-
>>   include/hw/virtio/vhost-user-spi.h          |  25 +++
>>   include/standard-headers/linux/virtio_ids.h |   1 +
>>   include/standard-headers/linux/virtio_spi.h | 186 ++++++++++++++++++++
>>   8 files changed, 358 insertions(+), 1 deletion(-)
>>   create mode 100644 hw/virtio/vhost-user-spi-pci.c
>>   create mode 100644 hw/virtio/vhost-user-spi.c
>>   create mode 100644 include/hw/virtio/vhost-user-spi.h
>>   create mode 100644 include/standard-headers/linux/virtio_spi.h
> 
> Generally we want separate headers patches for the importing of headers.
> Doubly so in this case because I can't see the SPI definitions in the
> current Linux master. So:
> 
>    - 1/2 - Import headers for SPI (!merge until upstream)
>    - 2/2 - Implement vhost-user stub for virtio-spi
> 

Should I move only virtio_spi.h to the first patch, or all of the header 
files? I don't quite understand here.

Best Regards
Thanks
> 
> 
>>
>> diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
>> index aa63ff7fd4..d5857651e5 100644
>> --- a/hw/virtio/Kconfig
>> +++ b/hw/virtio/Kconfig
>> @@ -110,3 +110,8 @@ config VHOST_USER_SCMI
>>       bool
>>       default y
>>       depends on VIRTIO && VHOST_USER
>> +
>> +config VHOST_USER_SPI
>> +    bool
>> +    default y
>> +    depends on VIRTIO && VHOST_USER
>> diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
>> index 621fc65454..42296219e5 100644
>> --- a/hw/virtio/meson.build
>> +++ b/hw/virtio/meson.build
>> @@ -26,6 +26,7 @@ if have_vhost
>>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
>>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SND', if_true: files('vhost-user-snd.c'))
>>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c'))
>> +    system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SPI', if_true: files('vhost-user-spi.c'))
>>   
>>       # PCI Stubs
>>       system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('vhost-user-device-pci.c'))
>> @@ -39,6 +40,8 @@ if have_vhost
>>                            if_true: files('vhost-user-snd-pci.c'))
>>       system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_INPUT'],
>>                            if_true: files('vhost-user-input-pci.c'))
>> +    system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SPI'],
>> +                         if_true: files('vhost-user-spi-pci.c'))
>>     endif
>>     if have_vhost_vdpa
>>       system_virtio_ss.add(files('vhost-vdpa.c'))
>> diff --git a/hw/virtio/vhost-user-spi-pci.c b/hw/virtio/vhost-user-spi-pci.c
>> new file mode 100644
>> index 0000000000..3565d526af
>> --- /dev/null
>> +++ b/hw/virtio/vhost-user-spi-pci.c
>> @@ -0,0 +1,69 @@
>> +/*
>> + * Vhost-user spi virtio device PCI glue
>> + *
>> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
>> + *
>> + * SPDX-License-Identifier: GPL-2.0-or-later
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "hw/qdev-properties.h"
>> +#include "hw/virtio/vhost-user-spi.h"
>> +#include "hw/virtio/virtio-pci.h"
>> +
>> +struct VHostUserSPIPCI {
>> +    VirtIOPCIProxy parent_obj;
>> +    VHostUserSPI vdev;
>> +};
>> +
>> +typedef struct VHostUserSPIPCI VHostUserSPIPCI;
>> +
>> +#define TYPE_VHOST_USER_SPI_PCI "vhost-user-spi-pci-base"
>> +
>> +DECLARE_INSTANCE_CHECKER(VHostUserSPIPCI, VHOST_USER_SPI_PCI,
>> +                         TYPE_VHOST_USER_SPI_PCI)
>> +
>> +static void vhost_user_spi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
>> +{
>> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(vpci_dev);
>> +    DeviceState *vdev = DEVICE(&dev->vdev);
>> +
>> +    vpci_dev->nvectors = 1;
>> +    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
>> +}
>> +
>> +static void vhost_user_spi_pci_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
>> +    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
>> +    k->realize = vhost_user_spi_pci_realize;
>> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
>> +    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
>> +    pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
>> +    pcidev_k->revision = 0x00;
>> +    pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
>> +}
>> +
>> +static void vhost_user_spi_pci_instance_init(Object *obj)
>> +{
>> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(obj);
>> +
>> +    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
>> +                                TYPE_VHOST_USER_SPI);
>> +}
>> +
>> +static const VirtioPCIDeviceTypeInfo vhost_user_spi_pci_info = {
>> +    .base_name = TYPE_VHOST_USER_SPI_PCI,
>> +    .non_transitional_name = "vhost-user-spi-pci",
>> +    .instance_size = sizeof(VHostUserSPIPCI),
>> +    .instance_init = vhost_user_spi_pci_instance_init,
>> +    .class_init = vhost_user_spi_pci_class_init,
>> +};
>> +
>> +static void vhost_user_spi_pci_register(void)
>> +{
>> +    virtio_pci_types_register(&vhost_user_spi_pci_info);
>> +}
>> +
>> +type_init(vhost_user_spi_pci_register);
>> diff --git a/hw/virtio/vhost-user-spi.c b/hw/virtio/vhost-user-spi.c
>> new file mode 100644
>> index 0000000000..e138b8b53b
>> --- /dev/null
>> +++ b/hw/virtio/vhost-user-spi.c
>> @@ -0,0 +1,66 @@
>> +/*
>> + * Vhost-user spi virtio device
>> + *
>> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
>> + *
>> + * SPDX-License-Identifier: GPL-2.0-or-later
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qapi/error.h"
>> +#include "hw/qdev-properties.h"
>> +#include "hw/virtio/virtio-bus.h"
>> +#include "hw/virtio/vhost-user-spi.h"
>> +#include "qemu/error-report.h"
>> +#include "standard-headers/linux/virtio_ids.h"
>> +#include "standard-headers/linux/virtio_spi.h"
>> +
>> +static Property vspi_properties[] = {
>> +    DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
>> +    DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static void vspi_realize(DeviceState *dev, Error **errp)
>> +{
>> +    VHostUserBase *vub = VHOST_USER_BASE(dev);
>> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_GET_CLASS(dev);
>> +
>> +    /* Fixed for SPI */
>> +    vub->virtio_id = VIRTIO_ID_SPI;
>> +    vub->num_vqs = 1;
>> +    vub->vq_size = 4;
>> +    vub->config_size = sizeof(struct virtio_spi_config);
>> +
>> +    vubc->parent_realize(dev, errp);
>> +}
>> +
>> +static const VMStateDescription vu_spi_vmstate = {
>> +    .name = "vhost-user-spi",
>> +    .unmigratable = 1,
>> +};
>> +
>> +static void vu_spi_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
>> +
>> +    dc->vmsd = &vu_spi_vmstate;
>> +    device_class_set_props(dc, vspi_properties);
>> +    device_class_set_parent_realize(dc, vspi_realize,
>> +                                    &vubc->parent_realize);
>> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
>> +}
>> +
>> +static const TypeInfo vu_spi_info = {
>> +    .name = TYPE_VHOST_USER_SPI,
>> +    .parent = TYPE_VHOST_USER_BASE,
>> +    .instance_size = sizeof(VHostUserSPI),
>> +    .class_init = vu_spi_class_init,
>> +};
>> +
>> +static void vu_spi_register_types(void)
>> +{
>> +    type_register_static(&vu_spi_info);
>> +}
>> +
>> +type_init(vu_spi_register_types)
>> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
>> index 583a224163..689e2e21e7 100644
>> --- a/hw/virtio/virtio.c
>> +++ b/hw/virtio/virtio.c
>> @@ -46,6 +46,7 @@
>>   #include "standard-headers/linux/virtio_iommu.h"
>>   #include "standard-headers/linux/virtio_mem.h"
>>   #include "standard-headers/linux/virtio_vsock.h"
>> +#include "standard-headers/linux/virtio_spi.h"
>>   
>>   /*
>>    * Maximum size of virtio device config space
>> @@ -194,7 +195,8 @@ const char *virtio_device_names[] = {
>>       [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv",
>>       [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol",
>>       [VIRTIO_ID_BT] = "virtio-bluetooth",
>> -    [VIRTIO_ID_GPIO] = "virtio-gpio"
>> +    [VIRTIO_ID_GPIO] = "virtio-gpio",
>> +    [VIRTIO_ID_SPI] = "virtio-spi"
>>   };
> 
> 
> For the vhost-user-stub bits when split from the headers:
> 
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> 

Re: [PATCH] Add vhost-user-spi and vhost-user-spi-pci devices
Posted by Alex Bennée 2 months, 3 weeks ago
Haixu Cui <quic_haixcui@quicinc.com> writes:

> Hi Alex,
>     Thanks a lot for your comments, please refer to my response below.
>
> On 8/28/2024 1:14 AM, Alex Bennée wrote:
>> Haixu Cui <quic_haixcui@quicinc.com> writes:
>> Apologies for the delay in getting to this.
>> 
>>> This work is based on the virtio-spi spec, virtio-spi driver introduced by
>>> the following patch series:
>>> - https://github.com/oasis-tcs/virtio-spec/tree/virtio-1.4/device-types/spi
>>> - https://lwn.net/Articles/966715/
>>>
>>> To test with rust-vmm vhost-user-spi daemon, start the vhost-daemon firstly:
>>>      vhost-device-spi --socket-path=vspi.sock --socket-count=1 --device "/dev/spidev0.0"
>> I'm struggling to test this on my main dev box. Are there any dummy
>> SPI
>> modules for the kernel for testing? Otherwise we could consider
>> implementing something similar to "mock_gpio" for the rust-vmm
>> vhost-user-spi backend?
>
> I verified this on my board with physical SPI interface, and I don't
> know if these is dummy SPI module available in kernel. I'll look into
> this.

I'll see if I can boot full Linux into a QEMU machine with SPI devices
which would be another approach.

>> 
>>> Then invoke qemu with the following parameters:
>>>      qemu-system-aarch64 -m 1G \
>>>          -chardev socket,path=/home/root/vspi.sock0,id=vspi \
>>>          -device vhost-user-spi-pci,chardev=vspi,id=spi \
>>>          -object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on \
>>>          -numa node,memdev=mem
>>>          ...
>> 
>>>
>>> Signed-off-by: Haixu Cui <quic_haixcui@quicinc.com>
>>> ---
>>>   hw/virtio/Kconfig                           |   5 +
>>>   hw/virtio/meson.build                       |   3 +
>>>   hw/virtio/vhost-user-spi-pci.c              |  69 ++++++++
>>>   hw/virtio/vhost-user-spi.c                  |  66 +++++++
>>>   hw/virtio/virtio.c                          |   4 +-
>>>   include/hw/virtio/vhost-user-spi.h          |  25 +++
>>>   include/standard-headers/linux/virtio_ids.h |   1 +
>>>   include/standard-headers/linux/virtio_spi.h | 186 ++++++++++++++++++++
>>>   8 files changed, 358 insertions(+), 1 deletion(-)
>>>   create mode 100644 hw/virtio/vhost-user-spi-pci.c
>>>   create mode 100644 hw/virtio/vhost-user-spi.c
>>>   create mode 100644 include/hw/virtio/vhost-user-spi.h
>>>   create mode 100644 include/standard-headers/linux/virtio_spi.h
>> Generally we want separate headers patches for the importing of
>> headers.
>> Doubly so in this case because I can't see the SPI definitions in the
>> current Linux master. So:
>>    - 1/2 - Import headers for SPI (!merge until upstream)
>>    - 2/2 - Implement vhost-user stub for virtio-spi
>> 
>
> Should I move only virtio_spi.h to the first patch, or all of the
> header files? I don't quite understand here.

Just the kernel headers (include/standard-headers). You should import
the kernel headers from a checked out kernel tree using:

  ./scripts/update-linux-headers.sh <path/to/linux.git>

and save them as a single commit for the 1st patch. As the SPI code is
not yet upstream just make it clear in the commit to avoid merging. e.g.

  linux-headers: update to 6.10-rc5 + SPI patches (!merge)

  This imports the headers from the current Linux HEAD + the VirtIO SPI
  patches which are not yet upstream. Once the SPI work is up-streamed in
  the kernel they will be imported from there.

Just make sure you kernel base is newer than the last import otherwise
you will get a lot of additional noise.

>
> Best Regards
> Thanks
>> 
>>>
>>> diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
>>> index aa63ff7fd4..d5857651e5 100644
>>> --- a/hw/virtio/Kconfig
>>> +++ b/hw/virtio/Kconfig
>>> @@ -110,3 +110,8 @@ config VHOST_USER_SCMI
>>>       bool
>>>       default y
>>>       depends on VIRTIO && VHOST_USER
>>> +
>>> +config VHOST_USER_SPI
>>> +    bool
>>> +    default y
>>> +    depends on VIRTIO && VHOST_USER
>>> diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
>>> index 621fc65454..42296219e5 100644
>>> --- a/hw/virtio/meson.build
>>> +++ b/hw/virtio/meson.build
>>> @@ -26,6 +26,7 @@ if have_vhost
>>>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
>>>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SND', if_true: files('vhost-user-snd.c'))
>>>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c'))
>>> +    system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SPI', if_true: files('vhost-user-spi.c'))
>>>         # PCI Stubs
>>>       system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('vhost-user-device-pci.c'))
>>> @@ -39,6 +40,8 @@ if have_vhost
>>>                            if_true: files('vhost-user-snd-pci.c'))
>>>       system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_INPUT'],
>>>                            if_true: files('vhost-user-input-pci.c'))
>>> +    system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SPI'],
>>> +                         if_true: files('vhost-user-spi-pci.c'))
>>>     endif
>>>     if have_vhost_vdpa
>>>       system_virtio_ss.add(files('vhost-vdpa.c'))
>>> diff --git a/hw/virtio/vhost-user-spi-pci.c b/hw/virtio/vhost-user-spi-pci.c
>>> new file mode 100644
>>> index 0000000000..3565d526af
>>> --- /dev/null
>>> +++ b/hw/virtio/vhost-user-spi-pci.c
>>> @@ -0,0 +1,69 @@
>>> +/*
>>> + * Vhost-user spi virtio device PCI glue
>>> + *
>>> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
>>> + *
>>> + * SPDX-License-Identifier: GPL-2.0-or-later
>>> + */
>>> +
>>> +#include "qemu/osdep.h"
>>> +#include "hw/qdev-properties.h"
>>> +#include "hw/virtio/vhost-user-spi.h"
>>> +#include "hw/virtio/virtio-pci.h"
>>> +
>>> +struct VHostUserSPIPCI {
>>> +    VirtIOPCIProxy parent_obj;
>>> +    VHostUserSPI vdev;
>>> +};
>>> +
>>> +typedef struct VHostUserSPIPCI VHostUserSPIPCI;
>>> +
>>> +#define TYPE_VHOST_USER_SPI_PCI "vhost-user-spi-pci-base"
>>> +
>>> +DECLARE_INSTANCE_CHECKER(VHostUserSPIPCI, VHOST_USER_SPI_PCI,
>>> +                         TYPE_VHOST_USER_SPI_PCI)
>>> +
>>> +static void vhost_user_spi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
>>> +{
>>> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(vpci_dev);
>>> +    DeviceState *vdev = DEVICE(&dev->vdev);
>>> +
>>> +    vpci_dev->nvectors = 1;
>>> +    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
>>> +}
>>> +
>>> +static void vhost_user_spi_pci_class_init(ObjectClass *klass, void *data)
>>> +{
>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>> +    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
>>> +    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
>>> +    k->realize = vhost_user_spi_pci_realize;
>>> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
>>> +    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
>>> +    pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
>>> +    pcidev_k->revision = 0x00;
>>> +    pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
>>> +}
>>> +
>>> +static void vhost_user_spi_pci_instance_init(Object *obj)
>>> +{
>>> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(obj);
>>> +
>>> +    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
>>> +                                TYPE_VHOST_USER_SPI);
>>> +}
>>> +
>>> +static const VirtioPCIDeviceTypeInfo vhost_user_spi_pci_info = {
>>> +    .base_name = TYPE_VHOST_USER_SPI_PCI,
>>> +    .non_transitional_name = "vhost-user-spi-pci",
>>> +    .instance_size = sizeof(VHostUserSPIPCI),
>>> +    .instance_init = vhost_user_spi_pci_instance_init,
>>> +    .class_init = vhost_user_spi_pci_class_init,
>>> +};
>>> +
>>> +static void vhost_user_spi_pci_register(void)
>>> +{
>>> +    virtio_pci_types_register(&vhost_user_spi_pci_info);
>>> +}
>>> +
>>> +type_init(vhost_user_spi_pci_register);
>>> diff --git a/hw/virtio/vhost-user-spi.c b/hw/virtio/vhost-user-spi.c
>>> new file mode 100644
>>> index 0000000000..e138b8b53b
>>> --- /dev/null
>>> +++ b/hw/virtio/vhost-user-spi.c
>>> @@ -0,0 +1,66 @@
>>> +/*
>>> + * Vhost-user spi virtio device
>>> + *
>>> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
>>> + *
>>> + * SPDX-License-Identifier: GPL-2.0-or-later
>>> + */
>>> +
>>> +#include "qemu/osdep.h"
>>> +#include "qapi/error.h"
>>> +#include "hw/qdev-properties.h"
>>> +#include "hw/virtio/virtio-bus.h"
>>> +#include "hw/virtio/vhost-user-spi.h"
>>> +#include "qemu/error-report.h"
>>> +#include "standard-headers/linux/virtio_ids.h"
>>> +#include "standard-headers/linux/virtio_spi.h"
>>> +
>>> +static Property vspi_properties[] = {
>>> +    DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
>>> +    DEFINE_PROP_END_OF_LIST(),
>>> +};
>>> +
>>> +static void vspi_realize(DeviceState *dev, Error **errp)
>>> +{
>>> +    VHostUserBase *vub = VHOST_USER_BASE(dev);
>>> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_GET_CLASS(dev);
>>> +
>>> +    /* Fixed for SPI */
>>> +    vub->virtio_id = VIRTIO_ID_SPI;
>>> +    vub->num_vqs = 1;
>>> +    vub->vq_size = 4;
>>> +    vub->config_size = sizeof(struct virtio_spi_config);
>>> +
>>> +    vubc->parent_realize(dev, errp);
>>> +}
>>> +
>>> +static const VMStateDescription vu_spi_vmstate = {
>>> +    .name = "vhost-user-spi",
>>> +    .unmigratable = 1,
>>> +};
>>> +
>>> +static void vu_spi_class_init(ObjectClass *klass, void *data)
>>> +{
>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
>>> +
>>> +    dc->vmsd = &vu_spi_vmstate;
>>> +    device_class_set_props(dc, vspi_properties);
>>> +    device_class_set_parent_realize(dc, vspi_realize,
>>> +                                    &vubc->parent_realize);
>>> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
>>> +}
>>> +
>>> +static const TypeInfo vu_spi_info = {
>>> +    .name = TYPE_VHOST_USER_SPI,
>>> +    .parent = TYPE_VHOST_USER_BASE,
>>> +    .instance_size = sizeof(VHostUserSPI),
>>> +    .class_init = vu_spi_class_init,
>>> +};
>>> +
>>> +static void vu_spi_register_types(void)
>>> +{
>>> +    type_register_static(&vu_spi_info);
>>> +}
>>> +
>>> +type_init(vu_spi_register_types)
>>> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
>>> index 583a224163..689e2e21e7 100644
>>> --- a/hw/virtio/virtio.c
>>> +++ b/hw/virtio/virtio.c
>>> @@ -46,6 +46,7 @@
>>>   #include "standard-headers/linux/virtio_iommu.h"
>>>   #include "standard-headers/linux/virtio_mem.h"
>>>   #include "standard-headers/linux/virtio_vsock.h"
>>> +#include "standard-headers/linux/virtio_spi.h"
>>>     /*
>>>    * Maximum size of virtio device config space
>>> @@ -194,7 +195,8 @@ const char *virtio_device_names[] = {
>>>       [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv",
>>>       [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol",
>>>       [VIRTIO_ID_BT] = "virtio-bluetooth",
>>> -    [VIRTIO_ID_GPIO] = "virtio-gpio"
>>> +    [VIRTIO_ID_GPIO] = "virtio-gpio",
>>> +    [VIRTIO_ID_SPI] = "virtio-spi"
>>>   };
>> For the vhost-user-stub bits when split from the headers:
>> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
>> 

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro
Re: [PATCH] Add vhost-user-spi and vhost-user-spi-pci devices
Posted by Haixu Cui 2 months, 2 weeks ago

On 9/2/2024 6:15 PM, Alex Bennée wrote:
> Haixu Cui <quic_haixcui@quicinc.com> writes:
> 
>> Hi Alex,
>>      Thanks a lot for your comments, please refer to my response below.
>>
>> On 8/28/2024 1:14 AM, Alex Bennée wrote:
>>> Haixu Cui <quic_haixcui@quicinc.com> writes:
>>> Apologies for the delay in getting to this.
>>>
>>>> This work is based on the virtio-spi spec, virtio-spi driver introduced by
>>>> the following patch series:
>>>> - https://github.com/oasis-tcs/virtio-spec/tree/virtio-1.4/device-types/spi
>>>> - https://lwn.net/Articles/966715/
>>>>
>>>> To test with rust-vmm vhost-user-spi daemon, start the vhost-daemon firstly:
>>>>       vhost-device-spi --socket-path=vspi.sock --socket-count=1 --device "/dev/spidev0.0"
>>> I'm struggling to test this on my main dev box. Are there any dummy
>>> SPI
>>> modules for the kernel for testing? Otherwise we could consider
>>> implementing something similar to "mock_gpio" for the rust-vmm
>>> vhost-user-spi backend?
>>
>> I verified this on my board with physical SPI interface, and I don't
>> know if these is dummy SPI module available in kernel. I'll look into
>> this.
> 
> I'll see if I can boot full Linux into a QEMU machine with SPI devices
> which would be another approach.
> 

Great idea.

>>>
>>>> Then invoke qemu with the following parameters:
>>>>       qemu-system-aarch64 -m 1G \
>>>>           -chardev socket,path=/home/root/vspi.sock0,id=vspi \
>>>>           -device vhost-user-spi-pci,chardev=vspi,id=spi \
>>>>           -object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on \
>>>>           -numa node,memdev=mem
>>>>           ...
>>>
>>>>
>>>> Signed-off-by: Haixu Cui <quic_haixcui@quicinc.com>
>>>> ---
>>>>    hw/virtio/Kconfig                           |   5 +
>>>>    hw/virtio/meson.build                       |   3 +
>>>>    hw/virtio/vhost-user-spi-pci.c              |  69 ++++++++
>>>>    hw/virtio/vhost-user-spi.c                  |  66 +++++++
>>>>    hw/virtio/virtio.c                          |   4 +-
>>>>    include/hw/virtio/vhost-user-spi.h          |  25 +++
>>>>    include/standard-headers/linux/virtio_ids.h |   1 +
>>>>    include/standard-headers/linux/virtio_spi.h | 186 ++++++++++++++++++++
>>>>    8 files changed, 358 insertions(+), 1 deletion(-)
>>>>    create mode 100644 hw/virtio/vhost-user-spi-pci.c
>>>>    create mode 100644 hw/virtio/vhost-user-spi.c
>>>>    create mode 100644 include/hw/virtio/vhost-user-spi.h
>>>>    create mode 100644 include/standard-headers/linux/virtio_spi.h
>>> Generally we want separate headers patches for the importing of
>>> headers.
>>> Doubly so in this case because I can't see the SPI definitions in the
>>> current Linux master. So:
>>>     - 1/2 - Import headers for SPI (!merge until upstream)
>>>     - 2/2 - Implement vhost-user stub for virtio-spi
>>>
>>
>> Should I move only virtio_spi.h to the first patch, or all of the
>> header files? I don't quite understand here.
> 
> Just the kernel headers (include/standard-headers). You should import
> the kernel headers from a checked out kernel tree using:
> 
>    ./scripts/update-linux-headers.sh <path/to/linux.git>
> 
> and save them as a single commit for the 1st patch. As the SPI code is
> not yet upstream just make it clear in the commit to avoid merging. e.g.
> 
>    linux-headers: update to 6.10-rc5 + SPI patches (!merge)
> 
>    This imports the headers from the current Linux HEAD + the VirtIO SPI
>    patches which are not yet upstream. Once the SPI work is up-streamed in
>    the kernel they will be imported from there.
> 
> Just make sure you kernel base is newer than the last import otherwise
> you will get a lot of additional noise.
> 

Thank you so much for your guidance, I'll generate header file based on 
6.11-rc7, the latest version.

BR & Thanks

>>
>> Best Regards
>> Thanks
>>>
>>>>
>>>> diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
>>>> index aa63ff7fd4..d5857651e5 100644
>>>> --- a/hw/virtio/Kconfig
>>>> +++ b/hw/virtio/Kconfig
>>>> @@ -110,3 +110,8 @@ config VHOST_USER_SCMI
>>>>        bool
>>>>        default y
>>>>        depends on VIRTIO && VHOST_USER
>>>> +
>>>> +config VHOST_USER_SPI
>>>> +    bool
>>>> +    default y
>>>> +    depends on VIRTIO && VHOST_USER
>>>> diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
>>>> index 621fc65454..42296219e5 100644
>>>> --- a/hw/virtio/meson.build
>>>> +++ b/hw/virtio/meson.build
>>>> @@ -26,6 +26,7 @@ if have_vhost
>>>>        system_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
>>>>        system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SND', if_true: files('vhost-user-snd.c'))
>>>>        system_virtio_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c'))
>>>> +    system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SPI', if_true: files('vhost-user-spi.c'))
>>>>          # PCI Stubs
>>>>        system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('vhost-user-device-pci.c'))
>>>> @@ -39,6 +40,8 @@ if have_vhost
>>>>                             if_true: files('vhost-user-snd-pci.c'))
>>>>        system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_INPUT'],
>>>>                             if_true: files('vhost-user-input-pci.c'))
>>>> +    system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SPI'],
>>>> +                         if_true: files('vhost-user-spi-pci.c'))
>>>>      endif
>>>>      if have_vhost_vdpa
>>>>        system_virtio_ss.add(files('vhost-vdpa.c'))
>>>> diff --git a/hw/virtio/vhost-user-spi-pci.c b/hw/virtio/vhost-user-spi-pci.c
>>>> new file mode 100644
>>>> index 0000000000..3565d526af
>>>> --- /dev/null
>>>> +++ b/hw/virtio/vhost-user-spi-pci.c
>>>> @@ -0,0 +1,69 @@
>>>> +/*
>>>> + * Vhost-user spi virtio device PCI glue
>>>> + *
>>>> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
>>>> + *
>>>> + * SPDX-License-Identifier: GPL-2.0-or-later
>>>> + */
>>>> +
>>>> +#include "qemu/osdep.h"
>>>> +#include "hw/qdev-properties.h"
>>>> +#include "hw/virtio/vhost-user-spi.h"
>>>> +#include "hw/virtio/virtio-pci.h"
>>>> +
>>>> +struct VHostUserSPIPCI {
>>>> +    VirtIOPCIProxy parent_obj;
>>>> +    VHostUserSPI vdev;
>>>> +};
>>>> +
>>>> +typedef struct VHostUserSPIPCI VHostUserSPIPCI;
>>>> +
>>>> +#define TYPE_VHOST_USER_SPI_PCI "vhost-user-spi-pci-base"
>>>> +
>>>> +DECLARE_INSTANCE_CHECKER(VHostUserSPIPCI, VHOST_USER_SPI_PCI,
>>>> +                         TYPE_VHOST_USER_SPI_PCI)
>>>> +
>>>> +static void vhost_user_spi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
>>>> +{
>>>> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(vpci_dev);
>>>> +    DeviceState *vdev = DEVICE(&dev->vdev);
>>>> +
>>>> +    vpci_dev->nvectors = 1;
>>>> +    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
>>>> +}
>>>> +
>>>> +static void vhost_user_spi_pci_class_init(ObjectClass *klass, void *data)
>>>> +{
>>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>>> +    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
>>>> +    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
>>>> +    k->realize = vhost_user_spi_pci_realize;
>>>> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
>>>> +    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
>>>> +    pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
>>>> +    pcidev_k->revision = 0x00;
>>>> +    pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
>>>> +}
>>>> +
>>>> +static void vhost_user_spi_pci_instance_init(Object *obj)
>>>> +{
>>>> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(obj);
>>>> +
>>>> +    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
>>>> +                                TYPE_VHOST_USER_SPI);
>>>> +}
>>>> +
>>>> +static const VirtioPCIDeviceTypeInfo vhost_user_spi_pci_info = {
>>>> +    .base_name = TYPE_VHOST_USER_SPI_PCI,
>>>> +    .non_transitional_name = "vhost-user-spi-pci",
>>>> +    .instance_size = sizeof(VHostUserSPIPCI),
>>>> +    .instance_init = vhost_user_spi_pci_instance_init,
>>>> +    .class_init = vhost_user_spi_pci_class_init,
>>>> +};
>>>> +
>>>> +static void vhost_user_spi_pci_register(void)
>>>> +{
>>>> +    virtio_pci_types_register(&vhost_user_spi_pci_info);
>>>> +}
>>>> +
>>>> +type_init(vhost_user_spi_pci_register);
>>>> diff --git a/hw/virtio/vhost-user-spi.c b/hw/virtio/vhost-user-spi.c
>>>> new file mode 100644
>>>> index 0000000000..e138b8b53b
>>>> --- /dev/null
>>>> +++ b/hw/virtio/vhost-user-spi.c
>>>> @@ -0,0 +1,66 @@
>>>> +/*
>>>> + * Vhost-user spi virtio device
>>>> + *
>>>> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
>>>> + *
>>>> + * SPDX-License-Identifier: GPL-2.0-or-later
>>>> + */
>>>> +
>>>> +#include "qemu/osdep.h"
>>>> +#include "qapi/error.h"
>>>> +#include "hw/qdev-properties.h"
>>>> +#include "hw/virtio/virtio-bus.h"
>>>> +#include "hw/virtio/vhost-user-spi.h"
>>>> +#include "qemu/error-report.h"
>>>> +#include "standard-headers/linux/virtio_ids.h"
>>>> +#include "standard-headers/linux/virtio_spi.h"
>>>> +
>>>> +static Property vspi_properties[] = {
>>>> +    DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
>>>> +    DEFINE_PROP_END_OF_LIST(),
>>>> +};
>>>> +
>>>> +static void vspi_realize(DeviceState *dev, Error **errp)
>>>> +{
>>>> +    VHostUserBase *vub = VHOST_USER_BASE(dev);
>>>> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_GET_CLASS(dev);
>>>> +
>>>> +    /* Fixed for SPI */
>>>> +    vub->virtio_id = VIRTIO_ID_SPI;
>>>> +    vub->num_vqs = 1;
>>>> +    vub->vq_size = 4;
>>>> +    vub->config_size = sizeof(struct virtio_spi_config);
>>>> +
>>>> +    vubc->parent_realize(dev, errp);
>>>> +}
>>>> +
>>>> +static const VMStateDescription vu_spi_vmstate = {
>>>> +    .name = "vhost-user-spi",
>>>> +    .unmigratable = 1,
>>>> +};
>>>> +
>>>> +static void vu_spi_class_init(ObjectClass *klass, void *data)
>>>> +{
>>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>>> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
>>>> +
>>>> +    dc->vmsd = &vu_spi_vmstate;
>>>> +    device_class_set_props(dc, vspi_properties);
>>>> +    device_class_set_parent_realize(dc, vspi_realize,
>>>> +                                    &vubc->parent_realize);
>>>> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
>>>> +}
>>>> +
>>>> +static const TypeInfo vu_spi_info = {
>>>> +    .name = TYPE_VHOST_USER_SPI,
>>>> +    .parent = TYPE_VHOST_USER_BASE,
>>>> +    .instance_size = sizeof(VHostUserSPI),
>>>> +    .class_init = vu_spi_class_init,
>>>> +};
>>>> +
>>>> +static void vu_spi_register_types(void)
>>>> +{
>>>> +    type_register_static(&vu_spi_info);
>>>> +}
>>>> +
>>>> +type_init(vu_spi_register_types)
>>>> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
>>>> index 583a224163..689e2e21e7 100644
>>>> --- a/hw/virtio/virtio.c
>>>> +++ b/hw/virtio/virtio.c
>>>> @@ -46,6 +46,7 @@
>>>>    #include "standard-headers/linux/virtio_iommu.h"
>>>>    #include "standard-headers/linux/virtio_mem.h"
>>>>    #include "standard-headers/linux/virtio_vsock.h"
>>>> +#include "standard-headers/linux/virtio_spi.h"
>>>>      /*
>>>>     * Maximum size of virtio device config space
>>>> @@ -194,7 +195,8 @@ const char *virtio_device_names[] = {
>>>>        [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv",
>>>>        [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol",
>>>>        [VIRTIO_ID_BT] = "virtio-bluetooth",
>>>> -    [VIRTIO_ID_GPIO] = "virtio-gpio"
>>>> +    [VIRTIO_ID_GPIO] = "virtio-gpio",
>>>> +    [VIRTIO_ID_SPI] = "virtio-spi"
>>>>    };
>>> For the vhost-user-stub bits when split from the headers:
>>> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
>>>
> 

Re: [PATCH] Add vhost-user-spi and vhost-user-spi-pci devices
Posted by Haixu Cui 3 months ago
Hi team,

     I've added the vhost-user-spi patch here to support virtio-spi in 
qemu. You are the experts on both virtio and vhost-user, can you please 
help review the patch. Thanks a lot.

Best Regards

On 7/12/2024 11:42 AM, Haixu Cui wrote:
> This work is based on the virtio-spi spec, virtio-spi driver introduced by
> the following patch series:
> - https://github.com/oasis-tcs/virtio-spec/tree/virtio-1.4/device-types/spi
> - https://lwn.net/Articles/966715/
> 
> To test with rust-vmm vhost-user-spi daemon, start the vhost-daemon firstly:
>      vhost-device-spi --socket-path=vspi.sock --socket-count=1 --device "/dev/spidev0.0"
> 
> Then invoke qemu with the following parameters:
>      qemu-system-aarch64 -m 1G \
>          -chardev socket,path=/home/root/vspi.sock0,id=vspi \
>          -device vhost-user-spi-pci,chardev=vspi,id=spi \
>          -object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on \
>          -numa node,memdev=mem
>          ...
> 
> Signed-off-by: Haixu Cui <quic_haixcui@quicinc.com>
> ---
>   hw/virtio/Kconfig                           |   5 +
>   hw/virtio/meson.build                       |   3 +
>   hw/virtio/vhost-user-spi-pci.c              |  69 ++++++++
>   hw/virtio/vhost-user-spi.c                  |  66 +++++++
>   hw/virtio/virtio.c                          |   4 +-
>   include/hw/virtio/vhost-user-spi.h          |  25 +++
>   include/standard-headers/linux/virtio_ids.h |   1 +
>   include/standard-headers/linux/virtio_spi.h | 186 ++++++++++++++++++++
>   8 files changed, 358 insertions(+), 1 deletion(-)
>   create mode 100644 hw/virtio/vhost-user-spi-pci.c
>   create mode 100644 hw/virtio/vhost-user-spi.c
>   create mode 100644 include/hw/virtio/vhost-user-spi.h
>   create mode 100644 include/standard-headers/linux/virtio_spi.h
> 
> diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
> index aa63ff7fd4..d5857651e5 100644
> --- a/hw/virtio/Kconfig
> +++ b/hw/virtio/Kconfig
> @@ -110,3 +110,8 @@ config VHOST_USER_SCMI
>       bool
>       default y
>       depends on VIRTIO && VHOST_USER
> +
> +config VHOST_USER_SPI
> +    bool
> +    default y
> +    depends on VIRTIO && VHOST_USER
> diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
> index 621fc65454..42296219e5 100644
> --- a/hw/virtio/meson.build
> +++ b/hw/virtio/meson.build
> @@ -26,6 +26,7 @@ if have_vhost
>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SND', if_true: files('vhost-user-snd.c'))
>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c'))
> +    system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SPI', if_true: files('vhost-user-spi.c'))
>   
>       # PCI Stubs
>       system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('vhost-user-device-pci.c'))
> @@ -39,6 +40,8 @@ if have_vhost
>                            if_true: files('vhost-user-snd-pci.c'))
>       system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_INPUT'],
>                            if_true: files('vhost-user-input-pci.c'))
> +    system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SPI'],
> +                         if_true: files('vhost-user-spi-pci.c'))
>     endif
>     if have_vhost_vdpa
>       system_virtio_ss.add(files('vhost-vdpa.c'))
> diff --git a/hw/virtio/vhost-user-spi-pci.c b/hw/virtio/vhost-user-spi-pci.c
> new file mode 100644
> index 0000000000..3565d526af
> --- /dev/null
> +++ b/hw/virtio/vhost-user-spi-pci.c
> @@ -0,0 +1,69 @@
> +/*
> + * Vhost-user spi virtio device PCI glue
> + *
> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/virtio/vhost-user-spi.h"
> +#include "hw/virtio/virtio-pci.h"
> +
> +struct VHostUserSPIPCI {
> +    VirtIOPCIProxy parent_obj;
> +    VHostUserSPI vdev;
> +};
> +
> +typedef struct VHostUserSPIPCI VHostUserSPIPCI;
> +
> +#define TYPE_VHOST_USER_SPI_PCI "vhost-user-spi-pci-base"
> +
> +DECLARE_INSTANCE_CHECKER(VHostUserSPIPCI, VHOST_USER_SPI_PCI,
> +                         TYPE_VHOST_USER_SPI_PCI)
> +
> +static void vhost_user_spi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
> +{
> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(vpci_dev);
> +    DeviceState *vdev = DEVICE(&dev->vdev);
> +
> +    vpci_dev->nvectors = 1;
> +    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
> +}
> +
> +static void vhost_user_spi_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
> +    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
> +    k->realize = vhost_user_spi_pci_realize;
> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
> +    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
> +    pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
> +    pcidev_k->revision = 0x00;
> +    pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
> +}
> +
> +static void vhost_user_spi_pci_instance_init(Object *obj)
> +{
> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(obj);
> +
> +    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
> +                                TYPE_VHOST_USER_SPI);
> +}
> +
> +static const VirtioPCIDeviceTypeInfo vhost_user_spi_pci_info = {
> +    .base_name = TYPE_VHOST_USER_SPI_PCI,
> +    .non_transitional_name = "vhost-user-spi-pci",
> +    .instance_size = sizeof(VHostUserSPIPCI),
> +    .instance_init = vhost_user_spi_pci_instance_init,
> +    .class_init = vhost_user_spi_pci_class_init,
> +};
> +
> +static void vhost_user_spi_pci_register(void)
> +{
> +    virtio_pci_types_register(&vhost_user_spi_pci_info);
> +}
> +
> +type_init(vhost_user_spi_pci_register);
> diff --git a/hw/virtio/vhost-user-spi.c b/hw/virtio/vhost-user-spi.c
> new file mode 100644
> index 0000000000..e138b8b53b
> --- /dev/null
> +++ b/hw/virtio/vhost-user-spi.c
> @@ -0,0 +1,66 @@
> +/*
> + * Vhost-user spi virtio device
> + *
> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/virtio/virtio-bus.h"
> +#include "hw/virtio/vhost-user-spi.h"
> +#include "qemu/error-report.h"
> +#include "standard-headers/linux/virtio_ids.h"
> +#include "standard-headers/linux/virtio_spi.h"
> +
> +static Property vspi_properties[] = {
> +    DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void vspi_realize(DeviceState *dev, Error **errp)
> +{
> +    VHostUserBase *vub = VHOST_USER_BASE(dev);
> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_GET_CLASS(dev);
> +
> +    /* Fixed for SPI */
> +    vub->virtio_id = VIRTIO_ID_SPI;
> +    vub->num_vqs = 1;
> +    vub->vq_size = 4;
> +    vub->config_size = sizeof(struct virtio_spi_config);
> +
> +    vubc->parent_realize(dev, errp);
> +}
> +
> +static const VMStateDescription vu_spi_vmstate = {
> +    .name = "vhost-user-spi",
> +    .unmigratable = 1,
> +};
> +
> +static void vu_spi_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
> +
> +    dc->vmsd = &vu_spi_vmstate;
> +    device_class_set_props(dc, vspi_properties);
> +    device_class_set_parent_realize(dc, vspi_realize,
> +                                    &vubc->parent_realize);
> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
> +}
> +
> +static const TypeInfo vu_spi_info = {
> +    .name = TYPE_VHOST_USER_SPI,
> +    .parent = TYPE_VHOST_USER_BASE,
> +    .instance_size = sizeof(VHostUserSPI),
> +    .class_init = vu_spi_class_init,
> +};
> +
> +static void vu_spi_register_types(void)
> +{
> +    type_register_static(&vu_spi_info);
> +}
> +
> +type_init(vu_spi_register_types)
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 583a224163..689e2e21e7 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -46,6 +46,7 @@
>   #include "standard-headers/linux/virtio_iommu.h"
>   #include "standard-headers/linux/virtio_mem.h"
>   #include "standard-headers/linux/virtio_vsock.h"
> +#include "standard-headers/linux/virtio_spi.h"
>   
>   /*
>    * Maximum size of virtio device config space
> @@ -194,7 +195,8 @@ const char *virtio_device_names[] = {
>       [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv",
>       [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol",
>       [VIRTIO_ID_BT] = "virtio-bluetooth",
> -    [VIRTIO_ID_GPIO] = "virtio-gpio"
> +    [VIRTIO_ID_GPIO] = "virtio-gpio",
> +    [VIRTIO_ID_SPI] = "virtio-spi"
>   };
>   
>   static const char *virtio_id_to_name(uint16_t device_id)
> diff --git a/include/hw/virtio/vhost-user-spi.h b/include/hw/virtio/vhost-user-spi.h
> new file mode 100644
> index 0000000000..d6967d8431
> --- /dev/null
> +++ b/include/hw/virtio/vhost-user-spi.h
> @@ -0,0 +1,25 @@
> +/*
> + * Vhost-user spi virtio device
> + *
> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef QEMU_VHOST_USER_SPI_H
> +#define QEMU_VHOST_USER_SPI_H
> +
> +#include "hw/virtio/virtio.h"
> +#include "hw/virtio/vhost.h"
> +#include "hw/virtio/vhost-user.h"
> +#include "hw/virtio/vhost-user-base.h"
> +
> +#define TYPE_VHOST_USER_SPI "vhost-user-spi-device"
> +
> +OBJECT_DECLARE_SIMPLE_TYPE(VHostUserSPI, VHOST_USER_SPI)
> +
> +struct VHostUserSPI {
> +    VHostUserBase parent_obj;
> +};
> +
> +#endif /* QEMU_VHOST_USER_SPI_H */
> diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h
> index 7aa2eb7662..601d387c5a 100644
> --- a/include/standard-headers/linux/virtio_ids.h
> +++ b/include/standard-headers/linux/virtio_ids.h
> @@ -68,6 +68,7 @@
>   #define VIRTIO_ID_AUDIO_POLICY		39 /* virtio audio policy */
>   #define VIRTIO_ID_BT			40 /* virtio bluetooth */
>   #define VIRTIO_ID_GPIO			41 /* virtio gpio */
> +#define VIRTIO_ID_SPI                   45 /* virtio spi */
>   
>   /*
>    * Virtio Transitional IDs
> diff --git a/include/standard-headers/linux/virtio_spi.h b/include/standard-headers/linux/virtio_spi.h
> new file mode 100644
> index 0000000000..6631827bfa
> --- /dev/null
> +++ b/include/standard-headers/linux/virtio_spi.h
> @@ -0,0 +1,186 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
> +/*
> + * Definitions for virtio SPI Controller
> + *
> + * Copyright (c) 2021 Intel Corporation. All rights reserved.
> + */
> +
> +#ifndef _LINUX_VIRTIO_SPI_H
> +#define _LINUX_VIRTIO_SPI_H
> +
> +#include "standard-headers/linux/const.h"
> +#include "standard-headers/linux/types.h"
> +
> +/* Sample data on trailing clock edge */
> +#define VIRTIO_SPI_CPHA (1 << 0)
> +/* Clock is high when IDLE */
> +#define VIRTIO_SPI_CPOL (1 << 1)
> +/* Chip Select is active high */
> +#define VIRTIO_SPI_CS_HIGH (1 << 2)
> +/* Transmit LSB first */
> +#define VIRTIO_SPI_MODE_LSB_FIRST (1 << 3)
> +/* Loopback mode */
> +#define VIRTIO_SPI_MODE_LOOP (1 << 4)
> +
> +/*
> + * All config fields are read-only for the Virtio SPI driver
> + *
> + * @cs_max_number: maximum number of chipselect the host SPI controller
> + *   supports.
> + * @cs_change_supported: indicates if the host SPI controller supports to toggle
> + * chipselect after each transfer in one message:
> + *   0: unsupported, chipselect will be kept in active state throughout the
> + *      message transaction;
> + *   1: supported.
> + *   Note: Message here contains a sequence of SPI transfers.
> + * @tx_nbits_supported: indicates the supported number of bit for writing:
> + *   bit 0: DUAL (2-bit transfer), 1 for supported
> + *   bit 1: QUAD (4-bit transfer), 1 for supported
> + *   bit 2: OCTAL (8-bit transfer), 1 for supported
> + *   other bits are reserved as 0, 1-bit transfer is always supported.
> + * @rx_nbits_supported: indicates the supported number of bit for reading:
> + *   bit 0: DUAL (2-bit transfer), 1 for supported
> + *   bit 1: QUAD (4-bit transfer), 1 for supported
> + *   bit 2: OCTAL (8-bit transfer), 1 for supported
> + *   other bits are reserved as 0, 1-bit transfer is always supported.
> + * @bits_per_word_mask: mask indicating which values of bits_per_word are
> + *   supported. If not set, no limitation for bits_per_word.
> + * @mode_func_supported: indicates the following features are supported or not:
> + *   bit 0-1: CPHA feature
> + *     0b00: invalid, should support as least one CPHA setting
> + *     0b01: supports CPHA=0 only
> + *     0b10: supports CPHA=1 only
> + *     0b11: supports CPHA=0 and CPHA=1.
> + *   bit 2-3: CPOL feature
> + *     0b00: invalid, should support as least one CPOL setting
> + *     0b01: supports CPOL=0 only
> + *     0b10: supports CPOL=1 only
> + *     0b11: supports CPOL=0 and CPOL=1.
> + *   bit 4: chipselect active high feature, 0 for unsupported and 1 for
> + *     supported, chipselect active low should always be supported.
> + *   bit 5: LSB first feature, 0 for unsupported and 1 for supported,
> + *     MSB first should always be supported.
> + *   bit 6: loopback mode feature, 0 for unsupported and 1 for supported,
> + *     normal mode should always be supported.
> + * @max_freq_hz: the maximum clock rate supported in Hz unit, 0 means no
> + *   limitation for transfer speed.
> + * @max_word_delay_ns: the maximum word delay supported in ns unit,
> + *   0 means word delay feature is unsupported.
> + *   Note: Just as one message contains a sequence of transfers,
> + *         one transfer may contain a sequence of words.
> + * @max_cs_setup_ns: the maximum delay supported after chipselect is asserted,
> + *   in ns unit, 0 means delay is not supported to introduce after chipselect is
> + *   asserted.
> + * @max_cs_hold_ns: the maximum delay supported before chipselect is deasserted,
> + *   in ns unit, 0 means delay is not supported to introduce before chipselect
> + *   is deasserted.
> + * @max_cs_incative_ns: maximum delay supported after chipselect is deasserted,
> + *   in ns unit, 0 means delay is not supported to introduce after chipselect is
> + *   deasserted.
> + */
> +struct virtio_spi_config {
> +	/* # of /dev/spidev<bus_num>.CS with CS=0..chip_select_max_number -1 */
> +        uint8_t cs_max_number;
> +        uint8_t cs_change_supported;
> +#define VIRTIO_SPI_RX_TX_SUPPORT_DUAL (1 << 0)
> +#define VIRTIO_SPI_RX_TX_SUPPORT_QUAD (1 << 1)
> +#define VIRTIO_SPI_RX_TX_SUPPORT_OCTAL (1 << 2)
> +        uint8_t tx_nbits_supported;
> +        uint8_t rx_nbits_supported;
> +        uint32_t bits_per_word_mask;
> +#define VIRTIO_SPI_MF_SUPPORT_CPHA_0 (1 << 0)
> +#define VIRTIO_SPI_MF_SUPPORT_CPHA_1 (1 << 1)
> +#define VIRTIO_SPI_MF_SUPPORT_CPOL_0 (1 << 2)
> +#define VIRTIO_SPI_MF_SUPPORT_CPOL_1 (1 << 3)
> +#define VIRTIO_SPI_MF_SUPPORT_CS_HIGH (1 << 4)
> +#define VIRTIO_SPI_MF_SUPPORT_LSB_FIRST (1 << 5)
> +#define VIRTIO_SPI_MF_SUPPORT_LOOPBACK (1 << 6)
> +        uint32_t mode_func_supported;
> +        uint32_t max_freq_hz;
> +        uint32_t max_word_delay_ns;
> +        uint32_t max_cs_setup_ns;
> +        uint32_t max_cs_hold_ns;
> +        uint32_t max_cs_inactive_ns;
> +};
> +
> +/*
> + * @chip_select_id: chipselect index the SPI transfer used.
> + *
> + * @bits_per_word: the number of bits in each SPI transfer word.
> + *
> + * @cs_change: whether to deselect device after finishing this transfer
> + *     before starting the next transfer, 0 means cs keep asserted and
> + *     1 means cs deasserted then asserted again.
> + *
> + * @tx_nbits: bus width for write transfer.
> + *     0,1: bus width is 1, also known as SINGLE
> + *     2  : bus width is 2, also known as DUAL
> + *     4  : bus width is 4, also known as QUAD
> + *     8  : bus width is 8, also known as OCTAL
> + *     other values are invalid.
> + *
> + * @rx_nbits: bus width for read transfer.
> + *     0,1: bus width is 1, also known as SINGLE
> + *     2  : bus width is 2, also known as DUAL
> + *     4  : bus width is 4, also known as QUAD
> + *     8  : bus width is 8, also known as OCTAL
> + *     other values are invalid.
> + *
> + * @reserved: for future use.
> + *
> + * @mode: SPI transfer mode.
> + *     bit 0: CPHA, determines the timing (i.e. phase) of the data
> + *         bits relative to the clock pulses.For CPHA=0, the
> + *         "out" side changes the data on the trailing edge of the
> + *         preceding clock cycle, while the "in" side captures the data
> + *         on (or shortly after) the leading edge of the clock cycle.
> + *         For CPHA=1, the "out" side changes the data on the leading
> + *         edge of the current clock cycle, while the "in" side
> + *         captures the data on (or shortly after) the trailing edge of
> + *         the clock cycle.
> + *     bit 1: CPOL, determines the polarity of the clock. CPOL=0 is a
> + *         clock which idles at 0, and each cycle consists of a pulse
> + *         of 1. CPOL=1 is a clock which idles at 1, and each cycle
> + *         consists of a pulse of 0.
> + *     bit 2: CS_HIGH, if 1, chip select active high, else active low.
> + *     bit 3: LSB_FIRST, determines per-word bits-on-wire, if 0, MSB
> + *         first, else LSB first.
> + *     bit 4: LOOP, loopback mode.
> + *
> + * @freq: the transfer speed in Hz.
> + *
> + * @word_delay_ns: delay to be inserted between consecutive words of a
> + *     transfer, in ns unit.
> + *
> + * @cs_setup_ns: delay to be introduced after CS is asserted, in ns
> + *     unit.
> + *
> + * @cs_delay_hold_ns: delay to be introduced before CS is deasserted
> + *     for each transfer, in ns unit.
> + *
> + * @cs_change_delay_inactive_ns: delay to be introduced after CS is
> + *     deasserted and before next asserted, in ns unit.
> + */
> +struct spi_transfer_head {
> +        uint8_t chip_select_id;
> +        uint8_t bits_per_word;
> +        uint8_t cs_change;
> +        uint8_t tx_nbits;
> +        uint8_t rx_nbits;
> +        uint8_t reserved[3];
> +        uint32_t mode;
> +        uint32_t freq;
> +        uint32_t word_delay_ns;
> +        uint32_t cs_setup_ns;
> +        uint32_t cs_delay_hold_ns;
> +        uint32_t cs_change_delay_inactive_ns;
> +};
> +
> +struct spi_transfer_result {
> +#define VIRTIO_SPI_TRANS_OK 0
> +#define VIRTIO_SPI_PARAM_ERR 1
> +#define VIRTIO_SPI_TRANS_ERR 2
> +	uint8_t status;
> +};
> +
> +#endif /* _LINUX_VIRTIO_SPI_H */
Re: [PATCH] Add vhost-user-spi and vhost-user-spi-pci devices
Posted by Haixu Cui 3 months, 2 weeks ago
Hi,

     Can anyone please review the patch? Thank you so much.

Best Regards
Haixu Cui

On 7/12/2024 11:42 AM, Haixu Cui wrote:
> This work is based on the virtio-spi spec, virtio-spi driver introduced by
> the following patch series:
> - https://github.com/oasis-tcs/virtio-spec/tree/virtio-1.4/device-types/spi
> - https://lwn.net/Articles/966715/
> 
> To test with rust-vmm vhost-user-spi daemon, start the vhost-daemon firstly:
>      vhost-device-spi --socket-path=vspi.sock --socket-count=1 --device "/dev/spidev0.0"
> 
> Then invoke qemu with the following parameters:
>      qemu-system-aarch64 -m 1G \
>          -chardev socket,path=/home/root/vspi.sock0,id=vspi \
>          -device vhost-user-spi-pci,chardev=vspi,id=spi \
>          -object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on \
>          -numa node,memdev=mem
>          ...
> 
> Signed-off-by: Haixu Cui <quic_haixcui@quicinc.com>
> ---
>   hw/virtio/Kconfig                           |   5 +
>   hw/virtio/meson.build                       |   3 +
>   hw/virtio/vhost-user-spi-pci.c              |  69 ++++++++
>   hw/virtio/vhost-user-spi.c                  |  66 +++++++
>   hw/virtio/virtio.c                          |   4 +-
>   include/hw/virtio/vhost-user-spi.h          |  25 +++
>   include/standard-headers/linux/virtio_ids.h |   1 +
>   include/standard-headers/linux/virtio_spi.h | 186 ++++++++++++++++++++
>   8 files changed, 358 insertions(+), 1 deletion(-)
>   create mode 100644 hw/virtio/vhost-user-spi-pci.c
>   create mode 100644 hw/virtio/vhost-user-spi.c
>   create mode 100644 include/hw/virtio/vhost-user-spi.h
>   create mode 100644 include/standard-headers/linux/virtio_spi.h
> 
> diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
> index aa63ff7fd4..d5857651e5 100644
> --- a/hw/virtio/Kconfig
> +++ b/hw/virtio/Kconfig
> @@ -110,3 +110,8 @@ config VHOST_USER_SCMI
>       bool
>       default y
>       depends on VIRTIO && VHOST_USER
> +
> +config VHOST_USER_SPI
> +    bool
> +    default y
> +    depends on VIRTIO && VHOST_USER
> diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
> index 621fc65454..42296219e5 100644
> --- a/hw/virtio/meson.build
> +++ b/hw/virtio/meson.build
> @@ -26,6 +26,7 @@ if have_vhost
>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SND', if_true: files('vhost-user-snd.c'))
>       system_virtio_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c'))
> +    system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SPI', if_true: files('vhost-user-spi.c'))
>   
>       # PCI Stubs
>       system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('vhost-user-device-pci.c'))
> @@ -39,6 +40,8 @@ if have_vhost
>                            if_true: files('vhost-user-snd-pci.c'))
>       system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_INPUT'],
>                            if_true: files('vhost-user-input-pci.c'))
> +    system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SPI'],
> +                         if_true: files('vhost-user-spi-pci.c'))
>     endif
>     if have_vhost_vdpa
>       system_virtio_ss.add(files('vhost-vdpa.c'))
> diff --git a/hw/virtio/vhost-user-spi-pci.c b/hw/virtio/vhost-user-spi-pci.c
> new file mode 100644
> index 0000000000..3565d526af
> --- /dev/null
> +++ b/hw/virtio/vhost-user-spi-pci.c
> @@ -0,0 +1,69 @@
> +/*
> + * Vhost-user spi virtio device PCI glue
> + *
> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/virtio/vhost-user-spi.h"
> +#include "hw/virtio/virtio-pci.h"
> +
> +struct VHostUserSPIPCI {
> +    VirtIOPCIProxy parent_obj;
> +    VHostUserSPI vdev;
> +};
> +
> +typedef struct VHostUserSPIPCI VHostUserSPIPCI;
> +
> +#define TYPE_VHOST_USER_SPI_PCI "vhost-user-spi-pci-base"
> +
> +DECLARE_INSTANCE_CHECKER(VHostUserSPIPCI, VHOST_USER_SPI_PCI,
> +                         TYPE_VHOST_USER_SPI_PCI)
> +
> +static void vhost_user_spi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
> +{
> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(vpci_dev);
> +    DeviceState *vdev = DEVICE(&dev->vdev);
> +
> +    vpci_dev->nvectors = 1;
> +    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
> +}
> +
> +static void vhost_user_spi_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
> +    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
> +    k->realize = vhost_user_spi_pci_realize;
> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
> +    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
> +    pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
> +    pcidev_k->revision = 0x00;
> +    pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
> +}
> +
> +static void vhost_user_spi_pci_instance_init(Object *obj)
> +{
> +    VHostUserSPIPCI *dev = VHOST_USER_SPI_PCI(obj);
> +
> +    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
> +                                TYPE_VHOST_USER_SPI);
> +}
> +
> +static const VirtioPCIDeviceTypeInfo vhost_user_spi_pci_info = {
> +    .base_name = TYPE_VHOST_USER_SPI_PCI,
> +    .non_transitional_name = "vhost-user-spi-pci",
> +    .instance_size = sizeof(VHostUserSPIPCI),
> +    .instance_init = vhost_user_spi_pci_instance_init,
> +    .class_init = vhost_user_spi_pci_class_init,
> +};
> +
> +static void vhost_user_spi_pci_register(void)
> +{
> +    virtio_pci_types_register(&vhost_user_spi_pci_info);
> +}
> +
> +type_init(vhost_user_spi_pci_register);
> diff --git a/hw/virtio/vhost-user-spi.c b/hw/virtio/vhost-user-spi.c
> new file mode 100644
> index 0000000000..e138b8b53b
> --- /dev/null
> +++ b/hw/virtio/vhost-user-spi.c
> @@ -0,0 +1,66 @@
> +/*
> + * Vhost-user spi virtio device
> + *
> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/virtio/virtio-bus.h"
> +#include "hw/virtio/vhost-user-spi.h"
> +#include "qemu/error-report.h"
> +#include "standard-headers/linux/virtio_ids.h"
> +#include "standard-headers/linux/virtio_spi.h"
> +
> +static Property vspi_properties[] = {
> +    DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void vspi_realize(DeviceState *dev, Error **errp)
> +{
> +    VHostUserBase *vub = VHOST_USER_BASE(dev);
> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_GET_CLASS(dev);
> +
> +    /* Fixed for SPI */
> +    vub->virtio_id = VIRTIO_ID_SPI;
> +    vub->num_vqs = 1;
> +    vub->vq_size = 4;
> +    vub->config_size = sizeof(struct virtio_spi_config);
> +
> +    vubc->parent_realize(dev, errp);
> +}
> +
> +static const VMStateDescription vu_spi_vmstate = {
> +    .name = "vhost-user-spi",
> +    .unmigratable = 1,
> +};
> +
> +static void vu_spi_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
> +
> +    dc->vmsd = &vu_spi_vmstate;
> +    device_class_set_props(dc, vspi_properties);
> +    device_class_set_parent_realize(dc, vspi_realize,
> +                                    &vubc->parent_realize);
> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
> +}
> +
> +static const TypeInfo vu_spi_info = {
> +    .name = TYPE_VHOST_USER_SPI,
> +    .parent = TYPE_VHOST_USER_BASE,
> +    .instance_size = sizeof(VHostUserSPI),
> +    .class_init = vu_spi_class_init,
> +};
> +
> +static void vu_spi_register_types(void)
> +{
> +    type_register_static(&vu_spi_info);
> +}
> +
> +type_init(vu_spi_register_types)
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 583a224163..689e2e21e7 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -46,6 +46,7 @@
>   #include "standard-headers/linux/virtio_iommu.h"
>   #include "standard-headers/linux/virtio_mem.h"
>   #include "standard-headers/linux/virtio_vsock.h"
> +#include "standard-headers/linux/virtio_spi.h"
>   
>   /*
>    * Maximum size of virtio device config space
> @@ -194,7 +195,8 @@ const char *virtio_device_names[] = {
>       [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv",
>       [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol",
>       [VIRTIO_ID_BT] = "virtio-bluetooth",
> -    [VIRTIO_ID_GPIO] = "virtio-gpio"
> +    [VIRTIO_ID_GPIO] = "virtio-gpio",
> +    [VIRTIO_ID_SPI] = "virtio-spi"
>   };
>   
>   static const char *virtio_id_to_name(uint16_t device_id)
> diff --git a/include/hw/virtio/vhost-user-spi.h b/include/hw/virtio/vhost-user-spi.h
> new file mode 100644
> index 0000000000..d6967d8431
> --- /dev/null
> +++ b/include/hw/virtio/vhost-user-spi.h
> @@ -0,0 +1,25 @@
> +/*
> + * Vhost-user spi virtio device
> + *
> + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef QEMU_VHOST_USER_SPI_H
> +#define QEMU_VHOST_USER_SPI_H
> +
> +#include "hw/virtio/virtio.h"
> +#include "hw/virtio/vhost.h"
> +#include "hw/virtio/vhost-user.h"
> +#include "hw/virtio/vhost-user-base.h"
> +
> +#define TYPE_VHOST_USER_SPI "vhost-user-spi-device"
> +
> +OBJECT_DECLARE_SIMPLE_TYPE(VHostUserSPI, VHOST_USER_SPI)
> +
> +struct VHostUserSPI {
> +    VHostUserBase parent_obj;
> +};
> +
> +#endif /* QEMU_VHOST_USER_SPI_H */
> diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h
> index 7aa2eb7662..601d387c5a 100644
> --- a/include/standard-headers/linux/virtio_ids.h
> +++ b/include/standard-headers/linux/virtio_ids.h
> @@ -68,6 +68,7 @@
>   #define VIRTIO_ID_AUDIO_POLICY		39 /* virtio audio policy */
>   #define VIRTIO_ID_BT			40 /* virtio bluetooth */
>   #define VIRTIO_ID_GPIO			41 /* virtio gpio */
> +#define VIRTIO_ID_SPI                   45 /* virtio spi */
>   
>   /*
>    * Virtio Transitional IDs
> diff --git a/include/standard-headers/linux/virtio_spi.h b/include/standard-headers/linux/virtio_spi.h
> new file mode 100644
> index 0000000000..6631827bfa
> --- /dev/null
> +++ b/include/standard-headers/linux/virtio_spi.h
> @@ -0,0 +1,186 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
> +/*
> + * Definitions for virtio SPI Controller
> + *
> + * Copyright (c) 2021 Intel Corporation. All rights reserved.
> + */
> +
> +#ifndef _LINUX_VIRTIO_SPI_H
> +#define _LINUX_VIRTIO_SPI_H
> +
> +#include "standard-headers/linux/const.h"
> +#include "standard-headers/linux/types.h"
> +
> +/* Sample data on trailing clock edge */
> +#define VIRTIO_SPI_CPHA (1 << 0)
> +/* Clock is high when IDLE */
> +#define VIRTIO_SPI_CPOL (1 << 1)
> +/* Chip Select is active high */
> +#define VIRTIO_SPI_CS_HIGH (1 << 2)
> +/* Transmit LSB first */
> +#define VIRTIO_SPI_MODE_LSB_FIRST (1 << 3)
> +/* Loopback mode */
> +#define VIRTIO_SPI_MODE_LOOP (1 << 4)
> +
> +/*
> + * All config fields are read-only for the Virtio SPI driver
> + *
> + * @cs_max_number: maximum number of chipselect the host SPI controller
> + *   supports.
> + * @cs_change_supported: indicates if the host SPI controller supports to toggle
> + * chipselect after each transfer in one message:
> + *   0: unsupported, chipselect will be kept in active state throughout the
> + *      message transaction;
> + *   1: supported.
> + *   Note: Message here contains a sequence of SPI transfers.
> + * @tx_nbits_supported: indicates the supported number of bit for writing:
> + *   bit 0: DUAL (2-bit transfer), 1 for supported
> + *   bit 1: QUAD (4-bit transfer), 1 for supported
> + *   bit 2: OCTAL (8-bit transfer), 1 for supported
> + *   other bits are reserved as 0, 1-bit transfer is always supported.
> + * @rx_nbits_supported: indicates the supported number of bit for reading:
> + *   bit 0: DUAL (2-bit transfer), 1 for supported
> + *   bit 1: QUAD (4-bit transfer), 1 for supported
> + *   bit 2: OCTAL (8-bit transfer), 1 for supported
> + *   other bits are reserved as 0, 1-bit transfer is always supported.
> + * @bits_per_word_mask: mask indicating which values of bits_per_word are
> + *   supported. If not set, no limitation for bits_per_word.
> + * @mode_func_supported: indicates the following features are supported or not:
> + *   bit 0-1: CPHA feature
> + *     0b00: invalid, should support as least one CPHA setting
> + *     0b01: supports CPHA=0 only
> + *     0b10: supports CPHA=1 only
> + *     0b11: supports CPHA=0 and CPHA=1.
> + *   bit 2-3: CPOL feature
> + *     0b00: invalid, should support as least one CPOL setting
> + *     0b01: supports CPOL=0 only
> + *     0b10: supports CPOL=1 only
> + *     0b11: supports CPOL=0 and CPOL=1.
> + *   bit 4: chipselect active high feature, 0 for unsupported and 1 for
> + *     supported, chipselect active low should always be supported.
> + *   bit 5: LSB first feature, 0 for unsupported and 1 for supported,
> + *     MSB first should always be supported.
> + *   bit 6: loopback mode feature, 0 for unsupported and 1 for supported,
> + *     normal mode should always be supported.
> + * @max_freq_hz: the maximum clock rate supported in Hz unit, 0 means no
> + *   limitation for transfer speed.
> + * @max_word_delay_ns: the maximum word delay supported in ns unit,
> + *   0 means word delay feature is unsupported.
> + *   Note: Just as one message contains a sequence of transfers,
> + *         one transfer may contain a sequence of words.
> + * @max_cs_setup_ns: the maximum delay supported after chipselect is asserted,
> + *   in ns unit, 0 means delay is not supported to introduce after chipselect is
> + *   asserted.
> + * @max_cs_hold_ns: the maximum delay supported before chipselect is deasserted,
> + *   in ns unit, 0 means delay is not supported to introduce before chipselect
> + *   is deasserted.
> + * @max_cs_incative_ns: maximum delay supported after chipselect is deasserted,
> + *   in ns unit, 0 means delay is not supported to introduce after chipselect is
> + *   deasserted.
> + */
> +struct virtio_spi_config {
> +	/* # of /dev/spidev<bus_num>.CS with CS=0..chip_select_max_number -1 */
> +        uint8_t cs_max_number;
> +        uint8_t cs_change_supported;
> +#define VIRTIO_SPI_RX_TX_SUPPORT_DUAL (1 << 0)
> +#define VIRTIO_SPI_RX_TX_SUPPORT_QUAD (1 << 1)
> +#define VIRTIO_SPI_RX_TX_SUPPORT_OCTAL (1 << 2)
> +        uint8_t tx_nbits_supported;
> +        uint8_t rx_nbits_supported;
> +        uint32_t bits_per_word_mask;
> +#define VIRTIO_SPI_MF_SUPPORT_CPHA_0 (1 << 0)
> +#define VIRTIO_SPI_MF_SUPPORT_CPHA_1 (1 << 1)
> +#define VIRTIO_SPI_MF_SUPPORT_CPOL_0 (1 << 2)
> +#define VIRTIO_SPI_MF_SUPPORT_CPOL_1 (1 << 3)
> +#define VIRTIO_SPI_MF_SUPPORT_CS_HIGH (1 << 4)
> +#define VIRTIO_SPI_MF_SUPPORT_LSB_FIRST (1 << 5)
> +#define VIRTIO_SPI_MF_SUPPORT_LOOPBACK (1 << 6)
> +        uint32_t mode_func_supported;
> +        uint32_t max_freq_hz;
> +        uint32_t max_word_delay_ns;
> +        uint32_t max_cs_setup_ns;
> +        uint32_t max_cs_hold_ns;
> +        uint32_t max_cs_inactive_ns;
> +};
> +
> +/*
> + * @chip_select_id: chipselect index the SPI transfer used.
> + *
> + * @bits_per_word: the number of bits in each SPI transfer word.
> + *
> + * @cs_change: whether to deselect device after finishing this transfer
> + *     before starting the next transfer, 0 means cs keep asserted and
> + *     1 means cs deasserted then asserted again.
> + *
> + * @tx_nbits: bus width for write transfer.
> + *     0,1: bus width is 1, also known as SINGLE
> + *     2  : bus width is 2, also known as DUAL
> + *     4  : bus width is 4, also known as QUAD
> + *     8  : bus width is 8, also known as OCTAL
> + *     other values are invalid.
> + *
> + * @rx_nbits: bus width for read transfer.
> + *     0,1: bus width is 1, also known as SINGLE
> + *     2  : bus width is 2, also known as DUAL
> + *     4  : bus width is 4, also known as QUAD
> + *     8  : bus width is 8, also known as OCTAL
> + *     other values are invalid.
> + *
> + * @reserved: for future use.
> + *
> + * @mode: SPI transfer mode.
> + *     bit 0: CPHA, determines the timing (i.e. phase) of the data
> + *         bits relative to the clock pulses.For CPHA=0, the
> + *         "out" side changes the data on the trailing edge of the
> + *         preceding clock cycle, while the "in" side captures the data
> + *         on (or shortly after) the leading edge of the clock cycle.
> + *         For CPHA=1, the "out" side changes the data on the leading
> + *         edge of the current clock cycle, while the "in" side
> + *         captures the data on (or shortly after) the trailing edge of
> + *         the clock cycle.
> + *     bit 1: CPOL, determines the polarity of the clock. CPOL=0 is a
> + *         clock which idles at 0, and each cycle consists of a pulse
> + *         of 1. CPOL=1 is a clock which idles at 1, and each cycle
> + *         consists of a pulse of 0.
> + *     bit 2: CS_HIGH, if 1, chip select active high, else active low.
> + *     bit 3: LSB_FIRST, determines per-word bits-on-wire, if 0, MSB
> + *         first, else LSB first.
> + *     bit 4: LOOP, loopback mode.
> + *
> + * @freq: the transfer speed in Hz.
> + *
> + * @word_delay_ns: delay to be inserted between consecutive words of a
> + *     transfer, in ns unit.
> + *
> + * @cs_setup_ns: delay to be introduced after CS is asserted, in ns
> + *     unit.
> + *
> + * @cs_delay_hold_ns: delay to be introduced before CS is deasserted
> + *     for each transfer, in ns unit.
> + *
> + * @cs_change_delay_inactive_ns: delay to be introduced after CS is
> + *     deasserted and before next asserted, in ns unit.
> + */
> +struct spi_transfer_head {
> +        uint8_t chip_select_id;
> +        uint8_t bits_per_word;
> +        uint8_t cs_change;
> +        uint8_t tx_nbits;
> +        uint8_t rx_nbits;
> +        uint8_t reserved[3];
> +        uint32_t mode;
> +        uint32_t freq;
> +        uint32_t word_delay_ns;
> +        uint32_t cs_setup_ns;
> +        uint32_t cs_delay_hold_ns;
> +        uint32_t cs_change_delay_inactive_ns;
> +};
> +
> +struct spi_transfer_result {
> +#define VIRTIO_SPI_TRANS_OK 0
> +#define VIRTIO_SPI_PARAM_ERR 1
> +#define VIRTIO_SPI_TRANS_ERR 2
> +	uint8_t status;
> +};
> +
> +#endif /* _LINUX_VIRTIO_SPI_H */