Message ID | 20240712034246.2553812-1-quic_haixcui@quicinc.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add vhost-user-spi and vhost-user-spi-pci devices | expand |
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 */
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 */
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>
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> >>
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> >>> >
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 */
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