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
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
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
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> >
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
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> >>> >
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 */
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 */
© 2016 - 2024 Red Hat, Inc.