diff options
| author | GuEe-GUI <[email protected]> | 2026-03-01 13:06:32 +0800 |
|---|---|---|
| committer | Rbb666 <[email protected]> | 2026-06-15 10:00:57 +0800 |
| commit | 8517f2d086924f66fcb867f7a84ff2855f9926bd (patch) | |
| tree | f78dfea50b184d616c6b092496cb703238eaaff2 /components/drivers | |
| parent | 79e7d919094ebf213d43f3ce84f643a44020d229 (diff) | |
[dm][virtio] support virtio dm
1. version for v1.2
2. support packed queue
1. support MMIO/PCI over bus
2. new virtio queue api with dma/cpu sync
3. update for virtio device drivers:
- net
- block
- console
- input
- gpu
4. new virtio device drivers:
- 9p
- crypto
- rng
- scmi
- scsi
Signed-off-by: GuEe-GUI <[email protected]>
Diffstat (limited to 'components/drivers')
43 files changed, 9833 insertions, 5114 deletions
diff --git a/components/drivers/include/drivers/virtio.h b/components/drivers/include/drivers/virtio.h new file mode 100644 index 0000000000..e38aed5793 --- /dev/null +++ b/components/drivers/include/drivers/virtio.h @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-9-16 GuEe-GUI the first version + * 2021-11-11 GuEe-GUI modify to virtio common interface + * 2023-02-25 GuEe-GUI support DM + */ + +#ifndef __VIRTIO_H__ +#define __VIRTIO_H__ + +#include <mm_page.h> + +#include <drivers/core/dm.h> +#include <drivers/core/driver.h> +#include <drivers/byteorder.h> + +#include "../../virtio/virtio_ids.h" + +#define VIRTIO_STATUS_ACKNOWLEDGE RT_BIT(0) +#define VIRTIO_STATUS_DRIVER RT_BIT(1) +#define VIRTIO_STATUS_DRIVER_OK RT_BIT(2) +#define VIRTIO_STATUS_FEATURES_OK RT_BIT(3) +#define VIRTIO_STATUS_NEEDS_RESET RT_BIT(6) +#define VIRTIO_STATUS_FAILED RT_BIT(7) + +#define VIRTIO_F_NOTIFY_ON_EMPTY 24 +#define VIRTIO_F_ANY_LAYOUT 27 +#define VIRTIO_F_RING_INDIRECT_DESC 28 +#define VIRTIO_F_RING_EVENT_IDX 29 +#define VIRTIO_F_VERSION_1 32 +#define VIRTIO_F_ACCESS_PLATFORM 33 +#define VIRTIO_F_RING_PACKED 34 +#define VIRTIO_F_IN_ORDER 35 +#define VIRTIO_F_ORDER_PLATFORM 36 +#define VIRTIO_F_SR_IOV 37 +#define VIRTIO_F_NOTIFICATION_DATA 38 +#define VIRTIO_F_NOTIF_CONFIG_DATA 39 +#define VIRTIO_F_RING_RESET 40 + +#define VIRTIO_TRANSPORT_F_START VIRTIO_F_RING_INDIRECT_DESC +#define VIRTIO_TRANSPORT_F_END VIRTIO_F_RING_RESET + +struct rt_virtio_device_id +{ +#define VIRTIO_DEVICE_ANY_ID 0xffffffff + rt_uint32_t device; + rt_uint32_t vendor; +}; + +struct rt_virtqueue; +struct rt_virtio_transport; + +typedef rt_bool_t (*rt_virtqueue_notifier)(struct rt_virtqueue *vq); +typedef void (*rt_virtqueue_callback)(struct rt_virtqueue *vq); + +struct rt_virtio_device +{ + struct rt_device parent; + + int idx; + struct rt_virtio_device_id id; + + rt_uint64_t features; + const struct rt_virtio_transport *trans; + + rt_list_t vq_node; + struct rt_spinlock vq_lock; + + rt_bool_t dma_dispatch; + void *priv; +}; + +struct virtqueue_split; +struct virtqueue_packed; + +struct rt_virtqueue_formula +{ + void *page; +}; + +struct rt_virtqueue +{ + rt_list_t list; + rt_list_t user_list; + + const char *name; + rt_uint32_t index; + rt_uint32_t num_max; + rt_uint32_t num_free; + + rt_virtqueue_callback callback; + + union + { + struct virtqueue_split *vq_split; + struct virtqueue_packed *vq_packed; + }; + rt_bool_t packed_ring; + + rt_virtqueue_notifier notify; + + rt_bool_t event; + rt_bool_t event_triggered; + rt_uint32_t free_head; + rt_uint32_t num_added; + rt_uint16_t last_used_idx; + + struct rt_virtio_device *vdev; + struct rt_virtqueue_formula formula; +}; + +struct rt_virtio_shm_region +{ + rt_uint8_t id; + + rt_uint64_t base; + rt_uint64_t size; +}; + +#define RT_VIRTQUEUE_CTL_IRQ_AFFINITY 0 +#define RT_VIRTQUEUE_CTL_READ_SHM_REGION 1 + +struct rt_virtio_transport +{ + rt_err_t (*get_status)(struct rt_virtio_device *vdev, rt_uint8_t *out_status); + rt_err_t (*set_status)(struct rt_virtio_device *vdev, rt_uint8_t status); + rt_err_t (*get_features)(struct rt_virtio_device *vdev, rt_uint64_t *out_features); + rt_err_t (*set_features)(struct rt_virtio_device *vdev); + rt_err_t (*get_config)(struct rt_virtio_device *vdev, rt_uint32_t offset, void *dst, int length); + rt_err_t (*set_config)(struct rt_virtio_device *vdev, rt_uint32_t offset, const void *src, int length); + rt_err_t (*install_vqs)(struct rt_virtio_device *vdev, int vqs_nr, + struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[]); + rt_err_t (*release_vqs)(struct rt_virtio_device *vdev); + rt_err_t (*control_vqs)(struct rt_virtio_device *vdev, rt_uint32_t cfg, void *data); + rt_err_t (*generation)(struct rt_virtio_device *vdev, rt_uint32_t *out_counter); + rt_err_t (*reset)(struct rt_virtio_device *vdev); +}; + +struct rt_virtio_driver +{ + struct rt_driver parent; + + const struct rt_virtio_device_id *ids; + + rt_uint64_t features; + + rt_err_t (*probe)(struct rt_virtio_device *vdev); + rt_err_t (*remove)(struct rt_virtio_device *vdev); + void (*config_changed)(struct rt_virtio_device *vdev); +}; + +struct rt_virtqueue *rt_virtqueue_create(struct rt_virtio_device *vdev, + const char *name, int index, int num, rt_uint32_t align, + rt_virtqueue_notifier notify, rt_virtqueue_callback callback, + struct rt_virtqueue_formula *formula); + +rt_err_t rt_virtqueue_delete(struct rt_virtio_device *vdev, struct rt_virtqueue *vq); + +rt_err_t rt_virtqueue_add_outbuf(struct rt_virtqueue *vq, void *dma_buf, rt_size_t size); +rt_err_t rt_virtqueue_add_inbuf(struct rt_virtqueue *vq, void *dma_buf, rt_size_t size); + +rt_bool_t rt_virtqueue_prepare(struct rt_virtqueue *vq, rt_uint32_t nr); +void rt_virtqueue_wait_prepare(struct rt_virtqueue *vq, rt_uint32_t nr); +rt_uint32_t rt_virtqueue_next_buf_index(struct rt_virtqueue *vq); + +rt_bool_t rt_virtqueue_submit(struct rt_virtqueue *vq); +rt_bool_t rt_virtqueue_notify(struct rt_virtqueue *vq); +rt_bool_t rt_virtqueue_kick(struct rt_virtqueue *vq); + +void rt_virtqueue_isr(int irq, struct rt_virtqueue *vq); +rt_bool_t rt_virtqueue_poll(struct rt_virtqueue *vq, rt_uint32_t last_used_idx); + +void rt_virtqueue_disable_callback(struct rt_virtqueue *vq); +rt_bool_t rt_virtqueue_enable_callback(struct rt_virtqueue *vq, + rt_uint32_t *out_last_used_idx); + +void *rt_virtqueue_read_buf(struct rt_virtqueue *vq, rt_size_t *out_len); + +rt_size_t rt_virtqueue_get_virtq_size(struct rt_virtqueue *vq); +rt_ubase_t rt_virtqueue_get_desc_addr(struct rt_virtqueue *vq); +rt_ubase_t rt_virtqueue_get_avail_addr(struct rt_virtqueue *vq); +rt_ubase_t rt_virtqueue_get_used_addr(struct rt_virtqueue *vq); + +void rt_virtio_device_ready(struct rt_virtio_device *vdev); +void rt_virtio_device_reset(struct rt_virtio_device *vdev); +void rt_virtio_device_config_changed(struct rt_virtio_device *vdev); + +void rt_virtio_add_status(struct rt_virtio_device *vdev, rt_uint32_t status); + +rt_bool_t rt_virtio_has_status(struct rt_virtio_device *vdev, rt_uint8_t status_bit); +rt_bool_t rt_virtio_has_feature(struct rt_virtio_device *vdev, rt_uint32_t feature_bit); + +rt_err_t rt_virtio_get_config(struct rt_virtio_device *vdev, + rt_uint32_t offset, void *dst, int length); +rt_err_t rt_virtio_set_config(struct rt_virtio_device *vdev, + rt_uint32_t offset, const void *src, int length); + +rt_inline void rt_virtio_read_bytes(struct rt_virtio_device *vdev, + rt_uint32_t offset, void *buf, rt_uint32_t bytes_size, rt_uint32_t count) +{ + rt_uint32_t old, gen; + + if (vdev->trans->generation) + { + vdev->trans->generation(vdev, &gen); + } + else + { + gen = 0; + } + + do { + old = gen; + + for (int i = 0; i < count; ++i) + { + vdev->trans->get_config(vdev, + offset + bytes_size * i, buf + i * bytes_size, bytes_size); + } + + if (vdev->trans->generation) + { + vdev->trans->generation(vdev, &gen); + } + else + { + gen = 0; + } + } while (gen != old); +} + +#define rt_virtio_le_to_cpu(value) \ + (sizeof(value) == 4 ? rt_le32_to_cpu(value) : \ + (sizeof(value) == 2 ? rt_le16_to_cpu(value) : \ + (sizeof(value) == 1 ? value : rt_le64_to_cpu(value)))) + +#define rt_virtio_cpu_to_le(value) \ + (sizeof(value) == 4 ? rt_cpu_to_le32(value) : \ + (sizeof(value) == 2 ? rt_cpu_to_le16(value) : \ + (sizeof(value) == 1 ? value : rt_cpu_to_le64(value)))) + +#define rt_virtio_read_config(vdev, type, member, out_value) \ +do { \ + typeof(((type *)0)->member) tmp; \ + rt_uint32_t offset = (rt_ubase_t)&((type *)0)->member; \ + switch (sizeof(tmp)) \ + { \ + case 1: case 2: case 4: \ + rt_virtio_get_config(vdev, offset, &tmp, sizeof(tmp)); \ + break; \ + default: \ + rt_virtio_read_bytes(vdev, offset, &tmp, sizeof(tmp), 1); \ + break; \ + } \ + *(out_value) = rt_virtio_le_to_cpu(tmp); \ +} while (0) + +#define rt_virtio_write_config(vdev, type, member, value) \ +do { \ + typeof(((type *)0)->member) tmp = rt_virtio_cpu_to_le(value); \ + rt_uint32_t offset = (rt_ubase_t)&((type *)0)->member; \ + rt_virtio_set_config(vdev, offset, &tmp, sizeof(tmp)); \ +} while (0) + +rt_err_t rt_virtio_virtqueue_install(struct rt_virtio_device *vdev, int vqs_nr, + struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[]); +rt_err_t rt_virtio_virtqueue_release(struct rt_virtio_device *vdev); +rt_err_t rt_virtio_virtqueue_control(struct rt_virtio_device *vdev, rt_uint32_t cfg, void *data); + +const char *rt_virtio_device_id_name(struct rt_virtio_device *vdev); + +rt_err_t rt_virtio_driver_register(struct rt_virtio_driver *vdrv); +rt_err_t rt_virtio_device_register(struct rt_virtio_device *vdev); + +#define RT_VIRTIO_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, virtio, BUILIN) + +#endif /* __VIRTIO_H__ */ diff --git a/components/drivers/include/drivers/virtq.h b/components/drivers/include/drivers/virtq.h new file mode 100644 index 0000000000..fa18ee82e3 --- /dev/null +++ b/components/drivers/include/drivers/virtq.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-11-11 GuEe-GUI the first version + * 2023-02-25 GuEe-GUI support packed + */ + +#ifndef __VIRTQ_H__ +#define __VIRTQ_H__ + +#include <drivers/misc.h> +#include <drivers/byteorder.h> + +#define VIRTQ_DESC_F_NEXT RT_BIT(0) /* This marks a buffer as continuing via the next field. */ +#define VIRTQ_DESC_F_WRITE RT_BIT(1) /* This marks a buffer as write-only (otherwise read-only). */ +#define VIRTQ_DESC_F_INDIRECT RT_BIT(3) /* This means the buffer contains a list of buffer descriptors. */ +#define VIRTQ_DESC_F_AVAIL RT_BIT(7) +#define VIRTQ_DESC_F_USED RT_BIT(15) + +/* + * The device uses this in used->flags to advise the driver: don't kick me + * when you add a buffer. It's unreliable, so it's simply an optimization. + */ +#define VIRTQ_USED_F_NO_NOTIFY 1 + +/* + * The driver uses this in avail->flags to advise the device: don't + * interrupt me when you consume a buffer. It's unreliable, so it's + * simply an optimization. + */ +#define VIRTQ_AVAIL_F_NO_INTERRUPT 1 + +/* Virtqueue descriptors: 16 bytes. These can chain together via "next". */ +struct virtq_desc +{ + rt_uint64_t addr; /* Address (guest-physical). */ + rt_uint32_t len; /* Length. */ + rt_uint16_t flags; /* The flags as indicated above. */ + rt_uint16_t next; /* We chain unused descriptors via this, too */ +}; + +struct virtq_avail +{ + rt_uint16_t flags; /* Notifications */ + rt_uint16_t idx; /* Where the driver would put the next descriptor entry in the ring (modulo the queue size) */ + rt_uint16_t ring[]; + + /* + * Only if VIRTIO_F_RING_EVENT_IDX + * rt_uint16_t used_event; + */ +}; + +struct virtq_used_elem +{ + rt_uint32_t id; /* Index of start of used descriptor chain. */ + rt_uint32_t len; /* Total length of the descriptor chain which was written to. */ +}; + +struct virtq_used +{ + rt_uint16_t flags; + rt_uint16_t idx; + struct virtq_used_elem ring[]; + + /* + * Only if VIRTIO_F_RING_EVENT_IDX + * rt_uint16_t avail_event; + */ +}; + +/* Enable events in packed ring. */ +#define VIRTQ_PACKED_EVENT_FLAG_ENABLE 0x0 +/* Disable events in packed ring. */ +#define VIRTQ_PACKED_EVENT_FLAG_DISABLE 0x1 +/* + * Enable events for a specific descriptor in packed ring. + * (as specified by Descriptor Ring Change Event Offset/Wrap Counter). + * Only valid if VIRTIO_F_RING_EVENT_IDX has been negotiated. + */ +#define VIRTQ_PACKED_EVENT_FLAG_DESC 0x2 + +/* Offset bit shift in event suppression structure of packed ring. */ +#define VIRTQ_PACKED_EVENT_OFF 0 +/* Wrap counter bit shift in event suppression structure of packed ring. */ +#define VIRTQ_PACKED_EVENT_WRAP_CTR 15 + +struct virtq_packed_desc +{ + rt_le64_t addr; /* Buffer Address. */ + rt_le32_t len; /* Buffer Length. */ + rt_le16_t id; /* Buffer ID (always at the last desc). */ + rt_le16_t flags; /* The flags depending on descriptor type. */ + /* + * For avail desc: + * When wrap counter is 1 => VIRTQ_DESC_F_AVAIL | ~VIRTQ_DESC_F_USED + * When wrap counter is 0 => ~VIRTQ_DESC_F_AVAIL | VIRTQ_DESC_F_USED + * + * For used desc: + * When wrap counter is 1 => VIRTQ_DESC_F_AVAIL | VIRTQ_DESC_F_USED + * When wrap counter is 0 => ~VIRTQ_DESC_F_AVAIL | ~VIRTQ_DESC_F_USED + */ +}; + +struct virtq_packed_desc_event +{ + rt_le16_t off_wrap; /* Descriptor ring change event offset/wrap counter. */ + rt_le16_t flags; /* Descriptor ring change event flags. */ +}; + +struct virtq +{ + rt_uint32_t num; + rt_uint32_t align; + + union + { + struct virtq_desc *desc; + struct virtq_packed_desc *desc_packed; + }; + union + { + struct virtq_avail *avail; + struct virtq_packed_desc_event *driver_event; + }; + union + { + struct virtq_used *used; + struct virtq_packed_desc_event *device_event; + }; +}; + +rt_inline void virtq_init(struct virtq *virtq, rt_uint32_t num, + void *pages, rt_ubase_t align) +{ + /* Only split */ + virtq->num = num; + virtq->align = align; + + virtq->desc = (struct virtq_desc *)pages; + virtq->avail = (struct virtq_avail *)&virtq->desc[num]; + /* Keep sizeof(used_event) */ + virtq->used = (struct virtq_used *)RT_ALIGN((rt_ubase_t)&virtq->avail->ring[num] + sizeof(rt_uint16_t), align); +} + +rt_inline rt_size_t virtq_size(struct virtq *virtq, rt_uint32_t try_num, rt_uint32_t try_align) +{ + /* Only split */ + rt_uint32_t align; + rt_size_t size, num; + + if (virtq) + { + num = virtq->num; + align = virtq->align; + } + else + { + num = try_num; + align = try_align; + } + + size = sizeof(struct virtq_desc) * num; + size += sizeof(struct virtq_avail) + sizeof(rt_uint16_t) * num; + /* Keep sizeof(used_event) */ + size += sizeof(rt_uint16_t); + size = RT_ALIGN(size, align); + size += sizeof(struct virtq_used) + sizeof(struct virtq_used_elem) * num; + /* Keep sizeof(avail_event) */ + size += sizeof(rt_uint16_t); + + return size; +} + +rt_inline rt_bool_t virtq_need_event(rt_uint16_t event_idx, + rt_uint16_t new_idx, rt_uint16_t old_idx) +{ + return (rt_uint16_t)(new_idx - event_idx - 1) < (rt_uint16_t)(new_idx - old_idx); +} + +/* Get location of event indices (only with VIRTIO_F_EVENT_IDX) */ +rt_inline rt_uint16_t *virtq_used_event(struct virtq *virtq) +{ + /* For backwards compat, used event index is at *end* of avail ring. */ + return &virtq->avail->ring[virtq->num]; +} + +rt_inline rt_uint16_t *virtq_avail_event(struct virtq *virtq) +{ + /* For backwards compat, avail event index is at *end* of used ring. */ + return (rt_uint16_t *)&virtq->used->ring[virtq->num]; +} + +#endif /* __VIRTQ_H__ */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 3d5aa23c44..0c83137087 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -156,6 +156,11 @@ extern "C" { #ifdef RT_USING_NVMEM #include "drivers/nvmem.h" #endif /* RT_USING_NVMEM */ + +#ifdef RT_USING_VIRTIO +#include "drivers/virtio.h" +#include "drivers/virtq.h" +#endif #endif /* RT_USING_DM */ #ifdef RT_USING_REGULATOR diff --git a/components/drivers/virtio/Kconfig b/components/drivers/virtio/Kconfig index 8298ff75be..5d974c886d 100644 --- a/components/drivers/virtio/Kconfig +++ b/components/drivers/virtio/Kconfig @@ -1,43 +1,99 @@ menuconfig RT_USING_VIRTIO bool "Using VirtIO device drivers" + depends on RT_USING_DM + depends on RT_USING_DMA default n - if RT_USING_VIRTIO - choice RT_USING_VIRTIO_VERSION - prompt "VirtIO Version" - default RT_USING_VIRTIO10 +config RT_VIRTIO_TRANSPORT_MMIO + bool "Using VirtIO MMIO transport" + depends on RT_USING_VIRTIO + depends on RT_USING_OFW + default y - config RT_USING_VIRTIO10 - bool "VirtIO v1.0" - endchoice +config RT_VIRTIO_TRANSPORT_PCI + bool "Using VirtIO PCI transport" + depends on RT_USING_VIRTIO + depends on RT_USING_PCI + default y + help + We not support the version of 0.95 in PCI. The minimum version >= 1.0 - config RT_USING_VIRTIO_MMIO_ALIGN - bool "Using VirtIO MMIO alignment" - default y +config RT_VIRTIO_NET + bool "VirtIO Net" + depends on RT_USING_VIRTIO + depends on RT_USING_ETHERNET + default y - config RT_USING_VIRTIO_BLK - bool "Using VirtIO BLK" - default y +config RT_VIRTIO_BLK + bool "VirtIO BLK" + depends on RT_USING_VIRTIO + depends on RT_USING_BLK + default y - config RT_USING_VIRTIO_NET - bool "Using VirtIO NET" - default y +config RT_VIRTIO_CONSOLE + bool "VirtIO Console" + depends on RT_USING_VIRTIO + depends on RT_USING_SERIAL + select RT_USING_DEVICE_IPC + select RT_USING_SYSTEM_WORKQUEUE + default y - menuconfig RT_USING_VIRTIO_CONSOLE - bool "Using VirtIO Console" - default y +config RT_VIRTIO_RNG + bool "VirtIO RNG" + depends on RT_USING_VIRTIO + depends on RT_USING_HWCRYPTO + depends on RT_HWCRYPTO_USING_RNG + default y - if RT_USING_VIRTIO_CONSOLE - config RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR - int "Max number of port in VirtIO Console" - default 4 - endif +config RT_VIRTIO_SCSI + bool "VirtIO SCSI" + depends on RT_USING_VIRTIO + depends on RT_SCSI_SD || RT_SCSI_CDROM + default y - config RT_USING_VIRTIO_GPU - bool "Using VirtIO GPU" - default y +config RT_VIRTIO_9P + bool "VirtIO 9P" + depends on RT_USING_VIRTIO + select RT_USING_DFS_9PFS + default y - config RT_USING_VIRTIO_INPUT - bool "Using VirtIO Input" - default y - endif +config RT_VIRTIO_RPROC_SERIAL + bool "VirtIO Remoteproc Serial Link" + depends on RT_USING_VIRTIO + select RT_VIRTIO_CONSOLE + default y + +config RT_VIRTIO_GPU + bool "VirtIO GPU" + depends on RT_USING_VIRTIO + default y + +config RT_VIRTIO_INPUT + bool "VirtIO Input" + depends on RT_USING_VIRTIO + depends on RT_USING_INPUT + depends on RT_INPUT_TOUCHSCREEN + default y + +config RT_VIRTIO_CRYPTO + bool "VirtIO Crypto" + depends on RT_USING_VIRTIO + depends on RT_USING_HWCRYPTO + depends on RT_HWCRYPTO_USING_AES + depends on RT_HWCRYPTO_USING_AES_ECB + depends on RT_HWCRYPTO_USING_AES_CBC + depends on RT_HWCRYPTO_USING_AES_CTR + depends on RT_HWCRYPTO_USING_DES + depends on RT_HWCRYPTO_USING_DES_ECB + depends on RT_HWCRYPTO_USING_DES_CBC + depends on RT_HWCRYPTO_USING_3DES + depends on RT_HWCRYPTO_USING_3DES_ECB + depends on RT_HWCRYPTO_USING_3DES_CBC + depends on RT_HWCRYPTO_USING_RC4 + default y + +config RT_VIRTIO_SCMI + bool "VirtIO SCMI" + depends on RT_USING_VIRTIO + depends on RT_FIRMWARE_ARM_SCMI + default y diff --git a/components/drivers/virtio/SConscript b/components/drivers/virtio/SConscript index d38ec0e356..a5d3817f0d 100644 --- a/components/drivers/virtio/SConscript +++ b/components/drivers/virtio/SConscript @@ -1,11 +1,51 @@ -# RT-Thread building script for component - from building import * -cwd = GetCurrentDir() -src = Glob('*.c') -CPPPATH = [cwd] +group = [] + +if not GetDepend(['RT_USING_VIRTIO']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['virtio.c', 'virtio_queue.c'] + +if GetDepend(['RT_VIRTIO_TRANSPORT_MMIO']): + src += ['virtio_mmio.c'] + +if GetDepend(['RT_VIRTIO_TRANSPORT_PCI']): + src += ['virtio_pci.c'] + +if GetDepend(['RT_VIRTIO_NET']): + src += ['virtio-net.c'] + +if GetDepend(['RT_VIRTIO_BLK']): + src += ['virtio-blk.c'] + +if GetDepend(['RT_VIRTIO_CONSOLE']) or GetDepend(['RT_VIRTIO_RPROC_SERIAL']): + src += ['virtio-console.c'] + +if GetDepend(['RT_VIRTIO_RNG']): + src += ['virtio-rng.c'] + +if GetDepend(['RT_VIRTIO_SCSI']): + src += ['virtio-scsi.c'] + +if GetDepend(['RT_VIRTIO_9P']): + src += ['virtio-9p.c'] + +if GetDepend(['RT_VIRTIO_GPU']): + src += ['virtio-gpu.c'] + +if GetDepend(['RT_VIRTIO_INPUT']): + src += ['virtio-input.c'] + +if GetDepend(['RT_VIRTIO_CRYPTO']): + src += ['virtio-crypto.c'] + +if GetDepend(['RT_VIRTIO_SCMI']): + src += ['virtio-scmi.c'] -group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_VIRTIO'], CPPPATH = CPPPATH) +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/virtio/virtio-9p.c b/components/drivers/virtio/virtio-9p.c new file mode 100644 index 0000000000..67ef8ca3e8 --- /dev/null +++ b/components/drivers/virtio/virtio-9p.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "virtio.dev.9p" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include <dfs_9pfs.h> +#include "virtio_config/virtio-9p.h" + +struct virtio_9p +{ + struct p9_protocol parent; + struct rt_virtio_device *vdev; + + char *tag; + struct rt_virtqueue *vqs[1]; + struct rt_completion done; + struct rt_spinlock lock; +}; + +static rt_err_t virtio_9p_transport(struct p9_protocol *p9p, + rt_uint8_t *tx_data, rt_uint32_t tx_size, + rt_uint8_t *rx_data, rt_uint32_t *ref_rx_size) +{ + rt_err_t err; + rt_ubase_t level; + struct rt_virtqueue *vq; + struct virtio_9p *v9p = rt_container_of(p9p, struct virtio_9p, parent); + + vq = v9p->vqs[0]; + rt_virtqueue_wait_prepare(vq, 2); + + level = rt_spin_lock_irqsave(&v9p->lock); + + rt_virtqueue_add_outbuf(vq, tx_data, tx_size); + rt_virtqueue_add_inbuf(vq, rx_data, *ref_rx_size); + + rt_virtqueue_kick(vq); + + rt_spin_unlock_irqrestore(&v9p->lock, level); + + if (!(err = rt_completion_wait(&v9p->done, rt_tick_from_millisecond(1000)))) + { + *ref_rx_size = rt_min_t(rt_uint32_t, + *ref_rx_size, rt_le32_to_cpu(*(rt_uint32_t*)(&rx_data[0]))); + } + + return err; +} + +static void virtio_9p_done(struct rt_virtqueue *vq) +{ + rt_ubase_t level; + struct virtio_9p *v9p = vq->vdev->priv; + + level = rt_spin_lock_irqsave(&v9p->lock); + + rt_virtqueue_read_buf(vq, RT_NULL); + rt_completion_done(&v9p->done); + + rt_spin_unlock_irqrestore(&v9p->lock, level); +} + +static rt_err_t virtio_9p_vq_init(struct virtio_9p *v9p) +{ + const char *names[] = + { + "req", + }; + rt_virtqueue_callback cbs[] = + { + &virtio_9p_done, + }; + + return rt_virtio_virtqueue_install(v9p->vdev, RT_ARRAY_SIZE(v9p->vqs), + v9p->vqs, names, cbs); +} + +static void virtio_9p_vq_finit(struct virtio_9p *v9p) +{ + if (v9p->vqs[0]) + { + rt_virtio_virtqueue_release(v9p->vdev); + } + if (v9p->tag) + { + rt_free(v9p->tag); + } + + rt_free(v9p); +} + +static rt_err_t virtio_9p_probe(struct rt_virtio_device *vdev) +{ + rt_err_t err; + rt_uint16_t tag_len = 0; + struct virtio_9p *v9p = rt_calloc(1, sizeof(*v9p)); + + if (!v9p) + { + return -RT_ENOMEM; + } + + vdev->priv = v9p; + v9p->vdev = vdev; + vdev->parent.user_data = v9p; + + if ((err = virtio_9p_vq_init(v9p))) + { + goto _fail; + } + + if (rt_virtio_has_feature(vdev, VIRTIO_9P_F_MOUNT_TAG)) + { + rt_virtio_read_config(vdev, struct virtio_9p_config, tag_len, &tag_len); + } + + v9p->tag = rt_malloc(tag_len + 1); + + if (!v9p->tag) + { + err = -RT_EINVAL; + goto _fail; + } + + rt_virtio_read_bytes(vdev, rt_offsetof(struct virtio_9p_config, tag), + v9p->tag, 1, tag_len); + v9p->tag[tag_len] = '\0'; + + rt_completion_init(&v9p->done); + rt_spin_lock_init(&v9p->lock); + + v9p->parent.name = "virtio"; + v9p->parent.tag = v9p->tag; + v9p->parent.transport = &virtio_9p_transport; + if ((err = dfs_9pfs_add_tag(&v9p->parent))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + virtio_9p_vq_finit(v9p); + + return err; +} + +static rt_err_t virtio_9p_remove(struct rt_virtio_device *vdev) +{ + struct virtio_9p *v9p = vdev->parent.user_data; + + dfs_9pfs_del_tag(&v9p->parent); + + virtio_9p_vq_finit(v9p); + + return RT_EOK; +} + +static const struct rt_virtio_device_id virtio_9p_ids[] = +{ + { VIRTIO_DEVICE_ID_9P, VIRTIO_DEVICE_ANY_ID }, + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_9p_driver = +{ + .ids = virtio_9p_ids, + .features = + RT_BIT(VIRTIO_9P_F_MOUNT_TAG) + | RT_BIT(VIRTIO_F_ANY_LAYOUT), + + .probe = virtio_9p_probe, + .remove = virtio_9p_remove, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_9p_driver); diff --git a/components/drivers/virtio/virtio-blk.c b/components/drivers/virtio/virtio-blk.c new file mode 100644 index 0000000000..32267ad0e0 --- /dev/null +++ b/components/drivers/virtio/virtio-blk.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-9-16 GuEe-GUI the first version + * 2021-11-11 GuEe-GUI using virtio common interface + * 2023-02-25 GuEe-GUI using virtio dm + */ + +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "virtio.dev.blk" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include "../block/blk_dev.h" +#include "virtio_internal.h" +#include "virtio_config/virtio-blk.h" + +struct virtio_blk +{ + struct rt_blk_disk parent; + struct rt_virtio_device *vdev; + + int vblk_id; + rt_le32_t blk_size; + + int vqs_nr; + struct rt_virtqueue *vqs[RT_CPUS_NR]; + struct rt_spinlock *lock; + struct rt_completion *done; +}; + +#define raw_to_virtio_blk(raw) rt_container_of(raw, struct virtio_blk, parent) + +static struct rt_dm_ida virtio_blk_ida = RT_DM_IDA_INIT(CUSTOM); +static struct rt_dm_ida vd_ida = RT_DM_IDA_INIT(VIRTUAL_BLOCK); + +static rt_err_t virtio_blk_request(struct virtio_blk *vblk, + rt_off_t sector, void *buffer, rt_size_t sector_count, int type) +{ + rt_base_t level; + rt_uint8_t status; + struct rt_virtqueue *vq; + struct virtio_blk_req req; + struct rt_virtio_device *vdev = vblk->vdev; + + vq = vblk->vqs[rt_hw_cpu_id() % vblk->vqs_nr]; + if (type == VIRTIO_BLK_T_OUT || type == VIRTIO_BLK_T_IN) + { + rt_virtqueue_wait_prepare(vq, 3); + } + else + { + rt_virtqueue_wait_prepare(vq, 2); + } + + level = rt_spin_lock_irqsave(&vblk->lock[vq->index]); + + req.type = cpu_to_virtio32(vdev, type); + req.ioprio = cpu_to_virtio32(vdev, blk_request_ioprio()); + req.sector = cpu_to_virtio64(vdev, sector * (vblk->blk_size / 512)); + rt_virtqueue_add_outbuf(vq, &req, sizeof(req)); + + if (type == VIRTIO_BLK_T_OUT) + { + rt_virtqueue_add_outbuf(vq, buffer, sector_count * vblk->blk_size); + } + else if (type == VIRTIO_BLK_T_IN) + { + rt_virtqueue_add_inbuf(vq, buffer, sector_count * vblk->blk_size); + } + + status = RT_UINT8_MAX; + rt_virtqueue_add_inbuf(vq, &status, sizeof(status)); + + rt_virtqueue_kick(vq); + + rt_spin_unlock_irqrestore(&vblk->lock[vq->index], level); + + rt_completion_wait(&vblk->done[vq->index], RT_WAITING_FOREVER); + + switch (status) + { + case VIRTIO_BLK_S_OK: + return RT_EOK; + + case VIRTIO_BLK_S_UNSUPP: + return -RT_ENOSYS; + + case VIRTIO_BLK_S_ZONE_OPEN_RESOURCE: + return 1; + + case VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE: + return 2; + + case VIRTIO_BLK_S_IOERR: + case VIRTIO_BLK_S_ZONE_UNALIGNED_WP: + default: + return -RT_EIO; + } +} + +static rt_ssize_t virtio_blk_read(struct rt_blk_disk *disk, rt_off_t sector, + void *buffer, rt_size_t sector_count) +{ + rt_ssize_t res; + struct virtio_blk *vblk = raw_to_virtio_blk(disk); + + res = virtio_blk_request(vblk, sector, buffer, sector_count, VIRTIO_BLK_T_IN); + + return res >= 0 ? sector_count : res; +} + +static rt_ssize_t virtio_blk_write(struct rt_blk_disk *disk, rt_off_t sector, + const void *buffer, rt_size_t sector_count) +{ + rt_ssize_t res; + struct virtio_blk *vblk = raw_to_virtio_blk(disk); + + res = virtio_blk_request(vblk, sector, (void *)buffer, sector_count, VIRTIO_BLK_T_OUT); + + return res >= 0 ? sector_count : res; +} + +static rt_err_t virtio_blk_getgeome(struct rt_blk_disk *disk, + struct rt_device_blk_geometry *geometry) +{ + rt_le64_t capacity; + struct virtio_blk *vblk = raw_to_virtio_blk(disk); + + rt_virtio_read_config(vblk->vdev, struct virtio_blk_config, capacity, &capacity); + + geometry->bytes_per_sector = 512; + geometry->block_size = vblk->blk_size; + geometry->sector_count = rt_le64_to_cpu(capacity); + + return RT_EOK; +} + +static rt_err_t virtio_blk_sync(struct rt_blk_disk *disk) +{ + struct virtio_blk *vblk = raw_to_virtio_blk(disk); + + return virtio_blk_request(vblk, 0, RT_NULL, 0, VIRTIO_BLK_T_FLUSH); +} + +static rt_err_t virtio_blk_erase(struct rt_blk_disk *disk) +{ + struct virtio_blk *vblk = raw_to_virtio_blk(disk); + + return virtio_blk_request(vblk, 0, RT_NULL, 0, VIRTIO_BLK_T_SECURE_ERASE); +} + +static rt_err_t virtio_blk_autorefresh(struct rt_blk_disk *disk, rt_bool_t is_auto) +{ + rt_uint8_t writeback = !is_auto; + struct virtio_blk *vblk = raw_to_virtio_blk(disk); + + /* + * 0: write through + * 1: write back + */ + rt_virtio_write_config(vblk->vdev, struct virtio_blk_config, writeback, writeback); + + return RT_EOK; +} + +static const struct rt_blk_disk_ops virtio_blk_ops = +{ + .read = virtio_blk_read, + .write = virtio_blk_write, + .getgeome = virtio_blk_getgeome, + .sync = virtio_blk_sync, + .erase = virtio_blk_erase, + .autorefresh = virtio_blk_autorefresh, +}; + +static void virtio_blk_done(struct rt_virtqueue *vq) +{ + rt_ubase_t level; + struct virtio_blk *vblk = vq->vdev->priv; + + level = rt_spin_lock_irqsave(&vblk->lock[vq->index]); + + rt_virtqueue_read_buf(vq, RT_NULL); + rt_completion_done(&vblk->done[vq->index]); + + rt_spin_unlock_irqrestore(&vblk->lock[vq->index], level); +} + +static rt_err_t virtio_blk_vq_init(struct virtio_blk *vblk) +{ + rt_uint16_t vqs_nr = 1; + const char *names[RT_ARRAY_SIZE(vblk->vqs)]; + rt_virtqueue_callback cbs[RT_ARRAY_SIZE(vblk->vqs)]; + struct rt_virtio_device *vdev = vblk->vdev; + + if (rt_virtio_has_feature(vdev, VIRTIO_BLK_F_MQ)) + { + rt_virtio_read_config(vdev, struct virtio_blk_config, num_queues, &vqs_nr); + } + + if (!(vblk->lock = rt_malloc(sizeof(vblk->lock[0]) * vqs_nr))) + { + return -RT_ENOMEM; + } + + if (!(vblk->done = rt_malloc(sizeof(vblk->done[0]) * vqs_nr))) + { + return -RT_ENOMEM; + } + + for (int i = 0; i < vqs_nr; ++i) + { + names[i] = "req"; + cbs[i] = &virtio_blk_done; + + rt_spin_lock_init(&vblk->lock[i]); + rt_completion_init(&vblk->done[i]); + } + + vblk->vqs_nr = vqs_nr; + return rt_virtio_virtqueue_install(vdev, vqs_nr, vblk->vqs, names, cbs); +} + +static void virtio_blk_vq_finit(struct virtio_blk *vblk) +{ + if (vblk->vqs[0]) + { + rt_virtio_virtqueue_release(vblk->vdev); + } + if (vblk->lock) + { + rt_free(vblk->lock); + } + if (vblk->done) + { + rt_free(vblk->done); + } +} + +static rt_err_t virtio_blk_probe(struct rt_virtio_device *vdev) +{ + rt_err_t err; + struct virtio_blk *vblk = rt_calloc(1, sizeof(*vblk)); + + if (!vblk) + { + return -RT_ENOMEM; + } + + if ((vblk->vblk_id = rt_dm_ida_alloc(&virtio_blk_ida)) < 0) + { + return -RT_EFULL; + } + + vdev->priv = vblk; + vblk->vdev = vdev; + vdev->parent.user_data = vblk; + vblk->parent.ida = &vd_ida; + vblk->parent.parallel_io = RT_TRUE; + vblk->parent.ops = &virtio_blk_ops; + vblk->parent.max_partitions = RT_BLK_PARTITION_MAX; + + if ((err = virtio_blk_vq_init(vblk))) + { + goto _fail; + } + + rt_virtio_read_config(vdev, struct virtio_blk_config, blk_size, &vblk->blk_size); + + rt_dm_dev_set_name(&vblk->parent.parent, "vd%c%c", letter_name(vblk->vblk_id)); + + if ((err = rt_hw_blk_disk_register(&vblk->parent))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + rt_dm_ida_free(&virtio_blk_ida, vblk->vblk_id); + virtio_blk_vq_finit(vblk); + rt_free(vblk); + + return err; +} + +static rt_err_t virtio_blk_remove(struct rt_virtio_device *vdev) +{ + struct virtio_blk *vblk = vdev->parent.user_data; + + rt_hw_blk_disk_unregister(&vblk->parent); + rt_dm_ida_free(&virtio_blk_ida, vblk->vblk_id); + + virtio_blk_vq_finit(vblk); + rt_free(vblk); + + return RT_EOK; +} + +static const struct rt_virtio_device_id virtio_blk_ids[] = +{ + { VIRTIO_DEVICE_ID_BLOCK, VIRTIO_DEVICE_ANY_ID }, + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_blk_driver = +{ + .ids = virtio_blk_ids, + .features = + RT_BIT(VIRTIO_BLK_F_SIZE_MAX) + | RT_BIT(VIRTIO_BLK_F_GEOMETRY) + | RT_BIT(VIRTIO_BLK_F_BLK_SIZE) + | RT_BIT(VIRTIO_BLK_F_FLUSH) + | RT_BIT(VIRTIO_BLK_F_TOPOLOGY) + | RT_BIT(VIRTIO_BLK_F_CONFIG_WCE) + | RT_BIT(VIRTIO_BLK_F_MQ) + | RT_BIT(VIRTIO_BLK_F_DISCARD) + | RT_BIT(VIRTIO_BLK_F_WRITE_ZEROES) + | RT_BIT(VIRTIO_BLK_F_SECURE_ERASE), + + .probe = virtio_blk_probe, + .remove = virtio_blk_remove, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_blk_driver); diff --git a/components/drivers/virtio/virtio-console.c b/components/drivers/virtio/virtio-console.c new file mode 100644 index 0000000000..b49391409e --- /dev/null +++ b/components/drivers/virtio/virtio-console.c @@ -0,0 +1,732 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-11-11 GuEe-GUI the first version + * 2023-02-25 GuEe-GUI using virtio dm + */ + +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "virtio.dev.console" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include <cpuport.h> + +#include "virtio_internal.h" +#include "virtio_config/virtio-console.h" + +#define QUEUE_PORT_RX 0 +#define QUEUE_PORT_TX 1 +#define QUEUE_CTRL_RX 2 +#define QUEUE_CTRL_TX 3 + +struct virtio_console; + +struct console_port +{ + struct rt_serial_device parent; + char name[64]; + + char *stream; + char *rx_stream; + char *tx_stream; + rt_bool_t irq_enabled; + rt_bool_t host_connected; + struct rt_spinlock lock; + struct virtio_console *vconsole; + + struct rt_virtqueue *rx_vq; + struct rt_virtqueue *tx_vq; +}; + +#define raw_to_console_port(raw) rt_container_of(raw, struct console_port, parent) + +struct virtio_console +{ + struct rt_virtio_device *vdev; + + rt_uint32_t uid; + rt_size_t stream_rx_size; + rt_size_t stream_tx_size; + + struct rt_spinlock lock; + struct rt_virtqueue *ctrl_rx_vq; + struct rt_virtqueue *ctrl_tx_vq; + + rt_size_t ctrl_packet_size; + struct virtio_console_control_ext *ctrl_packet; + + struct rt_work ctrl_work; + struct rt_work config_work; + + rt_size_t max_port_nr; + struct rt_virtqueue **vqs; + struct console_port *ports; +}; + +static struct rt_dm_ida virtio_console_ida = RT_DM_IDA_INIT(CUSTOM); + +rt_inline rt_bool_t console_multiport(struct virtio_console *vconsole) +{ + return rt_virtio_has_feature(vconsole->vdev, VIRTIO_CONSOLE_F_MULTIPORT); +} + +static rt_ssize_t console_send_ctrl_msg(struct virtio_console *vconsole, + rt_uint32_t port_id, rt_uint16_t event, rt_uint16_t value) +{ + struct rt_virtqueue *vq; + struct virtio_console_control ctrl_packet; + + if (!vconsole || vconsole->max_port_nr <= 1) + { + return RT_EOK; + } + + vq = vconsole->ctrl_tx_vq; + rt_spin_lock(&vconsole->lock); + + ctrl_packet.id = cpu_to_virtio32(vconsole->vdev, port_id); + ctrl_packet.event = cpu_to_virtio16(vconsole->vdev, event); + ctrl_packet.value = cpu_to_virtio16(vconsole->vdev, value); + + rt_virtqueue_add_outbuf(vq, &ctrl_packet, sizeof(ctrl_packet)); + rt_virtqueue_kick(vq); + + while (!rt_virtqueue_read_buf(vq, RT_NULL)) + { + rt_hw_cpu_relax(); + } + + rt_spin_unlock(&vconsole->lock); + + return RT_EOK; +} + +static void console_emergency_write(struct virtio_console *vconsole, + rt_uint32_t emerg_wr) +{ + rt_virtio_write_config(vconsole->vdev, struct virtio_console_config, + emerg_wr, emerg_wr); +} + +static rt_err_t console_port_configure(struct rt_serial_device *serial, + struct serial_configure *cfg) +{ + return RT_EOK; +} + +static rt_err_t console_port_control(struct rt_serial_device *serial, int cmd, void *arg) +{ + struct console_port *port = raw_to_console_port(serial); + + switch (cmd) + { + case RT_DEVICE_CTRL_CLR_INT: + port->irq_enabled = RT_FALSE; + break; + + case RT_DEVICE_CTRL_SET_INT: + port->irq_enabled = RT_TRUE; + break; + } + + return RT_EOK; +} + +static int console_port_putc(struct rt_serial_device *serial, char c) +{ + rt_base_t level; + char *tx_stream; + struct rt_virtqueue *vq; + struct console_port *port = raw_to_console_port(serial); + + if (!port->host_connected) + { + if (rt_virtio_has_feature(port->vconsole->vdev, VIRTIO_CONSOLE_F_EMERG_WRITE)) + { + console_emergency_write(port->vconsole, c); + + if (port->parent.parent.open_flag & RT_DEVICE_FLAG_INT_TX) + { + rt_hw_serial_isr(&port->parent, RT_SERIAL_EVENT_TX_DONE); + } + } + + return 1; + } + + vq = port->tx_vq; + rt_virtqueue_wait_prepare(vq, 1); + + level = rt_spin_lock_irqsave(&port->lock); + + tx_stream = &port->tx_stream[rt_virtqueue_next_buf_index(vq)]; + *tx_stream = c; + rt_virtqueue_add_outbuf(vq, tx_stream, sizeof(*tx_stream)); + rt_virtqueue_kick(vq); + + if (port->parent.parent.open_flag & ~RT_DEVICE_FLAG_INT_TX) + { + while (!rt_virtqueue_read_buf(vq, RT_NULL)) + { + rt_hw_cpu_relax(); + } + } + + rt_spin_unlock_irqrestore(&port->lock, level); + + return 1; +} + +static int console_port_getc(struct rt_serial_device *serial) +{ + rt_base_t level; + int ch = -1; + char *rx_stream; + struct rt_virtqueue *vq; + struct console_port *port = raw_to_console_port(serial); + + level = rt_spin_lock_irqsave(&port->lock); + + vq = port->rx_vq; + if ((rx_stream = rt_virtqueue_read_buf(vq, RT_NULL))) + { + ch = *rx_stream; + + rt_virtqueue_add_inbuf(vq, rx_stream, sizeof(char)); + + rt_virtqueue_kick(vq); + } + + rt_spin_unlock_irqrestore(&port->lock, level); + + return ch; +} + +static const struct rt_uart_ops console_port_ops = +{ + .configure = console_port_configure, + .control = console_port_control, + .putc = console_port_putc, + .getc = console_port_getc, +}; + +static rt_err_t console_port_add(struct virtio_console *vconsole, + struct console_port *port) +{ + char *stream; + const char *name; + rt_uint32_t id = port - vconsole->ports; + + rt_memset(port, 0, sizeof(*port)); + + if (!(stream = rt_malloc(sizeof(char) * (vconsole->stream_rx_size + vconsole->stream_tx_size)))) + { + return -RT_ENOMEM; + } + + port->stream = stream; + port->tx_stream = stream; + port->rx_stream = stream + vconsole->stream_tx_size; + port->vconsole = vconsole; + rt_spin_lock_init(&port->lock); + + if (!port->rx_vq || !port->tx_vq) + { + if (id != 0) + { + port->rx_vq = vconsole->vqs[4 + (id - 1) * 2 + QUEUE_PORT_RX]; + port->tx_vq = vconsole->vqs[4 + (id - 1) * 2 + QUEUE_PORT_TX]; + } + else + { + port->rx_vq = vconsole->vqs[QUEUE_PORT_RX]; + port->tx_vq = vconsole->vqs[QUEUE_PORT_TX]; + } + + for (int idx = 0; idx < vconsole->stream_rx_size; ++idx) + { + rt_virtqueue_add_inbuf(port->rx_vq, &port->rx_stream[idx], sizeof(char)); + + rt_virtqueue_submit(port->rx_vq); + } + + rt_virtqueue_notify(port->rx_vq); + } + + console_send_ctrl_msg(vconsole, VIRTIO_CONSOLE_BAD_ID, + VIRTIO_CONSOLE_DEVICE_READY, 1); + + if (!console_multiport(port->vconsole)) + { + port->host_connected = RT_TRUE; + } + + port->parent.ops = &console_port_ops; + port->parent.config = (struct serial_configure)RT_SERIAL_CONFIG_DEFAULT; + rt_dm_dev_set_name(&port->parent.parent, "vport%up%u", vconsole->uid, id); + name = rt_dm_dev_get_name(&port->parent.parent); + + return rt_hw_serial_register(&port->parent, name, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | + RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX, vconsole); +} + +static void console_port_remove(struct console_port *port, rt_bool_t sync) +{ + rt_uint32_t port_id; + + if (!port->vconsole) + { + return; + } + + /* Make sure pending buffer is empty */ + while (rt_virtqueue_read_buf(port->tx_vq, RT_NULL) || + rt_virtqueue_read_buf(port->rx_vq, RT_NULL)) + { + rt_thread_yield(); + } + + port_id = port - port->vconsole->ports; + + if (sync && port_id != 0) + { + console_send_ctrl_msg(port->vconsole, port_id, VIRTIO_CONSOLE_PORT_OPEN, 0); + } + + rt_device_unregister(&port->parent.parent); + + rt_free(port->stream); + port->vconsole = RT_NULL; +} + +static struct console_port *console_find_port_by_vq(struct virtio_console *vconsole, + struct rt_virtqueue *vq) +{ + for (int i = 0; i < vconsole->max_port_nr; ++i) + { + struct console_port *port = &vconsole->ports[i]; + + if (port->tx_vq == vq || port->rx_vq == vq) + { + return port; + } + } + + return RT_NULL; +} + +static struct console_port *console_find_port_by_id(struct virtio_console *vconsole, + rt_uint32_t id) +{ + return id < vconsole->max_port_nr ? &vconsole->ports[id] : RT_NULL; +} + +static void console_resize(struct virtio_console *vconsole, + rt_uint16_t cols, rt_uint16_t rows) +{ + LOG_D("%s: [cols, rows] resize [%u, %u]", + rt_dm_dev_get_name(&vconsole->vdev.parent), cols, rows); + + /* Port to TTY */ +} + +static void console_ctrl_work(struct rt_work *work, void *work_data) +{ + rt_uint32_t port_id; + struct console_port *port; + struct virtio_console_control *ctrl_packet; + struct virtio_console_control_ext *ctrl_packet_ext; + struct virtio_console *vconsole = work_data; + struct rt_virtio_device *vdev = vconsole->vdev; + +_next_ctrl: + if (!(ctrl_packet_ext = rt_virtqueue_read_buf(vconsole->ctrl_rx_vq, RT_NULL))) + { + return; + } + + ctrl_packet = &ctrl_packet_ext->ctrl; + port = console_find_port_by_id(vconsole, virtio32_to_cpu(vdev, ctrl_packet->id)); + port_id = virtio32_to_cpu(vdev, ctrl_packet->id); + + if (!port->vconsole && + cpu_to_virtio16(vdev, ctrl_packet->event) != VIRTIO_CONSOLE_PORT_ADD) + { + LOG_D("%s: Port%d in control is invalid", rt_dm_dev_get_name(&vdev->parent), + port_id); + + goto _prepare_next_ctrl; + } + + switch (virtio16_to_cpu(vdev, ctrl_packet->event)) + { + case VIRTIO_CONSOLE_PORT_ADD: + if (port->vconsole) + { + LOG_D("%s: Port%u already added", rt_dm_dev_get_name(&vdev->parent), + port_id); + + console_send_ctrl_msg(vconsole, port_id, VIRTIO_CONSOLE_PORT_READY, 1); + break; + } + if (port_id >= vconsole->max_port_nr) + { + LOG_W("%s: Port%u is out of %u max supported", + rt_dm_dev_get_name(&vdev->parent), port_id, vconsole->max_port_nr); + break; + } + console_port_add(vconsole, port); + break; + + case VIRTIO_CONSOLE_PORT_REMOVE: + console_port_remove(port, RT_FALSE); + break; + + case VIRTIO_CONSOLE_CONSOLE_PORT: + console_send_ctrl_msg(vconsole, port_id, VIRTIO_CONSOLE_PORT_OPEN, 1); + break; + + case VIRTIO_CONSOLE_RESIZE: + console_resize(vconsole, + virtio16_to_cpu(vdev, ctrl_packet_ext->resize.cols), + virtio16_to_cpu(vdev, ctrl_packet_ext->resize.rows)); + break; + + case VIRTIO_CONSOLE_PORT_OPEN: + port->host_connected = !!virtio16_to_cpu(vdev, ctrl_packet->value); + console_send_ctrl_msg(vconsole, port_id, VIRTIO_CONSOLE_PORT_OPEN, 1); + break; + + case VIRTIO_CONSOLE_PORT_NAME: + rt_strncpy(port->name, (const char *)ctrl_packet_ext->data, sizeof(port->name)); + break; + + default: + break; + } + +_prepare_next_ctrl: + rt_virtqueue_add_inbuf(vconsole->ctrl_rx_vq, + ctrl_packet_ext, sizeof(*ctrl_packet_ext)); + + rt_virtqueue_kick(vconsole->ctrl_rx_vq); + + goto _next_ctrl; +} + +static void console_config_work(struct rt_work *work, void *work_data) +{ + rt_uint16_t cols, rows; + struct virtio_console *vconsole = work_data; + struct rt_virtio_device *vdev = vconsole->vdev; + + rt_virtio_read_config(vdev, struct virtio_console_config, cols, &cols); + rt_virtio_read_config(vdev, struct virtio_console_config, rows, &rows); + + console_resize(vconsole, cols, rows); +} + +static void virtio_console_rx_done(struct rt_virtqueue *vq) +{ + struct virtio_console *vconsole = vq->vdev->priv; + struct console_port *port = console_find_port_by_vq(vconsole, vq); + + if (!port) + { + return; + } + + if (port->irq_enabled) + { + rt_hw_serial_isr(&port->parent, RT_SERIAL_EVENT_RX_IND); + } + else + { + /* Give up */ + console_port_getc(&port->parent); + } +} + +static void virtio_console_tx_done(struct rt_virtqueue *vq) +{ + struct virtio_console *vconsole = vq->vdev->priv; + struct console_port *port = console_find_port_by_vq(vconsole, vq); + + if (!port) + { + return; + } + + if (port->parent.parent.open_flag & RT_DEVICE_FLAG_INT_TX) + { + if (rt_virtqueue_read_buf(vq, RT_NULL)) + { + rt_hw_serial_isr(&port->parent, RT_SERIAL_EVENT_TX_DONE); + } + } +} + +static void virtio_console_ctrl_done(struct rt_virtqueue *vq) +{ + struct virtio_console *vconsole = vq->vdev->priv; + + rt_work_submit(&vconsole->ctrl_work, 0); +} + +static void virtio_console_config_changed(struct rt_virtio_device *vdev) +{ + struct virtio_console *vconsole = vdev->priv; + + if (!console_multiport(vconsole)) + { + rt_work_submit(&vconsole->config_work, 0); + } +} + +static rt_err_t virtio_console_vq_init(struct virtio_console *vconsole) +{ + rt_err_t err; + const char **names; + rt_size_t vqs_nr = 2; + rt_virtqueue_callback *cbs; + + if (vconsole->max_port_nr > 1) + { + vqs_nr = 2 * vconsole->max_port_nr + 2; + } + + vconsole->vqs = rt_calloc(vqs_nr, sizeof(*vconsole->vqs)); + + if (!vconsole->vqs) + { + return -RT_ENOMEM; + } + + if (!(names = rt_malloc(sizeof(*names) * vqs_nr))) + { + return -RT_ENOMEM; + } + + if (!(cbs = rt_malloc(sizeof(*cbs) * vqs_nr))) + { + rt_free(names); + + return -RT_ENOMEM; + } + + names[QUEUE_PORT_RX] = "ch-rx"; + names[QUEUE_PORT_TX] = "ch-tx"; + cbs[QUEUE_PORT_RX] = &virtio_console_rx_done; + cbs[QUEUE_PORT_TX] = &virtio_console_tx_done; + + if (vqs_nr > 2) + { + names[QUEUE_CTRL_RX] = "ctl-rx"; + names[QUEUE_CTRL_TX] = "ctl-tx"; + cbs[QUEUE_CTRL_RX] = &virtio_console_ctrl_done; + cbs[QUEUE_CTRL_TX] = RT_NULL; + } + + for (int i = 4; i < vqs_nr; i += 2) + { + names[i + QUEUE_PORT_RX] = "ch-rx"; + names[i + QUEUE_PORT_TX] = "ch-tx"; + cbs[i + QUEUE_PORT_RX] = &virtio_console_rx_done; + cbs[i + QUEUE_PORT_TX] = &virtio_console_tx_done; + } + + if ((err = rt_virtio_virtqueue_install(vconsole->vdev, vqs_nr, + vconsole->vqs, names, cbs))) + { + goto _out_free; + } + + vconsole->stream_rx_size = rt_virtqueue_get_virtq_size(vconsole->vqs[QUEUE_PORT_RX]); + vconsole->stream_tx_size = rt_virtqueue_get_virtq_size(vconsole->vqs[QUEUE_PORT_TX]); + + if (vqs_nr > 2) + { + struct rt_virtqueue *ctrl_rx_vq, *ctrl_tx_vq; + + ctrl_rx_vq = vconsole->vqs[QUEUE_CTRL_RX]; + ctrl_tx_vq = vconsole->vqs[QUEUE_CTRL_TX]; + + vconsole->ctrl_packet_size = rt_virtqueue_get_virtq_size(ctrl_rx_vq); + vconsole->ctrl_packet = rt_malloc(sizeof(*vconsole->ctrl_packet) * + vconsole->ctrl_packet_size); + + if (!vconsole->ctrl_packet) + { + goto _out_free; + } + + for (int idx = 0; idx < vconsole->ctrl_packet_size; ++idx) + { + rt_virtqueue_add_inbuf(ctrl_rx_vq, &vconsole->ctrl_packet[idx], + sizeof(vconsole->ctrl_packet[idx])); + + rt_virtqueue_submit(ctrl_rx_vq); + } + + rt_virtqueue_notify(ctrl_rx_vq); + + vconsole->ctrl_rx_vq = ctrl_rx_vq; + vconsole->ctrl_tx_vq = ctrl_tx_vq; + + rt_virtqueue_disable_callback(ctrl_tx_vq); + } + +_out_free: + rt_free(names); + rt_free(cbs); + + return err; +} + +static void virtio_console_vq_finit(struct virtio_console *vconsole) +{ + if (vconsole->ports) + { + rt_free(vconsole->ports); + } + + if (vconsole->vqs) + { + if (vconsole->vqs[0]) + { + rt_virtio_virtqueue_release(vconsole->vdev); + } + + rt_free(vconsole->vqs); + } + + if (vconsole->ctrl_packet) + { + rt_free(vconsole->ctrl_packet); + } +} + +static rt_err_t virtio_console_probe(struct rt_virtio_device *vdev) +{ + rt_err_t err; + struct virtio_console *vconsole = rt_calloc(1, sizeof(*vconsole)); + + if (!vconsole) + { + return -RT_ENOMEM; + } + + vdev->priv = vconsole; + vconsole->vdev = vdev; + vdev->parent.user_data = vconsole; + + rt_virtio_read_config(vdev, struct virtio_console_config, + max_nr_ports, &vconsole->max_port_nr); + vconsole->max_port_nr = rt_max_t(rt_size_t, 1, vconsole->max_port_nr); + + vconsole->ports = rt_malloc(sizeof(*vconsole->ports) * vconsole->max_port_nr); + + if (!vconsole->ports) + { + err = -RT_ENOMEM; + goto _fail; + } + + if ((err = virtio_console_vq_init(vconsole))) + { + goto _fail; + } + + if ((vconsole->uid = rt_dm_ida_alloc(&virtio_console_ida)) < 0) + { + return -RT_EFULL; + } + + if (vconsole->ctrl_rx_vq && vconsole->ctrl_tx_vq) + { + rt_work_init(&vconsole->ctrl_work, console_ctrl_work, vconsole); + } + + rt_work_init(&vconsole->config_work, console_config_work, vconsole); + + for (int i = 0; i < vconsole->max_port_nr; ++i) + { + vconsole->ports[i].vconsole = RT_NULL; + } + + if ((err = console_port_add(vconsole, &vconsole->ports[0]))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + rt_dm_ida_free(&virtio_console_ida, vconsole->uid); + virtio_console_vq_finit(vconsole); + rt_free(vconsole); + + return err; +} + +static rt_err_t virtio_console_remove(struct rt_virtio_device *vdev) +{ + struct virtio_console *vconsole = vdev->parent.user_data; + + for (int i = 0; i < vconsole->max_port_nr; ++i) + { + console_port_remove(&vconsole->ports[i], RT_TRUE); + } + + rt_dm_ida_free(&virtio_console_ida, vconsole->uid); + + virtio_console_vq_finit(vconsole); + rt_free(vconsole); + + return RT_EOK; +} + +static const struct rt_virtio_device_id virtio_console_ids[] = +{ + { VIRTIO_DEVICE_ID_CONSOLE, VIRTIO_DEVICE_ANY_ID }, + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_console_driver = +{ + .ids = virtio_console_ids, + .features = + RT_BIT(VIRTIO_CONSOLE_F_SIZE) + | RT_BIT(VIRTIO_CONSOLE_F_MULTIPORT) + | RT_BIT(VIRTIO_CONSOLE_F_EMERG_WRITE), + + .probe = virtio_console_probe, + .remove = virtio_console_remove, + .config_changed = virtio_console_config_changed, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_console_driver); + +static const struct rt_virtio_device_id virtio_rproc_serial_ids[] = +{ +#ifdef RT_VIRTIO_RPROC_SERIAL + { VIRTIO_DEVICE_ID_RPROC_SERIAL, VIRTIO_DEVICE_ANY_ID }, +#endif + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_rproc_serial_driver = +{ + .ids = virtio_rproc_serial_ids, + .probe = virtio_console_probe, + .remove = virtio_console_remove, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_rproc_serial_driver); diff --git a/components/drivers/virtio/virtio-crypto.c b/components/drivers/virtio/virtio-crypto.c new file mode 100644 index 0000000000..1f4d80abdf --- /dev/null +++ b/components/drivers/virtio/virtio-crypto.c @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "virtio.dev.crypto" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include "virtio_config/virtio-crypto.h" + +struct virtio_crypto_symmetric_contex +{ + rt_uint64_t session_id; + struct rt_virtqueue *data_vq; +}; + +struct virtio_crypto +{ + struct rt_hwcrypto_device parent; + struct rt_virtio_device *vdev; + + rt_uint32_t status; + rt_uint32_t services; + rt_uint32_t max_data_queues; + rt_uint64_t max_req_size; + rt_uint64_t max_cipher_key_len; + rt_uint64_t max_auth_key_len; + + struct rt_virtqueue **vqs; + struct rt_virtqueue *ctrl_vq; + struct rt_completion *data_done; + struct rt_completion ctrl_done; + struct rt_spinlock *data_lock; + struct rt_spinlock ctrl_lock; +}; + +#define raw_to_virtio_crypto(raw) rt_container_of((raw)->parent.device, struct virtio_crypto, parent) + +rt_inline struct rt_virtqueue *virtio_crypto_data_vq(struct virtio_crypto *vcrypto) +{ + return vcrypto->vqs[rt_hw_cpu_id() % vcrypto->max_data_queues]; +} + +static rt_err_t virtio_crypto_symmetric_create_session( + struct hwcrypto_symmetric *symmetric_ctx, rt_bool_t encrypt) +{ + rt_ubase_t level; + struct rt_virtqueue *ctrl_vq, *data_vq; + struct virtio_crypto_op_ctrl_req ctrl; + struct virtio_crypto_session_input input; + struct virtio_crypto_sym_create_session_req *sym_create_session; + struct virtio_crypto *vcrypto = raw_to_virtio_crypto(symmetric_ctx); + struct virtio_crypto_symmetric_contex *vctx = symmetric_ctx->parent.contex; + + ctrl_vq = vcrypto->ctrl_vq; + data_vq = virtio_crypto_data_vq(vcrypto); + + /* Pad ctrl header */ + ctrl.header.opcode = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_CREATE_SESSION); + switch (symmetric_ctx->parent.type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_AES: + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_AES_ECB: + ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_AES_ECB); + break; + + case HWCRYPTO_TYPE_AES_CBC: + ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_AES_CBC); + break; + + case HWCRYPTO_TYPE_AES_CTR: + ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_AES_CTR); + break; + + default: + return -RT_ENOSYS; + } + break; + + case HWCRYPTO_TYPE_DES: + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_DES_ECB: + ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DES_ECB); + break; + + case HWCRYPTO_TYPE_DES_CBC: + ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DES_CBC); + break; + + default: + return -RT_ENOSYS; + } + break; + + case HWCRYPTO_TYPE_3DES: + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_3DES_ECB: + ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_3DES_ECB); + break; + + case HWCRYPTO_TYPE_3DES_CBC: + ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_3DES_CBC); + break; + + default: + return -RT_ENOSYS; + } + break; + + case HWCRYPTO_TYPE_RC4: + ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_ARC4); + break; + } + ctrl.header.queue_id = data_vq->index; + + input.status = rt_cpu_to_le32(VIRTIO_CRYPTO_ERR); + + /* Pad cipher's parameters */ + sym_create_session = &ctrl.sym_create_session; + sym_create_session->op_type = rt_cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER); + sym_create_session->cipher.para.algo = ctrl.header.algo; + sym_create_session->cipher.para.keylen = rt_cpu_to_le32(symmetric_ctx->key_bitlen / 8); + sym_create_session->cipher.para.op = rt_cpu_to_le32(encrypt ? + VIRTIO_CRYPTO_OP_ENCRYPT : VIRTIO_CRYPTO_OP_DECRYPT); + + rt_virtqueue_wait_prepare(ctrl_vq, 3); + + level = rt_spin_lock_irqsave(&vcrypto->ctrl_lock); + + rt_virtqueue_add_outbuf(ctrl_vq, &ctrl, sizeof(ctrl)); + rt_virtqueue_add_outbuf(ctrl_vq, symmetric_ctx->key, symmetric_ctx->key_bitlen / 8); + rt_virtqueue_add_inbuf(ctrl_vq, &input, sizeof(input)); + + rt_virtqueue_kick(ctrl_vq); + + rt_spin_unlock_irqrestore(&vcrypto->ctrl_lock, level); + + rt_completion_wait(&vcrypto->ctrl_done, RT_WAITING_FOREVER); + + switch (input.status) + { + case VIRTIO_CRYPTO_OK: + break; + + case VIRTIO_CRYPTO_INVSESS: + RT_ASSERT(0); + case VIRTIO_CRYPTO_ERR: + case VIRTIO_CRYPTO_KEY_REJECTED: + return -RT_ERROR; + + case VIRTIO_CRYPTO_BADMSG: + return -RT_EINVAL; + + case VIRTIO_CRYPTO_NOTSUPP: + return -RT_ENOSYS; + + case VIRTIO_CRYPTO_NOSPC: + return -RT_EEMPTY; + } + + vctx->session_id = input.session_id; + vctx->data_vq = data_vq; + + return RT_EOK; +} + +static void virtio_crypto_symmetric_destroy_session( + struct hwcrypto_symmetric *symmetric_ctx) +{ + rt_ubase_t level; + struct rt_virtqueue *ctrl_vq; + struct virtio_crypto_inhdr inhdr; + struct virtio_crypto_op_ctrl_req ctrl; + struct virtio_crypto_destroy_session_req *destroy_session; + struct virtio_crypto *vcrypto = raw_to_virtio_crypto(symmetric_ctx); + struct virtio_crypto_symmetric_contex *vctx = symmetric_ctx->parent.contex; + + ctrl_vq = vcrypto->ctrl_vq; + inhdr.status = VIRTIO_CRYPTO_ERR; + + /* Pad ctrl header */ + ctrl.header.opcode = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION); + ctrl.header.queue_id = vctx->data_vq->index; + + destroy_session = &ctrl.destroy_session; + destroy_session->session_id = rt_cpu_to_le64(vctx->session_id); + + rt_virtqueue_wait_prepare(ctrl_vq, 2); + + level = rt_spin_lock_irqsave(&vcrypto->ctrl_lock); + + rt_virtqueue_add_outbuf(ctrl_vq, &ctrl, sizeof(ctrl)); + rt_virtqueue_add_inbuf(ctrl_vq, &inhdr.status, sizeof(inhdr.status)); + + rt_virtqueue_kick(ctrl_vq); + + rt_spin_unlock_irqrestore(&vcrypto->ctrl_lock, level); + + rt_completion_wait(&vcrypto->ctrl_done, RT_WAITING_FOREVER); + + if (inhdr.status != VIRTIO_CRYPTO_OK) + { + LOG_E("%s fail status = %d", __func__, inhdr.status); + } +} + +static rt_err_t virtio_crypto_symmetric_crypt( + struct hwcrypto_symmetric *symmetric_ctx, + struct hwcrypto_symmetric_info *symmetric_info) +{ + rt_err_t err; + rt_ubase_t level; + struct rt_virtqueue *data_vq; + struct virtio_crypto_inhdr inhdr; + struct virtio_crypto_op_data_req data; + struct virtio_crypto *vcrypto = raw_to_virtio_crypto(symmetric_ctx); + struct virtio_crypto_symmetric_contex *vctx = symmetric_ctx->parent.contex; + + if (!(vcrypto->status & VIRTIO_CRYPTO_S_HW_READY)) + { + LOG_D("%s: to %s %s is not ready", + rt_dm_dev_get_name(&vcrypto->parent.parent), "symmetric", "crypt"); + + return -RT_EIO; + } + + if (symmetric_info->mode == HWCRYPTO_MODE_ENCRYPT) + { + err = virtio_crypto_symmetric_create_session(symmetric_ctx, RT_TRUE); + } + else if (symmetric_info->mode == HWCRYPTO_MODE_DECRYPT) + { + err = virtio_crypto_symmetric_create_session(symmetric_ctx, RT_FALSE); + } + else + { + err = -RT_ENOSYS; + } + + if (err) + { + return err; + } + + vctx = symmetric_ctx->parent.contex; + data_vq = vctx->data_vq; + + data.header.session_id = rt_cpu_to_le64(vctx->session_id); + if (symmetric_info->mode == HWCRYPTO_MODE_ENCRYPT) + { + data.header.opcode = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_ENCRYPT); + } + else if (symmetric_info->mode == HWCRYPTO_MODE_DECRYPT) + { + data.header.opcode = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DECRYPT); + } + + if (!symmetric_ctx->iv_len) + { + symmetric_ctx->iv_len = sizeof(symmetric_ctx->iv); + rt_memset(symmetric_ctx->iv, 0, symmetric_ctx->iv_len); + } + + data.sym_req.op_type = rt_cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER); + data.sym_req.cipher.para.iv_len = rt_cpu_to_le32(symmetric_ctx->iv_len); + data.sym_req.cipher.para.src_data_len = rt_cpu_to_le32(symmetric_info->length); + data.sym_req.cipher.para.dst_data_len = rt_cpu_to_le32(symmetric_info->length); + + inhdr.status = VIRTIO_CRYPTO_ERR; + + rt_virtqueue_wait_prepare(data_vq, 5); + + level = rt_spin_lock_irqsave(&vcrypto->data_lock[data_vq->index]); + + /* Outhdr */ + rt_virtqueue_add_outbuf(data_vq, &data, sizeof(data)); + + rt_virtqueue_add_outbuf(data_vq, + &symmetric_ctx->iv[symmetric_ctx->iv_off], symmetric_ctx->iv_len); + + /* Source data */ + rt_virtqueue_add_outbuf(data_vq, (void *)symmetric_info->in, symmetric_info->length); + + /* Destination data */ + rt_virtqueue_add_inbuf(data_vq, symmetric_info->out, symmetric_info->length); + + rt_virtqueue_add_inbuf(data_vq, &inhdr.status, sizeof(inhdr.status)); + + rt_virtqueue_kick(data_vq); + + rt_spin_unlock_irqrestore(&vcrypto->data_lock[data_vq->index], level); + + rt_completion_wait(&vcrypto->data_done[data_vq->index], RT_WAITING_FOREVER); + + switch (inhdr.status) + { + case VIRTIO_CRYPTO_OK: + err = RT_EOK; + break; + + case VIRTIO_CRYPTO_INVSESS: + err = -RT_EINVAL; + break; + + case VIRTIO_CRYPTO_ERR: + case VIRTIO_CRYPTO_KEY_REJECTED: + err = -RT_ERROR; + break; + + case VIRTIO_CRYPTO_BADMSG: + err = -RT_EINVAL; + break; + + case VIRTIO_CRYPTO_NOTSUPP: + err = -RT_ENOSYS; + break; + + case VIRTIO_CRYPTO_NOSPC: + err = -RT_EEMPTY; + break; + } + + virtio_crypto_symmetric_destroy_session(symmetric_ctx); + + return err; +} + +static const struct hwcrypto_symmetric_ops virtio_crypto_symmetric_ops = +{ + .crypt = virtio_crypto_symmetric_crypt, +}; + +static rt_err_t virtio_crypto_create(struct rt_hwcrypto_ctx *ctx) +{ + struct hwcrypto_symmetric *crypto_symmetric; + + switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_AES: + case HWCRYPTO_TYPE_DES: + case HWCRYPTO_TYPE_3DES: + case HWCRYPTO_TYPE_RC4: + ctx->contex = rt_calloc(1, sizeof(struct virtio_crypto_symmetric_contex)); + + if (!ctx->contex) + { + return -RT_ENOMEM; + } + + crypto_symmetric = rt_container_of(ctx, struct hwcrypto_symmetric, parent); + crypto_symmetric->ops = &virtio_crypto_symmetric_ops; + break; + + default: + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static void virtio_crypto_destroy(struct rt_hwcrypto_ctx *ctx) +{ + if (!ctx->contex) + { + return; + } + + switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_AES: + case HWCRYPTO_TYPE_DES: + case HWCRYPTO_TYPE_3DES: + case HWCRYPTO_TYPE_RC4: + rt_free(ctx->contex); + break; + } +} + +static rt_err_t virtio_crypto_copy(struct rt_hwcrypto_ctx *des, + const struct rt_hwcrypto_ctx *src) +{ + rt_err_t err = RT_EOK; + + switch (src->type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_AES: + case HWCRYPTO_TYPE_DES: + case HWCRYPTO_TYPE_3DES: + case HWCRYPTO_TYPE_RC4: + break; + + default: + err = -RT_ENOSYS; + break; + } + + return err; +} + +static void virtio_crypto_reset(struct rt_hwcrypto_ctx *ctx) +{ +} + +static const struct rt_hwcrypto_ops virtio_crypto_ops = +{ + .create = virtio_crypto_create, + .destroy = virtio_crypto_destroy, + .copy = virtio_crypto_copy, + .reset = virtio_crypto_reset, +}; + +static void virtio_crypto_data_done(struct rt_virtqueue *vq) +{ + rt_ubase_t level; + struct virtio_crypto *vcrypto = vq->vdev->priv; + + level = rt_spin_lock_irqsave(&vcrypto->data_lock[vq->index]); + + rt_virtqueue_read_buf(vq, RT_NULL); + rt_completion_done(&vcrypto->data_done[vq->index]); + + rt_spin_unlock_irqrestore(&vcrypto->data_lock[vq->index], level); +} + +static void virtio_crypto_ctrl_done(struct rt_virtqueue *vq) +{ + rt_ubase_t level; + struct virtio_crypto *vcrypto = vq->vdev->priv; + + level = rt_spin_lock_irqsave(&vcrypto->ctrl_lock); + + rt_virtqueue_read_buf(vq, RT_NULL); + rt_completion_done(&vcrypto->ctrl_done); + + rt_spin_unlock_irqrestore(&vcrypto->ctrl_lock, level); +} + +static void virtio_crypto_config_changed(struct rt_virtio_device *vdev) +{ + rt_uint32_t status; + struct virtio_crypto *vcrypto = vdev->parent.user_data; + + rt_virtio_read_config(vdev, struct virtio_crypto_config, status, &status); + + if (status & (~VIRTIO_CRYPTO_S_HW_READY)) + { + LOG_E("%s: Unknown status bits = 0x%x", + rt_dm_dev_get_name(&vdev->parent), status); + + RT_ASSERT(0); + return; + } + + if (vcrypto->status != status) + { + /* Change status */ + vcrypto->status = status; + } +} + +static rt_err_t virtio_crypto_vq_init(struct virtio_crypto *vcrypto) +{ + rt_err_t err; + rt_size_t vqs_nr; + const char **names = RT_NULL; + rt_virtqueue_callback *cbs = RT_NULL; + + vqs_nr = vcrypto->max_data_queues + 1; + + vcrypto->vqs = rt_calloc(vqs_nr, sizeof(*vcrypto->vqs)); + + if (!vcrypto->vqs) + { + return -RT_ENOMEM; + } + + if (!(names = rt_malloc(sizeof(*names) * vqs_nr))) + { + return -RT_ENOMEM; + } + + if (!(cbs = rt_malloc(sizeof(*cbs) * vqs_nr))) + { + err = -RT_ENOMEM; + goto _out_free; + } + + vcrypto->data_lock = rt_malloc(sizeof(vcrypto->data_lock[0]) * + vcrypto->max_data_queues); + + if (!vcrypto->data_lock) + { + err = -RT_ENOMEM; + goto _out_free; + } + + vcrypto->data_done = rt_malloc(sizeof(vcrypto->data_done[0]) * + vcrypto->max_data_queues); + + if (!vcrypto->data_done) + { + err = -RT_ENOMEM; + goto _out_free; + } + + for (int i = 0; i < vcrypto->max_data_queues; ++i) + { + names[i] = "data"; + cbs[i] = &virtio_crypto_data_done; + + rt_spin_lock_init(&vcrypto->data_lock[i]); + rt_completion_init(&vcrypto->data_done[i]); + } + + names[vqs_nr - 1] = "ctrl"; + cbs[vqs_nr - 1] = &virtio_crypto_ctrl_done; + + if ((err = rt_virtio_virtqueue_install(vcrypto->vdev, vqs_nr, + vcrypto->vqs, names, cbs))) + { + goto _out_free; + } + + vcrypto->ctrl_vq = vcrypto->vqs[vcrypto->max_data_queues]; + +_out_free: + if (names) + { + rt_free(names); + } + if (cbs) + { + rt_free(cbs); + } + + return err; +} + +static void virtio_crypto_vq_finit(struct virtio_crypto *vcrypto) +{ + if (vcrypto->vqs) + { + if (vcrypto->vqs[0]) + { + rt_virtio_virtqueue_release(vcrypto->vdev); + } + + rt_free(vcrypto->vqs); + } + + if (vcrypto->data_lock) + { + rt_free(vcrypto->data_lock); + } + + if (vcrypto->data_done) + { + rt_free(vcrypto->data_done); + } +} + +static rt_err_t virtio_crypto_probe(struct rt_virtio_device *vdev) +{ + rt_err_t err; + struct virtio_crypto *vcrypto = rt_calloc(1, sizeof(*vcrypto)); + + if (!vcrypto) + { + return -RT_ENOMEM; + } + + vdev->priv = vcrypto; + vcrypto->vdev = vdev; + vdev->parent.user_data = vcrypto; + + rt_virtio_read_config(vdev, struct virtio_crypto_config, max_dataqueues, + &vcrypto->max_data_queues); + + if (vcrypto->max_data_queues > RT_CPUS_NR) + { + vcrypto->max_data_queues = RT_CPUS_NR; + } + else + { + vcrypto->max_data_queues = 1; + } + + rt_virtio_read_config(vdev, struct virtio_crypto_config, crypto_services, + &vcrypto->services); + rt_virtio_read_config(vdev, struct virtio_crypto_config, max_size, + &vcrypto->max_req_size); + rt_virtio_read_config(vdev, struct virtio_crypto_config, max_cipher_key_len, + &vcrypto->max_cipher_key_len); + rt_virtio_read_config(vdev, struct virtio_crypto_config, max_auth_key_len, + &vcrypto->max_auth_key_len); + + if ((err = virtio_crypto_vq_init(vcrypto))) + { + goto _fail; + } + + rt_spin_lock_init(&vcrypto->ctrl_lock); + rt_completion_init(&vcrypto->ctrl_done); + + vcrypto->parent.ops = &virtio_crypto_ops; + vcrypto->parent.id = ((rt_uint64_t)vdev->id.vendor << 32) | vdev->id.device; + + virtio_crypto_config_changed(vdev); + + if ((err = rt_hwcrypto_register(&vcrypto->parent, RT_HWCRYPTO_DEFAULT_NAME))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + virtio_crypto_vq_finit(vcrypto); + rt_free(vcrypto); + + return err; +} + +static rt_err_t virtio_crypto_remove(struct rt_virtio_device *vdev) +{ + struct virtio_crypto *vcrypto = vdev->parent.user_data; + + rt_device_unregister(&vcrypto->parent.parent); + + virtio_crypto_vq_finit(vcrypto); + rt_free(vcrypto); + + return RT_EOK; +} + +static const struct rt_virtio_device_id virtio_crypto_ids[] = +{ + { VIRTIO_DEVICE_ID_CRYPTO, VIRTIO_DEVICE_ANY_ID }, + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_crypto_driver = +{ + .ids = virtio_crypto_ids, + .features = + RT_BIT(VIRTIO_F_ANY_LAYOUT), + + .probe = virtio_crypto_probe, + .remove = virtio_crypto_remove, + .config_changed = virtio_crypto_config_changed, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_crypto_driver); diff --git a/components/drivers/virtio/virtio-gpu.c b/components/drivers/virtio/virtio-gpu.c new file mode 100644 index 0000000000..e090730f49 --- /dev/null +++ b/components/drivers/virtio/virtio-gpu.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-11-11 GuEe-GUI the first version + * 2023-02-25 GuEe-GUI using virtio dm + */ + +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "virtio.dev.gpu" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include <mmu.h> +#include <cpuport.h> +#include "virtio_internal.h" +#include "virtio_config/virtio-gpu.h" + +#define CTRL_QUEUE 0 +#define CURSOR_QUEUE 1 + +struct virtio_gpu +{ + struct rt_graphic_device parent; + struct rt_virtio_device *vdev; + + struct rt_virtqueue *vqs[2]; + + rt_bool_t vsync; + rt_uint32_t width; + rt_uint32_t height; + rt_uint32_t pmode_id; + rt_uint32_t num_scanouts; + rt_uint32_t resource_id; +#define PRIMARY_PLANE_RESOURCE_ID 1 +#define CURSOR_PLANE_RESOURCE_ID 2 + + struct rt_work event_work; + struct rt_completion done; + +#define CURSOR_WIDTH 64 +#define CURSOR_HEIGHT 64 + rt_uint8_t *cursor; +}; + +#define raw_to_virtio_gpu(raw) rt_container_of(raw, struct virtio_gpu, parent) + +static void virtio_gpu_ctrl_send_command(struct virtio_gpu *vgpu, + const void *cmd, rt_size_t cmd_len, void *res, rt_size_t res_len) +{ + struct rt_virtqueue *vq; + + vq = vgpu->vqs[CTRL_QUEUE]; + + rt_virtqueue_wait_prepare(vq, 2); + + rt_virtqueue_add_outbuf(vq, (void *)cmd, cmd_len); + rt_virtqueue_add_inbuf(vq, res, res_len); + + rt_virtqueue_kick(vq); + + while (!rt_virtqueue_read_buf(vq, RT_NULL)) + { + rt_hw_cpu_relax(); + } +} + +static void virtio_gpu_cursor_send_command(struct virtio_gpu *vgpu, + const void *cmd, rt_size_t cmd_len) +{ + struct rt_virtqueue *vq; + + vq = vgpu->vqs[CURSOR_QUEUE]; + + rt_virtqueue_wait_prepare(vq, 1); + + rt_virtqueue_add_outbuf(vq, (void *)cmd, cmd_len); + + rt_virtqueue_kick(vq); + + while (!rt_virtqueue_read_buf(vq, RT_NULL)) + { + rt_hw_cpu_relax(); + } +} + +static rt_uint32_t virtio_gpu_next_resource_id(struct virtio_gpu *vgpu) +{ + rt_uint32_t last_resource_id = vgpu->resource_id++; + + while (last_resource_id != vgpu->resource_id) + { + if (vgpu->resource_id && + vgpu->resource_id == PRIMARY_PLANE_RESOURCE_ID && + vgpu->resource_id == CURSOR_PLANE_RESOURCE_ID) + { + return vgpu->resource_id; + } + + ++vgpu->resource_id; + } + + return 0; +} + +static rt_err_t virtio_gpu_create_2d_resource(struct virtio_gpu *vgpu, + enum virtio_gpu_formats format, rt_uint32_t resource_id, + rt_uint32_t width, rt_uint32_t height) +{ + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_resource_create_2d req; + + req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D); + req.resource_id = rt_cpu_to_le32(resource_id); + req.format = rt_cpu_to_le32(format); + req.width = rt_cpu_to_le32(width); + req.height = rt_cpu_to_le32(height); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res)); + + return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; +} + +static rt_err_t virtio_gpu_unref_resource(struct virtio_gpu *vgpu, + rt_uint32_t resource_id) +{ + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_resource_unref req; + + rt_memset(&req, 0, sizeof(req)); + + req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_UNREF); + req.resource_id = rt_cpu_to_le32(resource_id); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res)); + + return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; +} + +static rt_err_t virtio_gpu_attach_backing_resource(struct virtio_gpu *vgpu, + rt_uint32_t resource_id, void *buffer, rt_size_t size) +{ + struct virtio_gpu_ctrl_hdr res; + struct + { + struct virtio_gpu_resource_attach_backing req; + struct virtio_gpu_mem_entry mem; + } req; + + rt_memset(&req, 0, sizeof(req)); + + req.req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING); + req.req.resource_id = rt_cpu_to_le32(resource_id); + req.req.nr_entries = rt_cpu_to_le32(1); + + req.mem.addr = rt_cpu_to_le64((rt_ubase_t)rt_kmem_v2p(buffer)); + req.mem.length = rt_cpu_to_le32(size); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res)); + + return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; +} + +static rt_err_t virtio_gpu_detach_backing_resource(struct virtio_gpu *vgpu, + rt_uint32_t resource_id) +{ + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_resource_detach_backing req; + + rt_memset(&req, 0, sizeof(req)); + + req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING); + req.resource_id = rt_cpu_to_le32(resource_id); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res)); + + return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; +} + +static rt_err_t virtio_gpu_set_scanout(struct virtio_gpu *vgpu, + rt_uint32_t scanout_id, rt_uint32_t resource_id, + rt_uint32_t width, rt_uint32_t height) +{ + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_set_scanout req; + + rt_memset(&req, 0, sizeof(req)); + + req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_SET_SCANOUT); + req.r.width = rt_cpu_to_le32(width); + req.r.height = rt_cpu_to_le32(height); + req.scanout_id = rt_cpu_to_le32(scanout_id); + req.resource_id = rt_cpu_to_le32(resource_id); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res)); + + return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; +} + +static rt_err_t virtio_gpu_flush_resource(struct virtio_gpu *vgpu, + rt_uint32_t resource_id, + rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height) +{ + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_resource_flush req; + + rt_memset(&req, 0, sizeof(req)); + + req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_FLUSH); + req.r.x = rt_cpu_to_le32(x); + req.r.y = rt_cpu_to_le32(y); + req.r.width = rt_cpu_to_le32(width); + req.r.height = rt_cpu_to_le32(height); + req.resource_id = rt_cpu_to_le32(resource_id); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res)); + + return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; +} + +static rt_err_t virtio_gpu_transfer_to_host_2d(struct virtio_gpu *vgpu, + rt_uint32_t resource_id, + rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height, + rt_uint64_t offset) +{ + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_transfer_to_host_2d req; + + rt_memset(&req, 0, sizeof(req)); + + req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D); + req.r.x = rt_cpu_to_le32(x); + req.r.y = rt_cpu_to_le32(y); + req.r.width = rt_cpu_to_le32(width); + req.r.height = rt_cpu_to_le32(height); + req.offset = rt_cpu_to_le64(offset); + req.resource_id = rt_cpu_to_le32(resource_id); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res)); + + return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; +} + +static rt_err_t virtio_gpu_update_cursor(struct virtio_gpu *vgpu, + rt_uint32_t scanout_id, rt_uint32_t resource_id, + rt_uint32_t hot_x, rt_uint32_t hot_y) +{ + struct virtio_gpu_update_cursor req; + + rt_memset(&req, 0, sizeof(req)); + + req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR); + req.pos.scanout_id = rt_cpu_to_le32(scanout_id); + req.resource_id = rt_cpu_to_le32(resource_id); + req.hot_x = rt_cpu_to_le32(hot_x); + req.hot_y = rt_cpu_to_le32(hot_y); + + virtio_gpu_cursor_send_command(vgpu, &req, sizeof(req)); + + return RT_EOK; +} + +static rt_err_t virtio_gpu_cursor_move(struct virtio_gpu *vgpu, + rt_uint32_t scanout_id, rt_uint32_t resource_id, + rt_uint32_t x, rt_uint32_t y) +{ + struct virtio_gpu_update_cursor req; + + rt_memset(&req, 0, sizeof(req)); + + req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR); + req.pos.scanout_id = rt_cpu_to_le32(scanout_id); + req.pos.x = rt_cpu_to_le32(x); + req.pos.y = rt_cpu_to_le32(y); + req.resource_id = rt_cpu_to_le32(resource_id); + + virtio_gpu_cursor_send_command(vgpu, &req, sizeof(req)); + + return RT_EOK; +} + +static rt_err_t virtio_gpu_get_edid(struct virtio_gpu *vgpu) +{ + rt_err_t err; + struct virtio_gpu_cmd_get_edid req; + struct virtio_gpu_resp_edid *res = rt_malloc(sizeof(*res)); + + if (!res) + { + return -RT_ENOMEM; + } + + rt_memset(&req, 0, sizeof(req)); + req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_GET_EDID); + req.scanout = rt_cpu_to_le32(vgpu->pmode_id); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), res, sizeof(*res)); + + if (res->hdr.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_EDID)) + { + rt_memcpy(&vgpu->parent.edid, res->edid, + rt_min_t(rt_size_t, sizeof(vgpu->parent.edid), res->size)); + err = RT_EOK; + } + else + { + err = -RT_EIO; + } + + rt_free(res); + + return err; +} + +static rt_err_t virtio_gpu_get_display_info(struct virtio_gpu *vgpu) +{ + struct virtio_gpu_ctrl_hdr req; + struct virtio_gpu_resp_display_info info; + + rt_memset(&req, 0, sizeof(req)); + req.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_GET_DISPLAY_INFO); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &info, sizeof(info)); + + if (info.hdr.type != rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_DISPLAY_INFO)) + { + return -RT_EIO; + } + + for (int i = 0; i < vgpu->num_scanouts; ++i) + { + if (info.pmodes[i].enabled) + { + struct virtio_gpu_display_one *pmode = &info.pmodes[i]; + + vgpu->pmode_id = i; + vgpu->width = pmode->r.width; + vgpu->height = pmode->r.height; + break; + } + } + + return RT_EOK; +} + +static rt_err_t virtio_gpu_resize(struct virtio_gpu *vgpu) +{ + rt_err_t err = RT_EOK; + + if (rt_virtio_has_feature(vgpu->vdev, VIRTIO_GPU_F_EDID)) + { + err = virtio_gpu_get_edid(vgpu); + } + + if (!err) + { + err = virtio_gpu_get_display_info(vgpu); + } + + return err; +} + +static enum virtio_gpu_formats virtio_gpu_raw_modes[] = +{ + VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM, + VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM, +}; + +static rt_uint32_t virtio_gpu_modes[] = +{ + RTGRAPHIC_PIXEL_FORMAT_ARGB888, + RTGRAPHIC_PIXEL_FORMAT_ABGR888, +}; + +typedef char __assert_virtio_gpu_modes[-(RT_ARRAY_SIZE(virtio_gpu_raw_modes) % RT_ARRAY_SIZE(virtio_gpu_modes))]; + +static enum virtio_gpu_formats virtio_gpu_mode(rt_uint32_t mode) +{ + for (int i = 0; i < RT_ARRAY_SIZE(virtio_gpu_modes); ++i) + { + if (virtio_gpu_modes[i] == mode) + { + return virtio_gpu_raw_modes[i]; + } + } + + LOG_E("BUG of the graphic framework"); + RT_ASSERT(0); + return -1; +} + +static rt_err_t virtio_gpu_cursor_plane_fb_update(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + rt_err_t err; + rt_uint32_t resource_id; + struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic); + + if (!rect->width && !rect->height) + { + return RT_EOK; + } + + if (rect->width > CURSOR_WIDTH || rect->height > CURSOR_HEIGHT) + { + return -RT_EINVAL; + } + + resource_id = CURSOR_PLANE_RESOURCE_ID; + + err = virtio_gpu_transfer_to_host_2d(vgpu, resource_id, + rect->x, rect->y, rect->width, rect->height, 0); + + if (!err) + { + err = virtio_gpu_flush_resource(vgpu, resource_id, + rect->x, rect->y, rect->width, rect->height); + } + + virtio_gpu_update_cursor(vgpu, vgpu->pmode_id, resource_id, rect->x, rect->y); + virtio_gpu_cursor_move(vgpu, vgpu->pmode_id, resource_id, rect->x, rect->y); + + return err; +} + +static rt_err_t virtio_gpu_cursor_plane_fb_remap(struct rt_graphic_plane *plane, + rt_uint32_t mode, struct rt_device_rect_info *rect) +{ + rt_err_t err; + rt_uint32_t framebuffer_len, bits_per_pixel, line_length, resource_id; + struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic); + + if (rect->width > CURSOR_WIDTH || rect->height > CURSOR_HEIGHT) + { + return -RT_EINVAL; + } + + resource_id = CURSOR_PLANE_RESOURCE_ID; + + err = virtio_gpu_create_2d_resource(vgpu, virtio_gpu_mode(mode), + resource_id, rect->width, rect->height); + + if (err) + { + return err; + } + + bits_per_pixel = rt_graphic_mode_bpp(mode); + line_length = rect->width * (bits_per_pixel / 8); + + framebuffer_len = line_length * rect->height; + + err = virtio_gpu_attach_backing_resource(vgpu, resource_id, vgpu->cursor, framebuffer_len); + + if (err) + { + goto _unref_resource; + } + + plane->line_length = line_length; + plane->bits_per_pixel = bits_per_pixel; + + plane->framebuffer = vgpu->cursor; + plane->screen_len = framebuffer_len; + plane->framebuffer_len = framebuffer_len; + + return RT_EOK; + +_unref_resource: + virtio_gpu_unref_resource(vgpu, resource_id); + + return err; +} + +static rt_err_t virtio_gpu_cursor_plane_fb_cleanup(struct rt_graphic_plane *plane) +{ + rt_uint32_t resource_id; + struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic); + + if (!plane->framebuffer) + { + return RT_EOK; + } + + resource_id = CURSOR_PLANE_RESOURCE_ID; + + virtio_gpu_detach_backing_resource(vgpu, resource_id); + virtio_gpu_unref_resource(vgpu, resource_id); + + plane->framebuffer = RT_NULL; + + return RT_EOK; +} + +static const struct rt_graphic_plane_ops virtio_gpu_cursor_plane_ops = +{ + .update = virtio_gpu_cursor_plane_fb_update, + .fb_remap = virtio_gpu_cursor_plane_fb_remap, + .fb_cleanup = virtio_gpu_cursor_plane_fb_cleanup, +}; + +static rt_err_t virtio_gpu_primary_plane_fb_update(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + rt_err_t err; + rt_uint32_t resource_id; + struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic); + + vgpu->vsync = RT_FALSE; + resource_id = PRIMARY_PLANE_RESOURCE_ID; + + err = virtio_gpu_transfer_to_host_2d(vgpu, resource_id, + rect->x, rect->y, rect->width, rect->height, 0); + + if (!err) + { + err = virtio_gpu_flush_resource(vgpu, resource_id, + rect->x, rect->y, rect->width, rect->height); + } + vgpu->vsync = RT_TRUE; + + return err; +} + +static rt_err_t virtio_gpu_primary_plane_fb_remap(struct rt_graphic_plane *plane, + rt_uint32_t mode, struct rt_device_rect_info *rect) +{ + rt_err_t err; + void *framebuffer; + rt_uint32_t framebuffer_len, bits_per_pixel, line_length, resource_id; + struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic); + + resource_id = PRIMARY_PLANE_RESOURCE_ID; + err = virtio_gpu_create_2d_resource(vgpu, virtio_gpu_mode(mode), + resource_id, rect->width, rect->height); + + if (err) + { + return err; + } + + bits_per_pixel = rt_graphic_mode_bpp(mode); + line_length = rect->width * (bits_per_pixel / 8); + + framebuffer_len = line_length * rect->height; + framebuffer = rt_malloc_align(framebuffer_len, ARCH_PAGE_SIZE); + + if (!framebuffer) + { + err = -RT_ENOMEM; + goto _unref_resource; + } + + err = virtio_gpu_attach_backing_resource(vgpu, resource_id, framebuffer, framebuffer_len); + + if (err) + { + goto _free_framebuffer; + } + + err = virtio_gpu_set_scanout(vgpu, vgpu->pmode_id, resource_id, + rect->width, rect->height); + + if (err) + { + goto _detach_backing; + } + + plane->line_length = line_length; + plane->bits_per_pixel = bits_per_pixel; + + plane->framebuffer = framebuffer; + plane->screen_len = framebuffer_len; + plane->framebuffer_len = framebuffer_len; + + return RT_EOK; + +_detach_backing: + virtio_gpu_detach_backing_resource(vgpu, resource_id); + +_free_framebuffer: + rt_free_align(framebuffer); + +_unref_resource: + virtio_gpu_unref_resource(vgpu, resource_id); + + return err; +} + +static rt_err_t virtio_gpu_primary_plane_fb_cleanup(struct rt_graphic_plane *plane) +{ + rt_uint32_t resource_id; + struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic); + + if (!plane->framebuffer) + { + return RT_EOK; + } + + resource_id = PRIMARY_PLANE_RESOURCE_ID; + + virtio_gpu_detach_backing_resource(vgpu, resource_id); + virtio_gpu_unref_resource(vgpu, resource_id); + rt_free_align(plane->framebuffer); + + plane->framebuffer = RT_NULL; + + return RT_EOK; +} + +static const struct rt_graphic_plane_ops virtio_gpu_primary_plane_ops = +{ + .update = virtio_gpu_primary_plane_fb_update, + .fb_remap = virtio_gpu_primary_plane_fb_remap, + .fb_cleanup = virtio_gpu_primary_plane_fb_cleanup, +}; + +static rt_err_t virtio_gpu_dpms_switch(struct rt_graphic_device *gdev, rt_uint32_t dpms) +{ + rt_uint32_t update_ms = 0; + struct virtio_gpu *vgpu = raw_to_virtio_gpu(gdev); + + if (dpms == RT_GRAPHIC_DPMS_ON) + { + update_ms = RT_GRAPHIC_UPDATE_MS; + } + + rt_graphic_device_update_auto(&vgpu->parent, update_ms); + + return RT_EOK; +} + +static rt_err_t virtio_gpu_wait_vsync(struct rt_graphic_device *gdev) +{ + struct virtio_gpu *vgpu = raw_to_virtio_gpu(gdev); + + while (!vgpu->vsync) + { + rt_hw_cpu_relax(); + } + + return RT_EOK; +} + +static rt_err_t virtio_gpu_virgl_control(struct rt_graphic_device *gdev, int cmd, void *args) +{ + rt_err_t err; + struct virtio_gpu *vgpu = raw_to_virtio_gpu(gdev); + + switch (cmd) + { + case VIRTIO_GPU_CMD_GET_CAPSET_INFO: + { + struct virtio_gpu_get_capset_info req; + struct virtio_gpu_resp_capset_info *res = args; + + rt_memcpy(&req, args, sizeof(req)); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), res, sizeof(*res)); + + err = res->hdr.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_CAPSET_INFO) ? RT_EOK : -RT_ERROR; + break; + } + + case VIRTIO_GPU_CMD_GET_CAPSET: + { + struct virtio_gpu_get_capset req; + struct virtio_gpu_resp_capset *res = args; + + rt_memcpy(&req, args, sizeof(req)); + + virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), res, sizeof(*res)); + + err = res->hdr.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_CAPSET) ? RT_EOK : -RT_ERROR; + break; + } + + case VIRTIO_GPU_CMD_CTX_CREATE: + { + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_ctx_create *req = args; + + virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res)); + + rt_memcpy(args, &res, sizeof(res)); + err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; + break; + } + + case VIRTIO_GPU_CMD_CTX_DESTROY: + { + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_ctx_destroy *req = args; + + virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res)); + + rt_memcpy(args, &res, sizeof(res)); + err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; + break; + } + + case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE: + { + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_ctx_resource *req = args; + + virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res)); + + rt_memcpy(args, &res, sizeof(res)); + err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; + break; + } + + case VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE: + { + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_ctx_resource *req = args; + + virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res)); + + rt_memcpy(args, &res, sizeof(res)); + err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; + break; + } + + case VIRTIO_GPU_CMD_RESOURCE_CREATE_3D: + { + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_resource_create_3d *req = args; + + /* + * Create a new resource id instead of user's. Because the + * `virtio_gpu_resource_create_3d` is base on the `virtio_gpu_ctrl_hdr`, + * user should pick the resource_id by res after request. + */ + req->resource_id = virtio_gpu_next_resource_id(vgpu); + + virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res)); + + rt_memcpy(args, &res, sizeof(res)); + err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; + break; + } + + case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D: + { + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_transfer_host_3d *req = args; + + virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res)); + + rt_memcpy(args, &res, sizeof(res)); + err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; + break; + } + + case VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D: + { + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_transfer_host_3d *req = args; + + virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res)); + + rt_memcpy(args, &res, sizeof(res)); + err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; + break; + } + + case VIRTIO_GPU_CMD_SUBMIT_3D: + { + struct virtio_gpu_ctrl_hdr res; + struct virtio_gpu_cmd_submit *req = args; + + virtio_gpu_ctrl_send_command(vgpu, req, req->size, &res, sizeof(res)); + + rt_memcpy(args, &res, sizeof(res)); + err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR; + break; + } + + default: + err = -RT_ENOSYS; + break; + } + + return err; +} + +static const struct rt_graphic_device_ops virtio_gpu_virgl_ops = +{ + .dpms_switch = virtio_gpu_dpms_switch, + .wait_vsync = virtio_gpu_wait_vsync, + .control = virtio_gpu_virgl_control, +}; + +static const struct rt_graphic_device_ops virtio_gpu_ops = +{ + .dpms_switch = virtio_gpu_dpms_switch, + .wait_vsync = virtio_gpu_wait_vsync, +}; + +static void virtio_gpu_event_work(struct rt_work *work, void *work_data) +{ + rt_uint32_t events_read, events_clear = 0; + struct virtio_gpu *vgpu = work_data; + struct rt_virtio_device *vdev = vgpu->vdev; + + rt_virtio_read_config(vdev, struct virtio_gpu_config, events_read, &events_read); + + if (events_read & VIRTIO_GPU_EVENT_DISPLAY) + { + rt_graphic_device_enter(&vgpu->parent); + virtio_gpu_resize(vgpu); + rt_graphic_device_leave(&vgpu->parent); + + rt_graphic_device_hotplug_event(&vgpu->parent); + + events_clear |= VIRTIO_GPU_EVENT_DISPLAY; + } + + rt_virtio_write_config(vdev, struct virtio_gpu_config, events_clear, events_clear); +} + +static void virtio_gpu_config_changed(struct rt_virtio_device *vdev) +{ + struct virtio_gpu *vgpu = vdev->priv; + + rt_work_submit(&vgpu->event_work, 0); +} + +static rt_err_t virtio_gpu_vq_init(struct virtio_gpu *vgpu) +{ + const char *names[] = + { + "ctrl", + "cursor" + }; + rt_virtqueue_callback cbs[] = + { + RT_NULL, /* Just poll */ + RT_NULL, /* Just poll */ + }; + + return rt_virtio_virtqueue_install(vgpu->vdev, + RT_ARRAY_SIZE(names), vgpu->vqs, names, cbs); +} + +static void virtio_gpu_vq_finit(struct virtio_gpu *vgpu) +{ + if (vgpu->vqs[0]) + { + rt_virtio_virtqueue_release(vgpu->vdev); + } +} + +static void virtio_gpu_unregister(struct virtio_gpu *vgpu) +{ + if (rt_virtio_has_feature(vgpu->vdev, VIRTIO_GPU_F_EDID)) + { + rt_graphic_device_unregister(&vgpu->parent); + } + else + { + rt_graphic_device_simple_unregister(&vgpu->parent); + } +} + +static rt_err_t virtio_gpu_probe(struct rt_virtio_device *vdev) +{ + rt_err_t err; + struct rt_graphic_plane *primary_plane, *cursor_plane; + struct virtio_gpu *vgpu = rt_calloc(1, sizeof(*vgpu)); + + if (!vgpu) + { + return -RT_ENOMEM; + } + + vdev->priv = vgpu; + vgpu->vdev = vdev; + + vgpu->cursor = rt_malloc_align( + CURSOR_WIDTH * CURSOR_HEIGHT * sizeof(rt_uint32_t), ARCH_PAGE_SIZE); + + if (!vgpu->cursor) + { + err = -RT_ENOMEM; + goto _fail; + } + + if ((err = virtio_gpu_vq_init(vgpu))) + { + goto _fail; + } + + vgpu->vsync = RT_TRUE; + + rt_virtio_read_config(vdev, struct virtio_gpu_config, num_scanouts, &vgpu->num_scanouts); + + rt_work_init(&vgpu->event_work, virtio_gpu_event_work, vgpu); + + virtio_gpu_resize(vgpu); + + if (rt_virtio_has_feature(vdev, VIRTIO_GPU_F_VIRGL)) + { + vgpu->parent.ops = &virtio_gpu_virgl_ops; + } + else + { + vgpu->parent.ops = &virtio_gpu_ops; + } + + if (rt_virtio_has_feature(vdev, VIRTIO_GPU_F_EDID)) + { + primary_plane = rt_graphic_device_alloc_plane(&vgpu->parent, 0, + &virtio_gpu_primary_plane_ops, + virtio_gpu_modes, RT_ARRAY_SIZE(virtio_gpu_modes), + RT_GRAPHIC_PLANE_TYPE_PRIMARY); + + if (!primary_plane) + { + err = -RT_EIO; + goto _fail; + } + + if ((err = rt_graphic_device_add_plane(&vgpu->parent, primary_plane))) + { + goto _free_primary_plane; + } + + err = rt_graphic_device_register(&vgpu->parent); + } + else + { + err = rt_graphic_device_simple_register(&vgpu->parent, + vgpu->width, vgpu->height, 0, &virtio_gpu_primary_plane_ops, + virtio_gpu_modes, RT_ARRAY_SIZE(virtio_gpu_modes)); + } + + if (err) + { + goto _fail; + } + + cursor_plane = rt_graphic_device_alloc_plane(&vgpu->parent, 0, + &virtio_gpu_cursor_plane_ops, + virtio_gpu_modes, RT_ARRAY_SIZE(virtio_gpu_modes), + RT_GRAPHIC_PLANE_TYPE_CURSOR); + + if (!cursor_plane) + { + err = -RT_EIO; + goto _fail; + } + + if ((err = rt_graphic_device_add_plane(&vgpu->parent, cursor_plane))) + { + goto _free_cursor_plane; + } + + cursor_plane->width = CURSOR_WIDTH; + cursor_plane->height = CURSOR_HEIGHT; + + return RT_EOK; + +_free_cursor_plane: + virtio_gpu_unregister(vgpu); + rt_graphic_device_free_plane(cursor_plane); + +_free_primary_plane: + rt_graphic_device_free_plane(primary_plane); + +_fail: + virtio_gpu_vq_finit(vgpu); + + if (vgpu->cursor) + { + rt_free_align(vgpu->cursor); + } + rt_free(vgpu); + + return err; +} + +static rt_err_t virtio_gpu_remove(struct rt_virtio_device *vdev) +{ + struct virtio_gpu *vgpu = vdev->parent.user_data; + + virtio_gpu_unregister(vgpu); + virtio_gpu_vq_finit(vgpu); + rt_free_align(vgpu->cursor); + rt_free(vgpu); + + return RT_EOK; +} + +static const struct rt_virtio_device_id virtio_gpu_ids[] = +{ + { VIRTIO_DEVICE_ID_GPU, VIRTIO_DEVICE_ANY_ID }, + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_gpu_driver = +{ + .ids = virtio_gpu_ids, + .features = + RT_BIT(VIRTIO_GPU_F_VIRGL) + | RT_BIT(VIRTIO_GPU_F_EDID) + | RT_BIT(VIRTIO_F_ANY_LAYOUT), + + .probe = virtio_gpu_probe, + .remove = virtio_gpu_remove, + .config_changed = virtio_gpu_config_changed, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_gpu_driver); diff --git a/components/drivers/virtio/virtio-input.c b/components/drivers/virtio/virtio-input.c new file mode 100644 index 0000000000..1b705b17d5 --- /dev/null +++ b/components/drivers/virtio/virtio-input.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-11-11 GuEe-GUI the first version + */ + +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "virtio.dev.input" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include "virtio_config/virtio-input.h" + +#define QUEUE_EVENTS 0 +#define QUEUE_STATUS 1 + +struct virtio_input +{ + struct rt_input_device parent; + struct rt_virtio_device *vdev; + + struct rt_virtqueue *vqs[2]; + + rt_size_t events_nr; + struct rt_spinlock lock; + struct virtio_input_event *events; +}; + +#define raw_to_virtio_input(raw) rt_container_of(raw, struct virtio_input, parent) + +static rt_err_t virtio_input_trigger(struct rt_input_device *idev, + rt_uint16_t type, rt_uint16_t code, rt_int32_t value) +{ + struct rt_virtqueue *vq; + struct virtio_input_event status; + struct virtio_input *vinput = raw_to_virtio_input(idev); + + vq = vinput->vqs[QUEUE_STATUS]; + + rt_virtqueue_wait_prepare(vq, 1); + + rt_spin_lock(&vinput->lock); + + status.type = rt_cpu_to_le16(type); + status.code = rt_cpu_to_le16(code); + status.value = rt_cpu_to_le32(value); + rt_virtqueue_add_outbuf(vq, &status, sizeof(status)); + + rt_virtqueue_kick(vq); + + while (!rt_virtqueue_read_buf(vq, RT_NULL)) + { + rt_hw_cpu_relax(); + } + + rt_spin_unlock(&vinput->lock); + + return RT_EOK; +} + +static void virtio_input_events_done(struct rt_virtqueue *vq) +{ + rt_ubase_t level; + struct virtio_input_event *event; + struct virtio_input *vinput = vq->vdev->priv; + + level = rt_spin_lock_irqsave(&vinput->lock); + + while ((event = rt_virtqueue_read_buf(vq, RT_NULL))) + { + rt_input_event(&vinput->parent, + rt_le16_to_cpu(event->type), + rt_le16_to_cpu(event->code), + rt_le32_to_cpu(event->value)); + + LOG_D("%s: Event (type: %d, code: %d, value: %d)", + rt_dm_dev_get_name(&vinput->parent), + rt_le16_to_cpu(event->type), + rt_le16_to_cpu(event->code), + rt_le32_to_cpu(event->value)); + + rt_virtqueue_add_inbuf(vq, event, sizeof(*event)); + + rt_virtqueue_kick(vq); + } + + rt_spin_unlock_irqrestore(&vinput->lock, level); +} + +static void virtio_input_status_done(struct rt_virtqueue *vq) +{ +} + +static rt_uint8_t virtio_input_cfg_select(struct virtio_input *vinput, + rt_uint8_t select, rt_uint8_t subsel) +{ + rt_uint8_t size = 0; + struct rt_virtio_device *vdev = vinput->vdev; + + rt_virtio_write_config(vdev, struct virtio_input_config, select, select); + rt_virtio_write_config(vdev, struct virtio_input_config, subsel, subsel); + rt_virtio_read_config(vdev, struct virtio_input_config, size, &size); + + return size; +} + +static void virtio_input_cfg_bits(struct virtio_input *vinput, + rt_uint8_t select, rt_uint8_t subsel, rt_bitmap_t *map, rt_size_t bitcount) +{ + rt_uint8_t size = virtio_input_cfg_select(vinput, select, subsel); + + if (!size) + { + return; + } + + bitcount = rt_min_t(rt_size_t, bitcount, size * RT_BITS_PER_BYTE); + + rt_virtio_read_bytes(vinput->vdev, + rt_offsetof(struct virtio_input_config, bitmap), map, 1, size); + + rt_bitmap_set_bit(vinput->parent.cap, subsel); +} + +static void virtio_input_cfg_abs(struct virtio_input *vinput, int abs) +{ + rt_uint32_t min, max, res, fuzz, flat; + struct rt_virtio_device *vdev = vinput->vdev; + + virtio_input_cfg_select(vinput, VIRTIO_INPUT_CFG_ABS_INFO, abs); + rt_virtio_read_config(vdev, struct virtio_input_config, abs.min, &min); + rt_virtio_read_config(vdev, struct virtio_input_config, abs.max, &max); + rt_virtio_read_config(vdev, struct virtio_input_config, abs.res, &res); + rt_virtio_read_config(vdev, struct virtio_input_config, abs.fuzz, &fuzz); + rt_virtio_read_config(vdev, struct virtio_input_config, abs.flat, &flat); + + rt_input_set_capability(&vinput->parent, EV_ABS, abs); + rt_input_set_absinfo(&vinput->parent, abs, min, max, fuzz, flat); + vinput->parent.absinfo->resolution = res; +} + +static rt_err_t virtio_input_vq_init(struct virtio_input *vinput) +{ + rt_err_t err; + const char *names[] = + { + "events", + "status" + }; + rt_virtqueue_callback cbs[] = + { + &virtio_input_events_done, + &virtio_input_status_done, + }; + struct rt_virtqueue *vq; + + err = rt_virtio_virtqueue_install(vinput->vdev, + RT_ARRAY_SIZE(names), vinput->vqs, names, cbs); + + if (err) + { + return err; + } + + vinput->events_nr = rt_virtqueue_get_virtq_size(vinput->vqs[QUEUE_EVENTS]); + + vinput->events = rt_malloc(sizeof(*vinput->events) * vinput->events_nr); + + if (!vinput->events) + { + return -RT_ENOMEM; + } + + vq = vinput->vqs[QUEUE_EVENTS]; + + for (int i = 0; i < vinput->events_nr; ++i) + { + rt_virtqueue_add_inbuf(vq, &vinput->events[i], sizeof(*vinput->events)); + + rt_virtqueue_submit(vq); + } + + rt_virtqueue_notify(vq); + + return RT_EOK; +} + +static void virtio_input_vq_finit(struct virtio_input *vinput) +{ + if (vinput->vqs[0]) + { + rt_virtio_virtqueue_release(vinput->vdev); + } + + if (vinput->events) + { + rt_free(vinput->events); + } +} + +static rt_err_t virtio_input_probe(struct rt_virtio_device *vdev) +{ + rt_err_t err; + struct virtio_input *vinput = rt_calloc(1, sizeof(*vinput)); + + if (!vinput) + { + return -RT_ENOMEM; + } + + vdev->priv = vinput; + vinput->vdev = vdev; + vdev->parent.user_data = vinput; + + if ((err = virtio_input_vq_init(vinput)) < 0) + { + goto _fail; + } + + rt_spin_lock_init(&vinput->lock); + + virtio_input_cfg_bits(vinput, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY, + vinput->parent.key_map, KEY_CNT); + virtio_input_cfg_bits(vinput, VIRTIO_INPUT_CFG_EV_BITS, EV_REL, + vinput->parent.rel_map, REL_CNT); + virtio_input_cfg_bits(vinput, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS, + vinput->parent.abs_map, ABS_CNT); + + if (rt_bitmap_test_bit(vinput->parent.cap, EV_ABS)) + { + for (int abs = 0; abs < ABS_CNT; ++abs) + { + if (!rt_bitmap_test_bit(vinput->parent.abs_map, abs)) + { + continue; + } + + virtio_input_cfg_abs(vinput, abs); + } + + if (rt_bitmap_test_bit(vinput->parent.abs_map, ABS_MT_SLOT)) + { + int nslots = vinput->parent.absinfo[ABS_MT_SLOT].maximum + 1; + + if ((err = rt_input_setup_touch(&vinput->parent, nslots, RT_NULL))) + { + goto _fail; + } + } + } + + vinput->parent.trigger = &virtio_input_trigger; + + if ((err = rt_input_device_register(&vinput->parent))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + virtio_input_vq_finit(vinput); + rt_input_remove_config(&vinput->parent); + rt_free(vinput); + + return err; +} + +static rt_err_t virtio_input_remove(struct rt_virtio_device *vdev) +{ + struct virtio_input *vinput = vdev->parent.user_data; + + rt_input_device_unregister(&vinput->parent); + + virtio_input_vq_finit(vinput); + rt_free(vinput); + + return RT_EOK; +} + +static const struct rt_virtio_device_id virtio_input_ids[] = +{ + { VIRTIO_DEVICE_ID_INPUT, VIRTIO_DEVICE_ANY_ID }, + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_input_driver = +{ + .ids = virtio_input_ids, + .probe = virtio_input_probe, + .remove = virtio_input_remove, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_input_driver); diff --git a/components/drivers/virtio/virtio-net.c b/components/drivers/virtio/virtio-net.c new file mode 100644 index 0000000000..e2e1b559a6 --- /dev/null +++ b/components/drivers/virtio/virtio-net.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-11-11 GuEe-GUI the first version + * 2023-02-25 GuEe-GUI using virtio dm + */ + +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "virtio.dev.net" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include <mm_aspace.h> +#include <netif/ethernetif.h> + +#include "virtio_config/virtio-net.h" + +#define QUEUE_RX(n) (n) +#define QUEUE_TX(n) ((n) + 1) + +rt_packed(struct net_packet +{ + struct virtio_net_hdr hdr; + + rt_uint8_t mss[VIRTIO_NET_MSS]; +}); + +struct virtio_net +{ + struct eth_device parent; + struct rt_virtio_device *vdev; + + rt_uint16_t status; + + int max_pairs; + int request_num; + void (*virtqueue_add_net_packet)(struct rt_virtqueue *, struct net_packet *, rt_size_t); + struct rt_virtqueue *vqs[RT_CPUS_NR * 2]; + + rt_list_t rx_vq_nodes; + struct rt_spinlock rx_lock; + + struct net_packet *tx_packet; + struct net_packet *rx_packet; +}; + +#define raw_to_virtio_net(raw) \ + rt_container_of(rt_container_of(raw, struct eth_device, parent), struct virtio_net, parent) + +static void virtqueue_add_net_packet_split(struct rt_virtqueue *vq, + struct net_packet *packet, rt_size_t len) +{ + rt_virtqueue_add_outbuf(vq, packet, sizeof(packet->hdr) + len); +} + +static void virtqueue_add_net_packet_packed(struct rt_virtqueue *vq, + struct net_packet *packet, rt_size_t len) +{ + rt_virtqueue_add_outbuf(vq, &packet->hdr, sizeof(packet->hdr)); + rt_virtqueue_add_outbuf(vq, &packet->mss, len); +} + +static rt_err_t virtio_net_tx(rt_device_t dev, struct pbuf *p) +{ + struct rt_virtqueue *vq; + struct net_packet *packet; + struct virtio_net *vnet = raw_to_virtio_net(dev); + + vq = vnet->vqs[QUEUE_TX(rt_hw_cpu_id() % vnet->max_pairs)]; + rt_virtqueue_wait_prepare(vq, vnet->request_num); + + packet = &vnet->tx_packet[vq->index * rt_virtqueue_next_buf_index(vq)]; + packet->hdr.flags = 0; + packet->hdr.gso_type = 0; + packet->hdr.hdr_len = 0; + packet->hdr.gso_size = 0; + packet->hdr.csum_start = 0; + packet->hdr.csum_offset = 0; + packet->hdr.num_buffers = 0; + + RT_ASSERT(p->tot_len <= sizeof(packet->mss)); + + pbuf_copy_partial(p, &packet->mss, p->tot_len, 0); + + vnet->virtqueue_add_net_packet(vq, packet, p->tot_len); + + rt_virtqueue_kick(vq); + + return RT_EOK; +} + +static struct pbuf *virtio_net_rx(rt_device_t dev) +{ + rt_size_t size; + rt_ubase_t level; + struct pbuf *p = RT_NULL; + struct net_packet *packet; + struct rt_virtqueue *vq; + struct virtio_net *vnet = raw_to_virtio_net(dev); + + level = rt_spin_lock_irqsave(&vnet->rx_lock); + + rt_list_for_each_entry(vq, &vnet->rx_vq_nodes, user_list) + { + packet = rt_virtqueue_read_buf(vq, &size); + + if (!packet) + { + rt_list_remove(&vq->user_list); + break; + } + size -= sizeof(packet->hdr); + + rt_spin_unlock_irqrestore(&vnet->rx_lock, level); + + p = pbuf_alloc(PBUF_RAW, size, PBUF_RAM); + + if (!p) + { + return RT_NULL; + } + + rt_memcpy(p->payload, &packet->mss, size); + + level = rt_spin_lock_irqsave(&vnet->rx_lock); + + if (!rt_virtqueue_poll(vq, packet - vnet->rx_packet)) + { + rt_list_remove(&vq->user_list); + } + + rt_virtqueue_add_inbuf(vq, packet, sizeof(*packet)); + + rt_virtqueue_kick(vq); + + break; + } + + rt_spin_unlock_irqrestore(&vnet->rx_lock, level); + + return p; +} + +static rt_err_t virtio_net_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + rt_uint8_t *mac; + struct virtio_net *vnet = raw_to_virtio_net(dev); + + switch (cmd) + { + case NIOCTL_GADDR: + mac = args; + + if (!mac) + { + err = -RT_EINVAL; + break; + } + + for (int i = 0; i < 6; ++i) + { + rt_virtio_read_config(vnet->vdev, struct virtio_net_config, mac[i], &mac[i]); + } + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops virtio_net_ops = +{ + .control = virtio_net_control, +}; +#endif + +static void virtio_net_rx_done(struct rt_virtqueue *vq) +{ + rt_ubase_t level; + struct virtio_net *vnet = vq->vdev->priv; + + level = rt_spin_lock_irqsave(&vnet->rx_lock); + + rt_list_insert_before(&vnet->rx_vq_nodes, &vq->user_list); + + rt_spin_unlock_irqrestore(&vnet->rx_lock, level); + + eth_device_ready(&vnet->parent); +} + +static void virtio_net_tx_done(struct rt_virtqueue *vq) +{ + rt_virtqueue_read_buf(vq, RT_NULL); +} + +static void virtio_net_config_changed(struct rt_virtio_device *vdev) +{ + rt_uint16_t status; + rt_bool_t link_up; + struct virtio_net *vnet = vdev->priv; + + if (!rt_virtio_has_feature(vdev, VIRTIO_NET_F_STATUS)) + { + return; + } + + rt_virtio_read_config(vdev, struct virtio_net_config, status, &status); + + /* Remove other status bit */ + status &= VIRTIO_NET_S_LINK_UP; + + if (vnet->status == status) + { + /* Status no change */ + return; + } + + link_up = !!((vnet->status = status) & VIRTIO_NET_S_LINK_UP); + + LOG_D("%s linkchange to %s", rt_dm_dev_get_name(&vdev->parent), link_up ? "up" : "down"); + + eth_device_linkchange(&vnet->parent, link_up); +} + +static rt_err_t virtio_net_vq_init(struct virtio_net *vnet) +{ + rt_err_t err; + rt_size_t vqs_nr = 2, qsize; + const char *names[RT_ARRAY_SIZE(vnet->vqs)]; + rt_virtqueue_callback cbs[RT_ARRAY_SIZE(vnet->vqs)]; + struct rt_virtio_device *vdev = vnet->vdev; + + if (rt_virtio_has_feature(vdev, VIRTIO_NET_F_MQ) || + rt_virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) + { + rt_virtio_read_config(vdev, struct virtio_net_config, max_virtqueue_pairs, &vqs_nr); + vqs_nr *= 2; + } + + for (int i = 0; i < vqs_nr; i += 2) + { + int rx = QUEUE_RX(i), tx = QUEUE_TX(i); + + names[rx] = "rx"; + names[tx] = "tx"; + + cbs[rx] = &virtio_net_rx_done; + cbs[tx] = &virtio_net_tx_done; + } + + vnet->max_pairs = vqs_nr / 2; + err = rt_virtio_virtqueue_install(vdev, vqs_nr, vnet->vqs, names, cbs); + + if (err) + { + return err; + } + + qsize = rt_virtqueue_get_virtq_size(vnet->vqs[QUEUE_TX(0)]); + + if (!(vnet->tx_packet = rt_malloc(sizeof(vnet->tx_packet[0]) * vqs_nr * qsize))) + { + return -RT_ENOMEM; + } + + qsize = rt_virtqueue_get_virtq_size(vnet->vqs[QUEUE_RX(0)]); + + if (!(vnet->rx_packet = rt_malloc(sizeof(vnet->rx_packet[0]) * vqs_nr * qsize))) + { + return -RT_ENOMEM; + } + + for (int i = 0; i < vqs_nr; i += 2) + { + int rx = QUEUE_RX(i); + struct net_packet *packet; + struct rt_virtqueue *vq = vnet->vqs[rx]; + + packet = &vnet->rx_packet[rx * qsize]; + + for (int idx = 0; idx < qsize; ++idx, ++packet) + { + rt_virtqueue_add_inbuf(vq, packet, sizeof(*packet)); + + rt_virtqueue_submit(vq); + } + + rt_virtqueue_notify(vq); + } + + return RT_EOK; +} + +static void virtio_net_vq_finit(struct virtio_net *vnet) +{ + if (vnet->vqs[0]) + { + rt_virtio_virtqueue_release(vnet->vdev); + } + if (vnet->tx_packet) + { + rt_free(vnet->tx_packet); + } + if (vnet->rx_packet) + { + rt_free(vnet->rx_packet); + } +} + +static rt_err_t virtio_net_probe(struct rt_virtio_device *vdev) +{ + rt_err_t err = RT_EOK; + struct virtio_net *vnet = rt_calloc(1, sizeof(*vnet)); + + if (!vnet) + { + return -RT_ENOMEM; + } + + vdev->priv = vnet; + vnet->vdev = vdev; + vdev->parent.user_data = vnet; +#ifdef RT_USING_DEVICE_OPS + vnet->parent.parent.ops = &virtio_net_ops; +#else + vnet->parent.parent.control = virtio_net_control; +#endif + vnet->parent.eth_tx = virtio_net_tx; + vnet->parent.eth_rx = virtio_net_rx; + + if (rt_virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) + { + vnet->request_num = 2; + vnet->virtqueue_add_net_packet = &virtqueue_add_net_packet_packed; + } + else + { + vnet->request_num = 1; + vnet->virtqueue_add_net_packet = &virtqueue_add_net_packet_split; + } + + if ((err = virtio_net_vq_init(vnet))) + { + goto _fail; + } + + rt_list_init(&vnet->rx_vq_nodes); + rt_spin_lock_init(&vnet->rx_lock); + + if ((err = rt_dm_dev_set_name_auto(&vnet->parent.parent, "e")) < 0) + { + goto _fail; + } + + if ((err = eth_device_init(&vnet->parent, rt_dm_dev_get_name(&vnet->parent.parent)))) + { + goto _fail; + } + + eth_device_linkchange(&vnet->parent, RT_TRUE); + + return RT_EOK; + +_fail: + virtio_net_vq_finit(vnet); + rt_free(vnet); + + return err; +} + +static rt_err_t virtio_net_remove(struct rt_virtio_device *vdev) +{ + struct virtio_net *vnet = vdev->parent.user_data; + + eth_device_linkchange(&vnet->parent, RT_FALSE); + eth_device_deinit(&vnet->parent); + + virtio_net_vq_finit(vnet); + rt_free(vnet); + + return RT_EOK; +} + +static const struct rt_virtio_device_id virtio_net_ids[] = +{ + { VIRTIO_DEVICE_ID_NET, VIRTIO_DEVICE_ANY_ID }, + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_net_driver = +{ + .ids = virtio_net_ids, + .features = + RT_BIT(VIRTIO_NET_F_MTU) + | RT_BIT(VIRTIO_NET_F_MAC) + | RT_BIT(VIRTIO_NET_F_MRG_RXBUF) + | RT_BIT(VIRTIO_NET_F_STATUS) + | RT_BIT(VIRTIO_NET_F_CTRL_RX) + | RT_BIT(VIRTIO_NET_F_CTRL_VLAN) + | RT_BIT(VIRTIO_NET_F_CTRL_RX_EXTRA) + | RT_BIT(VIRTIO_NET_F_GUEST_ANNOUNCE) + | RT_BIT(VIRTIO_NET_F_MQ) + | RT_BIT(VIRTIO_NET_F_CTRL_MAC_ADDR) + | RT_BIT(VIRTIO_NET_F_SPEED_DUPLEX) + | RT_BIT(VIRTIO_F_ANY_LAYOUT), + + .probe = virtio_net_probe, + .remove = virtio_net_remove, + .config_changed = virtio_net_config_changed, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_net_driver); diff --git a/components/drivers/virtio/virtio-rng.c b/components/drivers/virtio/virtio-rng.c new file mode 100644 index 0000000000..99d2781960 --- /dev/null +++ b/components/drivers/virtio/virtio-rng.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "virtio.dev.rng" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include <cpuport.h> + +struct virtio_rng +{ + struct rt_hwcrypto_device parent; + struct rt_virtio_device *vdev; + + struct rt_virtqueue *vqs[1]; + struct rt_spinlock lock; +}; + +static rt_uint32_t virtio_rng_rand(struct hwcrypto_rng *ctx) +{ + rt_uint32_t rand; + struct rt_virtqueue *vq; + struct virtio_rng *vrng = rt_container_of(ctx->parent.device, struct virtio_rng, parent); + + vq = vrng->vqs[0]; + rt_virtqueue_wait_prepare(vq, 1); + + rt_spin_lock(&vrng->lock); + + rt_virtqueue_add_inbuf(vq, &rand, sizeof(rand)); + rt_virtqueue_kick(vq); + + while (!rt_virtqueue_read_buf(vq, RT_NULL)) + { + rt_hw_cpu_relax(); + } + + rt_spin_unlock(&vrng->lock); + + return rand; +} + +static const struct hwcrypto_rng_ops rng_ops = +{ + .update = virtio_rng_rand, +}; + +static rt_err_t virtio_rng_create(struct rt_hwcrypto_ctx *ctx) +{ + if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_RNG) + { + struct hwcrypto_rng *rng; + + ctx->contex = RT_NULL; + + rng = rt_container_of(ctx, struct hwcrypto_rng, parent); + rng->ops = &rng_ops; + + return RT_EOK; + } + + return -RT_ENOSYS; +} + +static void virtio_rng_destroy(struct rt_hwcrypto_ctx *ctx) +{ +} + +static rt_err_t virtio_rng_copy(struct rt_hwcrypto_ctx *des, + const struct rt_hwcrypto_ctx *src) +{ + if ((src->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_RNG) + { + return RT_EOK; + } + + return -RT_ENOSYS; +} + +static void virtio_rng_reset(struct rt_hwcrypto_ctx *ctx) +{ +} + +static const struct rt_hwcrypto_ops virtio_rng_ops = +{ + .create = virtio_rng_create, + .destroy = virtio_rng_destroy, + .copy = virtio_rng_copy, + .reset = virtio_rng_reset, +}; + +static void virtio_rng_done(struct rt_virtqueue *vq) +{ +} + +static rt_err_t virtio_rng_vq_init(struct virtio_rng *vrng) +{ + const char *names[] = + { + "req", + }; + rt_virtqueue_callback cbs[] = + { + &virtio_rng_done, + }; + + return rt_virtio_virtqueue_install(vrng->vdev, RT_ARRAY_SIZE(vrng->vqs), + vrng->vqs, names, cbs); +} + +static void virtio_rng_vq_finit(struct virtio_rng *vrng) +{ + if (vrng->vqs[0]) + { + rt_virtio_virtqueue_release(vrng->vdev); + } +} + +static rt_err_t virtio_rng_probe(struct rt_virtio_device *vdev) +{ + rt_err_t err; + struct virtio_rng *vrng = rt_calloc(1, sizeof(*vrng)); + + if (!vrng) + { + return -RT_ENOMEM; + } + + vdev->priv = vrng; + vrng->vdev = vdev; + vdev->parent.user_data = vrng; + + if ((err = virtio_rng_vq_init(vrng))) + { + goto _fail; + } + + rt_spin_lock_init(&vrng->lock); + vrng->parent.ops = &virtio_rng_ops; + vrng->parent.id = vdev->id.vendor; + + if ((err = rt_hwcrypto_register(&vrng->parent, "hwrng"))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + virtio_rng_vq_finit(vrng); + rt_free(vrng); + + return err; +} + +static rt_err_t virtio_rng_remove(struct rt_virtio_device *vdev) +{ + struct virtio_rng *vrng = vdev->parent.user_data; + + rt_device_unregister(&vrng->parent.parent); + + virtio_rng_vq_finit(vrng); + rt_free(vrng); + + return RT_EOK; +} + +static const struct rt_virtio_device_id virtio_rng_ids[] = +{ + { VIRTIO_DEVICE_ID_RNG, VIRTIO_DEVICE_ANY_ID }, + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_rng_driver = +{ + .ids = virtio_rng_ids, + .probe = virtio_rng_probe, + .remove = virtio_rng_remove, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_rng_driver); diff --git a/components/drivers/virtio/virtio-scmi.c b/components/drivers/virtio/virtio-scmi.c new file mode 100644 index 0000000000..92343e4f7e --- /dev/null +++ b/components/drivers/virtio/virtio-scmi.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "virtio.dev.scmi" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include "virtio_internal.h" +#include "virtio_config/virtio-scmi.h" +#include "../firmware/arm_scmi/agent.h" + +#define QUEUE_CMDQ 0 +#define QUEUE_EVENTQ 1 + +struct virtio_scmi_event_msg_ext +{ + rt_list_t list; + + struct rt_scmi_device *sdev; + rt_scmi_msg_callback rx_callback; + + rt_size_t msg_size; + struct virtio_scmi_event_msg event_msg; +}; + +struct virtio_scmi +{ + struct rt_virtio_device *vdev; + + rt_list_t event_nodes; + struct rt_work event_work; + + struct rt_virtqueue *vqs[2]; + struct rt_completion done; + struct rt_spinlock lock; +}; + +static struct virtio_scmi *system_virtio_scmi = RT_NULL; + +static rt_err_t scmi_agent_virtio_setup(struct scmi_agent *agent, + struct rt_device *dev) +{ + RT_ASSERT(system_virtio_scmi != RT_NULL); + + agent->priv = system_virtio_scmi; + + return RT_EOK; +} + +static rt_err_t scmi_agent_virtio_process_msg(struct scmi_agent *agent, + struct rt_scmi_msg *msg) +{ + rt_base_t level; + struct rt_virtqueue *vq; + struct virtio_scmi *vscmi = agent->priv; + + if (!msg->rx_callback || + !rt_virtio_has_feature(vscmi->vdev, VIRTIO_SCMI_F_P2A_CHANNELS)) + { + void *buffer; + rt_size_t request_size, response_size; + struct virtio_scmi_request *request; + struct virtio_scmi_response *response; + + request_size = sizeof(*request) + msg->in_msg_size; + response_size = sizeof(*response) + msg->out_msg_size; + buffer = rt_malloc(request_size + response_size); + + if (!buffer) + { + return -RT_ENOMEM; + } + + request = buffer; + response = buffer + request_size; + + request->hdr = cpu_to_virtio32(vscmi->vdev, scmi_header( + msg->message_id, 0, msg->sdev->protocol_id, 0)); + rt_memcpy(request->params, msg->in_msg, msg->in_msg_size); + + vq = vscmi->vqs[QUEUE_CMDQ]; + rt_virtqueue_wait_prepare(vq, 2); + + level = rt_spin_lock_irqsave(&vscmi->lock); + + rt_virtqueue_add_outbuf(vq, request, request_size); + rt_virtqueue_add_inbuf(vq, response, response_size); + rt_virtqueue_kick(vq); + + rt_spin_unlock_irqrestore(&vscmi->lock, level); + + rt_completion_wait(&vscmi->done, RT_WAITING_FOREVER); + + if (msg->out_msg) + { + if (request->hdr != response->hdr) + { + LOG_W("WTF? request header(%x) != response header(%x)", + rt_le32_to_cpu(request->hdr), rt_le32_to_cpu(response->hdr)); + } + + rt_memcpy(msg->out_msg, response->ret_values, msg->out_msg_size); + } + + /* Fixup for device */ + if (msg->rx_callback) + { + msg->rx_callback(msg->sdev, response->ret_values, msg->out_msg_size); + } + + rt_free(buffer); + } + else + { + struct virtio_scmi_event_msg_ext *msge = rt_malloc(sizeof(*msge) + + rt_max(msg->in_msg_size, msg->out_msg_size)); + + if (!msge) + { + return -RT_ENOMEM; + } + + msge->sdev = msg->sdev; + msge->rx_callback = msg->rx_callback; + msge->msg_size = msg->out_msg_size; + msge->event_msg.hdr = cpu_to_virtio32(vscmi->vdev, scmi_header( + msg->message_id, 0, msg->sdev->protocol_id, 0)); + rt_memcpy(msge->event_msg.payload, msg->in_msg, msg->in_msg_size); + + vq = vscmi->vqs[QUEUE_EVENTQ]; + rt_virtqueue_wait_prepare(vq, 1); + + level = rt_spin_lock_irqsave(&vscmi->lock); + + rt_virtqueue_add_outbuf(vq, &msge->event_msg, + sizeof(msge->event_msg) + msg->in_msg_size); + rt_virtqueue_kick(vq); + + rt_spin_unlock_irqrestore(&vscmi->lock, level); + } + + return RT_EOK; +} + +struct scmi_agent_ops scmi_agent_virtio_ops = +{ + .name = "virtio", + .setup = scmi_agent_virtio_setup, + .process_msg = scmi_agent_virtio_process_msg, +}; + +static void virtio_scmi_work(struct rt_work *work, void *work_data) +{ + rt_ubase_t level; + struct virtio_scmi *vscmi = work_data; + struct virtio_scmi_event_msg_ext *msge, *msge_next; + + level = rt_spin_lock_irqsave(&vscmi->lock); + + rt_list_for_each_entry_safe(msge, msge_next, &vscmi->event_nodes, list) + { + rt_list_remove(&msge->list); + + rt_spin_unlock_irqrestore(&vscmi->lock, level); + + msge->rx_callback(msge->sdev, msge->event_msg.payload, msge->msg_size); + rt_free(msge); + + level = rt_spin_lock_irqsave(&vscmi->lock); + } + + rt_spin_unlock_irqrestore(&vscmi->lock, level); +} + +static void virtio_scmi_cmd_done(struct rt_virtqueue *vq) +{ + rt_ubase_t level; + struct virtio_scmi *vscmi = vq->vdev->priv; + + level = rt_spin_lock_irqsave(&vscmi->lock); + + rt_virtqueue_read_buf(vq, RT_NULL); + rt_completion_done(&vscmi->done); + + rt_spin_unlock_irqrestore(&vscmi->lock, level); +} + +static void virtio_scmi_event_done(struct rt_virtqueue *vq) +{ + rt_ubase_t level; + void *raw_buffer; + struct virtio_scmi *vscmi = vq->vdev->priv; + + level = rt_spin_lock_irqsave(&vscmi->lock); + + if ((raw_buffer = rt_virtqueue_read_buf(vq, RT_NULL))) + { + struct virtio_scmi_event_msg_ext *msge; + + msge = rt_container_of(raw_buffer, struct virtio_scmi_event_msg_ext, event_msg); + + rt_list_init(&msge->list); + rt_list_insert_before(&vscmi->event_nodes, &msge->list); + + rt_work_submit(&vscmi->event_work, 0); + } + + rt_spin_unlock_irqrestore(&vscmi->lock, level); +} + +static rt_err_t virtio_scmi_vq_init(struct virtio_scmi *vscmi) +{ + rt_size_t vqs_nr; + const char *names[] = + { + "cmd", + "event" + }; + rt_virtqueue_callback cbs[] = + { + &virtio_scmi_cmd_done, + &virtio_scmi_event_done, + }; + + vqs_nr = rt_virtio_has_feature(vscmi->vdev, VIRTIO_SCMI_F_P2A_CHANNELS) ? + RT_ARRAY_SIZE(names) : 1; + + return rt_virtio_virtqueue_install(vscmi->vdev, vqs_nr, vscmi->vqs, names, cbs); +} + +static rt_err_t virtio_scmi_probe(struct rt_virtio_device *vdev) +{ + rt_err_t err; + struct virtio_scmi *vscmi = rt_calloc(1, sizeof(*vscmi)); + + if (!vscmi) + { + return -RT_ENOMEM; + } + + vdev->priv = vscmi; + vscmi->vdev = vdev; + vdev->parent.user_data = vscmi; + + if ((err = virtio_scmi_vq_init(vscmi)) < 0) + { + rt_free(vscmi); + + return err; + } + + if (rt_virtio_has_feature(vscmi->vdev, VIRTIO_SCMI_F_P2A_CHANNELS)) + { + rt_list_init(&vscmi->event_nodes); + rt_work_init(&vscmi->event_work, virtio_scmi_work, vscmi); + } + + rt_spin_lock_init(&vscmi->lock); + rt_completion_init(&vscmi->done); + + system_virtio_scmi = vscmi; + + return RT_EOK; +} + +static const struct rt_virtio_device_id virtio_scmi_ids[] = +{ + { VIRTIO_DEVICE_ID_SCMI, VIRTIO_DEVICE_ANY_ID }, + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_scmi_driver = +{ + .ids = virtio_scmi_ids, + .features = + RT_BIT(VIRTIO_SCMI_F_P2A_CHANNELS) + | RT_BIT(VIRTIO_SCMI_F_SHARED_MEMORY) + | RT_BIT(VIRTIO_F_ANY_LAYOUT), + + .probe = virtio_scmi_probe, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_scmi_driver); diff --git a/components/drivers/virtio/virtio-scsi.c b/components/drivers/virtio/virtio-scsi.c new file mode 100644 index 0000000000..7080f1fd16 --- /dev/null +++ b/components/drivers/virtio/virtio-scsi.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +#define DBG_TAG "virtio.dev.scsi" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include "virtio_config/virtio-scsi.h" +#include "virtio_internal.h" + +#define QUEUE_CONTROL 0 +#define QUEUE_EVENT 1 +#define QUEUE_REQUEST 2 + +struct virtio_scsi +{ + struct rt_scsi_host parent; + struct rt_virtio_device *vdev; + + struct rt_virtqueue *vqs[3]; + struct rt_completion done; + struct rt_spinlock lock; + + rt_uint16_t max_target; + rt_uint32_t max_lun; + struct rt_work hotplug_work; +}; + +static void virtio_scsi_init_cmd_req(struct virtio_scsi *vscsi, + struct rt_scsi_device *sdev, struct rt_scsi_cmd *cmd, + struct virtio_scsi_cmd_req *req) +{ + req->lun[0] = 1; + req->lun[1] = sdev->id; + req->lun[2] = (sdev->lun >> 8) | 0x40; + req->lun[3] = sdev->lun & 0xff; + req->tag = cpu_to_virtio64(vscsi->vdev, (rt_ubase_t)cmd); + req->task_attr = VIRTIO_SCSI_S_SIMPLE; + req->prio = 0; + req->crn = 0; +} + +static rt_err_t virtio_scsi_transfer(struct rt_scsi_device *sdev, + struct rt_scsi_cmd *cmd) +{ + rt_ubase_t level; + struct rt_virtqueue *vq; + struct virtio_scsi_cmd_req req; + struct virtio_scsi_cmd_resp resp; + struct virtio_scsi *vscsi = rt_container_of(sdev->host, struct virtio_scsi, parent); + + virtio_scsi_init_cmd_req(vscsi, sdev, cmd, &req); + + RT_ASSERT(cmd->op_size < sizeof(req.cdb)); + rt_memcpy(&req.cdb, &cmd->op, cmd->op_size); + + vq = vscsi->vqs[QUEUE_REQUEST]; + if (!cmd->data.ptr || !cmd->data.size) + { + rt_virtqueue_wait_prepare(vq, 2); + } + else + { + rt_virtqueue_wait_prepare(vq, 3); + } + + level = rt_spin_lock_irqsave(&vscsi->lock); + + rt_virtqueue_add_outbuf(vq, &req, sizeof(req)); + + if (!cmd->data.ptr || !cmd->data.size) + { + rt_virtqueue_add_inbuf(vq, &resp, sizeof(resp)); + } + else if (!rt_scsi_cmd_is_write(cmd)) + { + rt_virtqueue_add_inbuf(vq, &resp, sizeof(resp)); + rt_virtqueue_add_inbuf(vq, cmd->data.ptr, cmd->data.size); + } + else + { + rt_virtqueue_add_outbuf(vq, cmd->data.ptr, cmd->data.size); + rt_virtqueue_add_inbuf(vq, &resp, sizeof(resp)); + } + + rt_virtqueue_kick(vq); + + rt_spin_unlock_irqrestore(&vscsi->lock, level); + + rt_completion_wait(&vscsi->done, RT_WAITING_FOREVER); + + switch (resp.response) + { + case VIRTIO_SCSI_S_OK: + if (resp.sense_len) + { + rt_memcpy(&cmd->data.request_sense, &resp.sense, + rt_min_t(rt_uint32_t, + virtio32_to_cpu(vscsi->vdev, resp.sense_len), + VIRTIO_SCSI_SENSE_SIZE)); + } + return RT_EOK; + + case VIRTIO_SCSI_S_OVERRUN: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "OVERRUN"); + return -RT_ERROR; + + case VIRTIO_SCSI_S_ABORTED: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "ABORTED"); + return -RT_EIO; + + case VIRTIO_SCSI_S_BAD_TARGET: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "BAD_TARGET"); + return -RT_EINVAL; + + case VIRTIO_SCSI_S_RESET: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "RESET"); + return -RT_EIO; + + case VIRTIO_SCSI_S_BUSY: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "BUSY"); + return -RT_EBUSY; + + case VIRTIO_SCSI_S_TRANSPORT_FAILURE: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "TRANSPORT_FAILURE"); + return -RT_EIO; + + case VIRTIO_SCSI_S_TARGET_FAILURE: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "TARGET_FAILURE"); + return -RT_EIO; + + case VIRTIO_SCSI_S_NEXUS_FAILURE: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "NEXUS_FAILURE"); + return -RT_EIO; + + case VIRTIO_SCSI_S_FAILURE: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "FAILURE"); + return -RT_EIO; + + case VIRTIO_SCSI_S_FUNCTION_SUCCEEDED: + return RT_EOK; + + case VIRTIO_SCSI_S_FUNCTION_REJECTED: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "FUNCTION_REJECTED"); + return -RT_EINVAL; + + case VIRTIO_SCSI_S_INCORRECT_LUN: + LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "INCORRECT_LUN"); + return -RT_EINVAL; + + default: + LOG_E("%s resp = UNKNOWN(%d)", rt_dm_dev_get_name(sdev->host->dev), resp.response); + return -RT_EIO; + } +} + +static struct rt_scsi_ops virtio_scsi_ops = +{ + .transfer = virtio_scsi_transfer, +}; + +static void virtio_scsi_hotplug_work(struct rt_work *work, void *work_data) +{ + struct virtio_scsi *vscsi = work_data; + + if (!rt_scsi_host_unregister(&vscsi->parent)) + { + vscsi->parent.max_id = vscsi->max_target; + vscsi->parent.max_lun = vscsi->max_lun; + + rt_scsi_host_register(&vscsi->parent); + } +} + +static void virtio_scsi_request_done(struct rt_virtqueue *vq) +{ + rt_ubase_t level; + struct virtio_scsi *vscsi = vq->vdev->priv; + + level = rt_spin_lock_irqsave(&vscsi->lock); + + rt_virtqueue_read_buf(vq, RT_NULL); + rt_completion_done(&vscsi->done); + + rt_spin_unlock_irqrestore(&vscsi->lock, level); +} + +static void virtio_scsi_config_changed(struct rt_virtio_device *vdev) +{ + struct virtio_scsi *vscsi = vdev->priv; + + rt_virtio_read_config(vdev, struct virtio_scsi_config, + max_target, &vscsi->max_target); + rt_virtio_read_config(vdev, struct virtio_scsi_config, + max_lun, &vscsi->max_lun); + + if (vscsi->parent.max_id != vscsi->max_target || + vscsi->parent.max_lun != vscsi->max_lun) + { + rt_work_submit(&vscsi->hotplug_work, 0); + } +} + +static rt_err_t virtio_scsi_vq_init(struct virtio_scsi *vscsi) +{ + const char *names[] = + { + RT_NULL, /* ctrl */ + RT_NULL, /* event */ + "req", + }; + rt_virtqueue_callback cbs[] = + { + RT_NULL, + RT_NULL, + &virtio_scsi_request_done, + }; + + return rt_virtio_virtqueue_install(vscsi->vdev, RT_ARRAY_SIZE(vscsi->vqs), + vscsi->vqs, names, cbs); +} + +static void virtio_scsi_vq_finit(struct virtio_scsi *vscsi) +{ + if (vscsi->vqs[0]) + { + rt_virtio_virtqueue_release(vscsi->vdev); + } +} + +static rt_err_t virtio_scsi_probe(struct rt_virtio_device *vdev) +{ + rt_err_t err; + rt_uint32_t cdb_size; + struct virtio_scsi *vscsi = rt_calloc(1, sizeof(*vscsi)); + + if (!vscsi) + { + return -RT_ENOMEM; + } + + vdev->priv = vscsi; + vscsi->vdev = vdev; + vdev->parent.user_data = vscsi; + vscsi->parent.dev = &vdev->parent; + vscsi->parent.ops = &virtio_scsi_ops; + + rt_virtio_read_config(vdev, struct virtio_scsi_config, + max_target, &vscsi->max_target); + rt_virtio_read_config(vdev, struct virtio_scsi_config, + max_lun, &vscsi->max_lun); + + vscsi->parent.max_id = vscsi->max_target; + vscsi->parent.max_lun = vscsi->max_lun; + + if ((err = virtio_scsi_vq_init(vscsi))) + { + goto _fail; + } + + cdb_size = RT_ALIGN(sizeof(((struct rt_scsi_cmd *)RT_NULL)->op), 32); + rt_virtio_write_config(vdev, struct virtio_scsi_config, cdb_size, cdb_size); + + rt_completion_init(&vscsi->done); + rt_spin_lock_init(&vscsi->lock); + + rt_work_init(&vscsi->hotplug_work, virtio_scsi_hotplug_work, vscsi); + + if ((err = rt_scsi_host_register(&vscsi->parent))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + virtio_scsi_vq_finit(vscsi); + rt_free(vscsi); + + return err; +} + +static rt_err_t virtio_scsi_remove(struct rt_virtio_device *vdev) +{ + struct virtio_scsi *vscsi = vdev->parent.user_data; + + rt_scsi_host_unregister(&vscsi->parent); + + virtio_scsi_vq_finit(vscsi); + rt_free(vscsi); + + return RT_EOK; +} + +static const struct rt_virtio_device_id virtio_scsi_ids[] = +{ + { VIRTIO_DEVICE_ID_SCSI, VIRTIO_DEVICE_ANY_ID }, + { /* sentinel */ } +}; + +static struct rt_virtio_driver virtio_scsi_driver = +{ + .ids = virtio_scsi_ids, + .features = + RT_BIT(VIRTIO_F_ANY_LAYOUT), + + .probe = virtio_scsi_probe, + .remove = virtio_scsi_remove, + .config_changed = virtio_scsi_config_changed, +}; +RT_VIRTIO_DRIVER_EXPORT(virtio_scsi_driver); diff --git a/components/drivers/virtio/virtio.c b/components/drivers/virtio/virtio.c index a7937dfaee..083922eaf4 100644 --- a/components/drivers/virtio/virtio.c +++ b/components/drivers/virtio/virtio.c @@ -6,468 +6,356 @@ * Change Logs: * Date Author Notes * 2021-11-11 GuEe-GUI the first version - * 2023-10-12 fangjianzhou support SDL2 + * 2023-04-13 ErikChan add virtio bus */ +#include <rtatomic.h> #include <rtthread.h> -#include <cpuport.h> -#include <virtio.h> +#define DBG_TAG "rtdm.virtio" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> -rt_inline void _virtio_dev_check(struct virtio_device *dev) -{ - RT_ASSERT(dev != RT_NULL); - RT_ASSERT(dev->mmio_config != RT_NULL); -} +#include <cpuport.h> -void virtio_reset_device(struct virtio_device *dev) +#include <drivers/virtio.h> +#include <drivers/core/bus.h> + +void rt_virtio_device_ready(struct rt_virtio_device *vdev) { - _virtio_dev_check(dev); + rt_uint8_t status; - dev->mmio_config->status = 0; -} + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->trans != RT_NULL); -void virtio_status_acknowledge_driver(struct virtio_device *dev) -{ - _virtio_dev_check(dev); + if (!vdev->trans->get_status(vdev, &status)) + { + if (status & VIRTIO_STATUS_DRIVER_OK) + { + LOG_W("%s device driver is OK yet"); + } - dev->mmio_config->status |= VIRTIO_STATUS_ACKNOWLEDGE | VIRTIO_STATUS_DRIVER; + vdev->trans->set_status(vdev, status | VIRTIO_STATUS_DRIVER_OK); + } } -void virtio_status_driver_ok(struct virtio_device *dev) +void rt_virtio_device_reset(struct rt_virtio_device *vdev) { - _virtio_dev_check(dev); + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->trans != RT_NULL); - dev->mmio_config->status |= VIRTIO_STATUS_FEATURES_OK | VIRTIO_STATUS_DRIVER_OK; + vdev->trans->reset(vdev); } -void virtio_interrupt_ack(struct virtio_device *dev) +void rt_virtio_device_config_changed(struct rt_virtio_device *vdev) { - rt_uint32_t status; + struct rt_virtio_driver *vdrv; - _virtio_dev_check(dev); + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->parent.drv != RT_NULL); - status = dev->mmio_config->interrupt_status; + vdrv = rt_container_of(vdev->parent.drv, struct rt_virtio_driver, parent); - if (status != 0) + if (vdrv->config_changed) { - dev->mmio_config->interrupt_ack = status; + vdrv->config_changed(vdev); } } -rt_bool_t virtio_has_feature(struct virtio_device *dev, rt_uint32_t feature_bit) +void rt_virtio_add_status(struct rt_virtio_device *vdev, rt_uint32_t status) { - _virtio_dev_check(dev); + rt_uint8_t cur_status; + + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->trans != RT_NULL); - return !!(dev->mmio_config->device_features & (1UL << feature_bit)); + if (!vdev->trans->get_status(vdev, &cur_status)) + { + vdev->trans->set_status(vdev, cur_status | status); + } } -rt_err_t virtio_queues_alloc(struct virtio_device *dev, rt_size_t queues_num) +rt_bool_t rt_virtio_has_status(struct rt_virtio_device *vdev, rt_uint8_t status_bit) { - _virtio_dev_check(dev); + rt_uint8_t status; - dev->queues = rt_malloc(sizeof(struct virtq) * queues_num); + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->trans != RT_NULL); - if (dev->queues != RT_NULL) + if (!vdev->trans->get_status(vdev, &status)) { - dev->queues_num = queues_num; - - return RT_EOK; + return (status & RT_BIT(status_bit)) != 0; } - return -RT_ENOMEM; + return RT_FALSE; } -void virtio_queues_free(struct virtio_device *dev) +rt_bool_t rt_virtio_has_feature(struct rt_virtio_device *vdev, rt_uint32_t feature_bit) { - if (dev->queues != RT_NULL) - { - dev->queues_num = 0; - rt_free(dev->queues); - } + RT_ASSERT(vdev != RT_NULL); + + return (vdev->features & RT_BIT(feature_bit)) != 0; } -rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t ring_size) +rt_err_t rt_virtio_get_config(struct rt_virtio_device *vdev, rt_uint32_t offset, void *dst, int length) { - int i; - void *pages; - rt_size_t pages_total_size; - struct virtq *queue; + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->trans != RT_NULL); - _virtio_dev_check(dev); + return vdev->trans->get_config(vdev, offset, dst, length); +} - RT_ASSERT(queue_index < dev->queues_num); - /* ring_size is power of 2 */ - RT_ASSERT(ring_size > 0); - RT_ASSERT(((ring_size - 1) & ring_size) == 0); +rt_err_t rt_virtio_set_config(struct rt_virtio_device *vdev, rt_uint32_t offset, const void *src, int length) +{ + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->trans != RT_NULL); - /* Select the queue first, then read queue_num_max */ - dev->mmio_config->queue_sel = queue_index; - RT_ASSERT(dev->mmio_config->queue_num_max > 0); - RT_ASSERT(ring_size <= dev->mmio_config->queue_num_max); + return vdev->trans->set_config(vdev, offset, src, length); +} - queue = &dev->queues[queue_index]; - pages_total_size = VIRTIO_PAGE_ALIGN( - VIRTQ_DESC_TOTAL_SIZE(ring_size) + VIRTQ_AVAIL_TOTAL_SIZE(ring_size)) + VIRTQ_USED_TOTAL_SIZE(ring_size); +rt_err_t rt_virtio_virtqueue_install(struct rt_virtio_device *vdev, int vqs_nr, + struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[]) +{ + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->trans != RT_NULL); + RT_ASSERT(vqs_nr >= 0); + RT_ASSERT(vqs != RT_NULL); + RT_ASSERT(names != RT_NULL); + RT_ASSERT(cbs != RT_NULL); - pages = rt_malloc_align(pages_total_size, VIRTIO_PAGE_SIZE); + return vdev->trans->install_vqs(vdev, vqs_nr, vqs, names, cbs); +} - if (pages == RT_NULL) - { - return -RT_ENOMEM; - } +rt_err_t rt_virtio_virtqueue_release(struct rt_virtio_device *vdev) +{ + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->trans != RT_NULL); - queue->free = rt_malloc(sizeof(rt_bool_t) * ring_size); + return vdev->trans->release_vqs(vdev); +} - if (queue->free == RT_NULL) - { - rt_free_align(pages); - return -RT_ENOMEM; - } +rt_err_t rt_virtio_virtqueue_control(struct rt_virtio_device *vdev, rt_uint32_t cfg, void *data) +{ + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->trans != RT_NULL); - rt_memset(pages, 0, pages_total_size); + return vdev->trans->control_vqs(vdev, cfg, data); +} - dev->mmio_config->guest_page_size = VIRTIO_PAGE_SIZE; - dev->mmio_config->queue_num = ring_size; - dev->mmio_config->queue_align = VIRTIO_PAGE_SIZE; - dev->mmio_config->queue_pfn = VIRTIO_VA2PA(pages) >> VIRTIO_PAGE_SHIFT; +static const char *const virtio_device_id_name[] = +{ + [VIRTIO_DEVICE_ID_INVALID] = "invalid", + [VIRTIO_DEVICE_ID_NET] = "net", + [VIRTIO_DEVICE_ID_BLOCK] = "blk", + [VIRTIO_DEVICE_ID_CONSOLE] = "console", + [VIRTIO_DEVICE_ID_RNG] = "rng", + [VIRTIO_DEVICE_ID_RPMSG] = "rpmsg", + [VIRTIO_DEVICE_ID_SCSI] = "scsi", + [VIRTIO_DEVICE_ID_9P] = "9p", + [VIRTIO_DEVICE_ID_RPROC_SERIAL] = "rproc-serial", + [VIRTIO_DEVICE_ID_GPU] = "gpu", + [VIRTIO_DEVICE_ID_INPUT] = "input", + [VIRTIO_DEVICE_ID_CRYPTO] = "crypto", + [VIRTIO_DEVICE_ID_IOMMU] = "iommu", + [VIRTIO_DEVICE_ID_AUDIO] = "sound", + [VIRTIO_DEVICE_ID_SCMI] = "scmi", - queue->num = ring_size; - queue->desc = (struct virtq_desc *)((rt_ubase_t)pages); - queue->avail = (struct virtq_avail *)(((rt_ubase_t)pages) + VIRTQ_DESC_TOTAL_SIZE(ring_size)); - queue->used = (struct virtq_used *)VIRTIO_PAGE_ALIGN( - (rt_ubase_t)&queue->avail->ring[ring_size] + VIRTQ_AVAIL_RES_SIZE); + [VIRTIO_DEVICE_ID_MAX] = RT_NULL, +}; - queue->used_idx = 0; +const char *rt_virtio_device_id_name(struct rt_virtio_device *vdev) +{ + int device; + const char *name = RT_NULL; - /* All descriptors start out unused */ - for (i = 0; i < ring_size; ++i) - { - queue->free[i] = RT_TRUE; - } + RT_ASSERT(vdev != RT_NULL); - queue->free_count = ring_size; + device = vdev->id.device; - return RT_EOK; -} + if (device < RT_ARRAY_SIZE(virtio_device_id_name)) + { + name = virtio_device_id_name[device]; -void virtio_queue_destroy(struct virtio_device *dev, rt_uint32_t queue_index) -{ - struct virtq *queue; + if (!name) + { + name = "nosys"; + } - _virtio_dev_check(dev); + return name; + } - RT_ASSERT(queue_index < dev->queues_num); + return name; +} - /* Select the queue first, then read queue_num_max */ - dev->mmio_config->queue_sel = queue_index; - RT_ASSERT(dev->mmio_config->queue_num_max > 0); +static struct rt_bus virtio_bus; - queue = &dev->queues[queue_index]; +rt_err_t rt_virtio_driver_register(struct rt_virtio_driver *vdrv) +{ + const struct rt_virtio_device_id *id; - RT_ASSERT(queue->num > 0); + RT_ASSERT(vdrv != RT_NULL); - rt_free(queue->free); - rt_free_align((void *)queue->desc); + id = vdrv->ids; + while (id->device && (id + 1)->device) + { + ++id; + } - dev->mmio_config->queue_pfn = RT_NULL; + vdrv->parent.bus = &virtio_bus; +#if RT_NAME_MAX > 0 + rt_strcpy(vdrv->parent.parent.name, virtio_device_id_name[id->device]); +#else + vdrv->parent.parent.name = virtio_device_id_name[id->device]; +#endif - queue->num = 0; - queue->desc = RT_NULL; - queue->avail = RT_NULL; - queue->used = RT_NULL; + return rt_driver_register(&vdrv->parent); } -void virtio_queue_notify(struct virtio_device *dev, rt_uint32_t queue_index) +static struct rt_dm_ida virtio_ida = RT_DM_IDA_INIT(CUSTOM); + +rt_err_t rt_virtio_device_register(struct rt_virtio_device *vdev) { - _virtio_dev_check(dev); + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vdev->trans != RT_NULL); - dev->mmio_config->queue_notify = queue_index; -} + if ((vdev->idx = rt_dm_ida_alloc(&virtio_ida)) < 0) + { + return -RT_EFULL; + } -void virtio_submit_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index) -{ - rt_size_t ring_size; - struct virtq *queue; + rt_dm_dev_set_name(&vdev->parent, "virtio%u-%s", vdev->idx, + virtio_device_id_name[vdev->id.device]); - _virtio_dev_check(dev); + rt_list_init(&vdev->vq_node); - queue = &dev->queues[queue_index]; - ring_size = queue->num; + rt_spin_lock_init(&vdev->vq_lock); - /* Tell the device the first index in our chain of descriptors */ - queue->avail->ring[queue->avail->idx % ring_size] = desc_index; - rt_hw_dsb(); + rt_virtio_device_reset(vdev); + rt_virtio_add_status(vdev, VIRTIO_STATUS_ACKNOWLEDGE); - /* Tell the device another avail ring entry is available */ - queue->avail->idx++; - rt_hw_dsb(); + return rt_bus_add_device(&virtio_bus, &vdev->parent); } -rt_uint16_t virtio_alloc_desc(struct virtio_device *dev, rt_uint32_t queue_index) +static rt_bool_t virtio_match(rt_driver_t drv, rt_device_t dev) { - int i; - struct virtq *queue; + const struct rt_virtio_device_id *id; + struct rt_virtio_driver *vdrv = rt_container_of(drv, struct rt_virtio_driver, parent); + struct rt_virtio_device *vdev = rt_container_of(dev, struct rt_virtio_device, parent); - _virtio_dev_check(dev); - - RT_ASSERT(queue_index < dev->queues_num); - - queue = &dev->queues[queue_index]; - - if (queue->free_count > 0) + for (id = vdrv->ids; id->device; ++id) { - rt_size_t ring_size = queue->num; - - for (i = 0; i < ring_size; ++i) + if (id->device != vdev->id.device && id->device != VIRTIO_DEVICE_ANY_ID) { - if (queue->free[i]) - { - queue->free[i] = RT_FALSE; - queue->free_count--; + continue; + } - return (rt_uint16_t)i; - } + if (id->vendor == VIRTIO_DEVICE_ANY_ID || id->vendor == vdev->id.vendor) + { + return RT_TRUE; } } - return VIRTQ_INVALID_DESC_ID; + return RT_FALSE; } -void virtio_free_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index) +static rt_err_t virtio_probe(rt_device_t dev) { - struct virtq *queue; - - _virtio_dev_check(dev); + rt_err_t err; + rt_uint8_t status; + rt_uint64_t device_features, driver_features; + struct rt_virtio_driver *vdrv = rt_container_of(dev->drv, struct rt_virtio_driver, parent); + struct rt_virtio_device *vdev = rt_container_of(dev, struct rt_virtio_device, parent); - queue = &dev->queues[queue_index]; + rt_virtio_add_status(vdev, VIRTIO_STATUS_DRIVER); - RT_ASSERT(queue_index < dev->queues_num); - RT_ASSERT(!queue->free[desc_index]); + vdev->trans->get_features(vdev, &device_features); - queue->desc[desc_index].addr = 0; - queue->desc[desc_index].len = 0; - queue->desc[desc_index].flags = 0; - queue->desc[desc_index].next = 0; + driver_features = vdrv->features; - queue->free[desc_index] = RT_TRUE; - - queue->free_count++; -} + for (int i = VIRTIO_TRANSPORT_F_START; i <= VIRTIO_TRANSPORT_F_END; ++i) + { + rt_uint64_t flag = RT_BIT_ULL(i); -rt_err_t virtio_alloc_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t count, - rt_uint16_t *indexs) -{ - int i, j; + if (device_features & flag) + { + driver_features |= flag; + } + } - _virtio_dev_check(dev); + vdev->features = driver_features & device_features; - RT_ASSERT(indexs != RT_NULL); + err = vdev->trans->set_features(vdev); - if (dev->queues[queue_index].free_count < count) + if (err) { - return -RT_ERROR; + goto _err; } - for (i = 0; i < count; ++i) + if (rt_virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { - indexs[i] = virtio_alloc_desc(dev, queue_index); + rt_virtio_add_status(vdev, VIRTIO_STATUS_FEATURES_OK); + vdev->trans->get_status(vdev, &status); - if (indexs[i] == VIRTQ_INVALID_DESC_ID) + if (!(status & VIRTIO_STATUS_FEATURES_OK)) { - for (j = 0; j < i; ++j) - { - virtio_free_desc(dev, queue_index, indexs[j]); - } + LOG_E("%s device refuses features: %x", rt_dm_dev_get_name(dev), status); - return -RT_ERROR; + err = -RT_EIO; + goto _err; } } - return RT_EOK; -} - -void virtio_free_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index) -{ - rt_uint16_t flags, next; - struct virtq_desc *desc; - - _virtio_dev_check(dev); + err = vdrv->probe(vdev); - desc = &dev->queues[queue_index].desc[0]; - - for (;;) + if (err) { - flags = desc[desc_index].flags; - next = desc[desc_index].next; - - virtio_free_desc(dev, queue_index, desc_index); - - if (flags & VIRTQ_DESC_F_NEXT) - { - desc_index = next; - } - else - { - break; - } + goto _err; } -} - -void virtio_fill_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index, - rt_uint64_t addr, rt_uint32_t len, rt_uint16_t flags, rt_uint16_t next) -{ - struct virtq_desc *desc; - - _virtio_dev_check(dev); - desc = &dev->queues[queue_index].desc[desc_index]; + vdev->trans->get_status(vdev, &status); - desc->addr = addr; - desc->len = len; - desc->flags = flags; - desc->next = next; -} - -#ifdef RT_USING_SMART -#ifdef RT_USING_VIRTIO_GPU + if (!(status & VIRTIO_STATUS_DRIVER_OK)) + { + rt_virtio_device_ready(vdev); + } -#include <virtio_gpu.h> -#include "drivers/lcd.h" -#include <dfs_file.h> -#include <lwp_user_mm.h> + return RT_EOK; -static struct rt_device_graphic_info _graphic_info; -static struct rt_device_rect_info _rect_info; -static struct rt_device _fb = {}; -static rt_device_t _gpu_dev = RT_NULL; +_err: + rt_virtio_add_status(vdev, VIRTIO_STATUS_FAILED); -static rt_err_t fb_open(rt_device_t dev, rt_uint16_t oflag) -{ - return RT_EOK; + return err; } -static rt_err_t fb_close(rt_device_t dev) +static rt_err_t virtio_remove(rt_device_t dev) { - return RT_EOK; -} + struct rt_virtio_driver *vdrv = rt_container_of(dev->drv, struct rt_virtio_driver, parent); + struct rt_virtio_device *vdev = rt_container_of(dev, struct rt_virtio_device, parent); -static rt_err_t fb_control(rt_device_t dev, int cmd, void *args) -{ - switch(cmd) + if (vdrv && vdrv->remove) { - case FBIOPAN_DISPLAY: - { - rt_hw_cpu_dcache_clean(_graphic_info.framebuffer, _graphic_info.smem_len); - rt_device_control(_gpu_dev, RTGRAPHIC_CTRL_RECT_UPDATE, &_rect_info); - break; - } - case FBIOGET_FSCREENINFO: - { - struct fb_fix_screeninfo *info = (struct fb_fix_screeninfo *)args; - strncpy(info->id, "lcd", sizeof(info->id)); - info->smem_len = _graphic_info.smem_len; - break; - } - case FBIOGET_VSCREENINFO: - { - struct fb_var_screeninfo *info = (struct fb_var_screeninfo *)args; - info->bits_per_pixel = _graphic_info.bits_per_pixel; - info->xres = _graphic_info.width; - info->yres = _graphic_info.height; - info->yres_virtual = _graphic_info.height; - info->xres_virtual = _graphic_info.width; - info->transp.offset = 24; - info->transp.length = 8; - info->red.offset = 0; - info->red.length = 8; - info->green.offset = 8; - info->green.length = 8; - info->blue.offset = 16; - info->blue.length = 8; - break; - } - case RT_FIOMMAP2: - { - struct dfs_mmap2_args *mmap2 = (struct dfs_mmap2_args *)args; + vdrv->remove(vdev); + } - if(mmap2) - { - mmap2->ret = lwp_map_user_phy(lwp_self(), RT_NULL, rt_kmem_v2p(_graphic_info.framebuffer), mmap2->length, 1); - } - else - { - return -EIO; - } + rt_virtio_add_status(vdev, VIRTIO_STATUS_ACKNOWLEDGE); - break; - } - default: - break; - } + rt_dm_ida_free(&virtio_ida, vdev->idx); return RT_EOK; } -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops fb_ops = +static struct rt_bus virtio_bus = { - RT_NULL, - fb_open, - fb_close, - RT_NULL, - RT_NULL, - fb_control + .name = "virtio", + .match = virtio_match, + .probe = virtio_probe, + .remove = virtio_remove, }; -#endif -static int fb_init() +static int virtio_bus_init(void) { - _gpu_dev = rt_device_find("virtio-gpu0"); - - if(_gpu_dev == RT_NULL) - { - return -RT_ERROR; - } - - if(_gpu_dev != RT_NULL && rt_device_open(_gpu_dev, 0) == RT_EOK) - { - rt_memset(&_graphic_info, 0, sizeof(_graphic_info)); - rt_memset(&_rect_info, 0, sizeof(_rect_info)); - rt_device_control(_gpu_dev, VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY, RT_NULL); - rt_device_control(_gpu_dev, VIRTIO_DEVICE_CTRL_GPU_CREATE_2D, (void *)RTGRAPHIC_PIXEL_FORMAT_RGB888); - rt_device_control(_gpu_dev, RTGRAPHIC_CTRL_GET_INFO, &_graphic_info); - _rect_info.x = 0; - _rect_info.y = 0; - _rect_info.width = _graphic_info.width; - _rect_info.height = _graphic_info.height; - memset(_graphic_info.framebuffer, 0xff, _graphic_info.smem_len); - rt_device_control(_gpu_dev, RTGRAPHIC_CTRL_RECT_UPDATE, &_rect_info); - } - - if(rt_device_find("fb0") != RT_NULL) - { - rt_kprintf("a device named fb0 already exists\n"); - return -RT_ERROR; - } + rt_bus_register(&virtio_bus); - _fb.type = RT_Device_Class_Miscellaneous; - -#ifdef RT_USING_DEVICE_OPS - _fb.ops = &fb_ops; -#else - _fb.init = RT_NULL; - _fb.open = fb_open; - _fb.close = fb_close; - _fb.read = RT_NULL; - _fb.write = RT_NULL; - _fb.control = fb_control; - _fb.user_data = RT_NULL; -#endif - - rt_device_register(&_fb, "fb0", RT_DEVICE_FLAG_RDWR); - return RT_EOK; + return 0; } -INIT_COMPONENT_EXPORT(fb_init); -#endif -#endif +INIT_CORE_EXPORT(virtio_bus_init); diff --git a/components/drivers/virtio/virtio.h b/components/drivers/virtio/virtio.h deleted file mode 100644 index 3807585d82..0000000000 --- a/components/drivers/virtio/virtio.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-9-16 GuEe-GUI the first version - * 2021-11-11 GuEe-GUI modify to virtio common interface - */ - -#ifndef __VIRTIO_H__ -#define __VIRTIO_H__ - -#include <rthw.h> -#include <rtdef.h> - -#ifdef RT_USING_SMART -#include <mmu.h> -#include <ioremap.h> -#endif - -#if RT_NAME_MAX < 16 -#error "Please set RT_NAME_MAX to at lest 16" -#endif - -#ifdef RT_USING_VIRTIO10 -#define RT_USING_VIRTIO_VERSION 0x1 -#endif - -#include <virtio_mmio.h> -#include <virtio_queue.h> - -#define VIRTIO_MAGIC_VALUE 0x74726976 /* "virt" */ - -#define VIRTIO_STATUS_ACKNOWLEDGE (1 << 0) -#define VIRTIO_STATUS_DRIVER (1 << 1) -#define VIRTIO_STATUS_DRIVER_OK (1 << 2) -#define VIRTIO_STATUS_FEATURES_OK (1 << 3) -#define VIRTIO_STATUS_NEEDS_RESET (1 << 6) -#define VIRTIO_STATUS_FAILED (1 << 7) - -#define VIRTIO_F_NOTIFY_ON_EMPTY 24 -#define VIRTIO_F_ANY_LAYOUT 27 -#define VIRTIO_F_RING_INDIRECT_DESC 28 -#define VIRTIO_F_RING_EVENT_IDX 29 -#define VIRTIO_F_VERSION_1 32 -#define VIRTIO_F_RING_PACKED 34 - -#ifdef RT_USING_SMART -#define VIRTIO_VA2PA(vaddr) ((rt_ubase_t)rt_kmem_v2p(vaddr)) -#define VIRTIO_PA2VA(paddr) ((rt_ubase_t)rt_ioremap((void *)paddr, ARCH_PAGE_SIZE)) -#else -#define VIRTIO_VA2PA(vaddr) ((rt_ubase_t)vaddr) -#define VIRTIO_PA2VA(paddr) ((rt_ubase_t)paddr) -#endif /* RT_USING_SMART */ -#define VIRTIO_PAGE_SHIFT 12 -#define VIRTIO_PAGE_SIZE (1 << VIRTIO_PAGE_SHIFT) -#define VIRTIO_PAGE_ALIGN(addr) (RT_ALIGN(addr, VIRTIO_PAGE_SIZE)) - -enum -{ - /* virtio 1.0 */ - VIRTIO_DEVICE_ID_INVALID = 0, /* Invalid device */ - VIRTIO_DEVICE_ID_NET = 1, /* Net */ - VIRTIO_DEVICE_ID_BLOCK = 2, /* Block */ - VIRTIO_DEVICE_ID_CONSOLE = 3, /* Console */ - VIRTIO_DEVICE_ID_RNG = 4, /* Rng */ - VIRTIO_DEVICE_ID_BALLOON = 5, /* Balloon */ - VIRTIO_DEVICE_ID_IOMEM = 6, /* IO memory */ - VIRTIO_DEVICE_ID_RPMSG = 7, /* Remote processor messaging */ - VIRTIO_DEVICE_ID_SCSI = 8, /* SCSI */ - VIRTIO_DEVICE_ID_9P = 9, /* 9p console */ - VIRTIO_DEVICE_ID_MAC80211_WLAN = 10, /* Mac80211 wlan */ - VIRTIO_DEVICE_ID_RPROC_SERIAL = 11, /* Remoteproc serial link */ - VIRTIO_DEVICE_ID_CAIF = 12, /* CAIF */ - VIRTIO_DEVICE_ID_MEM_BALLOON = 13, /* Memory balloon */ - VIRTIO_DEVICE_ID_GPU = 16, /* GPU */ - VIRTIO_DEVICE_ID_TIME = 17, /* Timer/clock device */ - VIRTIO_DEVICE_ID_INPUT = 18, /* Input */ - /* virtio 1.1 */ - VIRTIO_DEVICE_ID_SOCKET = 19, /* Socket device */ - VIRTIO_DEVICE_ID_CRYPTO = 20, /* Crypto device */ - VIRTIO_DEVICE_ID_SIG_DIS_MOD = 21, /* Signal Distribution Module */ - VIRTIO_DEVICE_ID_PSTORE = 22, /* Pstore device */ - VIRTIO_DEVICE_ID_IOMMU = 23, /* IOMMU device */ - VIRTIO_DEVICE_ID_MEM = 24, /* Memory device */ - /* virtio 1.2 */ - VIRTIO_DEVICE_ID_AUDIO = 25, /* Audio device */ - VIRTIO_DEVICE_ID_FS = 26, /* File system device */ - VIRTIO_DEVICE_ID_PMEM = 27, /* PMEM device */ - VIRTIO_DEVICE_ID_RPMB = 28, /* RPMB device */ - VIRTIO_DEVICE_ID_MAC80211_HWSIM = 29, /* Mac80211 hwsim wireless simulation device */ - VIRTIO_DEVICE_ID_VIDEO_ENCODER = 30, /* Video encoder device */ - VIRTIO_DEVICE_ID_VIDEO_DECODER = 31, /* Video decoder device */ - VIRTIO_DEVICE_ID_SCMI = 32, /* SCMI device */ - VIRTIO_DEVICE_ID_NITRO_SEC_MOD = 33, /* NitroSecureModule */ - VIRTIO_DEVICE_ID_I2C_ADAPTER = 34, /* I2C adapter */ - VIRTIO_DEVICE_ID_WATCHDOG = 35, /* Watchdog */ - VIRTIO_DEVICE_ID_CAN = 36, /* CAN device */ - VIRTIO_DEVICE_ID_DMABUF = 37, /* Virtio dmabuf */ - VIRTIO_DEVICE_ID_PARAM_SERV = 38, /* Parameter Server */ - VIRTIO_DEVICE_ID_AUDIO_POLICY = 39, /* Audio policy device */ - VIRTIO_DEVICE_ID_BT = 40, /* Bluetooth device */ - VIRTIO_DEVICE_ID_GPIO = 41, /* GPIO device */ - VIRTIO_DEVICE_ID_RDMA = 42, /* RDMA device */ - - VIRTIO_DEVICE_TYPE_SIZE -}; - -struct virtio_device -{ - rt_uint32_t irq; - - struct virtq *queues; - rt_size_t queues_num; - - union - { - rt_ubase_t *mmio_base; - struct virtio_mmio_config *mmio_config; - }; - -#ifdef RT_USING_SMP - struct rt_spinlock spinlock; -#endif - - void *priv; -}; - -typedef rt_err_t (*virtio_device_init_handler)(rt_ubase_t *mmio_base, rt_uint32_t irq); - -void virtio_reset_device(struct virtio_device *dev); -void virtio_status_acknowledge_driver(struct virtio_device *dev); -void virtio_status_driver_ok(struct virtio_device *dev); -void virtio_interrupt_ack(struct virtio_device *dev); -rt_bool_t virtio_has_feature(struct virtio_device *dev, rt_uint32_t feature_bit); - -rt_err_t virtio_queues_alloc(struct virtio_device *dev, rt_size_t queues_num); -void virtio_queues_free(struct virtio_device *dev); -rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t ring_size); -void virtio_queue_destroy(struct virtio_device *dev, rt_uint32_t queue_index); -void virtio_queue_notify(struct virtio_device *dev, rt_uint32_t queue_index); - -void virtio_submit_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index); - -rt_uint16_t virtio_alloc_desc(struct virtio_device *dev, rt_uint32_t queue_index); -void virtio_free_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index); -rt_err_t virtio_alloc_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t count, - rt_uint16_t *indexs); -void virtio_free_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index); -void virtio_fill_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index, - rt_uint64_t addr, rt_uint32_t len, rt_uint16_t flags, rt_uint16_t next); - -#endif /* __VIRTIO_H__ */ diff --git a/components/drivers/virtio/virtio_blk.c b/components/drivers/virtio/virtio_blk.c deleted file mode 100644 index 4161e5907b..0000000000 --- a/components/drivers/virtio/virtio_blk.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-9-16 GuEe-GUI the first version - * 2021-11-11 GuEe-GUI using virtio common interface - */ - -#include <rthw.h> -#include <rtthread.h> -#include <cpuport.h> -#include <rtdevice.h> - -#ifdef RT_USING_VIRTIO_BLK - -#include <virtio_blk.h> - -static void virtio_blk_rw(struct virtio_blk_device *virtio_blk_dev, rt_off_t pos, void *buffer, rt_size_t count, - int flags) -{ - rt_uint16_t idx[3]; - rt_size_t size = count * virtio_blk_dev->config->blk_size; - struct virtio_device *virtio_dev = &virtio_blk_dev->virtio_dev; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - - /* Allocate 3 descriptors */ - while (virtio_alloc_desc_chain(virtio_dev, 0, 3, idx)) - { -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif - rt_thread_yield(); - -#ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - } - - virtio_blk_dev->info[idx[0]].status = 0xff; - virtio_blk_dev->info[idx[0]].valid = RT_TRUE; - virtio_blk_dev->info[idx[0]].req.type = flags; - virtio_blk_dev->info[idx[0]].req.ioprio = 0; - virtio_blk_dev->info[idx[0]].req.sector = pos * (virtio_blk_dev->config->blk_size / 512); - - flags = flags == VIRTIO_BLK_T_OUT ? 0 : VIRTQ_DESC_F_WRITE; - - virtio_fill_desc(virtio_dev, VIRTIO_BLK_QUEUE, idx[0], - VIRTIO_VA2PA(&virtio_blk_dev->info[idx[0]].req), sizeof(struct virtio_blk_req), VIRTQ_DESC_F_NEXT, idx[1]); - - virtio_fill_desc(virtio_dev, VIRTIO_BLK_QUEUE, idx[1], - VIRTIO_VA2PA(buffer), size, flags | VIRTQ_DESC_F_NEXT, idx[2]); - - virtio_fill_desc(virtio_dev, VIRTIO_BLK_QUEUE, idx[2], - VIRTIO_VA2PA(&virtio_blk_dev->info[idx[0]].status), sizeof(rt_uint8_t), VIRTQ_DESC_F_WRITE, 0); - - virtio_submit_chain(virtio_dev, VIRTIO_BLK_QUEUE, idx[0]); - - virtio_queue_notify(virtio_dev, VIRTIO_BLK_QUEUE); - - /* Wait for virtio_blk_isr() to done */ - while (virtio_blk_dev->info[idx[0]].valid) - { -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif - rt_thread_yield(); - -#ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - } - - virtio_free_desc_chain(virtio_dev, VIRTIO_BLK_QUEUE, idx[0]); - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif -} - -static rt_ssize_t virtio_blk_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t count) -{ - virtio_blk_rw((struct virtio_blk_device *)dev, pos, buffer, count, VIRTIO_BLK_T_IN); - - return count; -} - -static rt_ssize_t virtio_blk_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t count) -{ - virtio_blk_rw((struct virtio_blk_device *)dev, pos, (void *)buffer, count, VIRTIO_BLK_T_OUT); - - return count; -} - -static rt_err_t virtio_blk_control(rt_device_t dev, int cmd, void *args) -{ - rt_err_t status = RT_EOK; - struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)dev; - - switch (cmd) - { - case RT_DEVICE_CTRL_BLK_GETGEOME: - { - struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *)args; - - if (geometry == RT_NULL) - { - status = -RT_ERROR; - break; - } - - geometry->bytes_per_sector = VIRTIO_BLK_BYTES_PER_SECTOR; - geometry->block_size = virtio_blk_dev->config->blk_size; - geometry->sector_count = virtio_blk_dev->config->capacity; - } - break; - default: - status = -RT_EINVAL; - break; - } - - return status; -} - -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops virtio_blk_ops = -{ - RT_NULL, - RT_NULL, - RT_NULL, - virtio_blk_read, - virtio_blk_write, - virtio_blk_control -}; -#endif - -static void virtio_blk_isr(int irqno, void *param) -{ - rt_uint32_t id; - struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)param; - struct virtio_device *virtio_dev = &virtio_blk_dev->virtio_dev; - struct virtq *queue = &virtio_dev->queues[VIRTIO_BLK_QUEUE]; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - - virtio_interrupt_ack(virtio_dev); - rt_hw_dsb(); - - /* The device increments disk.used->idx when it adds an entry to the used ring */ - while (queue->used_idx != queue->used->idx) - { - rt_hw_dsb(); - id = queue->used->ring[queue->used_idx % queue->num].id; - - RT_ASSERT(virtio_blk_dev->info[id].status == 0); - - /* Done with buffer */ - virtio_blk_dev->info[id].valid = RT_FALSE; - - queue->used_idx++; - } - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif -} - -rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq) -{ - static int dev_no = 0; - char dev_name[RT_NAME_MAX]; - struct virtio_device *virtio_dev; - struct virtio_blk_device *virtio_blk_dev; - - virtio_blk_dev = rt_malloc(sizeof(struct virtio_blk_device)); - - if (virtio_blk_dev == RT_NULL) - { - return -RT_ENOMEM; - } - - virtio_dev = &virtio_blk_dev->virtio_dev; - virtio_dev->irq = irq; - virtio_dev->mmio_base = mmio_base; - - virtio_blk_dev->config = (struct virtio_blk_config *)virtio_dev->mmio_config->config; - -#ifdef RT_USING_SMP - rt_spin_lock_init(&virtio_dev->spinlock); -#endif - - virtio_reset_device(virtio_dev); - virtio_status_acknowledge_driver(virtio_dev); - - /* Negotiate features */ - virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~( - (1 << VIRTIO_BLK_F_RO) | - (1 << VIRTIO_BLK_F_MQ) | - (1 << VIRTIO_BLK_F_SCSI) | - (1 << VIRTIO_BLK_F_CONFIG_WCE) | - (1 << VIRTIO_F_ANY_LAYOUT) | - (1 << VIRTIO_F_RING_EVENT_IDX) | - (1 << VIRTIO_F_RING_INDIRECT_DESC)); - - /* Tell device that feature negotiation is complete and we're completely ready */ - virtio_status_driver_ok(virtio_dev); - - if (virtio_queues_alloc(virtio_dev, 1) != RT_EOK) - { - goto _alloc_fail; - } - - /* Initialize queue 0 */ - if (virtio_queue_init(virtio_dev, 0, VIRTIO_BLK_QUEUE_RING_SIZE) != RT_EOK) - { - goto _alloc_fail; - } - - virtio_blk_dev->parent.type = RT_Device_Class_Block; -#ifdef RT_USING_DEVICE_OPS - virtio_blk_dev->parent.ops = &virtio_blk_ops; -#else - virtio_blk_dev->parent.init = RT_NULL; - virtio_blk_dev->parent.open = RT_NULL; - virtio_blk_dev->parent.close = RT_NULL; - virtio_blk_dev->parent.read = virtio_blk_read; - virtio_blk_dev->parent.write = virtio_blk_write; - virtio_blk_dev->parent.control = virtio_blk_control; -#endif - - rt_snprintf(dev_name, RT_NAME_MAX, "virtio-blk%d", dev_no++); - - rt_hw_interrupt_install(irq, virtio_blk_isr, virtio_blk_dev, dev_name); - rt_hw_interrupt_umask(irq); - - return rt_device_register((rt_device_t)virtio_blk_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE); - -_alloc_fail: - - if (virtio_blk_dev != RT_NULL) - { - virtio_queues_free(virtio_dev); - rt_free(virtio_blk_dev); - } - return -RT_ENOMEM; -} -#endif /* RT_USING_VIRTIO_BLK */ diff --git a/components/drivers/virtio/virtio_blk.h b/components/drivers/virtio/virtio_blk.h deleted file mode 100644 index 21ac7a1c85..0000000000 --- a/components/drivers/virtio/virtio_blk.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-9-16 GuEe-GUI the first version - * 2021-11-11 GuEe-GUI using virtio common interface - */ - -#ifndef __VIRTIO_BLK_H__ -#define __VIRTIO_BLK_H__ - -#include <rtdef.h> - -#include <virtio.h> - -#define VIRTIO_BLK_QUEUE 0 -#define VIRTIO_BLK_BYTES_PER_SECTOR 512 -#define VIRTIO_BLK_QUEUE_RING_SIZE 4 - -#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ -#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ -#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */ -#define VIRTIO_BLK_F_MQ 12 /* Support more than one vq */ - -#define VIRTIO_BLK_T_IN 0 /* Read the blk */ -#define VIRTIO_BLK_T_OUT 1 /* Write the blk */ -#define VIRTIO_BLK_T_SCSI_CMD 2 -#define VIRTIO_BLK_T_SCSI_CMD_OUT 3 -#define VIRTIO_BLK_T_FLUSH 4 -#define VIRTIO_BLK_T_FLUSH_OUT 5 - -struct virtio_blk_req -{ - rt_uint32_t type; - rt_uint32_t ioprio; - rt_uint64_t sector; -}; - -struct virtio_blk_config -{ - rt_uint64_t capacity; /* The capacity (in 512-byte sectors). */ - rt_uint32_t size_max; /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */ - rt_uint32_t seg_max; /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */ - - /* Geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */ - struct virtio_blk_geometry - { - rt_uint16_t cylinders; - rt_uint8_t heads; - rt_uint8_t sectors; - } geometry; - - rt_uint32_t blk_size; /* Block size of device (if VIRTIO_BLK_F_BLK_SIZE) */ - - struct virtio_blk_topology - { - /* # Of logical blocks per physical block (log2) */ - rt_uint8_t physical_block_exp; - /* Offset of first aligned logical block */ - rt_uint8_t alignment_offset; - /* Suggested minimum I/O size in blocks */ - rt_uint16_t min_io_size; - /* Optimal (suggested maximum) I/O size in blocks */ - rt_uint32_t opt_io_size; - } topology; - - rt_uint8_t writeback; - rt_uint8_t unused0; - rt_uint16_t num_queues; - rt_uint32_t max_discard_sectors; - rt_uint32_t max_discard_seg; - rt_uint32_t discard_sector_alignment; - rt_uint32_t max_write_zeroes_sectors; - rt_uint32_t max_write_zeroes_seg; - rt_uint8_t write_zeroes_may_unmap; - rt_uint8_t unused1[3]; - rt_uint32_t max_secure_erase_sectors; - rt_uint32_t max_secure_erase_seg; - rt_uint32_t secure_erase_sector_alignment; -} __attribute__((packed)); - -struct virtio_blk_device -{ - struct rt_device parent; - - struct virtio_device virtio_dev; - - struct virtio_blk_config *config; - - struct - { - rt_bool_t valid; - rt_uint8_t status; - - struct virtio_blk_req req; - - } info[VIRTIO_BLK_QUEUE_RING_SIZE]; -}; - -rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq); - -#endif /* __VIRTIO_BLK_H__ */ diff --git a/components/drivers/virtio/virtio_config/virtio-9p.h b/components/drivers/virtio/virtio_config/virtio-9p.h new file mode 100644 index 0000000000..be870d9984 --- /dev/null +++ b/components/drivers/virtio/virtio_config/virtio-9p.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#ifndef __VIRTIO_9P_H__ +#define __VIRTIO_9P_H__ + +#include <drivers/core/dm.h> + +#define VIRTIO_9P_F_MOUNT_TAG 0 + +rt_packed(struct virtio_9p_config +{ + /* length of the tag name */ + rt_le16_t tag_len; + /* non-NULL terminated tag name */ + rt_uint8_t tag[]; +}); + +#endif /* __VIRTIO_9P_H__ */ diff --git a/components/drivers/virtio/virtio_config/virtio-blk.h b/components/drivers/virtio/virtio_config/virtio-blk.h new file mode 100644 index 0000000000..045aa78087 --- /dev/null +++ b/components/drivers/virtio/virtio_config/virtio-blk.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-9-16 GuEe-GUI the first version + * 2021-11-11 GuEe-GUI using virtio common interface + * 2023-02-25 GuEe-GUI using virtio dm + */ + +#ifndef __VIRTIO_BLK_H__ +#define __VIRTIO_BLK_H__ + +#include <drivers/core/dm.h> + +#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */ +#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */ +#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */ +#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ +#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ +#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ +#define VIRTIO_BLK_F_FLUSH 9 /* Flush command supported */ +#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */ +#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */ +#define VIRTIO_BLK_F_MQ 12 /* Support more than one vq */ +#define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */ +#define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */ +#define VIRTIO_BLK_F_SECURE_ERASE 16 /* Secure Erase is supported */ + +#define VIRTIO_BLK_T_IN 0 /* Read the blk */ +#define VIRTIO_BLK_T_OUT 1 /* Write the blk */ +#define VIRTIO_BLK_T_SCSI_CMD 2 +#define VIRTIO_BLK_T_SCSI_CMD_OUT 3 +#define VIRTIO_BLK_T_FLUSH 4 +#define VIRTIO_BLK_T_FLUSH_OUT 5 +#define VIRTIO_BLK_T_GET_ID 8 /* Get device ID command */ +#define VIRTIO_BLK_T_DISCARD 11 /* Discard command */ +#define VIRTIO_BLK_T_WRITE_ZEROES 13 /* Write zeroes command */ +#define VIRTIO_BLK_T_SECURE_ERASE 14 /* Secure erase command */ +#define VIRTIO_BLK_T_ZONE_APPEND 15 /* Zone append command */ +#define VIRTIO_BLK_T_ZONE_REPORT 16 /* Report zones command */ +#define VIRTIO_BLK_T_ZONE_OPEN 18 /* Open zone command */ +#define VIRTIO_BLK_T_ZONE_CLOSE 20 /* Close zone command */ +#define VIRTIO_BLK_T_ZONE_FINISH 22 /* Finish zone command */ +#define VIRTIO_BLK_T_ZONE_RESET 24 /* Reset zone command */ +#define VIRTIO_BLK_T_ZONE_RESET_ALL 26 /* Reset All zones command */ + +struct virtio_blk_req +{ + rt_le32_t type; + rt_le32_t ioprio; + rt_le64_t sector; + +#define VIRTIO_BLK_S_OK 0 +#define VIRTIO_BLK_S_IOERR 1 +#define VIRTIO_BLK_S_UNSUPP 2 +#define VIRTIO_BLK_S_ZONE_INVALID_CMD 3 +#define VIRTIO_BLK_S_ZONE_UNALIGNED_WP 4 +#define VIRTIO_BLK_S_ZONE_OPEN_RESOURCE 5 +#define VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE 6 + /* + * next: + * rt_uint8_t data[]; + * rt_uint8_t status; + */ +}; + +struct virtio_blk_discard_write_zeroes +{ + rt_le64_t sector; + rt_le32_t num_sectors; + + /* + * unmap:1 + * reserved:31 + */ + rt_le32_t flags; +}; + +rt_packed(struct virtio_blk_config +{ + /* The capacity (in 512-byte sectors). */ + rt_le64_t capacity; + /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */ + rt_le32_t size_max; + /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */ + rt_le32_t seg_max; + + /* Geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */ + struct virtio_blk_geometry + { + rt_le16_t cylinders; + rt_uint8_t heads; + rt_uint8_t sectors; + } geometry; + + /* Block size of device (if VIRTIO_BLK_F_BLK_SIZE) */ + rt_le32_t blk_size; + + struct virtio_blk_topology + { + /* # Of logical blocks per physical block (log2) */ + rt_uint8_t physical_block_exp; + /* Offset of first aligned logical block */ + rt_uint8_t alignment_offset; + /* Suggested minimum I/O size in blocks */ + rt_le16_t min_io_size; + /* Optimal (suggested maximum) I/O size in blocks */ + rt_le32_t opt_io_size; + } topology; + + rt_uint8_t writeback; + rt_uint8_t unused0; + rt_uint16_t num_queues; + rt_le32_t max_discard_sectors; + rt_le32_t max_discard_seg; + rt_le32_t discard_sector_alignment; + rt_le32_t max_write_zeroes_sectors; + rt_le32_t max_write_zeroes_seg; + rt_uint8_t write_zeroes_may_unmap; + rt_uint8_t unused1[3]; + rt_le32_t max_secure_erase_sectors; + rt_le32_t max_secure_erase_seg; + rt_le32_t secure_erase_sector_alignment; +}); + +#endif /* __VIRTIO_BLK_H__ */ diff --git a/components/drivers/virtio/virtio_config/virtio-console.h b/components/drivers/virtio/virtio_config/virtio-console.h new file mode 100644 index 0000000000..cf51ab41a4 --- /dev/null +++ b/components/drivers/virtio/virtio_config/virtio-console.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-11-11 GuEe-GUI the first version + * 2023-02-25 GuEe-GUI using virtio dm + */ + +#ifndef __VIRTIO_CONSOLE_H__ +#define __VIRTIO_CONSOLE_H__ + +#include <drivers/core/dm.h> + +#define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */ +#define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */ +#define VIRTIO_CONSOLE_F_EMERG_WRITE 2 /* Does host support emergency write? */ + +rt_packed(struct virtio_console_config +{ + rt_le16_t cols; + rt_le16_t rows; + rt_le32_t max_nr_ports; + rt_le32_t emerg_wr; +}); + +rt_packed(struct virtio_console_resize +{ + rt_le16_t cols; + rt_le16_t rows; +}); + +rt_packed(struct virtio_console_control +{ +#define VIRTIO_CONSOLE_BAD_ID (~(rt_uint32_t)0) + rt_le32_t id; /* Port number */ + +#define VIRTIO_CONSOLE_DEVICE_READY 0 +#define VIRTIO_CONSOLE_PORT_ADD 1 +#define VIRTIO_CONSOLE_PORT_REMOVE 2 +#define VIRTIO_CONSOLE_PORT_READY 3 +#define VIRTIO_CONSOLE_CONSOLE_PORT 4 +#define VIRTIO_CONSOLE_RESIZE 5 +#define VIRTIO_CONSOLE_PORT_OPEN 6 +#define VIRTIO_CONSOLE_PORT_NAME 7 + rt_le16_t event; /* The kind of control event */ + rt_le16_t value; /* Extra information for the event */ +}); + +rt_packed(struct virtio_console_control_ext +{ + struct virtio_console_control ctrl; + + union + { + struct virtio_console_resize resize; + rt_uint8_t data[64]; + }; +}); + +#endif /* __VIRTIO_CONSOLE_H__ */ diff --git a/components/drivers/virtio/virtio_config/virtio-crypto.h b/components/drivers/virtio/virtio_config/virtio-crypto.h new file mode 100644 index 0000000000..49df7ef96c --- /dev/null +++ b/components/drivers/virtio/virtio_config/virtio-crypto.h @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#ifndef __VIRTIO_CRYPTO_H__ +#define __VIRTIO_CRYPTO_H__ + +#include <drivers/core/dm.h> + +#define VIRTIO_CRYPTO_SERVICE_CIPHER 0 +#define VIRTIO_CRYPTO_SERVICE_HASH 1 +#define VIRTIO_CRYPTO_SERVICE_MAC 2 +#define VIRTIO_CRYPTO_SERVICE_AEAD 3 +#define VIRTIO_CRYPTO_SERVICE_AKCIPHER 4 + +#define VIRTIO_CRYPTO_OPCODE(service, op) (((VIRTIO_CRYPTO_SERVICE_##service) << 8) | (op)) + +struct virtio_crypto_ctrl_header +{ +#define VIRTIO_CRYPTO_CIPHER_CREATE_SESSION VIRTIO_CRYPTO_OPCODE(CIPHER, 0x02) +#define VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION VIRTIO_CRYPTO_OPCODE(CIPHER, 0x03) +#define VIRTIO_CRYPTO_HASH_CREATE_SESSION VIRTIO_CRYPTO_OPCODE(HASH, 0x02) +#define VIRTIO_CRYPTO_HASH_DESTROY_SESSION VIRTIO_CRYPTO_OPCODE(HASH, 0x03) +#define VIRTIO_CRYPTO_MAC_CREATE_SESSION VIRTIO_CRYPTO_OPCODE(MAC, 0x02) +#define VIRTIO_CRYPTO_MAC_DESTROY_SESSION VIRTIO_CRYPTO_OPCODE(MAC, 0x03) +#define VIRTIO_CRYPTO_AEAD_CREATE_SESSION VIRTIO_CRYPTO_OPCODE(AEAD, 0x02) +#define VIRTIO_CRYPTO_AEAD_DESTROY_SESSION VIRTIO_CRYPTO_OPCODE(AEAD, 0x03) +#define VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x04) +#define VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x05) + rt_le32_t opcode; + rt_le32_t algo; + rt_le32_t flag; + /* data virtqueue id */ + rt_le32_t queue_id; +}; + +struct virtio_crypto_cipher_session_para +{ +#define VIRTIO_CRYPTO_NO_CIPHER 0 +#define VIRTIO_CRYPTO_CIPHER_ARC4 1 +#define VIRTIO_CRYPTO_CIPHER_AES_ECB 2 +#define VIRTIO_CRYPTO_CIPHER_AES_CBC 3 +#define VIRTIO_CRYPTO_CIPHER_AES_CTR 4 +#define VIRTIO_CRYPTO_CIPHER_DES_ECB 5 +#define VIRTIO_CRYPTO_CIPHER_DES_CBC 6 +#define VIRTIO_CRYPTO_CIPHER_3DES_ECB 7 +#define VIRTIO_CRYPTO_CIPHER_3DES_CBC 8 +#define VIRTIO_CRYPTO_CIPHER_3DES_CTR 9 +#define VIRTIO_CRYPTO_CIPHER_KASUMI_F8 10 +#define VIRTIO_CRYPTO_CIPHER_SNOW3G_UEA2 11 +#define VIRTIO_CRYPTO_CIPHER_AES_F8 12 +#define VIRTIO_CRYPTO_CIPHER_AES_XTS 13 +#define VIRTIO_CRYPTO_CIPHER_ZUC_EEA3 14 + rt_le32_t algo; + /* length of key */ + rt_le32_t keylen; + +#define VIRTIO_CRYPTO_OP_ENCRYPT 1 +#define VIRTIO_CRYPTO_OP_DECRYPT 2 + /* encrypt or decrypt */ + rt_le32_t op; + rt_le32_t padding; +}; + +struct virtio_crypto_session_input +{ + /* Device-writable part */ + rt_le64_t session_id; + rt_le32_t status; + rt_le32_t padding; +}; + +struct virtio_crypto_cipher_session_req +{ + struct virtio_crypto_cipher_session_para para; + rt_uint8_t padding[32]; +}; + +struct virtio_crypto_hash_session_para +{ +#define VIRTIO_CRYPTO_NO_HASH 0 +#define VIRTIO_CRYPTO_HASH_MD5 1 +#define VIRTIO_CRYPTO_HASH_SHA1 2 +#define VIRTIO_CRYPTO_HASH_SHA_224 3 +#define VIRTIO_CRYPTO_HASH_SHA_256 4 +#define VIRTIO_CRYPTO_HASH_SHA_384 5 +#define VIRTIO_CRYPTO_HASH_SHA_512 6 +#define VIRTIO_CRYPTO_HASH_SHA3_224 7 +#define VIRTIO_CRYPTO_HASH_SHA3_256 8 +#define VIRTIO_CRYPTO_HASH_SHA3_384 9 +#define VIRTIO_CRYPTO_HASH_SHA3_512 10 +#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE128 11 +#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE256 12 + rt_le32_t algo; + /* hash result length */ + rt_le32_t hash_result_len; + rt_uint8_t padding[8]; +}; + +struct virtio_crypto_hash_create_session_req +{ + struct virtio_crypto_hash_session_para para; + rt_uint8_t padding[40]; +}; + +struct virtio_crypto_mac_session_para +{ +#define VIRTIO_CRYPTO_NO_MAC 0 +#define VIRTIO_CRYPTO_MAC_HMAC_MD5 1 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA1 2 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_224 3 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_256 4 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_384 5 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_512 6 +#define VIRTIO_CRYPTO_MAC_CMAC_3DES 25 +#define VIRTIO_CRYPTO_MAC_CMAC_AES 26 +#define VIRTIO_CRYPTO_MAC_KASUMI_F9 27 +#define VIRTIO_CRYPTO_MAC_SNOW3G_UIA2 28 +#define VIRTIO_CRYPTO_MAC_GMAC_AES 41 +#define VIRTIO_CRYPTO_MAC_GMAC_TWOFISH 42 +#define VIRTIO_CRYPTO_MAC_CBCMAC_AES 49 +#define VIRTIO_CRYPTO_MAC_CBCMAC_KASUMI_F9 50 +#define VIRTIO_CRYPTO_MAC_XCBC_AES 53 + rt_le32_t algo; + /* hash result length */ + rt_le32_t hash_result_len; + /* length of authenticated key */ + rt_le32_t auth_key_len; + rt_le32_t padding; +}; + +struct virtio_crypto_mac_create_session_req +{ + struct virtio_crypto_mac_session_para para; + rt_uint8_t padding[40]; +}; + +struct virtio_crypto_aead_session_para +{ +#define VIRTIO_CRYPTO_NO_AEAD 0 +#define VIRTIO_CRYPTO_AEAD_GCM 1 +#define VIRTIO_CRYPTO_AEAD_CCM 2 +#define VIRTIO_CRYPTO_AEAD_CHACHA20_POLY1305 3 + rt_le32_t algo; + /* length of key */ + rt_le32_t key_len; + /* hash result length */ + rt_le32_t hash_result_len; + /* length of the additional authenticated data (AAD) in bytes */ + rt_le32_t aad_len; + /* encrypt or decrypt, See above VIRTIO_CRYPTO_OP_* */ + rt_le32_t op; + rt_le32_t padding; +}; + +struct virtio_crypto_aead_create_session_req +{ + struct virtio_crypto_aead_session_para para; + rt_uint8_t padding[32]; +}; + +struct virtio_crypto_rsa_session_para +{ +#define VIRTIO_CRYPTO_RSA_RAW_PADDING 0 +#define VIRTIO_CRYPTO_RSA_PKCS1_PADDING 1 + rt_le32_t padding_algo; + +#define VIRTIO_CRYPTO_RSA_NO_HASH 0 +#define VIRTIO_CRYPTO_RSA_MD2 1 +#define VIRTIO_CRYPTO_RSA_MD3 2 +#define VIRTIO_CRYPTO_RSA_MD4 3 +#define VIRTIO_CRYPTO_RSA_MD5 4 +#define VIRTIO_CRYPTO_RSA_SHA1 5 +#define VIRTIO_CRYPTO_RSA_SHA256 6 +#define VIRTIO_CRYPTO_RSA_SHA384 7 +#define VIRTIO_CRYPTO_RSA_SHA512 8 +#define VIRTIO_CRYPTO_RSA_SHA224 9 + rt_le32_t hash_algo; +}; + +struct virtio_crypto_ecdsa_session_para +{ +#define VIRTIO_CRYPTO_CURVE_UNKNOWN 0 +#define VIRTIO_CRYPTO_CURVE_NIST_P192 1 +#define VIRTIO_CRYPTO_CURVE_NIST_P224 2 +#define VIRTIO_CRYPTO_CURVE_NIST_P256 3 +#define VIRTIO_CRYPTO_CURVE_NIST_P384 4 +#define VIRTIO_CRYPTO_CURVE_NIST_P521 5 + rt_le32_t curve_id; + rt_le32_t padding; +}; + +struct virtio_crypto_akcipher_session_para +{ +#define VIRTIO_CRYPTO_NO_AKCIPHER 0 +#define VIRTIO_CRYPTO_AKCIPHER_RSA 1 +#define VIRTIO_CRYPTO_AKCIPHER_DSA 2 +#define VIRTIO_CRYPTO_AKCIPHER_ECDSA 3 + rt_le32_t algo; + +#define VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC 1 +#define VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE 2 + rt_le32_t keytype; + rt_le32_t keylen; + + union + { + struct virtio_crypto_rsa_session_para rsa; + struct virtio_crypto_ecdsa_session_para ecdsa; + }; +}; + +struct virtio_crypto_akcipher_create_session_req +{ + struct virtio_crypto_akcipher_session_para para; + rt_uint8_t padding[36]; +}; + +struct virtio_crypto_alg_chain_session_para +{ +#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER 1 +#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH 2 + rt_le32_t alg_chain_order; +/* Plain hash */ +#define VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN 1 +/* Authenticated hash (mac) */ +#define VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH 2 +/* Nested hash */ +#define VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED 3 + rt_le32_t hash_mode; + struct virtio_crypto_cipher_session_para cipher_param; + union + { + struct virtio_crypto_hash_session_para hash_param; + struct virtio_crypto_mac_session_para mac_param; + rt_uint8_t padding_union[16]; + }; + /* length of the additional authenticated data (AAD) in bytes */ + rt_le32_t aad_len; + rt_le32_t padding; +}; + +struct virtio_crypto_alg_chain_session_req +{ + struct virtio_crypto_alg_chain_session_para para; +}; + +struct virtio_crypto_sym_create_session_req +{ + union + { + struct virtio_crypto_cipher_session_req cipher; + struct virtio_crypto_alg_chain_session_req chain; + rt_uint8_t padding_union[48]; + }; + + /* Device-readable part */ + +/* No operation */ +#define VIRTIO_CRYPTO_SYM_OP_NONE 0 +/* Cipher only operation on the data */ +#define VIRTIO_CRYPTO_SYM_OP_CIPHER 1 +/* + * Chain any cipher with any hash or mac operation. The order + * depends on the value of alg_chain_order param + */ +#define VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING 2 + rt_le32_t op_type; + rt_le32_t padding; +}; + +struct virtio_crypto_destroy_session_req +{ + /* Device-readable part */ + rt_le64_t session_id; + rt_uint8_t padding[48]; +}; + +/* The request of the control virtqueue's packet */ +struct virtio_crypto_op_ctrl_req +{ + struct virtio_crypto_ctrl_header header; + + union + { + struct virtio_crypto_sym_create_session_req sym_create_session; + struct virtio_crypto_hash_create_session_req hash_create_session; + struct virtio_crypto_mac_create_session_req mac_create_session; + struct virtio_crypto_aead_create_session_req aead_create_session; + struct virtio_crypto_akcipher_create_session_req akcipher_create_session; + struct virtio_crypto_destroy_session_req destroy_session; + rt_uint8_t padding[56]; + }; +}; + +struct virtio_crypto_op_header +{ +#define VIRTIO_CRYPTO_CIPHER_ENCRYPT VIRTIO_CRYPTO_OPCODE(CIPHER, 0x00) +#define VIRTIO_CRYPTO_CIPHER_DECRYPT VIRTIO_CRYPTO_OPCODE(CIPHER, 0x01) +#define VIRTIO_CRYPTO_HASH VIRTIO_CRYPTO_OPCODE(HASH, 0x00) +#define VIRTIO_CRYPTO_MAC VIRTIO_CRYPTO_OPCODE(MAC, 0x00) +#define VIRTIO_CRYPTO_AEAD_ENCRYPT VIRTIO_CRYPTO_OPCODE(AEAD, 0x00) +#define VIRTIO_CRYPTO_AEAD_DECRYPT VIRTIO_CRYPTO_OPCODE(AEAD, 0x01) +#define VIRTIO_CRYPTO_AKCIPHER_ENCRYPT VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x00) +#define VIRTIO_CRYPTO_AKCIPHER_DECRYPT VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x01) +#define VIRTIO_CRYPTO_AKCIPHER_SIGN VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x02) +#define VIRTIO_CRYPTO_AKCIPHER_VERIFY VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x03) + rt_le32_t opcode; + /* algo should be service-specific algorithms */ + rt_le32_t algo; + /* session_id should be service-specific algorithms */ + rt_le64_t session_id; + /* control flag to control the request */ + rt_le32_t flag; + rt_le32_t padding; +}; + +struct virtio_crypto_cipher_para +{ + /* + * Byte Length of valid IV/Counter + * + * For block ciphers in CBC or F8 mode, or for Kasumi in F8 mode, or for + * SNOW3G in UEA2 mode, this is the length of the IV (which + * must be the same as the block length of the cipher). + * For block ciphers in CTR mode, this is the length of the counter + * (which must be the same as the block length of the cipher). + * For AES-XTS, this is the 128bit tweak, i, from IEEE Std 1619-2007. + * + * The IV/Counter will be updated after every partial cryptographic + * operation. + */ + rt_le32_t iv_len; + /* length of source data */ + rt_le32_t src_data_len; + /* length of dst data */ + rt_le32_t dst_data_len; + rt_le32_t padding; +}; + +struct virtio_crypto_hash_para +{ + /* length of source data */ + rt_le32_t src_data_len; + /* hash result length */ + rt_le32_t hash_result_len; +}; + +struct virtio_crypto_mac_para +{ + struct virtio_crypto_hash_para hash; +}; + +struct virtio_crypto_aead_para +{ + /* + * Byte Length of valid IV data pointed to by the below iv_addr + * parameter. + * + * For GCM mode, this is either 12 (for 96-bit IVs) or 16, in which + * case iv_addr points to J0. + * For CCM mode, this is the length of the nonce, which can be in the + * range 7 to 13 inclusive. + */ + rt_le32_t iv_len; + /* length of additional auth data */ + rt_le32_t aad_len; + /* length of source data */ + rt_le32_t src_data_len; + /* length of dst data */ + rt_le32_t dst_data_len; +}; + +struct virtio_crypto_cipher_data_req +{ + /* Device-readable part */ + struct virtio_crypto_cipher_para para; + rt_uint8_t padding[24]; +}; + +struct virtio_crypto_hash_data_req +{ + /* Device-readable part */ + struct virtio_crypto_hash_para para; + rt_uint8_t padding[40]; +}; + +struct virtio_crypto_mac_data_req +{ + /* Device-readable part */ + struct virtio_crypto_mac_para para; + rt_uint8_t padding[40]; +}; + +struct virtio_crypto_alg_chain_data_para +{ + rt_le32_t iv_len; + /* Length of source data */ + rt_le32_t src_data_len; + /* Length of destination data */ + rt_le32_t dst_data_len; + /* Starting point for cipher processing in source data */ + rt_le32_t cipher_start_src_offset; + /* Length of the source data that the cipher will be computed on */ + rt_le32_t len_to_cipher; + /* Starting point for hash processing in source data */ + rt_le32_t hash_start_src_offset; + /* Length of the source data that the hash will be computed on */ + rt_le32_t len_to_hash; + /* Length of the additional auth data */ + rt_le32_t aad_len; + /* Length of the hash result */ + rt_le32_t hash_result_len; + rt_le32_t reserved; +}; + +struct virtio_crypto_alg_chain_data_req +{ + /* Device-readable part */ + struct virtio_crypto_alg_chain_data_para para; +}; + +struct virtio_crypto_sym_data_req +{ + union + { + struct virtio_crypto_cipher_data_req cipher; + struct virtio_crypto_alg_chain_data_req chain; + rt_uint8_t padding_union[40]; + }; + + /* See above VIRTIO_CRYPTO_SYM_OP_* */ + rt_le32_t op_type; + rt_le32_t padding; +}; + +struct virtio_crypto_aead_data_req +{ + /* Device-readable part */ + struct virtio_crypto_aead_para para; + rt_uint8_t padding[32]; +}; + +struct virtio_crypto_akcipher_para +{ + rt_le32_t src_data_len; + rt_le32_t dst_data_len; +}; + +struct virtio_crypto_akcipher_data_req +{ + struct virtio_crypto_akcipher_para para; + rt_uint8_t padding[40]; +}; + +/* The request of the data virtqueue's packet */ +struct virtio_crypto_op_data_req +{ + struct virtio_crypto_op_header header; + + union + { + struct virtio_crypto_sym_data_req sym_req; + struct virtio_crypto_hash_data_req hash_req; + struct virtio_crypto_mac_data_req mac_req; + struct virtio_crypto_aead_data_req aead_req; + struct virtio_crypto_akcipher_data_req akcipher_req; + rt_uint8_t padding[48]; + }; +}; + +#define VIRTIO_CRYPTO_OK 0 +#define VIRTIO_CRYPTO_ERR 1 +#define VIRTIO_CRYPTO_BADMSG 2 +#define VIRTIO_CRYPTO_NOTSUPP 3 +#define VIRTIO_CRYPTO_INVSESS 4 /* Invalid session id */ +#define VIRTIO_CRYPTO_NOSPC 5 /* no free session ID */ +#define VIRTIO_CRYPTO_KEY_REJECTED 6 /* Signature verification failed */ + +/* The accelerator hardware is ready */ +#define VIRTIO_CRYPTO_S_HW_READY (1 << 0) + +struct virtio_crypto_config +{ + /* See VIRTIO_CRYPTO_OP_* above */ + rt_le32_t status; + + /* + * Maximum number of data queue + */ + rt_le32_t max_dataqueues; + + /* + * Specifies the services mask which the device support, + * see VIRTIO_CRYPTO_SERVICE_* above + */ + rt_le32_t crypto_services; + + /* Detailed algorithms mask */ + rt_le32_t cipher_algo_l; + rt_le32_t cipher_algo_h; + rt_le32_t hash_algo; + rt_le32_t mac_algo_l; + rt_le32_t mac_algo_h; + rt_le32_t aead_algo; + /* Maximum length of cipher key */ + rt_le32_t max_cipher_key_len; + /* Maximum length of authenticated key */ + rt_le32_t max_auth_key_len; + rt_le32_t akcipher_algo; + /* Maximum size of each crypto request's content */ + rt_le64_t max_size; +}; + +struct virtio_crypto_inhdr +{ + /* See VIRTIO_CRYPTO_* above */ + rt_uint8_t status; +}; + +#endif /* __VIRTIO_CRYPTO_H__ */ diff --git a/components/drivers/virtio/virtio_config/virtio-gpu.h b/components/drivers/virtio/virtio_config/virtio-gpu.h new file mode 100644 index 0000000000..20e2ca6d2e --- /dev/null +++ b/components/drivers/virtio/virtio_config/virtio-gpu.h @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-11-11 GuEe-GUI the first version + * 2023-02-25 GuEe-GUI using virtio dm + */ + +#ifndef __VIRTIO_GPU_H__ +#define __VIRTIO_GPU_H__ + +#include <drivers/core/dm.h> + +#define VIRTIO_GPU_F_VIRGL 0 /* VIRTIO_GPU_CMD_CTX_*, VIRTIO_GPU_CMD_*_3D */ +#define VIRTIO_GPU_F_EDID 1 /* VIRTIO_GPU_CMD_GET_EDID */ +#define VIRTIO_GPU_F_RESOURCE_UUID 2 /* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */ +#define VIRTIO_GPU_F_RESOURCE_BLOB 3 /* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */ +#define VIRTIO_GPU_F_CONTEXT_INIT 4 /* VIRTIO_GPU_CMD_CREATE_CONTEXT with context_init and multiple timelines */ + +enum virtio_gpu_ctrl_type +{ + VIRTIO_GPU_UNDEFINED = 0, + + /* 2d commands */ + VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100, + VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, + VIRTIO_GPU_CMD_RESOURCE_UNREF, + VIRTIO_GPU_CMD_SET_SCANOUT, + VIRTIO_GPU_CMD_RESOURCE_FLUSH, + VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, + VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, + VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, + VIRTIO_GPU_CMD_GET_CAPSET_INFO, + VIRTIO_GPU_CMD_GET_CAPSET, + VIRTIO_GPU_CMD_GET_EDID, + VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID, + VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB, + VIRTIO_GPU_CMD_SET_SCANOUT_BLOB, + + /* 3d commands */ + VIRTIO_GPU_CMD_CTX_CREATE = 0x0200, + VIRTIO_GPU_CMD_CTX_DESTROY, + VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, + VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE, + VIRTIO_GPU_CMD_RESOURCE_CREATE_3D, + VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, + VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D, + VIRTIO_GPU_CMD_SUBMIT_3D, + VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB, + VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB, + + /* cursor commands */ + VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300, + VIRTIO_GPU_CMD_MOVE_CURSOR, + + /* success responses */ + VIRTIO_GPU_RESP_OK_NODATA = 0x1100, + VIRTIO_GPU_RESP_OK_DISPLAY_INFO, + VIRTIO_GPU_RESP_OK_CAPSET_INFO, + VIRTIO_GPU_RESP_OK_CAPSET, + VIRTIO_GPU_RESP_OK_EDID, + VIRTIO_GPU_RESP_OK_RESOURCE_UUID, + VIRTIO_GPU_RESP_OK_MAP_INFO, + + /* error responses */ + VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, + VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY, + VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID, + VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID, + VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID, + VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER, +}; + +enum virtio_gpu_shm_id +{ + VIRTIO_GPU_SHM_ID_UNDEFINED = 0, + /* + * VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB + * VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB + */ + VIRTIO_GPU_SHM_ID_HOST_VISIBLE = 1 +}; + +#define VIRTIO_GPU_FLAG_FENCE (1 << 0) +/* + * If the following flag is set, then ring_idx contains the index + * of the command ring that needs to used when creating the fence + */ +#define VIRTIO_GPU_FLAG_INFO_RING_IDX (1 << 1) + +struct virtio_gpu_ctrl_hdr +{ + /* + * specifies the type of the driver request (VIRTIO_GPU_CMD_*) or + * device response (VIRTIO_GPU_RESP_*). + */ + rt_le32_t type; + /* + * request / response flags. + */ + rt_le32_t flags; + /* + * If the driver sets the VIRTIO_GPU_FLAG_FENCE bit + * in the request flags field the device MUST: + * set VIRTIO_GPU_FLAG_FENCE bit in the response, + * copy the content of the fence_id field from the request to the response, + * and send the response only after command processing is complete. + */ + rt_le64_t fence_id; + /* + * Rendering context (used in 3D mode only). + */ + rt_le32_t ctx_id; + /* + * If VIRTIO_GPU_F_CONTEXT_INIT is supported, + * then the driver MAY set VIRTIO_GPU_FLAG_INFO_RING_IDX bit + * in the request flags. In that case: + * ring_idx indicates the value of a context-specific ring index. + * The minimum value is 0 and maximum value is 63 (inclusive). + * If VIRTIO_GPU_FLAG_FENCE is set, fence_id acts as a sequence number + * on the synchronization timeline defined by ctx_idx and the ring index. + * If VIRTIO_GPU_FLAG_FENCE is set and when the command associated + * with fence_id is complete, the device MUST send a response for + * all outstanding commands with a sequence number less than or + * equal to fence_id on the same synchronization timeline. + */ + rt_uint8_t ring_idx; + rt_uint8_t padding[3]; +}; + +/* data passed in the cursor vq */ + +struct virtio_gpu_cursor_pos +{ + rt_le32_t scanout_id; + rt_le32_t x; + rt_le32_t y; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */ +struct virtio_gpu_update_cursor +{ + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_cursor_pos pos; /* update & move */ + rt_le32_t resource_id; /* update only */ + rt_le32_t hot_x; /* update only */ + rt_le32_t hot_y; /* update only */ + rt_le32_t padding; +}; + +/* data passed in the control vq, 2d related */ + +struct virtio_gpu_rect +{ + rt_le32_t x; + rt_le32_t y; + rt_le32_t width; + rt_le32_t height; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_UNREF */ +struct virtio_gpu_resource_unref +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t resource_id; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a format */ +struct virtio_gpu_resource_create_2d +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t resource_id; + rt_le32_t format; + rt_le32_t width; + rt_le32_t height; +}; + +/* VIRTIO_GPU_CMD_SET_SCANOUT */ +struct virtio_gpu_set_scanout +{ + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + rt_le32_t scanout_id; + rt_le32_t resource_id; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */ +struct virtio_gpu_resource_flush +{ + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + rt_le32_t resource_id; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */ +struct virtio_gpu_transfer_to_host_2d +{ + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + rt_le64_t offset; + rt_le32_t resource_id; + rt_le32_t padding; +}; + +struct virtio_gpu_mem_entry +{ + rt_le64_t addr; + rt_le32_t length; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */ +struct virtio_gpu_resource_attach_backing +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t resource_id; + rt_le32_t nr_entries; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */ +struct virtio_gpu_resource_detach_backing +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t resource_id; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */ +#define VIRTIO_GPU_MAX_SCANOUTS 16 +struct virtio_gpu_resp_display_info +{ + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_display_one + { + struct virtio_gpu_rect r; + rt_le32_t enabled; + rt_le32_t flags; + } pmodes[VIRTIO_GPU_MAX_SCANOUTS]; +}; + +/* data passed in the control vq, 3d related */ + +struct virtio_gpu_box +{ + rt_le32_t x, y, z; + rt_le32_t w, h, d; +}; + +/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */ +struct virtio_gpu_transfer_host_3d +{ + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_box box; + rt_le64_t offset; + rt_le32_t resource_id; + rt_le32_t level; + rt_le32_t stride; + rt_le32_t layer_stride; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */ +#define VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP (1 << 0) +struct virtio_gpu_resource_create_3d +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t resource_id; + rt_le32_t target; + rt_le32_t format; + rt_le32_t bind; + rt_le32_t width; + rt_le32_t height; + rt_le32_t depth; + rt_le32_t array_size; + rt_le32_t last_level; + rt_le32_t nr_samples; + rt_le32_t flags; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_CMD_CTX_CREATE */ +#define VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK 0x000000ff +struct virtio_gpu_ctx_create +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t nlen; + rt_le32_t context_init; + char debug_name[64]; +}; + +/* VIRTIO_GPU_CMD_CTX_DESTROY */ +struct virtio_gpu_ctx_destroy +{ + struct virtio_gpu_ctrl_hdr hdr; +}; + +/* VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE */ +struct virtio_gpu_ctx_resource +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t resource_id; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_CMD_SUBMIT_3D */ +struct virtio_gpu_cmd_submit +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t size; + rt_le32_t padding; +}; + +#define VIRTIO_GPU_CAPSET_VIRGL 1 +#define VIRTIO_GPU_CAPSET_VIRGL2 2 +#define VIRTIO_GPU_CAPSET_GFXSTREAM 3 +#define VIRTIO_GPU_CAPSET_VENUS 4 +#define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5 + +/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */ +struct virtio_gpu_get_capset_info +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t capset_index; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */ +struct virtio_gpu_resp_capset_info +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t capset_id; + rt_le32_t capset_max_version; + rt_le32_t capset_max_size; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_CMD_GET_CAPSET */ +struct virtio_gpu_get_capset +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t capset_id; + rt_le32_t capset_version; +}; + +/* VIRTIO_GPU_RESP_OK_CAPSET */ +struct virtio_gpu_resp_capset +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_uint8_t capset_data[]; +}; + +/* VIRTIO_GPU_CMD_GET_EDID */ +struct virtio_gpu_cmd_get_edid +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t scanout; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_RESP_OK_EDID */ +struct virtio_gpu_resp_edid +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t size; + rt_le32_t padding; + rt_uint8_t edid[1024]; +}; + +#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) + +struct virtio_gpu_config +{ + /* + * signals pending events to the driver. + * The driver MUST NOT write to this field. + */ + rt_le32_t events_read; + /* + * clears pending events in the device. + * Writing a '1' into a bit will clear the corresponding bit in events_read, + * mimicking write-to-clear behavior. + */ + rt_le32_t events_clear; + /* + * specifies the maximum number of scanouts supported by the device. + * Minimum value is 1, maximum value is 16. + */ + rt_le32_t num_scanouts; + /* + * specifies the maximum number of capability sets supported by the device. + * The minimum value is zero. + */ + rt_le32_t num_capsets; +}; + +/* simple formats for fbcon/X use */ +enum virtio_gpu_formats +{ + VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1, + VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2, + VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3, + VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4, + + VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67, + VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68, + + VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121, + VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134, +}; + +/* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */ +struct virtio_gpu_resource_assign_uuid +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t resource_id; + rt_le32_t padding; +}; + +/* VIRTIO_GPU_RESP_OK_RESOURCE_UUID */ +struct virtio_gpu_resp_resource_uuid +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_uint8_t uuid[16]; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */ +struct virtio_gpu_resource_create_blob +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t resource_id; +#define VIRTIO_GPU_BLOB_MEM_GUEST 0x0001 +#define VIRTIO_GPU_BLOB_MEM_HOST3D 0x0002 +#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST 0x0003 + +#define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE 0x0001 +#define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE 0x0002 +#define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004 + /* zero is invalid blob mem */ + rt_le32_t blob_mem; + rt_le32_t blob_flags; + rt_le32_t nr_entries; + rt_le64_t blob_id; + rt_le64_t size; + /* + * sizeof(nr_entries * virtio_gpu_mem_entry) bytes follow + */ +}; + +/* VIRTIO_GPU_CMD_SET_SCANOUT_BLOB */ +struct virtio_gpu_set_scanout_blob +{ + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + rt_le32_t scanout_id; + rt_le32_t resource_id; + rt_le32_t width; + rt_le32_t height; + rt_le32_t format; + rt_le32_t padding; + rt_le32_t strides[4]; + rt_le32_t offsets[4]; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB */ +struct virtio_gpu_resource_map_blob +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t resource_id; + rt_le32_t padding; + rt_le64_t offset; +}; + +/* VIRTIO_GPU_RESP_OK_MAP_INFO */ +#define VIRTIO_GPU_MAP_CACHE_MASK 0x0f +#define VIRTIO_GPU_MAP_CACHE_NONE 0x00 +#define VIRTIO_GPU_MAP_CACHE_CACHED 0x01 +#define VIRTIO_GPU_MAP_CACHE_UNCACHED 0x02 +#define VIRTIO_GPU_MAP_CACHE_WC 0x03 +struct virtio_gpu_resp_map_info +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_uint32_t map_info; + rt_uint32_t padding; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB */ +struct virtio_gpu_resource_unmap_blob +{ + struct virtio_gpu_ctrl_hdr hdr; + rt_le32_t resource_id; + rt_le32_t padding; +}; + +#endif /* __VIRTIO_GPU_H__ */ diff --git a/components/drivers/virtio/virtio_config/virtio-input.h b/components/drivers/virtio/virtio_config/virtio-input.h new file mode 100644 index 0000000000..62c7c9953a --- /dev/null +++ b/components/drivers/virtio/virtio_config/virtio-input.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-11-11 GuEe-GUI the first version + * 2023-02-25 GuEe-GUI using virtio dm + */ + +#ifndef __VIRTIO_INPUT_H__ +#define __VIRTIO_INPUT_H__ + +#include <drivers/core/dm.h> + +enum virtio_input_config_select +{ + VIRTIO_INPUT_CFG_UNSET = 0x00, + VIRTIO_INPUT_CFG_ID_NAME = 0x01, + VIRTIO_INPUT_CFG_ID_SERIAL = 0x02, + VIRTIO_INPUT_CFG_ID_DEVIDS = 0x03, + VIRTIO_INPUT_CFG_PROP_BITS = 0x10, + VIRTIO_INPUT_CFG_EV_BITS = 0x11, + VIRTIO_INPUT_CFG_ABS_INFO = 0x12, +}; + +struct virtio_input_absinfo +{ + rt_le32_t min; /* Minimum value for the axis */ + rt_le32_t max; /* Maximum value for the axis */ + rt_le32_t fuzz; /* Fuzz value that is used to filter noise from the event stream */ + rt_le32_t flat; /* Within this value will be discarded by joydev interface and reported as 0 instead */ + rt_le32_t res; /* Resolution for the values reported for the axis */ +}; + +struct virtio_input_devids +{ + rt_le16_t bustype; + rt_le16_t vendor; + rt_le16_t product; + rt_le16_t version; +}; + +rt_packed(struct virtio_input_config +{ + rt_uint8_t select; + rt_uint8_t subsel; + rt_uint8_t size; + rt_uint8_t reserved[5]; + + union + { + char string[128]; + rt_uint8_t bitmap[128]; + struct virtio_input_absinfo abs; + struct virtio_input_devids ids; + }; +}); + +struct virtio_input_event +{ + rt_le16_t type; + rt_le16_t code; + rt_le32_t value; +}; + +#endif /* __VIRTIO_INPUT_H__ */ diff --git a/components/drivers/virtio/virtio_net.h b/components/drivers/virtio/virtio_config/virtio-net.h index 4bc57cb05b..1c5d0a2932 100644 --- a/components/drivers/virtio/virtio_net.h +++ b/components/drivers/virtio/virtio_config/virtio-net.h @@ -6,22 +6,13 @@ * Change Logs: * Date Author Notes * 2021-11-11 GuEe-GUI the first version + * 2023-02-25 GuEe-GUI using virtio dm */ #ifndef __VIRTIO_NET_H__ #define __VIRTIO_NET_H__ -#ifdef RT_USING_VIRTIO_NET - -#include <rtdef.h> -#include <netif/ethernetif.h> - -#include <virtio.h> - -#define VIRTIO_NET_QUEUE_RX 0 -#define VIRTIO_NET_QUEUE_TX 1 -#define VIRTIO_NET_RTX_QUEUE_SIZE 16 -#define VIRTIO_NET_RTX_BUF_SIZE 2048 +#include <drivers/core/dm.h> #define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */ #define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */ @@ -52,37 +43,32 @@ #define VIRTIO_NET_F_STANDBY 62 /* Act as standby for another device with the same MAC */ #define VIRTIO_NET_F_SPEED_DUPLEX 63 /* Device set linkspeed and duplex */ -#define VIRTIO_NET_S_LINK_UP (1 << 0) -#define VIRTIO_NET_S_ANNOUNCE (1 << 1) - +rt_packed(struct virtio_net_hdr +{ #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 #define VIRTIO_NET_HDR_F_DATA_VALID 2 #define VIRTIO_NET_HDR_F_RSC_INFO 4 - + rt_uint8_t flags; #define VIRTIO_NET_HDR_GSO_NONE 0 #define VIRTIO_NET_HDR_GSO_TCPV4 1 #define VIRTIO_NET_HDR_GSO_UDP 3 #define VIRTIO_NET_HDR_GSO_TCPV6 4 #define VIRTIO_NET_HDR_GSO_ECN 0x80 - -struct virtio_net_hdr -{ - rt_uint8_t flags; rt_uint8_t gso_type; rt_uint16_t hdr_len; rt_uint16_t gso_size; rt_uint16_t csum_start; rt_uint16_t csum_offset; rt_uint16_t num_buffers; -} __attribute__ ((packed)); +}); -#define VIRTIO_NET_MSS 1514 -#define VIRTIO_NET_HDR_SIZE (sizeof(struct virtio_net_hdr)) -#define VIRTIO_NET_PAYLOAD_MAX_SIZE (VIRTIO_NET_HDR_SIZE + VIRTIO_NET_MSS) +#define VIRTIO_NET_MSS 1514 -struct virtio_net_config +rt_packed(struct virtio_net_config { rt_uint8_t mac[6]; +#define VIRTIO_NET_S_LINK_UP (1 << 0) +#define VIRTIO_NET_S_ANNOUNCE (1 << 1) rt_uint16_t status; rt_uint16_t max_virtqueue_pairs; rt_uint16_t mtu; @@ -91,29 +77,6 @@ struct virtio_net_config rt_uint8_t rss_max_key_size; rt_uint16_t rss_max_indirection_table_length; rt_uint32_t supported_hash_types; -} __attribute__((packed)); - -struct virtio_net_device -{ - struct eth_device parent; - - struct virtio_device virtio_dev; - - struct virtio_net_config *config; - - struct - { - /* Transmit hdr */ - struct virtio_net_hdr hdr; - /* Transmit buffer */ - rt_uint8_t tx_buffer[VIRTIO_NET_PAYLOAD_MAX_SIZE]; - /* Receive buffer */ - rt_uint8_t rx_buffer[VIRTIO_NET_PAYLOAD_MAX_SIZE]; - } info[VIRTIO_NET_RTX_QUEUE_SIZE]; -}; - -rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq); - -#endif /* RT_USING_VIRTIO_NET */ +}); #endif /* __VIRTIO_NET_H__ */ diff --git a/components/drivers/virtio/virtio_config/virtio-scmi.h b/components/drivers/virtio/virtio_config/virtio-scmi.h new file mode 100644 index 0000000000..bd08006716 --- /dev/null +++ b/components/drivers/virtio/virtio_config/virtio-scmi.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#ifndef __VIRTIO_SCMI_H__ +#define __VIRTIO_SCMI_H__ + +#define VIRTIO_SCMI_F_P2A_CHANNELS 0 /* Device implements some SCMI notifications, or delayed responses. */ +#define VIRTIO_SCMI_F_SHARED_MEMORY 1 /* Device implements any SCMI statistics shared memory region */ + +rt_packed(struct virtio_scmi_request +{ + rt_le32_t hdr; + rt_uint8_t params[]; +}); + +rt_packed(struct virtio_scmi_response +{ + rt_le32_t hdr; + rt_uint8_t ret_values[]; +}); + +rt_packed(struct virtio_scmi_event_msg +{ + rt_le32_t hdr; + rt_uint8_t payload[]; +}); + +#endif /* __VIRTIO_SCMI_H__ */ diff --git a/components/drivers/virtio/virtio_config/virtio-scsi.h b/components/drivers/virtio/virtio_config/virtio-scsi.h new file mode 100644 index 0000000000..f0e5320adc --- /dev/null +++ b/components/drivers/virtio/virtio_config/virtio-scsi.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#ifndef __VIRTIO_SCSI_H__ +#define __VIRTIO_SCSI_H__ + +#include <drivers/core/dm.h> + +#define VIRTIO_SCSI_CDB_DEFAULT_SIZE 32 +#define VIRTIO_SCSI_SENSE_DEFAULT_SIZE 96 + +#ifndef VIRTIO_SCSI_CDB_SIZE +#define VIRTIO_SCSI_CDB_SIZE VIRTIO_SCSI_CDB_DEFAULT_SIZE +#endif +#ifndef VIRTIO_SCSI_SENSE_SIZE +#define VIRTIO_SCSI_SENSE_SIZE VIRTIO_SCSI_SENSE_DEFAULT_SIZE +#endif + +/* SCSI command request, followed by data-out */ +rt_packed(struct virtio_scsi_cmd_req +{ + rt_uint8_t lun[8]; /* Logical Unit Number */ + rt_le64_t tag; /* Command identifier */ + rt_uint8_t task_attr; /* Task attribute */ + rt_uint8_t prio; /* SAM command priority field */ + rt_uint8_t crn; + rt_uint8_t cdb[VIRTIO_SCSI_CDB_SIZE]; +}); + +/* SCSI command request, followed by protection information */ +rt_packed(struct virtio_scsi_cmd_req_pi +{ + rt_uint8_t lun[8]; /* Logical Unit Number */ + rt_le64_t tag; /* Command identifier */ + rt_uint8_t task_attr; /* Task attribute */ + rt_uint8_t prio; /* SAM command priority field */ + rt_uint8_t crn; + rt_le32_t pi_bytesout; /* DataOUT PI Number of bytes */ + rt_le32_t pi_bytesin; /* DataIN PI Number of bytes */ + rt_uint8_t cdb[VIRTIO_SCSI_CDB_SIZE]; +}); + +/* Response, followed by sense data and data-in */ +rt_packed(struct virtio_scsi_cmd_resp +{ + rt_le32_t sense_len; /* Sense data length */ + rt_le32_t resid; /* Residual bytes in data buffer */ + rt_le16_t status_qualifier; /* Status qualifier */ + rt_uint8_t status; /* Command completion status */ + rt_uint8_t response; /* Response values */ + rt_uint8_t sense[VIRTIO_SCSI_SENSE_SIZE]; +}); + +/* Task Management Request */ +rt_packed(struct virtio_scsi_ctrl_tmf_req +{ + rt_le32_t type; + rt_le32_t subtype; + rt_uint8_t lun[8]; + rt_le64_t tag; +}); + +rt_packed(struct virtio_scsi_ctrl_tmf_resp +{ + rt_uint8_t response; +}); + +/* Asynchronous notification query/subscription */ +rt_packed(struct virtio_scsi_ctrl_an_req +{ + rt_le32_t type; + rt_uint8_t lun[8]; + rt_le32_t event_requested; +}); + +rt_packed(struct virtio_scsi_ctrl_an_resp +{ + rt_le32_t event_actual; + rt_uint8_t response; +}); + +rt_packed(struct virtio_scsi_event +{ + rt_le32_t event; + rt_uint8_t lun[8]; + rt_le32_t reason; +}); + +rt_packed(struct virtio_scsi_config +{ + rt_le32_t num_queues; + rt_le32_t seg_max; + rt_le32_t max_sectors; + rt_le32_t cmd_per_lun; + rt_le32_t event_info_size; + rt_le32_t sense_size; + rt_le32_t cdb_size; + rt_le16_t max_channel; + rt_le16_t max_target; + rt_le32_t max_lun; +}); + +/* Feature Bits */ +#define VIRTIO_SCSI_F_INOUT 0 +#define VIRTIO_SCSI_F_HOTPLUG 1 +#define VIRTIO_SCSI_F_CHANGE 2 +#define VIRTIO_SCSI_F_T10_PI 3 + +/* Response codes */ +#define VIRTIO_SCSI_S_OK 0 +#define VIRTIO_SCSI_S_OVERRUN 1 +#define VIRTIO_SCSI_S_ABORTED 2 +#define VIRTIO_SCSI_S_BAD_TARGET 3 +#define VIRTIO_SCSI_S_RESET 4 +#define VIRTIO_SCSI_S_BUSY 5 +#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6 +#define VIRTIO_SCSI_S_TARGET_FAILURE 7 +#define VIRTIO_SCSI_S_NEXUS_FAILURE 8 +#define VIRTIO_SCSI_S_FAILURE 9 +#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10 +#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11 +#define VIRTIO_SCSI_S_INCORRECT_LUN 12 + +/* Controlq type codes */ +#define VIRTIO_SCSI_T_TMF 0 +#define VIRTIO_SCSI_T_AN_QUERY 1 +#define VIRTIO_SCSI_T_AN_SUBSCRIBE 2 + +/* Valid TMF subtypes */ +#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0 +#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1 +#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2 +#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3 +#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4 +#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5 +#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6 +#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7 + +/* Events */ +#define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000 +#define VIRTIO_SCSI_T_NO_EVENT 0 +#define VIRTIO_SCSI_T_TRANSPORT_RESET 1 +#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2 +#define VIRTIO_SCSI_T_PARAM_CHANGE 3 + +/* Reasons of transport reset event */ +#define VIRTIO_SCSI_EVT_RESET_HARD 0 +#define VIRTIO_SCSI_EVT_RESET_RESCAN 1 +#define VIRTIO_SCSI_EVT_RESET_REMOVED 2 + +#define VIRTIO_SCSI_S_SIMPLE 0 +#define VIRTIO_SCSI_S_ORDERED 1 +#define VIRTIO_SCSI_S_HEAD 2 +#define VIRTIO_SCSI_S_ACA 3 + +#endif /* __VIRTIO_SCSI_H__ */ diff --git a/components/drivers/virtio/virtio_console.c b/components/drivers/virtio/virtio_console.c deleted file mode 100644 index 7ad171cec3..0000000000 --- a/components/drivers/virtio/virtio_console.c +++ /dev/null @@ -1,778 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#include <rthw.h> -#include <rtthread.h> -#include <cpuport.h> - -#ifdef RT_USING_VIRTIO_CONSOLE - -#include <virtio_console.h> - -struct port_device -{ - struct rt_device parent; - - rt_list_t node; - rt_uint32_t port_id; - rt_bool_t rx_notify; - rt_bool_t need_destroy; - - struct virtio_console_device *console; - - struct virtq *queue_rx, *queue_tx; - rt_uint32_t queue_rx_index, queue_tx_index; - -#ifdef RT_USING_SMP - struct rt_spinlock spinlock_rx, spinlock_tx; -#endif - - struct rt_device_notify rx_notify_helper; - - struct - { - char rx_char, tx_char; - } info[VIRTIO_CONSOLE_QUEUE_SIZE]; -}; - -static void virtio_console_send_ctrl(struct virtio_console_device *virtio_console_dev, - struct virtio_console_control *ctrl) -{ - rt_uint16_t id; - struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev; - struct virtq *queue_ctrl_tx; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - - queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX]; - - id = queue_ctrl_tx->avail->idx % queue_ctrl_tx->num; - - rt_memcpy(&virtio_console_dev->info[id].tx_ctrl, ctrl, sizeof(struct virtio_console_control)); - - virtio_free_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id); - - virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id, - virtio_console_dev->info[id].tx_ctrl_paddr, sizeof(struct virtio_console_control), 0, 0); - - virtio_submit_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id); - - virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX); - - virtio_alloc_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX); - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif -} - -static rt_err_t virtio_console_port_init(rt_device_t dev); -static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag); -static rt_err_t virtio_console_port_close(rt_device_t dev); -static rt_ssize_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); -static rt_ssize_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); -static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args); - -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops virtio_console_port_ops = -{ - virtio_console_port_init, - virtio_console_port_open, - virtio_console_port_close, - virtio_console_port_read, - virtio_console_port_write, - virtio_console_port_control -}; -#endif - -static rt_err_t virtio_console_port_create(struct virtio_console_device *virtio_console_dev) -{ - rt_uint32_t port_id; - char dev_name[RT_NAME_MAX]; - struct port_device *port_dev, *prev_port_dev = RT_NULL; - struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev; - - if (virtio_console_dev->port_nr > 0 && !virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT)) - { - return -RT_ENOSYS; - } - - if (virtio_console_dev->port_nr >= virtio_console_dev->max_port_nr) - { - return -RT_EFULL; - } - - port_id = 0; - - /* The port device list is always ordered, so just find next number for id */ - rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node) - { - if (port_dev->port_id != port_id) - { - break; - } - ++port_id; - prev_port_dev = port_dev; - } - - port_dev = rt_malloc(sizeof(struct port_device)); - - if (port_dev == RT_NULL) - { - return -RT_ENOMEM; - } - - port_dev->parent.type = RT_Device_Class_Char; -#ifdef RT_USING_DEVICE_OPS - port_dev->parent.ops = &virtio_console_port_ops; -#else - port_dev->parent.init = virtio_console_port_init; - port_dev->parent.open = virtio_console_port_open; - port_dev->parent.close = virtio_console_port_close; - port_dev->parent.read = virtio_console_port_read; - port_dev->parent.write = virtio_console_port_write; - port_dev->parent.control = virtio_console_port_control; -#endif - - port_dev->parent.rx_indicate = RT_NULL; - port_dev->parent.tx_complete = RT_NULL; - - rt_list_init(&port_dev->node); - port_dev->port_id = port_id; - port_dev->need_destroy = RT_FALSE; - port_dev->rx_notify = RT_TRUE; - port_dev->console = virtio_console_dev; - port_dev->queue_rx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX); - port_dev->queue_tx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX); - port_dev->queue_rx = &virtio_dev->queues[port_dev->queue_rx_index]; - port_dev->queue_tx = &virtio_dev->queues[port_dev->queue_tx_index]; - -#ifdef RT_USING_SMP - rt_spin_lock_init(&port_dev->spinlock_rx); - rt_spin_lock_init(&port_dev->spinlock_tx); -#endif - - rt_snprintf(dev_name, RT_NAME_MAX, "vport%dp%d", virtio_console_dev->console_id, port_id); - - if (rt_device_register((rt_device_t)port_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX) != RT_EOK) - { - rt_free(port_dev); - - return -RT_ERROR; - } - - if (prev_port_dev != RT_NULL) - { - rt_list_insert_after(&prev_port_dev->node, &port_dev->node); - } - else - { - /* Port0 */ - rt_list_insert_after(&virtio_console_dev->port_head, &port_dev->node); - } - - virtio_console_dev->port_nr++; - - return RT_EOK; -} - -static void virtio_console_port_destroy(struct virtio_console_device *virtio_console_dev, - struct port_device *port_dev) -{ - struct virtio_console_control set_ctrl; - - set_ctrl.id = port_dev->port_id; - set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN; - set_ctrl.value = 0; - - virtio_console_send_ctrl(virtio_console_dev, &set_ctrl); - - virtio_console_dev->port_nr--; - - rt_list_remove(&port_dev->node); - - rt_device_unregister((rt_device_t)port_dev); - - rt_free(port_dev); -} - -static rt_err_t virtio_console_port_init(rt_device_t dev) -{ - rt_uint16_t id; - rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE]; - rt_uint16_t rx_queue_index, tx_queue_index; - struct port_device *port_dev = (struct port_device *)dev; - struct virtio_console_device *virtio_console_dev = port_dev->console; - struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev; - struct virtq *queue_rx, *queue_tx; - - rx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX); - tx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX); - - queue_rx = &virtio_dev->queues[rx_queue_index]; - queue_tx = &virtio_dev->queues[tx_queue_index]; - - virtio_alloc_desc_chain(virtio_dev, rx_queue_index, queue_rx->num, idx); - virtio_alloc_desc_chain(virtio_dev, tx_queue_index, queue_tx->num, idx); - - for (id = 0; id < queue_rx->num; ++id) - { - void *addr = &port_dev->info[id].rx_char; - - virtio_fill_desc(virtio_dev, rx_queue_index, id, - VIRTIO_VA2PA(addr), sizeof(char), VIRTQ_DESC_F_WRITE, 0); - - queue_rx->avail->ring[id] = id; - } - rt_hw_dsb(); - - queue_rx->avail->flags = 0; - queue_rx->avail->idx = queue_rx->num; - - queue_rx->used_idx = queue_rx->used->idx; - - queue_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT; - queue_tx->avail->idx = 0; - - virtio_queue_notify(virtio_dev, rx_queue_index); - - if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT)) - { - struct virtio_console_control set_ctrl; - - set_ctrl.id = VIRTIO_CONSOLE_PORT_BAD_ID; - set_ctrl.event = VIRTIO_CONSOLE_DEVICE_READY; - set_ctrl.value = 1; - - virtio_console_send_ctrl(virtio_console_dev, &set_ctrl); - } - - return RT_EOK; -} - -static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag) -{ - struct port_device *port_dev = (struct port_device *)dev; - - if (port_dev->port_id == 0 && virtio_has_feature(&port_dev->console->virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT)) - { - /* Port0 is reserve in multiport */ - return -RT_ERROR; - } - - port_dev->rx_notify = RT_TRUE; - - return RT_EOK; -} - -static rt_err_t virtio_console_port_close(rt_device_t dev) -{ - struct port_device *port_dev = (struct port_device *)dev; - - if (port_dev->need_destroy) - { - virtio_console_port_destroy(port_dev->console, port_dev); - - /* - * We released the device memory in virtio_console_port_destroy, - * rt_device_close has not finished yet, make the return value - * to empty so that rt_device_close will not access the device memory. - */ - return -RT_EEMPTY; - } - - port_dev->rx_notify = RT_FALSE; - - return RT_EOK; -} - -static rt_ssize_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) -{ - rt_off_t i = 0; - rt_uint16_t id; - rt_uint32_t len; - struct port_device *port_dev = (struct port_device *)dev; - struct virtio_device *virtio_dev = &port_dev->console->virtio_dev; - rt_uint32_t queue_rx_index = port_dev->queue_rx_index; - struct virtq *queue_rx = port_dev->queue_rx; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx); -#endif - - while (i < size) - { - if (queue_rx->used_idx == queue_rx->used->idx) - { - break; - } - rt_hw_dsb(); - - id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id; - len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len; - - if (len > sizeof(char)) - { - rt_kprintf("%s: Receive buffer's size = %u is too big!\n", port_dev->parent.parent.name, len); - len = sizeof(char); - } - - *((char *)buffer + i) = port_dev->info[id].rx_char; - - queue_rx->used_idx++; - - virtio_submit_chain(virtio_dev, queue_rx_index, id); - - virtio_queue_notify(virtio_dev, queue_rx_index); - - i += len; - } - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level); -#endif - - size = i; - - return size; -} - -static rt_ssize_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - char ch = 0; - rt_off_t i = 0; - rt_uint16_t id; - struct port_device *port_dev = (struct port_device *)dev; - struct virtio_device *virtio_dev = &port_dev->console->virtio_dev; - rt_uint32_t queue_tx_index = port_dev->queue_tx_index; - struct virtq *queue_tx = port_dev->queue_tx; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_tx); -#endif - - while (i < size || ch == '\r') - { - id = queue_tx->avail->idx % queue_tx->num; - - /* Keep the way until 'new line' are unified */ - if (ch != '\r') - { - ch = *((const char *)buffer + i); - } - else - { - i -= sizeof(char); - } - - port_dev->info[id].tx_char = ch; - - ch = (ch == '\n' ? '\r' : 0); - - virtio_free_desc(virtio_dev, queue_tx_index, id); - - virtio_fill_desc(virtio_dev, queue_tx_index, id, - VIRTIO_VA2PA(&port_dev->info[id].tx_char), sizeof(char), 0, 0); - - virtio_submit_chain(virtio_dev, queue_tx_index, id); - - virtio_queue_notify(virtio_dev, queue_tx_index); - - virtio_alloc_desc(virtio_dev, queue_tx_index); - - i += sizeof(char); - } - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&port_dev->spinlock_tx, level); -#endif - - return size; -} - -static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args) -{ - rt_err_t status = RT_EOK; - struct port_device *port_dev = (struct port_device *)dev; - - switch (cmd) - { - case RT_DEVICE_CTRL_NOTIFY_SET: - if (args == RT_NULL) - { - status = -RT_ERROR; - break; - } - rt_memcpy(&port_dev->rx_notify_helper, args, sizeof(port_dev->rx_notify_helper)); - break; - case RT_DEVICE_CTRL_CLR_INT: - /* Disable RX */ - port_dev->rx_notify = RT_FALSE; - break; - case RT_DEVICE_CTRL_SET_INT: - /* Enable RX */ - port_dev->rx_notify = RT_TRUE; - break; - case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_DESTROY: - { - port_dev->need_destroy = RT_TRUE; - port_dev->rx_notify = RT_FALSE; - } - break; - default: - status = -RT_EINVAL; - break; - } - - return status; -} - -static rt_err_t virtio_console_init(rt_device_t dev) -{ - struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev; - struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev; - - if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT)) - { - rt_uint16_t id; - rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE]; - struct virtq *queue_ctrl_rx, *queue_ctrl_tx; - - queue_ctrl_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX]; - queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX]; - - virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, queue_ctrl_rx->num, idx); - virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, queue_ctrl_tx->num, idx); - - for (id = 0; id < queue_ctrl_rx->num; ++id) - { - void *addr = &virtio_console_dev->info[id].rx_ctrl; - - virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, id, - VIRTIO_VA2PA(addr), sizeof(struct virtio_console_control), VIRTQ_DESC_F_WRITE, 0); - - queue_ctrl_rx->avail->ring[id] = id; - } - rt_hw_dsb(); - - for (id = 0; id < queue_ctrl_tx->num; ++id) - { - virtio_console_dev->info[id].tx_ctrl_paddr = VIRTIO_VA2PA(&virtio_console_dev->info[id].tx_ctrl); - } - - queue_ctrl_rx->avail->flags = 0; - queue_ctrl_rx->avail->idx = queue_ctrl_rx->num; - - queue_ctrl_rx->used_idx = queue_ctrl_rx->used->idx; - - queue_ctrl_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT; - queue_ctrl_tx->avail->idx = 0; - - virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX); - } - - return virtio_console_port_create(virtio_console_dev); -} - -static rt_err_t virtio_console_control(rt_device_t dev, int cmd, void *args) -{ - rt_err_t status = RT_EOK; - struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev; - - switch (cmd) - { - case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_CREATE: - status = virtio_console_port_create(virtio_console_dev); - break; - default: - status = -RT_EINVAL; - break; - } - - return status; -} - -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops virtio_console_ops = -{ - virtio_console_init, - RT_NULL, - RT_NULL, - RT_NULL, - RT_NULL, - virtio_console_control -}; -#endif - -static void virtio_console_isr(int irqno, void *param) -{ - rt_uint32_t id; - rt_uint32_t len; - struct port_device *port_dev; - struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)param; - struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev; - const char *dev_name = virtio_console_dev->parent.parent.name; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - - virtio_interrupt_ack(virtio_dev); - rt_hw_dsb(); - - do { - struct virtq *queue_rx; - struct virtio_console_control *ctrl, set_ctrl; - - if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT)) - { - break; - } - - queue_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX]; - - if (queue_rx->used_idx == queue_rx->used->idx) - { - break; - } - rt_hw_dsb(); - - id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id; - len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len; - - queue_rx->used_idx++; - - if (len != sizeof(struct virtio_console_control)) - { - rt_kprintf("%s: Invalid ctrl!\n", dev_name); - break; - } - - ctrl = &virtio_console_dev->info[id].rx_ctrl; - - switch (ctrl->event) - { - case VIRTIO_CONSOLE_PORT_ADD: - { - set_ctrl.id = ctrl->id; - set_ctrl.event = VIRTIO_CONSOLE_PORT_READY; - set_ctrl.value = 1; - - #ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); - #endif - - virtio_console_send_ctrl(virtio_console_dev, &set_ctrl); - - #ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&virtio_dev->spinlock); - #endif - } - break; - case VIRTIO_CONSOLE_PORT_REMOVE: - break; - case VIRTIO_CONSOLE_RESIZE: - break; - case VIRTIO_CONSOLE_PORT_OPEN: - { - set_ctrl.id = ctrl->id; - set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN; - set_ctrl.value = 1; - - #ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); - #endif - - virtio_console_send_ctrl(virtio_console_dev, &set_ctrl); - - #ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&virtio_dev->spinlock); - #endif - } - break; - case VIRTIO_CONSOLE_PORT_NAME: - break; - default: - rt_kprintf("%s: Unsupport ctrl[id: %d, event: %d, value: %d]!\n", - dev_name, ctrl->id, ctrl->event, ctrl->value); - break; - } - - } while (0); - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif - - rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node) - { - rt_uint32_t queue_rx_index = port_dev->queue_rx_index; - struct virtq *queue_rx = port_dev->queue_rx; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx); -#endif - - if (queue_rx->used_idx != queue_rx->used->idx) - { - rt_hw_dsb(); - - id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id; - len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len; - - if (port_dev->rx_notify) - { - #ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level); - #endif - /* Will call virtio_console_port_read to inc used_idx */ - - if (port_dev->parent.rx_indicate != RT_NULL) - { - port_dev->parent.rx_indicate(&port_dev->parent, len); - } - - if (port_dev->rx_notify_helper.notify != RT_NULL) - { - port_dev->rx_notify_helper.notify(port_dev->rx_notify_helper.dev); - } - - #ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&port_dev->spinlock_rx); - #endif - } - else - { - queue_rx->used_idx++; - - virtio_submit_chain(virtio_dev, queue_rx_index, id); - - virtio_queue_notify(virtio_dev, queue_rx_index); - } - } - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level); -#endif - } -} - -rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq) -{ - int i; - rt_size_t queues_num; - static int dev_no = 0; - char dev_name[RT_NAME_MAX]; - struct virtio_device *virtio_dev; - struct virtio_console_device *virtio_console_dev; - - RT_ASSERT(RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR > 0); - - virtio_console_dev = rt_malloc(sizeof(struct virtio_console_device)); - - if (virtio_console_dev == RT_NULL) - { - goto _alloc_fail; - } - - virtio_dev = &virtio_console_dev->virtio_dev; - virtio_dev->irq = irq; - virtio_dev->mmio_base = mmio_base; - - virtio_console_dev->config = (struct virtio_console_config *)virtio_dev->mmio_config->config; - -#ifdef RT_USING_SMP - rt_spin_lock_init(&virtio_dev->spinlock); -#endif - - virtio_reset_device(virtio_dev); - virtio_status_acknowledge_driver(virtio_dev); - - virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~( - (1 << VIRTIO_F_RING_EVENT_IDX) | - (1 << VIRTIO_F_RING_INDIRECT_DESC)); - - virtio_status_driver_ok(virtio_dev); - - if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT)) - { - virtio_console_dev->max_port_nr = 1; - queues_num = 2; - } - else - { - if (virtio_console_dev->config->max_nr_ports > RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR) - { - virtio_console_dev->max_port_nr = RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR; - virtio_console_dev->config->max_nr_ports = virtio_console_dev->max_port_nr; - } - else - { - virtio_console_dev->max_port_nr = virtio_console_dev->config->max_nr_ports; - } - - queues_num = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(virtio_console_dev->max_port_nr, VIRTIO_CONSOLE_QUEUE_DATA_RX); - } - - if (virtio_queues_alloc(virtio_dev, queues_num) != RT_EOK) - { - goto _alloc_fail; - } - - for (i = 0; i < virtio_dev->queues_num; ++i) - { - if (virtio_queue_init(virtio_dev, i, VIRTIO_CONSOLE_QUEUE_SIZE) != RT_EOK) - { - for (; i >= 0; --i) - { - virtio_queue_destroy(virtio_dev, i); - } - goto _alloc_fail; - } - } - - virtio_console_dev->parent.type = RT_Device_Class_Char; -#ifdef RT_USING_DEVICE_OPS - virtio_console_dev->parent.ops = &virtio_console_ops; -#else - virtio_console_dev->parent.init = virtio_console_init; - virtio_console_dev->parent.open = RT_NULL; - virtio_console_dev->parent.close = RT_NULL; - virtio_console_dev->parent.read = RT_NULL; - virtio_console_dev->parent.write = RT_NULL; - virtio_console_dev->parent.control = virtio_console_control; -#endif - - virtio_console_dev->parent.rx_indicate = RT_NULL; - virtio_console_dev->parent.tx_complete = RT_NULL; - - virtio_console_dev->console_id = dev_no; - virtio_console_dev->port_nr = 0; - rt_list_init(&virtio_console_dev->port_head); - - rt_snprintf(dev_name, RT_NAME_MAX, "virtio-console%d", dev_no++); - - rt_hw_interrupt_install(irq, virtio_console_isr, virtio_console_dev, dev_name); - rt_hw_interrupt_umask(irq); - - return rt_device_register((rt_device_t)virtio_console_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX); - -_alloc_fail: - - if (virtio_console_dev != RT_NULL) - { - virtio_queues_free(virtio_dev); - rt_free(virtio_console_dev); - } - return -RT_ENOMEM; -} -#endif /* RT_USING_VIRTIO_CONSOLE */ diff --git a/components/drivers/virtio/virtio_console.h b/components/drivers/virtio/virtio_console.h deleted file mode 100644 index 542a187e7c..0000000000 --- a/components/drivers/virtio/virtio_console.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#ifndef __VIRTIO_CONSOLE_H__ -#define __VIRTIO_CONSOLE_H__ - -#include <rtdef.h> - -#include <virtio.h> - -#ifndef RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR -#define RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR 4 -#endif - -#define VIRTIO_CONSOLE_QUEUE_DATA_RX 0 -#define VIRTIO_CONSOLE_QUEUE_DATA_TX 1 -#define VIRTIO_CONSOLE_QUEUE_CTRL_RX 2 -#define VIRTIO_CONSOLE_QUEUE_CTRL_TX 3 -#define VIRTIO_CONSOLE_QUEUE_SIZE 64 - -/* Every port has data rx & tx, and port0 has ctrl rx & tx in multiport */ -#define VIRTIO_CONSOLE_PORT_QUEUE_INDEX(id, queue) ((id) * 2 + (!!(id)) * 2 + (queue)) - -#define VIRTIO_CONSOLE_PORT_BAD_ID (~(rt_uint32_t)0) - -#define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */ -#define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */ -#define VIRTIO_CONSOLE_F_EMERG_WRITE 2 /* Does host support emergency write? */ - -struct virtio_console_config -{ - rt_uint16_t cols; - rt_uint16_t rows; - rt_uint32_t max_nr_ports; - rt_uint32_t emerg_wr; -} __attribute__((packed)); - -struct virtio_console_control -{ - rt_uint32_t id; /* Port number */ - rt_uint16_t event; /* The kind of control event */ - rt_uint16_t value; /* Extra information for the event */ -}; - -enum virtio_console_control_event -{ - VIRTIO_CONSOLE_DEVICE_READY = 0, - VIRTIO_CONSOLE_PORT_ADD, - VIRTIO_CONSOLE_PORT_REMOVE, - VIRTIO_CONSOLE_PORT_READY, - VIRTIO_CONSOLE_CONSOLE_PORT, - VIRTIO_CONSOLE_RESIZE, - VIRTIO_CONSOLE_PORT_OPEN, - VIRTIO_CONSOLE_PORT_NAME, -}; - -struct virtio_console_resize -{ - rt_uint16_t cols; - rt_uint16_t rows; -}; - -struct virtio_console_device -{ - struct rt_device parent; - - struct virtio_device virtio_dev; - - rt_uint32_t console_id; - rt_size_t port_nr; - rt_size_t max_port_nr; - rt_list_t port_head; - struct virtio_console_config *config; - - struct - { - rt_ubase_t tx_ctrl_paddr; - struct virtio_console_control rx_ctrl, tx_ctrl; - } info[VIRTIO_CONSOLE_QUEUE_SIZE]; -}; - -rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq); - -enum -{ - VIRTIO_DEVICE_CTRL_CONSOLE_PORT_CREATE = 0x20, - VIRTIO_DEVICE_CTRL_CONSOLE_PORT_DESTROY, -}; - -#endif /* __VIRTIO_CONSOLE_H__ */ diff --git a/components/drivers/virtio/virtio_gpu.c b/components/drivers/virtio/virtio_gpu.c deleted file mode 100644 index fa8981e56c..0000000000 --- a/components/drivers/virtio/virtio_gpu.c +++ /dev/null @@ -1,935 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#include <rthw.h> -#include <rtthread.h> -#include <cpuport.h> -#include <rtdevice.h> - -#ifdef RT_USING_VIRTIO_GPU - -#include <virtio_gpu.h> - -static struct virtio_gpu_device *_primary_virtio_gpu_dev = RT_NULL; - -static rt_ubase_t _pixel_format_convert(rt_ubase_t format, rt_bool_t to_virtio_gpu_format) -{ - rt_ubase_t ret = 0; - - if (to_virtio_gpu_format) - { - switch (format) - { - case RTGRAPHIC_PIXEL_FORMAT_RGB888: - ret = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM; - break; - case RTGRAPHIC_PIXEL_FORMAT_ARGB888: - ret = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM; - break; - case RTGRAPHIC_PIXEL_FORMAT_ABGR888: - ret = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM; - break; - default: - break; - } - } - else - { - switch (format) - { - case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: - ret = RTGRAPHIC_PIXEL_FORMAT_RGB888; - break; - case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: - ret = RTGRAPHIC_PIXEL_FORMAT_ARGB888; - break; - case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: - ret = RTGRAPHIC_PIXEL_FORMAT_ABGR888; - break; - default: - break; - } - } - - return ret; -} - -static void virtio_gpu_ctrl_send_command(struct virtio_gpu_device *virtio_gpu_dev, - const void *cmd, rt_size_t cmd_len, void *res, rt_size_t res_len) -{ - rt_uint16_t idx[2]; - void *addr = &virtio_gpu_dev->gpu_request; - void *ret_res = ((rt_uint8_t *)addr + cmd_len); - struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - - while (virtio_alloc_desc_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, 2, idx)) - { -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif - rt_thread_yield(); - -#ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - } - - rt_memcpy(&virtio_gpu_dev->gpu_request, cmd, cmd_len); - - virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0], - VIRTIO_VA2PA(addr), cmd_len, VIRTQ_DESC_F_NEXT, idx[1]); - - virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[1], - VIRTIO_VA2PA(addr) + cmd_len, res_len, VIRTQ_DESC_F_WRITE, 0); - - rt_memset(ret_res, 0, res_len); - - virtio_gpu_dev->info[idx[0]].ctrl_valid = RT_TRUE; - - virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]); - - virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CTRL); - - while (virtio_gpu_dev->info[idx[0]].ctrl_valid) - { -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif - rt_thread_yield(); - -#ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - } - - virtio_free_desc_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]); - - rt_memcpy(res, ret_res, res_len); - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif -} - -static void virtio_gpu_cursor_send_command(struct virtio_gpu_device *virtio_gpu_dev, - const void *cmd, rt_size_t cmd_len) -{ - rt_uint16_t id; - void *addr; - struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - - while ((id = virtio_alloc_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR)) == VIRTQ_INVALID_DESC_ID) - { -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif - rt_thread_yield(); - -#ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - } - - addr = &virtio_gpu_dev->info[id].cursor_cmd; - virtio_gpu_dev->info[id].cursor_valid = RT_TRUE; - - rt_memcpy(addr, cmd, cmd_len); - - virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id, VIRTIO_VA2PA(addr), cmd_len, 0, 0); - - virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id); - - virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR); - - while (virtio_gpu_dev->info[id].cursor_valid) - { -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif - rt_thread_yield(); - -#ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - } - - virtio_free_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id); - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif -} - -static rt_err_t virtio_gpu_create_2d_resource(struct virtio_gpu_device *virtio_gpu_dev, enum virtio_gpu_formats format, - rt_uint32_t *resource_id, rt_uint32_t width, rt_uint32_t height) -{ - struct virtio_gpu_ctrl_hdr res; - struct virtio_gpu_resource_create_2d req; - - *resource_id = ++virtio_gpu_dev->next_resource_id; - - req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D; - req.resource_id = *resource_id; - req.format = format; - req.width = width; - req.height = height; - - virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res)); - - if (res.type == VIRTIO_GPU_RESP_OK_NODATA) - { - return RT_EOK; - } - - return -RT_ERROR; -} - -static rt_err_t virtio_gpu_unref_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id) -{ - struct virtio_gpu_ctrl_hdr res; - struct virtio_gpu_resource_unref req; - - rt_memset(&req, 0, sizeof(req)); - - req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_UNREF; - req.resource_id = resource_id; - - virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res)); - - if (res.type == VIRTIO_GPU_RESP_OK_NODATA) - { - return RT_EOK; - } - - return -RT_ERROR; -} - -static rt_err_t virtio_gpu_attach_backing_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id, - void *buffer, rt_size_t size) -{ - struct virtio_gpu_ctrl_hdr res; - struct - { - struct virtio_gpu_resource_attach_backing req; - struct virtio_gpu_mem_entry mem; - } req; - - rt_memset(&req, 0, sizeof(req)); - - req.req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING; - req.req.resource_id = resource_id; - req.req.nr_entries = 1; - - req.mem.addr = VIRTIO_VA2PA(buffer); - req.mem.length = size; - - virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res)); - - if (res.type == VIRTIO_GPU_RESP_OK_NODATA) - { - return RT_EOK; - } - - return -RT_ERROR; -} - -static rt_err_t virtio_gpu_set_scanout(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id, - rt_uint32_t resource_id, rt_uint32_t width, rt_uint32_t height) -{ - struct virtio_gpu_ctrl_hdr res; - struct virtio_gpu_set_scanout req; - - rt_memset(&req, 0, sizeof(req)); - - req.hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT; - req.r.x = 0; - req.r.y = 0; - req.r.width = width; - req.r.height = height; - req.scanout_id = scanout_id; - req.resource_id = resource_id; - - virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res)); - - if (res.type == VIRTIO_GPU_RESP_OK_NODATA) - { - return RT_EOK; - } - - return -RT_ERROR; -} - -static rt_err_t virtio_gpu_flush_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id, - rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height) -{ - struct virtio_gpu_ctrl_hdr res; - struct virtio_gpu_resource_flush req; - - rt_memset(&req, 0, sizeof(req)); - - req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH; - req.r.x = x; - req.r.y = y; - req.r.width = width; - req.r.height = height; - req.resource_id = resource_id; - - virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res)); - - if (res.type == VIRTIO_GPU_RESP_OK_NODATA) - { - return RT_EOK; - } - - return -RT_ERROR; -} - -static rt_err_t virtio_gpu_transfer_to_host_2d(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id, - rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height, rt_uint32_t offset) -{ - struct virtio_gpu_ctrl_hdr res; - struct virtio_gpu_transfer_to_host_2d req; - - rt_memset(&req, 0, sizeof(req)); - - req.hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D; - req.r.x = x; - req.r.y = y; - req.r.width = width; - req.r.height = height; - req.offset = offset; - req.resource_id = resource_id; - - virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res)); - - if (res.type == VIRTIO_GPU_RESP_OK_NODATA) - { - return RT_EOK; - } - - return -RT_ERROR; -} - -static rt_err_t virtio_gpu_gfx_flush_2d(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id, - rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height) -{ - rt_err_t status = virtio_gpu_transfer_to_host_2d(virtio_gpu_dev, resource_id, x, y, width, height, 0); - - if (status == RT_EOK) - { - status = virtio_gpu_flush_resource(virtio_gpu_dev, resource_id, x, y, width, height); - } - - return status; -} - -static rt_err_t virtio_gpu_update_cursor(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id, - rt_uint32_t resource_id, rt_uint32_t hot_x, rt_uint32_t hot_y) -{ - struct virtio_gpu_update_cursor req; - - rt_memset(&req, 0, sizeof(req)); - - req.hdr.type = VIRTIO_GPU_CMD_UPDATE_CURSOR; - req.pos.scanout_id = scanout_id; - req.resource_id = resource_id; - req.hot_x = hot_x; - req.hot_y = hot_y; - - virtio_gpu_cursor_send_command(virtio_gpu_dev, &req, sizeof(req)); - - return RT_EOK; -} - -static rt_err_t virtio_gpu_cursor_move(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id, - rt_uint32_t resource_id, rt_uint32_t x, rt_uint32_t y) -{ - struct virtio_gpu_update_cursor req; - - rt_memset(&req, 0, sizeof(req)); - - req.hdr.type = VIRTIO_GPU_CMD_MOVE_CURSOR; - req.pos.scanout_id = scanout_id; - req.pos.x = x; - req.pos.y = y; - req.resource_id = resource_id; - - virtio_gpu_cursor_send_command(virtio_gpu_dev, &req, sizeof(req)); - - return RT_EOK; -} - -static rt_err_t virtio_gpu_cursor_set_img(struct virtio_gpu_device *virtio_gpu_dev, void *img) -{ - rt_err_t status; - - rt_memcpy(virtio_gpu_dev->cursor_img, img, VIRTIO_GPU_CURSOR_IMG_SIZE); - - status = virtio_gpu_attach_backing_resource(virtio_gpu_dev, - virtio_gpu_dev->cursor_resource_id, virtio_gpu_dev->cursor_img, VIRTIO_GPU_CURSOR_IMG_SIZE); - - if (status != RT_EOK) - { - return status; - } - - status = virtio_gpu_transfer_to_host_2d(virtio_gpu_dev, virtio_gpu_dev->cursor_resource_id, - 0, 0, VIRTIO_GPU_CURSOR_WIDTH, VIRTIO_GPU_CURSOR_HEIGHT, 0); - - return status; -} - -static rt_err_t virtio_gpu_get_display_info(struct virtio_gpu_device *virtio_gpu_dev) -{ - int i; - struct virtio_gpu_ctrl_hdr req; - struct virtio_gpu_resp_display_info info; - - rt_memset(&req, 0, sizeof(req)); - req.type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO; - - virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &info, sizeof(info)); - - if (info.hdr.type != VIRTIO_GPU_RESP_OK_DISPLAY_INFO) - { - return -RT_ERROR; - } - - for (i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; ++i) - { - if (info.pmodes[i].enabled) - { - if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID) - { - rt_memcpy(&virtio_gpu_dev->pmode, &info.pmodes[i], sizeof(virtio_gpu_dev->pmode)); - virtio_gpu_dev->pmode_id = i; - } - } - } - - return RT_EOK; -} - -static rt_err_t virtio_gpu_init(rt_device_t dev) -{ - rt_err_t status; - struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev; - struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev; - struct virtq *queue_ctrl, *queue_cursor; - - queue_ctrl = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CTRL]; - queue_cursor = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CURSOR]; - - queue_ctrl->avail->flags = 0; - queue_cursor->avail->flags = 0; - - status = virtio_gpu_get_display_info(virtio_gpu_dev); - - if (virtio_gpu_dev->pmode_id != VIRTIO_GPU_INVALID_PMODE_ID && _primary_virtio_gpu_dev == RT_NULL) - { - /* This device is ready */ - _primary_virtio_gpu_dev = virtio_gpu_dev; - } - - return status; -} - -static rt_ssize_t virtio_gpu_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) -{ - struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev; - - if (virtio_gpu_dev->framebuffer == RT_NULL || pos + size >= virtio_gpu_dev->smem_len) - { - return 0; - } - - rt_mutex_take(&virtio_gpu_dev->rw_mutex, RT_WAITING_FOREVER); - - rt_memcpy(buffer, (rt_uint8_t *)virtio_gpu_dev->framebuffer + pos, size); - - rt_mutex_release(&virtio_gpu_dev->rw_mutex); - - return size; -} - -static rt_ssize_t virtio_gpu_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev; - - if (virtio_gpu_dev->framebuffer == RT_NULL || pos + size >= virtio_gpu_dev->smem_len) - { - return 0; - } - - rt_mutex_take(&virtio_gpu_dev->rw_mutex, RT_WAITING_FOREVER); - - rt_memcpy((rt_uint8_t *)virtio_gpu_dev->framebuffer + pos, buffer, size); - - rt_mutex_release(&virtio_gpu_dev->rw_mutex); - - return size; -} - -static rt_err_t virtio_gpu_control(rt_device_t dev, int cmd, void *args) -{ - rt_err_t status = RT_EOK; - struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev; - - switch (cmd) - { - case VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY: - - _primary_virtio_gpu_dev = virtio_gpu_dev; - - return status; - } - - if (args == RT_NULL) - { - return -RT_ERROR; - } - - switch (cmd) - { - case RTGRAPHIC_CTRL_RECT_UPDATE: - { - struct rt_device_rect_info *info = (struct rt_device_rect_info *)args; - - if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID) - { - status = -RT_ERROR; - break; - } - - status = virtio_gpu_gfx_flush_2d(virtio_gpu_dev, virtio_gpu_dev->display_resource_id, - info->x, info->y, info->width, info->height); - } - break; - case RTGRAPHIC_CTRL_GET_INFO: - { - struct rt_device_graphic_info *info = (struct rt_device_graphic_info *)args; - - info->pixel_format = _pixel_format_convert((rt_ubase_t)args, RT_FALSE); - info->bits_per_pixel = VIRTIO_GPU_FORMAT_BPP; - info->pitch = virtio_gpu_dev->pmode.r.width * VIRTIO_GPU_FORMAT_PIXEL; - info->width = virtio_gpu_dev->pmode.r.width; - info->height = virtio_gpu_dev->pmode.r.height; - info->framebuffer = virtio_gpu_dev->framebuffer; - info->smem_len = virtio_gpu_dev->smem_len; - } - break; - case VIRTIO_DEVICE_CTRL_GPU_CREATE_2D: - - virtio_gpu_dev->format = _pixel_format_convert((rt_ubase_t)args, RT_TRUE); - - if (virtio_gpu_dev->format == 0 || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID) - { - status = -RT_ERROR; - break; - } - - status = virtio_gpu_create_2d_resource(virtio_gpu_dev, virtio_gpu_dev->format, - &virtio_gpu_dev->display_resource_id, virtio_gpu_dev->pmode.r.width, virtio_gpu_dev->pmode.r.height); - - if (status != RT_EOK) - { - break; - } - - virtio_gpu_dev->smem_len = - virtio_gpu_dev->pmode.r.width * virtio_gpu_dev->pmode.r.height * VIRTIO_GPU_FORMAT_PIXEL; - virtio_gpu_dev->smem_len = RT_ALIGN(virtio_gpu_dev->smem_len, VIRTIO_PAGE_SIZE); - virtio_gpu_dev->framebuffer = rt_malloc_align(virtio_gpu_dev->smem_len, VIRTIO_PAGE_SIZE); - - if (virtio_gpu_dev->framebuffer == RT_NULL) - { - virtio_gpu_unref_resource(virtio_gpu_dev, virtio_gpu_dev->display_resource_id); - - status = -RT_ENOMEM; - break; - } - - status = virtio_gpu_attach_backing_resource(virtio_gpu_dev, - virtio_gpu_dev->display_resource_id, virtio_gpu_dev->framebuffer, virtio_gpu_dev->smem_len); - - if (status != RT_EOK) - { - break; - } - - status = virtio_gpu_set_scanout(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->display_resource_id, - virtio_gpu_dev->pmode.r.width, virtio_gpu_dev->pmode.r.height); - - break; - case VIRTIO_DEVICE_CTRL_CURSOR_SETUP: - - if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID) - { - status = -RT_ERROR; - break; - } - - rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER); - - status = virtio_gpu_create_2d_resource(virtio_gpu_dev, virtio_gpu_dev->format, - &virtio_gpu_dev->cursor_resource_id, VIRTIO_GPU_CURSOR_WIDTH, VIRTIO_GPU_CURSOR_HEIGHT); - - if (status != RT_EOK) - { - goto _cursor_setup_end; - } - - status = virtio_gpu_cursor_set_img(virtio_gpu_dev, args); - - if (status != RT_EOK) - { - goto _cursor_setup_end; - } - - virtio_gpu_dev->cursor_x = 0; - virtio_gpu_dev->cursor_y = 0; - - status = virtio_gpu_update_cursor(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id, - virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y); - - if (status == RT_EOK) - { - virtio_gpu_dev->cursor_enable = RT_TRUE; - } - -_cursor_setup_end: - rt_mutex_release(&virtio_gpu_dev->ops_mutex); - - break; - case VIRTIO_DEVICE_CTRL_CURSOR_SET_IMG: - - if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || !virtio_gpu_dev->cursor_enable) - { - status = -RT_ERROR; - break; - } - - rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER); - - status = virtio_gpu_cursor_set_img(virtio_gpu_dev, args); - - if (status != RT_EOK) - { - goto _cursor_set_img_end; - } - - status = virtio_gpu_update_cursor(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id, - virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y); - -_cursor_set_img_end: - rt_mutex_release(&virtio_gpu_dev->ops_mutex); - - break; - case VIRTIO_DEVICE_CTRL_CURSOR_MOVE: - - if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || !virtio_gpu_dev->cursor_enable) - { - status = -RT_ERROR; - break; - } - - rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER); - - virtio_gpu_dev->cursor_x = ((rt_uint32_t *)args)[0]; - virtio_gpu_dev->cursor_y = ((rt_uint32_t *)args)[1]; - - status = virtio_gpu_cursor_move(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id, - virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y); - - rt_mutex_release(&virtio_gpu_dev->ops_mutex); - - break; - default: - status = -RT_EINVAL; - break; - } - - return status; -} - -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops virtio_gpu_ops = -{ - virtio_gpu_init, - RT_NULL, - RT_NULL, - virtio_gpu_read, - virtio_gpu_write, - virtio_gpu_control -}; -#endif - -static void virtio_gpu_set_pixel(const char *pixel, int x, int y) -{ - rt_uint8_t *fb; - struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev; - - if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID) - { - return; - } - - fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer; - fb += (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL; - *((rt_uint32_t *)fb) = *((rt_uint32_t *)pixel); -} - -static void virtio_gpu_get_pixel(char *pixel, int x, int y) -{ - rt_uint8_t *fb; - struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev; - - if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID) - { - return; - } - - fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer; - *((rt_uint32_t *)pixel) = *(fb + (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL); -} - -static void virtio_gpu_draw_hline(const char *pixel, int x1, int x2, int y) -{ - int i; - rt_uint8_t *fb; - rt_uint32_t color = *((rt_uint32_t *)pixel); - struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev; - - if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || - x1 < 0 || x2 < 0 || y < 0) - { - return; - } - - if (x1 > x2) - { - x1 ^= x2; - x2 ^= x1; - x1 ^= x2; - } - - fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer; - fb += (y * virtio_gpu_dev->pmode.r.width + x1) * VIRTIO_GPU_FORMAT_PIXEL; - - for (i = x1; i < x2; ++i) - { - *((rt_uint32_t *)fb) = color; - - fb += VIRTIO_GPU_FORMAT_PIXEL; - } -} - -static void virtio_gpu_draw_vline(const char *pixel, int x, int y1, int y2) -{ - int i; - rt_uint8_t *fb; - rt_uint16_t pitch; - rt_uint32_t color = *((rt_uint32_t *)pixel); - struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev; - - if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || - x < 0 || y1 < 0 || y2 < 0) - { - return; - } - - if (y1 > y2) - { - y1 ^= y2; - y2 ^= y1; - y1 ^= y2; - } - - fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer; - fb += (y1 * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL; - - pitch = virtio_gpu_dev->pmode.r.width * VIRTIO_GPU_FORMAT_PIXEL; - - for (i = y1; i < y2; ++i) - { - *((rt_uint32_t *)fb) = color; - - fb += pitch; - } -} - -static void virtio_gpu_blit_line(const char *pixel, int x, int y, rt_size_t size) -{ - int i; - rt_uint8_t *fb; - rt_uint32_t *colors = (rt_uint32_t *)pixel; - struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev; - - if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || x < 0 || y < 0) - { - return; - } - - fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer; - fb += (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL; - - for (i = 0; i < size; ++i) - { - *((rt_uint32_t *)fb) = *colors++; - fb += VIRTIO_GPU_FORMAT_PIXEL; - } -} - -static struct rt_device_graphic_ops virtio_gpu_graphic_ops = -{ - virtio_gpu_set_pixel, - virtio_gpu_get_pixel, - virtio_gpu_draw_hline, - virtio_gpu_draw_vline, - virtio_gpu_blit_line -}; - -static void virtio_gpu_isr(int irqno, void *param) -{ - rt_uint16_t id; - struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)param; - struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev; - struct virtq *queue_ctrl = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CTRL]; - struct virtq *queue_cursor = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CURSOR]; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - - virtio_interrupt_ack(virtio_dev); - rt_hw_dsb(); - - while (queue_ctrl->used_idx != queue_ctrl->used->idx) - { - rt_hw_dsb(); - id = queue_ctrl->used->ring[queue_ctrl->used_idx % queue_ctrl->num].id; - - virtio_gpu_dev->info[id].ctrl_valid = RT_FALSE; - - queue_ctrl->used_idx++; - } - - while (queue_cursor->used_idx != queue_cursor->used->idx) - { - rt_hw_dsb(); - id = queue_cursor->used->ring[queue_cursor->used_idx % queue_cursor->num].id; - - virtio_gpu_dev->info[id].cursor_valid = RT_FALSE; - - queue_cursor->used_idx++; - } - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif -} - -rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq) -{ - static int dev_no = 0; - char dev_name[RT_NAME_MAX]; - struct virtio_device *virtio_dev; - struct virtio_gpu_device *virtio_gpu_dev; - - virtio_gpu_dev = rt_malloc(sizeof(struct virtio_gpu_device)); - - if (virtio_gpu_dev == RT_NULL) - { - goto _alloc_fail; - } - - virtio_dev = &virtio_gpu_dev->virtio_dev; - virtio_dev->irq = irq; - virtio_dev->mmio_base = mmio_base; - - virtio_gpu_dev->pmode_id = VIRTIO_GPU_INVALID_PMODE_ID; - virtio_gpu_dev->display_resource_id = 0; - virtio_gpu_dev->cursor_resource_id = 0; - virtio_gpu_dev->next_resource_id = 0; - virtio_gpu_dev->framebuffer = RT_NULL; - virtio_gpu_dev->smem_len = 0; - virtio_gpu_dev->cursor_enable = RT_FALSE; - -#ifdef RT_USING_SMP - rt_spin_lock_init(&virtio_dev->spinlock); -#endif - - virtio_reset_device(virtio_dev); - virtio_status_acknowledge_driver(virtio_dev); - - virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~( - (1 << VIRTIO_F_RING_EVENT_IDX) | - (1 << VIRTIO_F_RING_INDIRECT_DESC)); - - virtio_status_driver_ok(virtio_dev); - - if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK) - { - goto _alloc_fail; - } - - if (virtio_queue_init(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, VIRTIO_GPU_QUEUE_SIZE) != RT_EOK) - { - goto _alloc_fail; - } - - if (virtio_queue_init(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, VIRTIO_GPU_QUEUE_SIZE) != RT_EOK) - { - virtio_queue_destroy(virtio_dev, VIRTIO_GPU_QUEUE_CTRL); - - goto _alloc_fail; - } - - virtio_gpu_dev->parent.type = RT_Device_Class_Graphic; -#ifdef RT_USING_DEVICE_OPS - virtio_gpu_dev->parent.ops = &virtio_gpu_ops; -#else - virtio_gpu_dev->parent.init = virtio_gpu_init; - virtio_gpu_dev->parent.open = RT_NULL; - virtio_gpu_dev->parent.close = RT_NULL; - virtio_gpu_dev->parent.read = virtio_gpu_read; - virtio_gpu_dev->parent.write = virtio_gpu_write; - virtio_gpu_dev->parent.control = virtio_gpu_control; -#endif - virtio_gpu_dev->parent.user_data = &virtio_gpu_graphic_ops; - - rt_snprintf(dev_name, RT_NAME_MAX, "virtio-gpu%d", dev_no++); - - rt_mutex_init(&virtio_gpu_dev->rw_mutex, dev_name, RT_IPC_FLAG_PRIO); - rt_mutex_init(&virtio_gpu_dev->ops_mutex, dev_name, RT_IPC_FLAG_PRIO); - - rt_hw_interrupt_install(irq, virtio_gpu_isr, virtio_gpu_dev, dev_name); - rt_hw_interrupt_umask(irq); - - return rt_device_register((rt_device_t)virtio_gpu_dev, dev_name, RT_DEVICE_FLAG_RDWR); - -_alloc_fail: - - if (virtio_gpu_dev != RT_NULL) - { - virtio_queues_free(virtio_dev); - rt_free(virtio_gpu_dev); - } - return -RT_ENOMEM; -} -#endif /* RT_USING_VIRTIO_GPU */ diff --git a/components/drivers/virtio/virtio_gpu.h b/components/drivers/virtio/virtio_gpu.h deleted file mode 100644 index 6f894ebacf..0000000000 --- a/components/drivers/virtio/virtio_gpu.h +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#ifndef __VIRTIO_GPU_H__ -#define __VIRTIO_GPU_H__ - -#include <rtdef.h> - -#include <virtio.h> - -#define VIRTIO_GPU_QUEUE_CTRL 0 -#define VIRTIO_GPU_QUEUE_CURSOR 1 -#define VIRTIO_GPU_QUEUE_SIZE 32 - -#define VIRTIO_GPU_F_VIRGL 0 /* VIRTIO_GPU_CMD_CTX_*, VIRTIO_GPU_CMD_*_3D */ -#define VIRTIO_GPU_F_EDID 1 /* VIRTIO_GPU_CMD_GET_EDID */ -#define VIRTIO_GPU_F_RESOURCE_UUID 2 /* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */ -#define VIRTIO_GPU_F_RESOURCE_BLOB 3 /* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */ -#define VIRTIO_GPU_F_CONTEXT_INIT 4 /* VIRTIO_GPU_CMD_CREATE_CONTEXT with context_init and multiple timelines */ - -#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) - -#define VIRTIO_GPU_FORMAT_BPP 32 -#define VIRTIO_GPU_FORMAT_PIXEL 4 -#define VIRTIO_GPU_CURSOR_WIDTH 64 -#define VIRTIO_GPU_CURSOR_HEIGHT 64 -#define VIRTIO_GPU_CURSOR_IMG_SIZE (VIRTIO_GPU_CURSOR_WIDTH * VIRTIO_GPU_CURSOR_HEIGHT * VIRTIO_GPU_FORMAT_PIXEL) -#define VIRTIO_GPU_INVALID_PMODE_ID RT_UINT32_MAX - -/* GPU control */ - -struct virtio_gpu_config -{ - rt_uint32_t events_read; - rt_uint32_t events_clear; - rt_uint32_t num_scanouts; /* 1 ~ 16 */ - rt_uint32_t reserved; -}; - -enum virtio_gpu_ctrl_type -{ - VIRTIO_GPU_UNDEFINED = 0, - - /* 2d commands */ - VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100, - VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, - VIRTIO_GPU_CMD_RESOURCE_UNREF, - VIRTIO_GPU_CMD_SET_SCANOUT, - VIRTIO_GPU_CMD_RESOURCE_FLUSH, - VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, - VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, - VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, - VIRTIO_GPU_CMD_GET_CAPSET_INFO, - VIRTIO_GPU_CMD_GET_CAPSET, - VIRTIO_GPU_CMD_GET_EDID, - VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID, - VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB, - VIRTIO_GPU_CMD_SET_SCANOUT_BLOB, - - /* 3d commands */ - VIRTIO_GPU_CMD_CTX_CREATE = 0x0200, - VIRTIO_GPU_CMD_CTX_DESTROY, - VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, - VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE, - VIRTIO_GPU_CMD_RESOURCE_CREATE_3D, - VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, - VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D, - VIRTIO_GPU_CMD_SUBMIT_3D, - VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB, - VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB, - - /* cursor commands */ - VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300, - VIRTIO_GPU_CMD_MOVE_CURSOR, - - /* success responses */ - VIRTIO_GPU_RESP_OK_NODATA = 0x1100, - VIRTIO_GPU_RESP_OK_DISPLAY_INFO, - VIRTIO_GPU_RESP_OK_CAPSET_INFO, - VIRTIO_GPU_RESP_OK_CAPSET, - VIRTIO_GPU_RESP_OK_EDID, - VIRTIO_GPU_RESP_OK_RESOURCE_UUID, - VIRTIO_GPU_RESP_OK_MAP_INFO, - - /* error responses */ - VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, - VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY, - VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID, - VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID, - VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID, - VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER, -}; - -#define VIRTIO_GPU_FLAG_FENCE (1 << 0) - -struct virtio_gpu_ctrl_hdr -{ - rt_uint32_t type; - rt_uint32_t flags; - rt_uint64_t fence_id; - rt_uint32_t ctx_id; - rt_uint8_t ring_idx; - rt_uint8_t padding[3]; -}; - -#define VIRTIO_GPU_MAX_SCANOUTS 16 - -struct virtio_gpu_rect -{ - rt_uint32_t x; - rt_uint32_t y; - rt_uint32_t width; - rt_uint32_t height; -}; - -struct virtio_gpu_resp_display_info -{ - struct virtio_gpu_ctrl_hdr hdr; - struct virtio_gpu_display_one - { - struct virtio_gpu_rect r; - rt_uint32_t enabled; - rt_uint32_t flags; - } pmodes[VIRTIO_GPU_MAX_SCANOUTS]; -}; - -struct virtio_gpu_get_edid -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t scanout; - rt_uint32_t padding; -}; - -struct virtio_gpu_resp_edid -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t size; - rt_uint32_t padding; - rt_uint8_t edid[1024]; -}; - -enum virtio_gpu_formats -{ - VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1, - VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2, - VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3, - VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4, - - VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67, - VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68, - - VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121, - VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134, -}; - -struct virtio_gpu_resource_create_2d -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t resource_id; - rt_uint32_t format; - rt_uint32_t width; - rt_uint32_t height; -}; - -struct virtio_gpu_resource_unref -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t resource_id; - rt_uint32_t padding; -}; - -struct virtio_gpu_set_scanout -{ - struct virtio_gpu_ctrl_hdr hdr; - struct virtio_gpu_rect r; - rt_uint32_t scanout_id; - rt_uint32_t resource_id; -}; - -struct virtio_gpu_resource_flush -{ - struct virtio_gpu_ctrl_hdr hdr; - struct virtio_gpu_rect r; - rt_uint32_t resource_id; - rt_uint32_t padding; -}; - -struct virtio_gpu_transfer_to_host_2d -{ - struct virtio_gpu_ctrl_hdr hdr; - struct virtio_gpu_rect r; - rt_uint64_t offset; - rt_uint32_t resource_id; - rt_uint32_t padding; -}; - -struct virtio_gpu_resource_attach_backing -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t resource_id; - rt_uint32_t nr_entries; -}; - -struct virtio_gpu_mem_entry -{ - rt_uint64_t addr; - rt_uint32_t length; - rt_uint32_t padding; -}; - -struct virtio_gpu_resource_detach_backing -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t resource_id; - rt_uint32_t padding; -}; - -struct virtio_gpu_get_capset_info -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t capset_index; - rt_uint32_t padding; -}; - -#define VIRTIO_GPU_CAPSET_VIRGL 1 -#define VIRTIO_GPU_CAPSET_VIRGL2 2 -#define VIRTIO_GPU_CAPSET_GFXSTREAM 3 -#define VIRTIO_GPU_CAPSET_VENUS 4 -#define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5 - -struct virtio_gpu_resp_capset_info -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t capset_id; - rt_uint32_t capset_max_version; - rt_uint32_t capset_max_size; - rt_uint32_t padding; -}; - -struct virtio_gpu_get_capset -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t capset_id; - rt_uint32_t capset_version; -}; - -struct virtio_gpu_resp_capset -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint8_t capset_data[]; -}; - -struct virtio_gpu_resource_assign_uuid -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t resource_id; - rt_uint32_t padding; -}; - -struct virtio_gpu_resp_resource_uuid -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint8_t uuid[16]; -}; - -#define VIRTIO_GPU_BLOB_MEM_GUEST 0x0001 -#define VIRTIO_GPU_BLOB_MEM_HOST3D 0x0002 -#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST 0x0003 - -#define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE 0x0001 -#define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE 0x0002 -#define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004 - -struct virtio_gpu_resource_create_blob -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t resource_id; - rt_uint32_t blob_mem; - rt_uint32_t blob_flags; - rt_uint32_t nr_entries; - rt_uint64_t blob_id; - rt_uint64_t size; -}; - -struct virtio_gpu_set_scanout_blob -{ - struct virtio_gpu_ctrl_hdr hdr; - struct virtio_gpu_rect r; - rt_uint32_t scanout_id; - rt_uint32_t resource_id; - rt_uint32_t width; - rt_uint32_t height; - rt_uint32_t format; - rt_uint32_t padding; - rt_uint32_t strides[4]; - rt_uint32_t offsets[4]; -}; - -#define VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK 0x000000ff -struct virtio_gpu_ctx_create -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t nlen; - rt_uint32_t context_init; - char debug_name[64]; -}; - -struct virtio_gpu_resource_map_blob -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t resource_id; - rt_uint32_t padding; - rt_uint64_t offset; -}; - -#define VIRTIO_GPU_MAP_CACHE_MASK 0x0f -#define VIRTIO_GPU_MAP_CACHE_NONE 0x00 -#define VIRTIO_GPU_MAP_CACHE_CACHED 0x01 -#define VIRTIO_GPU_MAP_CACHE_UNCACHED 0x02 -#define VIRTIO_GPU_MAP_CACHE_WC 0x03 - -struct virtio_gpu_resp_map_info -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t map_info; - rt_uint32_t padding; -}; - -struct virtio_gpu_resource_unmap_blob -{ - struct virtio_gpu_ctrl_hdr hdr; - rt_uint32_t resource_id; - rt_uint32_t padding; -}; - -/* GPU cursor */ - -struct virtio_gpu_cursor_pos -{ - rt_uint32_t scanout_id; - rt_uint32_t x; - rt_uint32_t y; - rt_uint32_t padding; -}; - -struct virtio_gpu_update_cursor -{ - struct virtio_gpu_ctrl_hdr hdr; - struct virtio_gpu_cursor_pos pos; - rt_uint32_t resource_id; - rt_uint32_t hot_x; - rt_uint32_t hot_y; - rt_uint32_t padding; -}; - -struct virtio_gpu_device -{ - struct rt_device parent; - - struct virtio_device virtio_dev; - - /* Current display's info */ - struct virtio_gpu_display_one pmode; - enum virtio_gpu_formats format; - rt_uint32_t pmode_id; - rt_uint32_t cursor_x, cursor_y; - rt_uint32_t display_resource_id; - rt_uint32_t cursor_resource_id; - rt_uint32_t next_resource_id; - - /* Display framebuffer */ - struct rt_mutex rw_mutex; - void *framebuffer; - rt_uint32_t smem_len; - - /* Cursor image info */ - rt_bool_t cursor_enable; - struct rt_mutex ops_mutex; - rt_uint8_t cursor_img[VIRTIO_GPU_CURSOR_IMG_SIZE]; - - /* GPU request info */ - struct virtio_gpu_resp_display_info gpu_request; - - struct - { - rt_bool_t ctrl_valid; - rt_bool_t cursor_valid; - - struct virtio_gpu_update_cursor cursor_cmd; - } info[VIRTIO_GPU_QUEUE_SIZE]; -}; - -rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq); - -enum -{ - VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY = 0x20, - VIRTIO_DEVICE_CTRL_GPU_CREATE_2D, - - VIRTIO_DEVICE_CTRL_CURSOR_SETUP, - VIRTIO_DEVICE_CTRL_CURSOR_SET_IMG, - VIRTIO_DEVICE_CTRL_CURSOR_MOVE, -}; - -#endif /* __VIRTIO_GPU_H__ */ diff --git a/components/drivers/virtio/virtio_ids.h b/components/drivers/virtio/virtio_ids.h new file mode 100644 index 0000000000..f3452e4f6d --- /dev/null +++ b/components/drivers/virtio/virtio_ids.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __VIRTIO_IDS_H__ +#define __VIRTIO_IDS_H__ + +enum +{ + /* virtio 1.0 */ + VIRTIO_DEVICE_ID_INVALID = 0, /* Invalid device */ + VIRTIO_DEVICE_ID_NET = 1, /* Net */ + VIRTIO_DEVICE_ID_BLOCK = 2, /* Block */ + VIRTIO_DEVICE_ID_CONSOLE = 3, /* Console */ + VIRTIO_DEVICE_ID_RNG = 4, /* Rng */ + VIRTIO_DEVICE_ID_BALLOON = 5, /* Balloon */ + VIRTIO_DEVICE_ID_IOMEM = 6, /* IO memory */ + VIRTIO_DEVICE_ID_RPMSG = 7, /* Remote processor messaging */ + VIRTIO_DEVICE_ID_SCSI = 8, /* SCSI */ + VIRTIO_DEVICE_ID_9P = 9, /* 9p console */ + VIRTIO_DEVICE_ID_MAC80211_WLAN = 10, /* Mac80211 wlan */ + VIRTIO_DEVICE_ID_RPROC_SERIAL = 11, /* Remoteproc serial link */ + VIRTIO_DEVICE_ID_CAIF = 12, /* CAIF */ + VIRTIO_DEVICE_ID_MEM_BALLOON = 13, /* Memory balloon */ + VIRTIO_DEVICE_ID_GPU = 16, /* GPU */ + VIRTIO_DEVICE_ID_TIME = 17, /* Timer/clock device */ + VIRTIO_DEVICE_ID_INPUT = 18, /* Input */ + /* virtio 1.1 */ + VIRTIO_DEVICE_ID_SOCKET = 19, /* Socket device */ + VIRTIO_DEVICE_ID_CRYPTO = 20, /* Crypto device */ + VIRTIO_DEVICE_ID_SIG_DIS_MOD = 21, /* Signal Distribution Module */ + VIRTIO_DEVICE_ID_PSTORE = 22, /* Pstore device */ + VIRTIO_DEVICE_ID_IOMMU = 23, /* IOMMU device */ + VIRTIO_DEVICE_ID_MEM = 24, /* Memory device */ + /* virtio 1.2 */ + VIRTIO_DEVICE_ID_AUDIO = 25, /* Audio device */ + VIRTIO_DEVICE_ID_FS = 26, /* File system device */ + VIRTIO_DEVICE_ID_PMEM = 27, /* PMEM device */ + VIRTIO_DEVICE_ID_RPMB = 28, /* Replay protected memory block device */ + VIRTIO_DEVICE_ID_MAC80211_HWSIM = 29, /* Mac80211 hwsim wireless simulation device */ + VIRTIO_DEVICE_ID_VIDEO_ENCODER = 30, /* Video encoder device */ + VIRTIO_DEVICE_ID_VIDEO_DECODER = 31, /* Video decoder device */ + VIRTIO_DEVICE_ID_SCMI = 32, /* SCMI device */ + VIRTIO_DEVICE_ID_NITRO_SEC_MOD = 33, /* NitroSecureModule */ + VIRTIO_DEVICE_ID_I2C_ADAPTER = 34, /* I2C adapter */ + VIRTIO_DEVICE_ID_WATCHDOG = 35, /* Watchdog */ + VIRTIO_DEVICE_ID_CAN = 36, /* CAN device */ + VIRTIO_DEVICE_ID_DMABUF = 37, /* Virtio dmabuf */ + VIRTIO_DEVICE_ID_PARAM_SERV = 38, /* Parameter Server */ + VIRTIO_DEVICE_ID_AUDIO_POLICY = 39, /* Audio policy device */ + VIRTIO_DEVICE_ID_BT = 40, /* Bluetooth device */ + VIRTIO_DEVICE_ID_GPIO = 41, /* GPIO device */ + VIRTIO_DEVICE_ID_RDMA = 42, /* RDMA device */ + /* virtio 1.3 */ + VIRTIO_DEVICE_ID_CAMERA = 43, /* Camera device */ + VIRTIO_DEVICE_ID_ISM = 44, /* Internal shared memory device */ + VIRTIO_DEVICE_ID_SPI_MASTER = 45, /* SPI master */ + + VIRTIO_DEVICE_ID_MAX +}; + +enum +{ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_NET = 0x1000, /* Network card */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_BLOCK = 0x1001, /* Block device */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_BALLOON = 0x1002, /* Memory ballooning (traditional) */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_CONSOLE = 0x1003, /* Console */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_SCSI = 0x1004, /* SCSI host */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_RNG = 0x1005, /* Entropy source */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_9P = 0x1009, /* 9P transport */ + + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_MAX +}; + +#endif /* __VIRTIO_IDS_H__ */ diff --git a/components/drivers/virtio/virtio_input.c b/components/drivers/virtio/virtio_input.c deleted file mode 100644 index 564b32bcaf..0000000000 --- a/components/drivers/virtio/virtio_input.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#include <rthw.h> -#include <rtthread.h> -#include <cpuport.h> - -#ifdef RT_USING_VIRTIO_INPUT - -#include <virtio_input.h> - -static void _set_bit(rt_uint32_t nr, volatile rt_ubase_t *addr) -{ - rt_ubase_t mask = BIT_MASK(nr); - rt_ubase_t *p = ((rt_ubase_t *)addr) + BIT_WORD(nr); - - *p |= mask; -} - -static rt_ssize_t virtio_input_cfg_select(struct virtio_input_device *virtio_input_dev, - rt_uint8_t select, rt_uint8_t subsel) -{ - struct virtio_input_config *config = virtio_input_dev->config; - - rt_hw_dsb(); - config->select = select; - config->subsel = subsel; - rt_hw_dsb(); - - return config->size; -} - -static void virtio_input_cfg_bits(struct virtio_input_device *virtio_input_dev, - rt_uint8_t select, rt_uint8_t subsel, rt_ubase_t *bits, rt_uint32_t bitcount) -{ - int i; - rt_uint32_t bit; - rt_uint8_t bytes; - rt_uint8_t *virtio_bits; - void *config_base = virtio_input_dev->config; - rt_off_t offset = (rt_size_t)&((struct virtio_input_config *)0)->bitmap; - - bytes = virtio_input_cfg_select(virtio_input_dev, select, subsel); - - if (bytes == 0) - { - return; - } - - if (bitcount > bytes * 8) - { - bitcount = bytes * 8; - } - - /* - * Bitmap in virtio config space is a simple stream of bytes, - * with the first byte carrying bits 0-7, second bits 8-15 and - * so on. - */ - virtio_bits = rt_malloc(bytes); - - if (virtio_bits == RT_NULL) - { - return; - } - - for (i = 0; i < bytes; ++i) - { - void *buffer = (void *)virtio_bits + i; - - if (virtio_input_dev->virtio_dev.mmio_config->version == 1) - { - HWREG8(config_base + offset + i) = *((rt_uint8_t *)buffer); - } - else - { - rt_memcpy(config_base + offset + i, buffer, sizeof(rt_uint8_t)); - } - } - - for (bit = 0; bit < bitcount; ++bit) - { - if (virtio_bits[bit / 8] & (1 << (bit % 8))) - { - _set_bit(bit, bits); - } - } - - rt_free(virtio_bits); - - if (select == VIRTIO_INPUT_CFG_EV_BITS) - { - _set_bit(subsel, virtio_input_dev->ev_bit); - } -} - -static rt_err_t virtio_input_init(rt_device_t dev) -{ - int i; - rt_uint16_t idx[VIRTIO_INPUT_QUEUE_MAX_SIZE]; - struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev; - struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev; - struct virtq *queue_event, *queue_status; - - virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY, virtio_input_dev->key_bit, KEY_CNT); - virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_REL, virtio_input_dev->rel_bit, REL_CNT); - virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS, virtio_input_dev->abs_bit, ABS_CNT); - - queue_event = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_EVENT]; - queue_status = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_STATUS]; - - virtio_alloc_desc_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, queue_event->num, idx); - virtio_alloc_desc_chain(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, queue_status->num, idx); - - for (i = 0; i < queue_event->num; ++i) - { - rt_uint16_t id = i; - void *addr = &virtio_input_dev->recv_events[i]; - - virtio_fill_desc(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id, - VIRTIO_VA2PA(addr), sizeof(struct virtio_input_event), VIRTQ_DESC_F_WRITE, 0); - - virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id); - } - rt_hw_dsb(); - - queue_event->avail->flags = 0; - queue_status->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT; - - virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT); - - return RT_EOK; -} - -static rt_ssize_t virtio_input_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) -{ - struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev; - - if (buffer == RT_NULL || pos + size >= virtio_input_dev->virtio_dev.queues[VIRTIO_INPUT_QUEUE_EVENT].num) - { - return 0; - } - - rt_mutex_take(&virtio_input_dev->rw_mutex, RT_WAITING_FOREVER); - - rt_memcpy(buffer, &virtio_input_dev->bcst_events[pos], size); - - rt_mutex_release(&virtio_input_dev->rw_mutex); - - return size; -} - -static rt_ssize_t virtio_input_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev; - - if (buffer == RT_NULL || pos + size >= virtio_input_dev->virtio_dev.queues[VIRTIO_INPUT_QUEUE_EVENT].num) - { - return 0; - } - - rt_mutex_take(&virtio_input_dev->rw_mutex, RT_WAITING_FOREVER); - - rt_memcpy(&virtio_input_dev->bcst_events[pos], buffer, size); - - rt_mutex_release(&virtio_input_dev->rw_mutex); - - return size; -} - -static rt_err_t virtio_input_control(rt_device_t dev, int cmd, void *args) -{ - rt_err_t status = RT_EOK; - struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev; - struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev; - struct virtio_input_config *config = virtio_input_dev->config; - - if (args == RT_NULL) - { - return -RT_ERROR; - } - - switch (cmd) - { - case VIRTIO_DEVICE_CTRL_INPUT_GET_TYPE: - - *(enum virtio_input_type *)args = virtio_input_dev->type; - - break; - case VIRTIO_DEVICE_CTRL_INPUT_BIND_BSCT_HANDLER: - - virtio_input_dev->bsct_handler = args; - - break; - case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_X_INFO: - - virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_ABS_AXIS_X); - rt_memcpy(args, config, sizeof(struct virtio_input_config)); - - break; - case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_Y_INFO: - - virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_ABS_AXIS_Y); - rt_memcpy(args, config, sizeof(struct virtio_input_config)); - - break; - case VIRTIO_DEVICE_CTRL_INPUT_SET_STATUS: - { - rt_uint16_t id; - void *addr; - struct virtq *queue_status = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_STATUS]; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - id = queue_status->avail->idx % queue_status->num; - addr = &virtio_input_dev->xmit_events[id]; - - rt_memcpy(addr, args, sizeof(struct virtio_input_event)); - - virtio_free_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id); - - virtio_fill_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id, - VIRTIO_VA2PA(addr), sizeof(struct virtio_input_event), 0, 0); - - virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id); - - virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS); - - virtio_alloc_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS); - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif - } - break; - case VIRTIO_DEVICE_CTRL_INPUT_GET_EV_BIT: - - rt_memcpy(args, virtio_input_dev->ev_bit, sizeof(virtio_input_dev->ev_bit)); - - break; - case VIRTIO_DEVICE_CTRL_INPUT_GET_KEY_BIT: - - rt_memcpy(args, virtio_input_dev->key_bit, sizeof(virtio_input_dev->key_bit)); - - break; - case VIRTIO_DEVICE_CTRL_INPUT_GET_REL_BIT: - - rt_memcpy(args, virtio_input_dev->rel_bit, sizeof(virtio_input_dev->rel_bit)); - - break; - case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_BIT: - - rt_memcpy(args, virtio_input_dev->abs_bit, sizeof(virtio_input_dev->abs_bit)); - - break; - default: - status = -RT_EINVAL; - break; - } - - return status; -} - -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops virtio_input_ops = -{ - virtio_input_init, - RT_NULL, - RT_NULL, - virtio_input_read, - virtio_input_write, - virtio_input_control -}; -#endif - -static void virtio_input_isr(int irqno, void *param) -{ - struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)param; - struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev; - struct virtq *event_queue = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_EVENT]; - const char *dev_name = virtio_input_dev->parent.parent.name; - -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock); -#endif - - virtio_interrupt_ack(virtio_dev); - rt_hw_dsb(); - - while (event_queue->used_idx != event_queue->used->idx) - { - rt_uint16_t id = event_queue->used->ring[event_queue->used_idx % event_queue->num].id; - rt_uint32_t len = event_queue->used->ring[event_queue->used_idx % event_queue->num].len; - - if (len == sizeof(struct virtio_input_event)) - { - struct virtio_input_event *recv_events = &virtio_input_dev->recv_events[id]; - struct virtio_input_event *bcst_events = &virtio_input_dev->bcst_events[id]; - - if (recv_events->type >= EV_SYN && recv_events->type <= EV_ABS) - { - bcst_events->type = recv_events->type; - bcst_events->code = recv_events->code; - bcst_events->value = recv_events->value; - - if (virtio_input_dev->bsct_handler != RT_NULL) - { - virtio_input_dev->bsct_handler(*bcst_events); - } - } - else - { - rt_kprintf("%s: Unsupport event[type: %02x, code: %02x, value: %08x]!\n", - dev_name, recv_events->type, recv_events->code, recv_events->value); - } - } - else - { - rt_kprintf("%s: Invalid event!\n", dev_name); - } - - event_queue->used_idx++; - - virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id); - - virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT); - } - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); -#endif -} - -rt_err_t rt_virtio_input_init(rt_ubase_t *mmio_base, rt_uint32_t irq) -{ - rt_uint32_t flag; - static int dev_no = 0; - char dev_name[RT_NAME_MAX]; - struct virtio_device *virtio_dev; - struct virtio_input_device *virtio_input_dev; - - virtio_input_dev = rt_malloc(sizeof(struct virtio_input_device)); - - if (virtio_input_dev == RT_NULL) - { - goto _alloc_fail; - } - - virtio_dev = &virtio_input_dev->virtio_dev; - virtio_dev->irq = irq; - virtio_dev->mmio_base = mmio_base; - - virtio_input_dev->config = (struct virtio_input_config *)virtio_dev->mmio_config->config; - virtio_input_dev->bsct_handler = RT_NULL; - -#ifdef RT_USING_SMP - rt_spin_lock_init(&virtio_dev->spinlock); -#endif - - virtio_reset_device(virtio_dev); - virtio_status_acknowledge_driver(virtio_dev); - - virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~( - (1 << VIRTIO_F_RING_EVENT_IDX) | - (1 << VIRTIO_F_RING_INDIRECT_DESC)); - - virtio_status_driver_ok(virtio_dev); - - if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK) - { - goto _alloc_fail; - } - - if (virtio_queue_init(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, VIRTIO_INPUT_EVENT_QUEUE_SIZE) != RT_EOK) - { - goto _alloc_fail; - } - - if (virtio_queue_init(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, VIRTIO_INPUT_STATUS_QUEUE_SIZE) != RT_EOK) - { - virtio_queue_destroy(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT); - - goto _alloc_fail; - } - - virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ID_DEVIDS, 0); - - if (virtio_input_dev->config->ids.product == EV_ABS) - { - virtio_input_dev->type = VIRTIO_INPUT_TYPE_TABLET; - - virtio_input_dev->parent.type = RT_Device_Class_Touch; - - flag = RT_DEVICE_FLAG_STANDALONE | RT_DEVICE_FLAG_INT_RX; - } - else - { - if (virtio_input_dev->config->ids.product == EV_KEY) - { - virtio_input_dev->type = VIRTIO_INPUT_TYPE_KEYBOARD; - } - else - { - virtio_input_dev->type = VIRTIO_INPUT_TYPE_MOUSE; - } - - /* Replace it to "KeyBoard" or "Mouse" if support in the future */ - virtio_input_dev->parent.type = RT_Device_Class_Miscellaneous; - - flag = RT_DEVICE_FLAG_RDWR; - } -#ifdef RT_USING_DEVICE_OPS - virtio_input_dev->parent.ops = &virtio_input_ops; -#else - virtio_input_dev->parent.init = virtio_input_init; - virtio_input_dev->parent.open = RT_NULL; - virtio_input_dev->parent.close = RT_NULL; - virtio_input_dev->parent.read = virtio_input_read; - virtio_input_dev->parent.write = virtio_input_write; - virtio_input_dev->parent.control = virtio_input_control; -#endif - - rt_snprintf(dev_name, RT_NAME_MAX, "virtio-input%d", dev_no++); - - rt_mutex_init(&virtio_input_dev->rw_mutex, dev_name, RT_IPC_FLAG_PRIO); - - rt_hw_interrupt_install(irq, virtio_input_isr, virtio_input_dev, dev_name); - rt_hw_interrupt_umask(irq); - - return rt_device_register((rt_device_t)virtio_input_dev, dev_name, flag); - -_alloc_fail: - - if (virtio_input_dev != RT_NULL) - { - virtio_queues_free(virtio_dev); - rt_free(virtio_input_dev); - } - return -RT_ENOMEM; -} -#endif /* RT_USING_VIRTIO_INPUT */ diff --git a/components/drivers/virtio/virtio_input.h b/components/drivers/virtio/virtio_input.h deleted file mode 100644 index 700088e19e..0000000000 --- a/components/drivers/virtio/virtio_input.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#ifndef __VIRTIO_INPUT_H__ -#define __VIRTIO_INPUT_H__ - -#include <rtdef.h> - -#include <virtio.h> -#include <virtio_input_event_codes.h> - -#define VIRTIO_INPUT_QUEUE_EVENT 0 -#define VIRTIO_INPUT_QUEUE_STATUS 1 -#define VIRTIO_INPUT_EVENT_QUEUE_SIZE 64 -#define VIRTIO_INPUT_STATUS_QUEUE_SIZE 8 -#define VIRTIO_INPUT_QUEUE_MAX_SIZE (VIRTIO_INPUT_EVENT_QUEUE_SIZE > VIRTIO_INPUT_STATUS_QUEUE_SIZE ? \ - VIRTIO_INPUT_EVENT_QUEUE_SIZE : VIRTIO_INPUT_STATUS_QUEUE_SIZE) - -#define VIRTIO_INPUT_ABS_AXIS_X 0 -#define VIRTIO_INPUT_ABS_AXIS_Y 1 - -enum virtio_input_type -{ - VIRTIO_INPUT_TYPE_KEYBOARD, - VIRTIO_INPUT_TYPE_MOUSE, - VIRTIO_INPUT_TYPE_TABLET, - - VIRTIO_INPUT_TYPE_SIZE, -}; - -enum virtio_input_config_select -{ - VIRTIO_INPUT_CFG_UNSET = 0x00, - VIRTIO_INPUT_CFG_ID_NAME = 0x01, - VIRTIO_INPUT_CFG_ID_SERIAL = 0x02, - VIRTIO_INPUT_CFG_ID_DEVIDS = 0x03, - VIRTIO_INPUT_CFG_PROP_BITS = 0x10, - VIRTIO_INPUT_CFG_EV_BITS = 0x11, - VIRTIO_INPUT_CFG_ABS_INFO = 0x12, -}; - -struct virtio_input_absinfo -{ - rt_uint32_t min; /* Minimum value for the axis */ - rt_uint32_t max; /* Maximum value for the axis */ - rt_uint32_t fuzz; /* Fuzz value that is used to filter noise from the event stream */ - rt_uint32_t flat; /* Within this value will be discarded by joydev interface and reported as 0 instead */ - rt_uint32_t res; /* Resolution for the values reported for the axis */ -}; - -struct virtio_input_devids -{ - rt_uint16_t bustype; - rt_uint16_t vendor; - rt_uint16_t product; - rt_uint16_t version; -}; - -struct virtio_input_config -{ - rt_uint8_t select; - rt_uint8_t subsel; - rt_uint8_t size; - rt_uint8_t reserved[5]; - - union - { - char string[128]; - rt_uint8_t bitmap[128]; - struct virtio_input_absinfo abs; - struct virtio_input_devids ids; - }; -} __attribute__((packed)); - -struct virtio_input_event -{ - rt_uint16_t type; - rt_uint16_t code; - rt_uint32_t value; -}; - -#ifdef ARCH_CPU_64BIT -#define BITS_PER_LONG 64 -#else -#define BITS_PER_LONG 32 -#endif -#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - -#define BITS_PER_BYTE 8 -#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE) -#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(char)) -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) - -struct virtio_input_device -{ - struct rt_device parent; - - struct virtio_device virtio_dev; - - rt_ubase_t ev_bit[BITS_TO_LONGS(EV_CNT)]; - rt_ubase_t key_bit[BITS_TO_LONGS(KEY_CNT)]; - rt_ubase_t rel_bit[BITS_TO_LONGS(REL_CNT)]; - rt_ubase_t abs_bit[BITS_TO_LONGS(ABS_CNT)]; - - enum virtio_input_type type; - struct virtio_input_config *config; - - /* Broadcast events */ - struct rt_mutex rw_mutex; - void (*bsct_handler)(struct virtio_input_event event); - struct virtio_input_event bcst_events[VIRTIO_INPUT_EVENT_QUEUE_SIZE]; - - /* Receive events */ - struct virtio_input_event recv_events[VIRTIO_INPUT_EVENT_QUEUE_SIZE]; - - /* Transmit status */ - struct virtio_input_event xmit_events[VIRTIO_INPUT_STATUS_QUEUE_SIZE]; -}; - -enum -{ - VIRTIO_DEVICE_CTRL_INPUT_GET_TYPE = 0x20, - VIRTIO_DEVICE_CTRL_INPUT_BIND_BSCT_HANDLER, - VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_X_INFO, - VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_Y_INFO, - VIRTIO_DEVICE_CTRL_INPUT_SET_STATUS, - - VIRTIO_DEVICE_CTRL_INPUT_GET_EV_BIT, - VIRTIO_DEVICE_CTRL_INPUT_GET_KEY_BIT, - VIRTIO_DEVICE_CTRL_INPUT_GET_REL_BIT, - VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_BIT, -}; - -rt_err_t rt_virtio_input_init(rt_ubase_t *mmio_base, rt_uint32_t irq); - -#endif /* __VIRTIO_INPUT_H__ */ diff --git a/components/drivers/virtio/virtio_input_event_codes.h b/components/drivers/virtio/virtio_input_event_codes.h deleted file mode 100644 index 3e8d6d00f9..0000000000 --- a/components/drivers/virtio/virtio_input_event_codes.h +++ /dev/null @@ -1,932 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#ifndef __VIRTIO_INPUT_EVENT_CODES__ -#define __VIRTIO_INPUT_EVENT_CODES__ - -/* Device properties and quirks */ -#define INPUT_PROP_POINTER 0x00 /* Needs a pointer */ -#define INPUT_PROP_DIRECT 0x01 /* Direct input devices */ -#define INPUT_PROP_BUTTONPAD 0x02 /* Has button(s) under pad */ -#define INPUT_PROP_SEMI_MT 0x03 /* Touch rectangle only */ -#define INPUT_PROP_TOPBUTTONPAD 0x04 /* Softbuttons at top of pad */ -#define INPUT_PROP_POINTING_STICK 0x05 /* Is a pointing stick */ -#define INPUT_PROP_ACCELEROMETER 0x06 /* Has accelerometer */ - -#define INPUT_PROP_MAX 0x1f -#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) - -/* Event types */ -#define EV_SYN 0x00 /* Synchronization events */ -#define EV_KEY 0x01 /* Keys and buttons type */ -#define EV_REL 0x02 /* Relative axes events */ -#define EV_ABS 0x03 /* Absolute axes events */ -#define EV_MSC 0x04 /* Misc events */ -#define EV_SW 0x05 /* Switch events */ -#define EV_LED 0x11 /* LEDs events */ -#define EV_SND 0x12 /* Sounds events */ -#define EV_REP 0x14 /* Repeat events */ -#define EV_FF 0x15 /* Force feedback events */ -#define EV_PWR 0x16 /* Power management events */ -#define EV_FF_STATUS 0x17 /* Force feedback state */ -#define EV_MAX 0x1f /* Maximum number of events */ -#define EV_CNT (EV_MAX + 1)/* Event count */ - -/* Synchronization events.*/ -#define SYN_REPORT 0 -#define SYN_CONFIG 1 -#define SYN_MT_REPORT 2 -#define SYN_DROPPED 3 -#define SYN_MAX 0xf -#define SYN_CNT (SYN_MAX + 1) - -/* - * Keys and buttons - * - * Most of the keys/buttons are modeled after USB HUT 1.12 - * (see http://www.usb.org/developers/hidpage). - * Abbreviations in the comments: - * AC - Application Control - * AL - Application Launch Button - * SC - System Control - */ -#define KEY_RESERVED 0 -#define KEY_ESC 1 -#define KEY_1 2 -#define KEY_2 3 -#define KEY_3 4 -#define KEY_4 5 -#define KEY_5 6 -#define KEY_6 7 -#define KEY_7 8 -#define KEY_8 9 -#define KEY_9 10 -#define KEY_0 11 -#define KEY_MINUS 12 -#define KEY_EQUAL 13 -#define KEY_BACKSPACE 14 -#define KEY_TAB 15 -#define KEY_Q 16 -#define KEY_W 17 -#define KEY_E 18 -#define KEY_R 19 -#define KEY_T 20 -#define KEY_Y 21 -#define KEY_U 22 -#define KEY_I 23 -#define KEY_O 24 -#define KEY_P 25 -#define KEY_LEFTBRACE 26 -#define KEY_RIGHTBRACE 27 -#define KEY_ENTER 28 -#define KEY_LEFTCTRL 29 -#define KEY_A 30 -#define KEY_S 31 -#define KEY_D 32 -#define KEY_F 33 -#define KEY_G 34 -#define KEY_H 35 -#define KEY_J 36 -#define KEY_K 37 -#define KEY_L 38 -#define KEY_SEMICOLON 39 -#define KEY_APOSTROPHE 40 -#define KEY_GRAVE 41 -#define KEY_LEFTSHIFT 42 -#define KEY_BACKSLASH 43 -#define KEY_Z 44 -#define KEY_X 45 -#define KEY_C 46 -#define KEY_V 47 -#define KEY_B 48 -#define KEY_N 49 -#define KEY_M 50 -#define KEY_COMMA 51 -#define KEY_DOT 52 -#define KEY_SLASH 53 -#define KEY_RIGHTSHIFT 54 -#define KEY_KPASTERISK 55 -#define KEY_LEFTALT 56 -#define KEY_SPACE 57 -#define KEY_CAPSLOCK 58 -#define KEY_F1 59 -#define KEY_F2 60 -#define KEY_F3 61 -#define KEY_F4 62 -#define KEY_F5 63 -#define KEY_F6 64 -#define KEY_F7 65 -#define KEY_F8 66 -#define KEY_F9 67 -#define KEY_F10 68 -#define KEY_NUMLOCK 69 -#define KEY_SCROLLLOCK 70 -#define KEY_KP7 71 -#define KEY_KP8 72 -#define KEY_KP9 73 -#define KEY_KPMINUS 74 -#define KEY_KP4 75 -#define KEY_KP5 76 -#define KEY_KP6 77 -#define KEY_KPPLUS 78 -#define KEY_KP1 79 -#define KEY_KP2 80 -#define KEY_KP3 81 -#define KEY_KP0 82 -#define KEY_KPDOT 83 - -#define KEY_ZENKAKUHANKAKU 85 -#define KEY_102ND 86 -#define KEY_F11 87 -#define KEY_F12 88 -#define KEY_RO 89 -#define KEY_KATAKANA 90 -#define KEY_HIRAGANA 91 -#define KEY_HENKAN 92 -#define KEY_KATAKANAHIRAGANA 93 -#define KEY_MUHENKAN 94 -#define KEY_KPJPCOMMA 95 -#define KEY_KPENTER 96 -#define KEY_RIGHTCTRL 97 -#define KEY_KPSLASH 98 -#define KEY_SYSRQ 99 -#define KEY_RIGHTALT 100 -#define KEY_LINEFEED 101 -#define KEY_HOME 102 -#define KEY_UP 103 -#define KEY_PAGEUP 104 -#define KEY_LEFT 105 -#define KEY_RIGHT 106 -#define KEY_END 107 -#define KEY_DOWN 108 -#define KEY_PAGEDOWN 109 -#define KEY_INSERT 110 -#define KEY_DELETE 111 -#define KEY_MACRO 112 -#define KEY_MUTE 113 -#define KEY_VOLUMEDOWN 114 -#define KEY_VOLUMEUP 115 -#define KEY_POWER 116 /* SC System Power Down */ -#define KEY_KPEQUAL 117 -#define KEY_KPPLUSMINUS 118 -#define KEY_PAUSE 119 -#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */ - -#define KEY_KPCOMMA 121 -#define KEY_HANGEUL 122 -#define KEY_HANGUEL KEY_HANGEUL -#define KEY_HANJA 123 -#define KEY_YEN 124 -#define KEY_LEFTMETA 125 -#define KEY_RIGHTMETA 126 -#define KEY_COMPOSE 127 - -#define KEY_STOP 128 /* AC Stop */ -#define KEY_AGAIN 129 -#define KEY_PROPS 130 /* AC Properties */ -#define KEY_UNDO 131 /* AC Undo */ -#define KEY_FRONT 132 -#define KEY_COPY 133 /* AC Copy */ -#define KEY_OPEN 134 /* AC Open */ -#define KEY_PASTE 135 /* AC Paste */ -#define KEY_FIND 136 /* AC Search */ -#define KEY_CUT 137 /* AC Cut */ -#define KEY_HELP 138 /* AL Integrated Help Center */ -#define KEY_MENU 139 /* Menu (show menu) */ -#define KEY_CALC 140 /* AL Calculator */ -#define KEY_SETUP 141 -#define KEY_SLEEP 142 /* SC System Sleep */ -#define KEY_WAKEUP 143 /* System Wake Up */ -#define KEY_FILE 144 /* AL Local Machine Browser */ -#define KEY_SENDFILE 145 -#define KEY_DELETEFILE 146 -#define KEY_XFER 147 -#define KEY_PROG1 148 -#define KEY_PROG2 149 -#define KEY_WWW 150 /* AL Internet Browser */ -#define KEY_MSDOS 151 -#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */ -#define KEY_SCREENLOCK KEY_COFFEE -#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */ -#define KEY_DIRECTION KEY_ROTATE_DISPLAY -#define KEY_CYCLEWINDOWS 154 -#define KEY_MAIL 155 -#define KEY_BOOKMARKS 156 /* AC Bookmarks */ -#define KEY_COMPUTER 157 -#define KEY_BACK 158 /* AC Back */ -#define KEY_FORWARD 159 /* AC Forward */ -#define KEY_CLOSECD 160 -#define KEY_EJECTCD 161 -#define KEY_EJECTCLOSECD 162 -#define KEY_NEXTSONG 163 -#define KEY_PLAYPAUSE 164 -#define KEY_PREVIOUSSONG 165 -#define KEY_STOPCD 166 -#define KEY_RECORD 167 -#define KEY_REWIND 168 -#define KEY_PHONE 169 /* Media Select Telephone */ -#define KEY_ISO 170 -#define KEY_CONFIG 171 /* AL Consumer Control Configuration */ -#define KEY_HOMEPAGE 172 /* AC Home */ -#define KEY_REFRESH 173 /* AC Refresh */ -#define KEY_EXIT 174 /* AC Exit */ -#define KEY_MOVE 175 -#define KEY_EDIT 176 -#define KEY_SCROLLUP 177 -#define KEY_SCROLLDOWN 178 -#define KEY_KPLEFTPAREN 179 -#define KEY_KPRIGHTPAREN 180 -#define KEY_NEW 181 /* AC New */ -#define KEY_REDO 182 /* AC Redo/Repeat */ - -#define KEY_F13 183 -#define KEY_F14 184 -#define KEY_F15 185 -#define KEY_F16 186 -#define KEY_F17 187 -#define KEY_F18 188 -#define KEY_F19 189 -#define KEY_F20 190 -#define KEY_F21 191 -#define KEY_F22 192 -#define KEY_F23 193 -#define KEY_F24 194 - -#define KEY_PLAYCD 200 -#define KEY_PAUSECD 201 -#define KEY_PROG3 202 -#define KEY_PROG4 203 -#define KEY_ALL_APPLICATIONS 204 /* AC Desktop Show All Applications */ -#define KEY_DASHBOARD KEY_ALL_APPLICATIONS -#define KEY_SUSPEND 205 -#define KEY_CLOSE 206 /* AC Close */ -#define KEY_PLAY 207 -#define KEY_FASTFORWARD 208 -#define KEY_BASSBOOST 209 -#define KEY_PRINT 210 /* AC Print */ -#define KEY_HP 211 -#define KEY_CAMERA 212 -#define KEY_SOUND 213 -#define KEY_QUESTION 214 -#define KEY_EMAIL 215 -#define KEY_CHAT 216 -#define KEY_SEARCH 217 -#define KEY_CONNECT 218 -#define KEY_FINANCE 219 /* AL Checkbook/Finance */ -#define KEY_SPORT 220 -#define KEY_SHOP 221 -#define KEY_ALTERASE 222 -#define KEY_CANCEL 223 /* AC Cancel */ -#define KEY_BRIGHTNESSDOWN 224 -#define KEY_BRIGHTNESSUP 225 -#define KEY_MEDIA 226 - -#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video outputs (Monitor/LCD/TV-out/etc) */ -#define KEY_KBDILLUMTOGGLE 228 -#define KEY_KBDILLUMDOWN 229 -#define KEY_KBDILLUMUP 230 - -#define KEY_SEND 231 /* AC Send */ -#define KEY_REPLY 232 /* AC Reply */ -#define KEY_FORWARDMAIL 233 /* AC Forward Msg */ -#define KEY_SAVE 234 /* AC Save */ -#define KEY_DOCUMENTS 235 - -#define KEY_BATTERY 236 - -#define KEY_BLUETOOTH 237 -#define KEY_WLAN 238 -#define KEY_UWB 239 - -#define KEY_UNKNOWN 240 - -#define KEY_VIDEO_NEXT 241 /* Drive next video source */ -#define KEY_VIDEO_PREV 242 /* Drive previous video source */ -#define KEY_BRIGHTNESS_CYCLE 243 /* Brightness up, after max is min */ -#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual brightness control is off, rely on ambient */ -#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO -#define KEY_DISPLAY_OFF 245 /* Display device to off state */ - -#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */ -#define KEY_WIMAX KEY_WWAN -#define KEY_RFKILL 247 /* Key that controls all radios */ - -#define KEY_MICMUTE 248 /* Mute / unmute the microphone */ - -/* Code 255 is reserved for special needs of AT keyboard driver */ -#define BTN_MISC 0x100 -#define BTN_0 0x100 -#define BTN_1 0x101 -#define BTN_2 0x102 -#define BTN_3 0x103 -#define BTN_4 0x104 -#define BTN_5 0x105 -#define BTN_6 0x106 -#define BTN_7 0x107 -#define BTN_8 0x108 -#define BTN_9 0x109 - -#define BTN_MOUSE 0x110 -#define BTN_LEFT 0x110 -#define BTN_RIGHT 0x111 -#define BTN_MIDDLE 0x112 -#define BTN_SIDE 0x113 -#define BTN_EXTRA 0x114 -#define BTN_FORWARD 0x115 -#define BTN_BACK 0x116 -#define BTN_TASK 0x117 - -#define BTN_JOYSTICK 0x120 -#define BTN_TRIGGER 0x120 -#define BTN_THUMB 0x121 -#define BTN_THUMB2 0x122 -#define BTN_TOP 0x123 -#define BTN_TOP2 0x124 -#define BTN_PINKIE 0x125 -#define BTN_BASE 0x126 -#define BTN_BASE2 0x127 -#define BTN_BASE3 0x128 -#define BTN_BASE4 0x129 -#define BTN_BASE5 0x12a -#define BTN_BASE6 0x12b -#define BTN_DEAD 0x12f - -#define BTN_GAMEPAD 0x130 -#define BTN_SOUTH 0x130 -#define BTN_A BTN_SOUTH -#define BTN_EAST 0x131 -#define BTN_B BTN_EAST -#define BTN_C 0x132 -#define BTN_NORTH 0x133 -#define BTN_X BTN_NORTH -#define BTN_WEST 0x134 -#define BTN_Y BTN_WEST -#define BTN_Z 0x135 -#define BTN_TL 0x136 -#define BTN_TR 0x137 -#define BTN_TL2 0x138 -#define BTN_TR2 0x139 -#define BTN_SELECT 0x13a -#define BTN_START 0x13b -#define BTN_MODE 0x13c -#define BTN_THUMBL 0x13d -#define BTN_THUMBR 0x13e - -#define BTN_DIGI 0x140 -#define BTN_TOOL_PEN 0x140 -#define BTN_TOOL_RUBBER 0x141 -#define BTN_TOOL_BRUSH 0x142 -#define BTN_TOOL_PENCIL 0x143 -#define BTN_TOOL_AIRBRUSH 0x144 -#define BTN_TOOL_FINGER 0x145 -#define BTN_TOOL_MOUSE 0x146 -#define BTN_TOOL_LENS 0x147 -#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ -#define BTN_STYLUS3 0x149 -#define BTN_TOUCH 0x14a -#define BTN_STYLUS 0x14b -#define BTN_STYLUS2 0x14c -#define BTN_TOOL_DOUBLETAP 0x14d -#define BTN_TOOL_TRIPLETAP 0x14e -#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */ - -#define BTN_WHEEL 0x150 -#define BTN_GEAR_DOWN 0x150 -#define BTN_GEAR_UP 0x151 - -#define KEY_OK 0x160 -#define KEY_SELECT 0x161 -#define KEY_GOTO 0x162 -#define KEY_CLEAR 0x163 -#define KEY_POWER2 0x164 -#define KEY_OPTION 0x165 -#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */ -#define KEY_TIME 0x167 -#define KEY_VENDOR 0x168 -#define KEY_ARCHIVE 0x169 -#define KEY_PROGRAM 0x16a /* Media Select Program Guide */ -#define KEY_CHANNEL 0x16b -#define KEY_FAVORITES 0x16c -#define KEY_EPG 0x16d -#define KEY_PVR 0x16e /* Media Select Home */ -#define KEY_MHP 0x16f -#define KEY_LANGUAGE 0x170 -#define KEY_TITLE 0x171 -#define KEY_SUBTITLE 0x172 -#define KEY_ANGLE 0x173 -#define KEY_FULL_SCREEN 0x174 /* AC View Toggle */ -#define KEY_ZOOM KEY_FULL_SCREEN -#define KEY_MODE 0x175 -#define KEY_KEYBOARD 0x176 -#define KEY_ASPECT_RATIO 0x177 /* HUTRR37: Aspect */ -#define KEY_SCREEN KEY_ASPECT_RATIO -#define KEY_PC 0x178 /* Media Select Computer */ -#define KEY_TV 0x179 /* Media Select TV */ -#define KEY_TV2 0x17a /* Media Select Cable */ -#define KEY_VCR 0x17b /* Media Select VCR */ -#define KEY_VCR2 0x17c /* VCR Plus */ -#define KEY_SAT 0x17d /* Media Select Satellite */ -#define KEY_SAT2 0x17e -#define KEY_CD 0x17f /* Media Select CD */ -#define KEY_TAPE 0x180 /* Media Select Tape */ -#define KEY_RADIO 0x181 -#define KEY_TUNER 0x182 /* Media Select Tuner */ -#define KEY_PLAYER 0x183 -#define KEY_TEXT 0x184 -#define KEY_DVD 0x185 /* Media Select DVD */ -#define KEY_AUX 0x186 -#define KEY_MP3 0x187 -#define KEY_AUDIO 0x188 /* AL Audio Browser */ -#define KEY_VIDEO 0x189 /* AL Movie Browser */ -#define KEY_DIRECTORY 0x18a -#define KEY_LIST 0x18b -#define KEY_MEMO 0x18c /* Media Select Messages */ -#define KEY_CALENDAR 0x18d -#define KEY_RED 0x18e -#define KEY_GREEN 0x18f -#define KEY_YELLOW 0x190 -#define KEY_BLUE 0x191 -#define KEY_CHANNELUP 0x192 /* Channel Increment */ -#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */ -#define KEY_FIRST 0x194 -#define KEY_LAST 0x195 /* Recall Last */ -#define KEY_AB 0x196 -#define KEY_NEXT 0x197 -#define KEY_RESTART 0x198 -#define KEY_SLOW 0x199 -#define KEY_SHUFFLE 0x19a -#define KEY_BREAK 0x19b -#define KEY_PREVIOUS 0x19c -#define KEY_DIGITS 0x19d -#define KEY_TEEN 0x19e -#define KEY_TWEN 0x19f -#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */ -#define KEY_GAMES 0x1a1 /* Media Select Games */ -#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */ -#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */ -#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */ -#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */ -#define KEY_EDITOR 0x1a6 /* AL Text Editor */ -#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */ -#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */ -#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */ -#define KEY_DATABASE 0x1aa /* AL Database App */ -#define KEY_NEWS 0x1ab /* AL Newsreader */ -#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */ -#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ -#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ -#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ -#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE -#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ -#define KEY_LOGOFF 0x1b1 /* AL Logoff */ - -#define KEY_DOLLAR 0x1b2 -#define KEY_EURO 0x1b3 - -#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */ -#define KEY_FRAMEFORWARD 0x1b5 -#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ -#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ -#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ -#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ -#define KEY_IMAGES 0x1ba /* AL Image Browser */ -#define KEY_NOTIFICATION_CENTER 0x1bc /* Show/hide the notification center */ -#define KEY_PICKUP_PHONE 0x1bd /* Answer incoming call */ -#define KEY_HANGUP_PHONE 0x1be /* Decline incoming call */ - -#define KEY_DEL_EOL 0x1c0 -#define KEY_DEL_EOS 0x1c1 -#define KEY_INS_LINE 0x1c2 -#define KEY_DEL_LINE 0x1c3 - -#define KEY_FN 0x1d0 -#define KEY_FN_ESC 0x1d1 -#define KEY_FN_F1 0x1d2 -#define KEY_FN_F2 0x1d3 -#define KEY_FN_F3 0x1d4 -#define KEY_FN_F4 0x1d5 -#define KEY_FN_F5 0x1d6 -#define KEY_FN_F6 0x1d7 -#define KEY_FN_F7 0x1d8 -#define KEY_FN_F8 0x1d9 -#define KEY_FN_F9 0x1da -#define KEY_FN_F10 0x1db -#define KEY_FN_F11 0x1dc -#define KEY_FN_F12 0x1dd -#define KEY_FN_1 0x1de -#define KEY_FN_2 0x1df -#define KEY_FN_D 0x1e0 -#define KEY_FN_E 0x1e1 -#define KEY_FN_F 0x1e2 -#define KEY_FN_S 0x1e3 -#define KEY_FN_B 0x1e4 -#define KEY_FN_RIGHT_SHIFT 0x1e5 - -#define KEY_BRL_DOT1 0x1f1 -#define KEY_BRL_DOT2 0x1f2 -#define KEY_BRL_DOT3 0x1f3 -#define KEY_BRL_DOT4 0x1f4 -#define KEY_BRL_DOT5 0x1f5 -#define KEY_BRL_DOT6 0x1f6 -#define KEY_BRL_DOT7 0x1f7 -#define KEY_BRL_DOT8 0x1f8 -#define KEY_BRL_DOT9 0x1f9 -#define KEY_BRL_DOT10 0x1fa - -#define KEY_NUMERIC_0 0x200 /* Used by phones, remote controls, and other keypads */ -#define KEY_NUMERIC_1 0x201 -#define KEY_NUMERIC_2 0x202 -#define KEY_NUMERIC_3 0x203 -#define KEY_NUMERIC_4 0x204 -#define KEY_NUMERIC_5 0x205 -#define KEY_NUMERIC_6 0x206 -#define KEY_NUMERIC_7 0x207 -#define KEY_NUMERIC_8 0x208 -#define KEY_NUMERIC_9 0x209 -#define KEY_NUMERIC_STAR 0x20a -#define KEY_NUMERIC_POUND 0x20b -#define KEY_NUMERIC_A 0x20c /* Phone key A - HUT Telephony 0xb9 */ -#define KEY_NUMERIC_B 0x20d -#define KEY_NUMERIC_C 0x20e -#define KEY_NUMERIC_D 0x20f - -#define KEY_CAMERA_FOCUS 0x210 -#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */ - -#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */ -#define KEY_TOUCHPAD_ON 0x213 -#define KEY_TOUCHPAD_OFF 0x214 - -#define KEY_CAMERA_ZOOMIN 0x215 -#define KEY_CAMERA_ZOOMOUT 0x216 -#define KEY_CAMERA_UP 0x217 -#define KEY_CAMERA_DOWN 0x218 -#define KEY_CAMERA_LEFT 0x219 -#define KEY_CAMERA_RIGHT 0x21a - -#define KEY_ATTENDANT_ON 0x21b -#define KEY_ATTENDANT_OFF 0x21c -#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */ -#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */ - -#define BTN_DPAD_UP 0x220 -#define BTN_DPAD_DOWN 0x221 -#define BTN_DPAD_LEFT 0x222 -#define BTN_DPAD_RIGHT 0x223 - -#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ -#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */ - -#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ -#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ -#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */ -#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */ -#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ -#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ -#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ -#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */ -#define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */ -#define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */ -#define KEY_DICTATE 0x24a /* Start or Stop Voice Dictation Session (HUTRR99) */ - -#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ -#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ - -#define KEY_KBDINPUTASSIST_PREV 0x260 -#define KEY_KBDINPUTASSIST_NEXT 0x261 -#define KEY_KBDINPUTASSIST_PREVGROUP 0x262 -#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263 -#define KEY_KBDINPUTASSIST_ACCEPT 0x264 -#define KEY_KBDINPUTASSIST_CANCEL 0x265 - -/* Diagonal movement keys */ -#define KEY_RIGHT_UP 0x266 -#define KEY_RIGHT_DOWN 0x267 -#define KEY_LEFT_UP 0x268 -#define KEY_LEFT_DOWN 0x269 - -#define KEY_ROOT_MENU 0x26a /* Show Device's Root Menu */ -/* Show Top Menu of the Media (e.g. DVD) */ -#define KEY_MEDIA_TOP_MENU 0x26b -#define KEY_NUMERIC_11 0x26c -#define KEY_NUMERIC_12 0x26d -/* - * Toggle Audio Description: refers to an audio service that helps blind and - * visually impaired consumers understand the action in a program. Note: in - * some countries this is referred to as "Video Description". - */ -#define KEY_AUDIO_DESC 0x26e -#define KEY_3D_MODE 0x26f -#define KEY_NEXT_FAVORITE 0x270 -#define KEY_STOP_RECORD 0x271 -#define KEY_PAUSE_RECORD 0x272 -#define KEY_VOD 0x273 /* Video on Demand */ -#define KEY_UNMUTE 0x274 -#define KEY_FASTREVERSE 0x275 -#define KEY_SLOWREVERSE 0x276 -/* - * Control a data application associated with the currently viewed channel, - * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.) - */ -#define KEY_DATA 0x277 -#define KEY_ONSCREEN_KEYBOARD 0x278 -/* Electronic privacy screen control */ -#define KEY_PRIVACY_SCREEN_TOGGLE 0x279 - -/* Select an area of screen to be copied */ -#define KEY_SELECTIVE_SCREENSHOT 0x27a - -/* Move the focus to the next or previous user controllable element within a UI container */ -#define KEY_NEXT_ELEMENT 0x27b -#define KEY_PREVIOUS_ELEMENT 0x27c - -/* Toggle Autopilot engagement */ -#define KEY_AUTOPILOT_ENGAGE_TOGGLE 0x27d - -/* Shortcut Keys */ -#define KEY_MARK_WAYPOINT 0x27e -#define KEY_SOS 0x27f -#define KEY_NAV_CHART 0x280 -#define KEY_FISHING_CHART 0x281 -#define KEY_SINGLE_RANGE_RADAR 0x282 -#define KEY_DUAL_RANGE_RADAR 0x283 -#define KEY_RADAR_OVERLAY 0x284 -#define KEY_TRADITIONAL_SONAR 0x285 -#define KEY_CLEARVU_SONAR 0x286 -#define KEY_SIDEVU_SONAR 0x287 -#define KEY_NAV_INFO 0x288 -#define KEY_BRIGHTNESS_MENU 0x289 - -/* - * Some keyboards have keys which do not have a defined meaning, these keys - * are intended to be programmed / bound to macros by the user. For most - * keyboards with these macro-keys the key-sequence to inject, or action to - * take, is all handled by software on the host side. So from the kernel's - * point of view these are just normal keys. - * - * The KEY_MACRO# codes below are intended for such keys, which may be labeled - * e.g. G1-G18, or S1 - S30. The KEY_MACRO# codes MUST NOT be used for keys - * where the marking on the key does indicate a defined meaning / purpose. - * - * The KEY_MACRO# codes MUST also NOT be used as fallback for when no existing - * KEY_FOO define matches the marking / purpose. In this case a new KEY_FOO - * define MUST be added. - */ -#define KEY_MACRO1 0x290 -#define KEY_MACRO2 0x291 -#define KEY_MACRO3 0x292 -#define KEY_MACRO4 0x293 -#define KEY_MACRO5 0x294 -#define KEY_MACRO6 0x295 -#define KEY_MACRO7 0x296 -#define KEY_MACRO8 0x297 -#define KEY_MACRO9 0x298 -#define KEY_MACRO10 0x299 -#define KEY_MACRO11 0x29a -#define KEY_MACRO12 0x29b -#define KEY_MACRO13 0x29c -#define KEY_MACRO14 0x29d -#define KEY_MACRO15 0x29e -#define KEY_MACRO16 0x29f -#define KEY_MACRO17 0x2a0 -#define KEY_MACRO18 0x2a1 -#define KEY_MACRO19 0x2a2 -#define KEY_MACRO20 0x2a3 -#define KEY_MACRO21 0x2a4 -#define KEY_MACRO22 0x2a5 -#define KEY_MACRO23 0x2a6 -#define KEY_MACRO24 0x2a7 -#define KEY_MACRO25 0x2a8 -#define KEY_MACRO26 0x2a9 -#define KEY_MACRO27 0x2aa -#define KEY_MACRO28 0x2ab -#define KEY_MACRO29 0x2ac -#define KEY_MACRO30 0x2ad - -/* - * Some keyboards with the macro-keys described above have some extra keys - * for controlling the host-side software responsible for the macro handling: - * -A macro recording start/stop key. Note that not all keyboards which emit - * KEY_MACRO_RECORD_START will also emit KEY_MACRO_RECORD_STOP if - * KEY_MACRO_RECORD_STOP is not advertised, then KEY_MACRO_RECORD_START - * should be interpreted as a recording start/stop toggle; - * -Keys for switching between different macro (pre)sets, either a key for - * cycling through the configured presets or keys to directly select a preset. - */ -#define KEY_MACRO_RECORD_START 0x2b0 -#define KEY_MACRO_RECORD_STOP 0x2b1 -#define KEY_MACRO_PRESET_CYCLE 0x2b2 -#define KEY_MACRO_PRESET1 0x2b3 -#define KEY_MACRO_PRESET2 0x2b4 -#define KEY_MACRO_PRESET3 0x2b5 - -/* - * Some keyboards have a buildin LCD panel where the contents are controlled - * by the host. Often these have a number of keys directly below the LCD - * intended for controlling a menu shown on the LCD. These keys often don't - * have any labeling so we just name them KEY_KBD_LCD_MENU# - */ -#define KEY_KBD_LCD_MENU1 0x2b8 -#define KEY_KBD_LCD_MENU2 0x2b9 -#define KEY_KBD_LCD_MENU3 0x2ba -#define KEY_KBD_LCD_MENU4 0x2bb -#define KEY_KBD_LCD_MENU5 0x2bc - -#define BTN_TRIGGER_HAPPY 0x2c0 -#define BTN_TRIGGER_HAPPY1 0x2c0 -#define BTN_TRIGGER_HAPPY2 0x2c1 -#define BTN_TRIGGER_HAPPY3 0x2c2 -#define BTN_TRIGGER_HAPPY4 0x2c3 -#define BTN_TRIGGER_HAPPY5 0x2c4 -#define BTN_TRIGGER_HAPPY6 0x2c5 -#define BTN_TRIGGER_HAPPY7 0x2c6 -#define BTN_TRIGGER_HAPPY8 0x2c7 -#define BTN_TRIGGER_HAPPY9 0x2c8 -#define BTN_TRIGGER_HAPPY10 0x2c9 -#define BTN_TRIGGER_HAPPY11 0x2ca -#define BTN_TRIGGER_HAPPY12 0x2cb -#define BTN_TRIGGER_HAPPY13 0x2cc -#define BTN_TRIGGER_HAPPY14 0x2cd -#define BTN_TRIGGER_HAPPY15 0x2ce -#define BTN_TRIGGER_HAPPY16 0x2cf -#define BTN_TRIGGER_HAPPY17 0x2d0 -#define BTN_TRIGGER_HAPPY18 0x2d1 -#define BTN_TRIGGER_HAPPY19 0x2d2 -#define BTN_TRIGGER_HAPPY20 0x2d3 -#define BTN_TRIGGER_HAPPY21 0x2d4 -#define BTN_TRIGGER_HAPPY22 0x2d5 -#define BTN_TRIGGER_HAPPY23 0x2d6 -#define BTN_TRIGGER_HAPPY24 0x2d7 -#define BTN_TRIGGER_HAPPY25 0x2d8 -#define BTN_TRIGGER_HAPPY26 0x2d9 -#define BTN_TRIGGER_HAPPY27 0x2da -#define BTN_TRIGGER_HAPPY28 0x2db -#define BTN_TRIGGER_HAPPY29 0x2dc -#define BTN_TRIGGER_HAPPY30 0x2dd -#define BTN_TRIGGER_HAPPY31 0x2de -#define BTN_TRIGGER_HAPPY32 0x2df -#define BTN_TRIGGER_HAPPY33 0x2e0 -#define BTN_TRIGGER_HAPPY34 0x2e1 -#define BTN_TRIGGER_HAPPY35 0x2e2 -#define BTN_TRIGGER_HAPPY36 0x2e3 -#define BTN_TRIGGER_HAPPY37 0x2e4 -#define BTN_TRIGGER_HAPPY38 0x2e5 -#define BTN_TRIGGER_HAPPY39 0x2e6 -#define BTN_TRIGGER_HAPPY40 0x2e7 - -/* We avoid low common keys in module aliases so they don't get huge. */ -#define KEY_MIN_INTERESTING KEY_MUTE -#define KEY_MAX 0x2ff -#define KEY_CNT (KEY_MAX + 1) - -/* Relative axes */ -#define REL_X 0x00 -#define REL_Y 0x01 -#define REL_Z 0x02 -#define REL_RX 0x03 -#define REL_RY 0x04 -#define REL_RZ 0x05 -#define REL_HWHEEL 0x06 -#define REL_DIAL 0x07 -#define REL_WHEEL 0x08 -#define REL_MISC 0x09 -/* - * 0x0a is reserved and should not be used in input drivers. - * It was used by HID as REL_MISC + 1 and userspace needs to detect if - * the next REL_* event is correct or is just REL_MISC + n. - * We define here REL_RESERVED so userspace can rely on it and detect - * the situation described above. - */ -#define REL_RESERVED 0x0a -#define REL_WHEEL_HI_RES 0x0b -#define REL_HWHEEL_HI_RES 0x0c -#define REL_MAX 0x0f -#define REL_CNT (REL_MAX + 1) - -/* Absolute axes */ -#define ABS_X 0x00 -#define ABS_Y 0x01 -#define ABS_Z 0x02 -#define ABS_RX 0x03 -#define ABS_RY 0x04 -#define ABS_RZ 0x05 -#define ABS_THROTTLE 0x06 -#define ABS_RUDDER 0x07 -#define ABS_WHEEL 0x08 -#define ABS_GAS 0x09 -#define ABS_BRAKE 0x0a -#define ABS_HAT0X 0x10 -#define ABS_HAT0Y 0x11 -#define ABS_HAT1X 0x12 -#define ABS_HAT1Y 0x13 -#define ABS_HAT2X 0x14 -#define ABS_HAT2Y 0x15 -#define ABS_HAT3X 0x16 -#define ABS_HAT3Y 0x17 -#define ABS_PRESSURE 0x18 -#define ABS_DISTANCE 0x19 -#define ABS_TILT_X 0x1a -#define ABS_TILT_Y 0x1b -#define ABS_TOOL_WIDTH 0x1c - -#define ABS_VOLUME 0x20 - -#define ABS_MISC 0x28 - -/* - * 0x2e is reserved and should not be used in input drivers. - * It was used by HID as ABS_MISC + 6 and userspace needs to detect if - * the next ABS_* event is correct or is just ABS_MISC + n. - * We define here ABS_RESERVED so userspace can rely on it and detect - * the situation described above. - */ -#define ABS_RESERVED 0x2e - -#define ABS_MT_SLOT 0x2f /* MT slot being modified */ -#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ -#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ -#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ -#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ -#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ -#define ABS_MT_POSITION_X 0x35 /* Center X touch position */ -#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */ -#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ -#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ -#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ -#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ -#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */ -#define ABS_MT_TOOL_X 0x3c /* Center X tool position */ -#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */ - - -#define ABS_MAX 0x3f -#define ABS_CNT (ABS_MAX + 1) - -/* Switch events */ -#define SW_LID 0x00 /* Set = lid shut */ -#define SW_TABLET_MODE 0x01 /* Set = tablet mode */ -#define SW_HEADPHONE_INSERT 0x02 /* Set = inserted */ -#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" set = radio enabled */ -#define SW_RADIO SW_RFKILL_ALL /* deprecated */ -#define SW_MICROPHONE_INSERT 0x04 /* Set = inserted */ -#define SW_DOCK 0x05 /* Set = plugged into dock */ -#define SW_LINEOUT_INSERT 0x06 /* Set = inserted */ -#define SW_JACK_PHYSICAL_INSERT 0x07 /* Set = mechanical switch set */ -#define SW_VIDEOOUT_INSERT 0x08 /* Set = inserted */ -#define SW_CAMERA_LENS_COVER 0x09 /* Set = lens covered */ -#define SW_KEYPAD_SLIDE 0x0a /* Set = keypad slide out */ -#define SW_FRONT_PROXIMITY 0x0b /* Set = front proximity sensor active */ -#define SW_ROTATE_LOCK 0x0c /* Set = rotate locked/disabled */ -#define SW_LINEIN_INSERT 0x0d /* Set = inserted */ -#define SW_MUTE_DEVICE 0x0e /* Set = device disabled */ -#define SW_PEN_INSERTED 0x0f /* Set = pen inserted */ -#define SW_MACHINE_COVER 0x10 /* Set = cover closed */ -#define SW_MAX 0x10 -#define SW_CNT (SW_MAX + 1) - -/* Misc events */ -#define MSC_SERIAL 0x00 -#define MSC_PULSELED 0x01 -#define MSC_GESTURE 0x02 -#define MSC_RAW 0x03 -#define MSC_SCAN 0x04 -#define MSC_TIMESTAMP 0x05 -#define MSC_MAX 0x07 -#define MSC_CNT (MSC_MAX + 1) - -/* LEDs */ -#define LED_NUML 0x00 -#define LED_CAPSL 0x01 -#define LED_SCROLLL 0x02 -#define LED_COMPOSE 0x03 -#define LED_KANA 0x04 -#define LED_SLEEP 0x05 -#define LED_SUSPEND 0x06 -#define LED_MUTE 0x07 -#define LED_MISC 0x08 -#define LED_MAIL 0x09 -#define LED_CHARGING 0x0a -#define LED_MAX 0x0f -#define LED_CNT (LED_MAX + 1) - -/* Autorepeat values */ -#define REP_DELAY 0x00 -#define REP_PERIOD 0x01 -#define REP_MAX 0x01 -#define REP_CNT (REP_MAX + 1) - -/* Sounds */ -#define SND_CLICK 0x00 -#define SND_BELL 0x01 -#define SND_TONE 0x02 -#define SND_MAX 0x07 -#define SND_CNT (SND_MAX + 1) - -#endif /* __VIRTIO_INPUT_EVENT_CODES__ */ diff --git a/components/drivers/virtio/virtio_internal.h b/components/drivers/virtio/virtio_internal.h new file mode 100644 index 0000000000..b86ae224b1 --- /dev/null +++ b/components/drivers/virtio/virtio_internal.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#ifndef __VIRTIO_INTERNAL_H__ +#define __VIRTIO_INTERNAL_H__ + +#include <drivers/virtio.h> +#include <drivers/core/dm.h> + +rt_inline rt_bool_t virtio_legacy_is_little_endian(void) +{ +#ifdef ARCH_CPU_BIG_ENDIAN + return RT_FALSE; +#else + return RT_TRUE; +#endif +} + +rt_inline rt_bool_t virtio_is_little_endian(struct rt_virtio_device *vdev) +{ + return rt_virtio_has_feature(vdev, VIRTIO_F_VERSION_1) || + virtio_legacy_is_little_endian(); +} + +#ifdef __CHECKER__ +#define FORCE __attribute__((force)) +#else +#define FORCE +#endif + +rt_inline rt_uint16_t virtio16_to_cpu(struct rt_virtio_device *vdev, rt_uint16_t val) +{ + if (virtio_is_little_endian(vdev)) + { + return rt_le16_to_cpu((FORCE rt_le16_t)val); + } + else + { + return rt_be16_to_cpu((FORCE rt_be16_t)val); + } +} + +rt_inline rt_uint16_t cpu_to_virtio16(struct rt_virtio_device *vdev, rt_uint16_t val) +{ + if (virtio_is_little_endian(vdev)) + { + return (FORCE rt_le16_t)rt_cpu_to_le16(val); + } + else + { + return (FORCE rt_be16_t)rt_cpu_to_be16(val); + } +} + +rt_inline rt_uint32_t virtio32_to_cpu(struct rt_virtio_device *vdev, rt_uint32_t val) +{ + if (virtio_is_little_endian(vdev)) + { + return rt_le32_to_cpu((FORCE rt_le32_t)val); + } + else + { + return rt_be32_to_cpu((FORCE rt_be32_t)val); + } +} + +rt_inline rt_uint32_t cpu_to_virtio32(struct rt_virtio_device *vdev, rt_uint32_t val) +{ + if (virtio_is_little_endian(vdev)) + { + return (FORCE rt_le32_t)rt_cpu_to_le32(val); + } + else + { + return (FORCE rt_be32_t)rt_cpu_to_be32(val); + } +} + +rt_inline rt_uint64_t virtio64_to_cpu(struct rt_virtio_device *vdev, rt_uint64_t val) +{ + if (virtio_is_little_endian(vdev)) + { + return rt_le64_to_cpu((FORCE rt_le64_t)val); + } + else + { + return rt_be64_to_cpu((FORCE rt_be64_t)val); + } +} + +rt_inline rt_uint64_t cpu_to_virtio64(struct rt_virtio_device *vdev, rt_uint64_t val) +{ + if (virtio_is_little_endian(vdev)) + { + return (FORCE rt_le64_t)rt_cpu_to_le64(val); + } + else + { + return (FORCE rt_be64_t)rt_cpu_to_be64(val); + } +} + +#undef FORCE + +#endif /* __VIRTIO_INTERNAL_H__ */ diff --git a/components/drivers/virtio/virtio_mmio.c b/components/drivers/virtio/virtio_mmio.c new file mode 100644 index 0000000000..12f2f93dcf --- /dev/null +++ b/components/drivers/virtio/virtio_mmio.c @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include <rtthread.h> + +#define DBG_TAG "virtio.mmio" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include <mmu.h> + +#include <drivers/ofw.h> +#include <drivers/pic.h> +#include <drivers/virtio.h> +#include <drivers/platform.h> +#include <drivers/core/bus.h> + +#define VIRTIO_MMIO_MAGIC 0x000 /* <RO> Magic value */ +#define VIRTIO_MMIO_VERSION 0x004 /* <RO> Device version number */ +#define VIRTIO_MMIO_DEVICE_ID 0x008 /* <RO> Virtio Subsystem Device ID */ +#define VIRTIO_MMIO_VENDOR_ID 0x00c /* <RO> Virtio Subsystem Vendor ID */ +#define VIRTIO_MMIO_DEVICE_FEATURES 0x010 /* <RO> Flags representing features the device supports */ +#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 /* <WO> Device (host) features word selection. */ +#define VIRTIO_MMIO_DRIVER_FEATURES 0x020 /* <WO> Device features understood and activated by the driver */ +#define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 /* <WO> Activated (guest) features word selection */ +#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 /* <WO> Guest page size, this value should be a power of 2 */ +#define VIRTIO_MMIO_QUEUE_SEL 0x030 /* <WO> Virtual queue index */ +#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 /* <RO> Maximum virtual queue size */ +#define VIRTIO_MMIO_QUEUE_NUM 0x038 /* <WO> Virtual queue size */ +#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c /* <WO> Used Ring alignment in the virtual queue */ +#define VIRTIO_MMIO_QUEUE_PFN 0x040 /* <RW> Guest physical page number of the virtual queue */ +#define VIRTIO_MMIO_QUEUE_READY 0x044 /* <RW> Virtual queue ready bit */ +#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 /* <WO> Queue notifier */ +#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 /* <RO> Interrupt status */ +#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 /* <WO> Interrupt acknowledge */ +#define VIRTIO_MMIO_STATUS 0x070 /* <RW> Device status */ +#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 /* <WO> Virtual queue's descriptor Area 64 bit long physical address */ +#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 /* <WO> */ +#define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090 /* <WO> Virtual queue's available Ring (Driver Area) 64 bit long physical address */ +#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094 /* <WO> */ +#define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0 /* <WO> Virtual queue's used Ring (Device Area) 64 bit long physical address */ +#define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4 /* <WO> */ +#define VIRTIO_MMIO_SHM_SEL 0x0ac /* <WO> Shared memory region id */ +#define VIRTIO_MMIO_SHM_LEN_LOW 0x0b0 /* <RO> Shared memory region length, 64 bits in two halves */ +#define VIRTIO_MMIO_SHM_LEN_HIGH 0x0b4 /* <RO> */ +#define VIRTIO_MMIO_SHM_BASE_LOW 0x0b8 /* <RO> Shared memory region base address, 64 bits in two halves */ +#define VIRTIO_MMIO_SHM_BASE_HIGH 0x0bc /* <RO> */ +#define VIRTIO_MMIO_CONFIG_GENERATION 0x0fc /* <RO> Configuration atomicity value */ +#define VIRTIO_MMIO_CONFIG 0x100 /* <RO> Configuration space */ + +#define VIRTIO_MMIO_INT_VIRTQ (1 << 0) /* The device has used a buffer in at least one of the active virtual queues */ +#define VIRTIO_MMIO_INT_CONFIG (1 << 1) /* The configuration of the device has changed */ + +#define VIRTIO_MMIO_VIRTQ_PAGE_SHIFT ARCH_PAGE_SHIFT +#define VIRTIO_MMIO_VIRTQ_PAGE_SZIE (1 << VIRTIO_MMIO_VIRTQ_PAGE_SHIFT) +#define VIRTIO_MMIO_VIRTQ_ALIGN_SHIFT VIRTIO_MMIO_VIRTQ_PAGE_SHIFT +#define VIRTIO_MMIO_VIRTQ_ALIGN (1 << VIRTIO_MMIO_VIRTQ_ALIGN_SHIFT) + +struct virtio_mmio +{ + struct rt_virtio_device parent; + + void *base; + int irq; + rt_ubase_t version; + + struct rt_spinlock spinlock; +}; + +#define raw_to_virtio_mmio(raw) rt_container_of(raw, struct virtio_mmio, parent) + +rt_inline rt_uint64_t virtio_mmio_read64(struct virtio_mmio *vio, int offset) +{ + return rt_cpu_to_le64(HWREG64(vio->base + offset)); +} + +rt_inline void virtio_mmio_write64(struct virtio_mmio *vio, int offset, rt_uint64_t value) +{ + HWREG64(vio->base + offset) = rt_le64_to_cpu(value); +} + +rt_inline rt_uint32_t virtio_mmio_read32(struct virtio_mmio *vio, int offset) +{ + return rt_cpu_to_le32(HWREG32(vio->base + offset)); +} + +rt_inline void virtio_mmio_write32(struct virtio_mmio *vio, int offset, rt_uint32_t value) +{ + HWREG32(vio->base + offset) = rt_le32_to_cpu(value); +} + +rt_inline rt_uint16_t virtio_mmio_read16(struct virtio_mmio *vio, int offset) +{ + return rt_cpu_to_le16(HWREG16(vio->base + offset)); +} + +rt_inline void virtio_mmio_write16(struct virtio_mmio *vio, int offset, rt_uint16_t value) +{ + HWREG16(vio->base + offset) = rt_le16_to_cpu(value); +} + +rt_inline rt_uint8_t virtio_mmio_read8(struct virtio_mmio *vio, int offset) +{ + return HWREG8(vio->base + offset); +} + +rt_inline void virtio_mmio_write8(struct virtio_mmio *vio, int offset, rt_uint8_t value) +{ + HWREG8(vio->base + offset) = value; +} + +static void virtio_mmio_isr(int irqno, void *param) +{ + rt_uint32_t status; + struct virtio_mmio *vio = param; + + /* Read interrupts */ + status = virtio_mmio_read32(vio, VIRTIO_MMIO_INTERRUPT_STATUS); + + /* Acknowledge interrupts */ + virtio_mmio_write32(vio, VIRTIO_MMIO_INTERRUPT_ACK, status); + + if (status & VIRTIO_MMIO_INT_CONFIG) + { + rt_virtio_device_config_changed(&vio->parent); + } + + if (status & VIRTIO_MMIO_INT_VIRTQ) + { + struct rt_virtqueue *vq; + rt_ubase_t level = rt_spin_lock_irqsave(&vio->spinlock); + + rt_list_for_each_entry(vq, &vio->parent.vq_node, list) + { + rt_virtqueue_isr(irqno, vq); + } + + rt_spin_unlock_irqrestore(&vio->spinlock, level); + } +} + +static rt_bool_t virtio_mmio_notify(struct rt_virtqueue *vq) +{ + struct virtio_mmio *vio = raw_to_virtio_mmio(vq->vdev); + + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_NOTIFY, vq->index); + + return RT_TRUE; +} + +static rt_err_t virtio_mmio_read_shm_region(struct virtio_mmio *vio, + struct rt_virtio_shm_region *shm) +{ + virtio_mmio_write32(vio, VIRTIO_MMIO_SHM_SEL, shm->id); + + shm->size = virtio_mmio_read32(vio, VIRTIO_MMIO_SHM_LEN_HIGH); + shm->size <<= 32; + shm->size |= virtio_mmio_read32(vio, VIRTIO_MMIO_SHM_LEN_LOW); + + if (shm->size == ~(rt_uint64_t)0UL) + { + return -RT_EEMPTY; + } + + shm->base = virtio_mmio_read32(vio, VIRTIO_MMIO_SHM_BASE_HIGH); + shm->base <<= 32; + shm->base |= virtio_mmio_read32(vio, VIRTIO_MMIO_SHM_BASE_LOW); + + return RT_EOK; +} + +static rt_err_t virtio_mmio_get_status(struct rt_virtio_device *vdev, + rt_uint8_t *out_status) +{ + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + *out_status = virtio_mmio_read32(vio, VIRTIO_MMIO_STATUS); + + return RT_EOK; +} + +static rt_err_t virtio_mmio_set_status(struct rt_virtio_device *vdev, + rt_uint8_t status) +{ + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + RT_ASSERT(status != 0); + + virtio_mmio_write32(vio, VIRTIO_MMIO_STATUS, status); + + return RT_EOK; +} + +static rt_err_t virtio_mmio_get_features(struct rt_virtio_device *vdev, + rt_uint64_t *out_features) +{ + rt_uint64_t features; + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + virtio_mmio_write32(vio, VIRTIO_MMIO_DEVICE_FEATURES_SEL, 1); + features = virtio_mmio_read32(vio, VIRTIO_MMIO_DEVICE_FEATURES); + features <<= 32; + + virtio_mmio_write32(vio, VIRTIO_MMIO_DEVICE_FEATURES_SEL, 0); + features |= virtio_mmio_read32(vio, VIRTIO_MMIO_DEVICE_FEATURES); + + *out_features = features; + + return RT_EOK; +} + +static rt_err_t virtio_mmio_set_features(struct rt_virtio_device *vdev) +{ + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + /* Make sure there are no mixed devices */ + if (vio->version == 2 && !(vdev->features & RT_BIT(VIRTIO_F_VERSION_1))) + { + LOG_E("%s devices (version 2) must provide VIRTIO_F_VERSION_1 feature", + rt_dm_dev_get_name(&vdev->parent)); + + return -RT_EINVAL; + } + + virtio_mmio_write32(vio, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 1); + virtio_mmio_write32(vio, VIRTIO_MMIO_DRIVER_FEATURES, + (rt_uint32_t)(vdev->features >> 32)); + + virtio_mmio_write32(vio, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 0); + virtio_mmio_write32(vio, VIRTIO_MMIO_DRIVER_FEATURES, + (rt_uint32_t)vdev->features); + + return RT_EOK; +} + +static rt_err_t virtio_mmio_get_config(struct rt_virtio_device *vdev, + rt_uint32_t offset, void *dst, int length) +{ + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + offset += VIRTIO_MMIO_CONFIG; + + if (vio->version == 1) + { + for (int i = 0; i < length; ++i) + { + ((rt_uint8_t *)dst)[i] = virtio_mmio_read8(vio, offset + i); + } + + return RT_EOK; + } + + switch (length) + { + case 4: + *(rt_uint32_t *)dst = virtio_mmio_read32(vio, offset); + break; + case 1: + *(rt_uint8_t *)dst = virtio_mmio_read8(vio, offset); + break; + case 2: + *(rt_uint16_t *)dst = virtio_mmio_read16(vio, offset); + break; + case 8: + *(rt_uint64_t *)dst = virtio_mmio_read64(vio, offset); + break; + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t virtio_mmio_set_config(struct rt_virtio_device *vdev, + rt_uint32_t offset, const void *src, int length) +{ + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + offset += VIRTIO_MMIO_CONFIG; + + if (vio->version == 1) + { + for (int i = 0; i < length; ++i) + { + virtio_mmio_write8(vio, offset + i, ((rt_uint8_t *)src)[i]); + } + + return RT_EOK; + } + + switch (length) + { + case 4: + virtio_mmio_write32(vio, offset, *(rt_uint32_t *)src); + break; + case 1: + virtio_mmio_write8(vio, offset, *(rt_uint8_t *)src); + break; + case 2: + virtio_mmio_write16(vio, offset, *(rt_uint16_t *)src); + break; + case 8: + virtio_mmio_write64(vio, offset, *(rt_uint64_t *)src); + break; + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +static struct rt_virtqueue *virtio_mmio_install_vq(struct rt_virtio_device *vdev, + int index, const char *name, rt_virtqueue_callback cb, + struct rt_virtqueue_formula *formula) +{ + rt_uint32_t num_max; + struct rt_virtqueue *vq; + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_SEL, index); + + if (virtio_mmio_read32(vio, vio->version == 1 ? + VIRTIO_MMIO_QUEUE_PFN : VIRTIO_MMIO_QUEUE_READY)) + { + return RT_NULL; + } + + num_max = virtio_mmio_read32(vio, VIRTIO_MMIO_QUEUE_NUM_MAX); + + if (num_max == 0) + { + LOG_E("%s.virtqueue[%d](%s) num_max is zero", + rt_dm_dev_get_name(&vdev->parent), index, name); + + return RT_NULL; + } + + vq = rt_virtqueue_create(vdev, name, index, num_max, VIRTIO_MMIO_VIRTQ_ALIGN, + virtio_mmio_notify, cb, formula); + + if (!vq) + { + return vq; + } + + vq->num_max = num_max; + + /* Activate the queue */ + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_NUM, rt_virtqueue_get_virtq_size(vq)); + + if (vio->version == 1) + { + rt_uint32_t pfn = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_desc_addr(vq)); + + pfn >>= VIRTIO_MMIO_VIRTQ_ALIGN_SHIFT; + + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_ALIGN, VIRTIO_MMIO_VIRTQ_ALIGN); + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_PFN, pfn); + } + else + { + rt_uint64_t page; + + page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_desc_addr(vq)); + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_DESC_LOW, (rt_uint32_t)page); + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_DESC_HIGH, (rt_uint32_t)(page >> 32)); + + page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_avail_addr(vq)); + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_AVAIL_LOW, (rt_uint32_t)page); + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_AVAIL_HIGH, (rt_uint32_t)(page >> 32)); + + page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_used_addr(vq)); + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_USED_LOW, (rt_uint32_t)page); + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_USED_HIGH, (rt_uint32_t)(page >> 32)); + + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_READY, 1); + } + + return vq; +} + +static rt_err_t virtio_mmio_install_vqs(struct rt_virtio_device *vdev, int vqs_nr, + struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[]) +{ + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + for (int i = 0, vq_idx = 0; i < vqs_nr; ++i) + { + if (!names[i]) + { + vqs[i] = RT_NULL; + + continue; + } + + vqs[i] = virtio_mmio_install_vq(vdev, vq_idx++, names[i], cbs[i], RT_NULL); + + if (!vqs[i]) + { + rt_virtio_virtqueue_release(vdev); + + return -RT_ERROR; + } + } + + rt_hw_interrupt_install(vio->irq, virtio_mmio_isr, vio, + rt_dm_dev_get_name(&vdev->parent)); + rt_hw_interrupt_umask(vio->irq); + + return RT_EOK; +} + +static rt_err_t virtio_mmio_release_vqs(struct rt_virtio_device *vdev) +{ + struct rt_virtqueue *vq, *vq_next; + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + rt_hw_interrupt_mask(vio->irq); + rt_pic_detach_irq(vio->irq, vio); + + rt_list_for_each_entry_safe(vq, vq_next, &vio->parent.vq_node, list) + { + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_SEL, vq->index); + + if (vio->version == 1) + { + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_PFN, RT_NULL); + } + else + { + rt_uint32_t status; + + virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_READY, RT_NULL); + status = virtio_mmio_read32(vio, VIRTIO_MMIO_QUEUE_READY); + + if (!status) + { + LOG_W("%s.virtqueue[%s] VIRTIO_MMIO_QUEUE_READY = %d", + rt_dm_dev_get_name(&vq->vdev->parent), vq->name, status); + } + } + + rt_virtqueue_delete(&vio->parent, vq); + } + + return RT_EOK; +} + +static rt_err_t virtio_mmio_control_vqs(struct rt_virtio_device *vdev, + rt_uint32_t cfg, void *data) +{ + rt_err_t err = RT_EOK; + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + switch (cfg) + { + case RT_VIRTQUEUE_CTL_IRQ_AFFINITY: + err = rt_pic_irq_set_affinity(vio->irq, (rt_bitmap_t *)data); + break; + + case RT_VIRTQUEUE_CTL_READ_SHM_REGION: + if (!data) + { + err = -RT_EINVAL; + break; + } + + err = virtio_mmio_read_shm_region(vio, data); + break; + + default: + err = -RT_ENOSYS; + break; + } + + return err; +} + +static rt_err_t virtio_mmio_generation(struct rt_virtio_device *vdev, + rt_uint32_t *out_counter) +{ + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + if (vio->version == 1) + { + *out_counter = 0; + } + else + { + *out_counter = virtio_mmio_read32(vio, VIRTIO_MMIO_CONFIG_GENERATION); + } + + return RT_EOK; +} + +static rt_err_t virtio_mmio_reset(struct rt_virtio_device *vdev) +{ + struct virtio_mmio *vio = raw_to_virtio_mmio(vdev); + + virtio_mmio_write32(vio, VIRTIO_MMIO_STATUS, 0); + + return RT_EOK; +} + +static const struct rt_virtio_transport virtio_mmio_trans = +{ + .get_status = virtio_mmio_get_status, + .set_status = virtio_mmio_set_status, + .get_features = virtio_mmio_get_features, + .set_features = virtio_mmio_set_features, + .get_config = virtio_mmio_get_config, + .set_config = virtio_mmio_set_config, + .install_vqs = virtio_mmio_install_vqs, + .release_vqs = virtio_mmio_release_vqs, + .control_vqs = virtio_mmio_control_vqs, + .generation = virtio_mmio_generation, + .reset = virtio_mmio_reset, +}; + +static rt_err_t virtio_mmio_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + rt_uint32_t magic; + struct rt_virtio_device *vdev; + struct rt_device *dev = &pdev->parent; + struct virtio_mmio *vio = rt_calloc(1, sizeof(*vio)); + + if (!vio) + { + return -RT_ENOMEM; + } + + vio->base = rt_dm_dev_iomap(dev, 0); + + if (!vio->base) + { + err = -RT_EIO; + + goto _fail; + } + + vio->irq = rt_dm_dev_get_irq(dev, 0); + + if (vio->irq < 0) + { + err = vio->irq; + + goto _fail; + } + + magic = virtio_mmio_read32(vio, VIRTIO_MMIO_MAGIC); + + /* 0x74726976 (a Little Endian equivalent of the "virt" string). */ + if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) + { + err = -RT_EINVAL; + + LOG_E("Invalid magic: %x", magic); + + goto _fail; + } + + vio->version = virtio_mmio_read32(vio, VIRTIO_MMIO_VERSION); + + /* Only support version 1~2 */ + if (vio->version < 1 || vio->version > 2) + { + err = -RT_ENOSYS; + + LOG_E("Not support version: %d", vio->version); + + goto _fail; + } + + vdev = &vio->parent; + + vdev->id.device = virtio_mmio_read32(vio, VIRTIO_MMIO_DEVICE_ID); + + if (vdev->id.device == VIRTIO_DEVICE_ID_INVALID) + { + err = -RT_EEMPTY; + goto _fail; + } + + vdev->id.vendor = virtio_mmio_read32(vio, VIRTIO_MMIO_VENDOR_ID); + + if (vio->version == 1) + { + virtio_mmio_write32(vio, VIRTIO_MMIO_GUEST_PAGE_SIZE, VIRTIO_MMIO_VIRTQ_PAGE_SZIE); + } + + rt_spin_lock_init(&vio->spinlock); + + vdev->trans = &virtio_mmio_trans; + vdev->parent.ofw_node = dev->ofw_node; + + if ((err = rt_virtio_device_register(vdev))) + { + goto _fail; + } + + dev->user_data = vio; + + return RT_EOK; + +_fail: + if (vio->base) + { + rt_iounmap(vio->base); + } + rt_free(vio); + + return err; +} + +static rt_err_t virtio_mmio_remove(struct rt_platform_device *pdev) +{ + struct virtio_mmio *vio = pdev->parent.user_data; + + rt_hw_interrupt_mask(vio->irq); + rt_pic_detach_irq(vio->irq, vio); + + rt_bus_remove_device(&vio->parent.parent); + + rt_iounmap(vio->base); + rt_free(vio); + + return RT_EOK; +} + +static const struct rt_ofw_node_id virtio_mmio_ofw_ids[] = +{ + { .compatible = "virtio,mmio" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver virtio_mmio_driver = +{ + .name = "virtio-mmio", + .ids = virtio_mmio_ofw_ids, + + .probe = virtio_mmio_probe, + .remove = virtio_mmio_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(virtio_mmio_driver); diff --git a/components/drivers/virtio/virtio_mmio.h b/components/drivers/virtio/virtio_mmio.h deleted file mode 100644 index bb5bc79b95..0000000000 --- a/components/drivers/virtio/virtio_mmio.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-9-16 GuEe-GUI the first version - * 2021-11-11 GuEe-GUI modify to virtio common interface - */ - -#ifndef __VIRTIO_MMIO_H__ -#define __VIRTIO_MMIO_H__ - -#include <rtdef.h> - -struct virtio_mmio_config -{ - rt_uint32_t magic; /* [0x00]<RO> Magic value */ - rt_uint32_t version; /* [0x04]<RO> Device version number */ - rt_uint32_t device_id; /* [0x08]<RO> Virtio Subsystem Device ID */ - rt_uint32_t vendor_id; /* [0x0c]<RO> Virtio Subsystem Vendor ID */ - rt_uint32_t device_features; /* [0x10]<RO> Flags representing features the device supports */ - rt_uint32_t device_features_sel; /* [0x14]<WO> Device (host) features word selection. */ - rt_uint32_t res0[2]; /* [0x18] */ - rt_uint32_t driver_features; /* [0x20]<WO> Device features understood and activated by the driver */ - rt_uint32_t driver_features_sel; /* [0x24]<WO> Activated (guest) features word selection */ - rt_uint32_t guest_page_size; /* [0x28]<WO> Guest page size, this value should be a power of 2 */ - rt_uint32_t res1[1]; /* [0x2c] */ - rt_uint32_t queue_sel; /* [0x30]<WO> Virtual queue index */ - rt_uint32_t queue_num_max; /* [0x34]<RO> Maximum virtual queue size */ - rt_uint32_t queue_num; /* [0x38]<WO> Virtual queue size */ - rt_uint32_t queue_align; /* [0x3c]<WO> Used Ring alignment in the virtual queue */ - rt_uint32_t queue_pfn; /* [0x40]<RW> Guest physical page number of the virtual queue */ - rt_uint32_t queue_ready; /* [0x44]<RW> Virtual queue ready bit */ - rt_uint32_t res2[2]; /* [0x48] */ - rt_uint32_t queue_notify; /* [0x50]<WO> Queue notifier */ - rt_uint32_t res3[3]; /* [0x54] */ - rt_uint32_t interrupt_status; /* [0x60]<RO> Interrupt status */ - rt_uint32_t interrupt_ack; /* [0x64]<WO> Interrupt acknowledge */ - rt_uint32_t res4[2]; /* [0x68] */ - rt_uint32_t status; /* [0x70]<RW> Device status */ - rt_uint32_t res5[3]; /* [0x74] */ - rt_uint32_t queue_desc_low; /* [0x80]<WO> Virtual queue’s Descriptor Area 64 bit long physical address */ - rt_uint32_t queue_desc_high; /* [0x84]<WO> */ - rt_uint32_t res6[2]; /* [0x88] */ - rt_uint32_t queue_driver_low; /* [0x90]<WO> Virtual queue’s Driver Area 64 bit long physical address */ - rt_uint32_t queue_driver_high; /* [0x94]<WO> */ - rt_uint32_t res7[2]; /* [0x98] */ - rt_uint32_t queue_device_low; /* [0xa0]<WO> Virtual queue’s Device Area 64 bit long physical address */ - rt_uint32_t queue_device_high; /* [0xa4]<WO> */ - rt_uint32_t res8[21]; /* [0xa8] */ - rt_uint32_t config_generation; /* [0xfc]<RO> Configuration atomicity value */ - rt_uint32_t config[]; /* [0x100+]<RO> Configuration space */ - -/* - * According to the compiler's optimization ways, we should force compiler not - * to optimization here, but it will cause some compilers generate memory access - * instructions fail. So we allow user to choose a toggle of optimize here. - */ -#ifdef RT_USING_VIRTIO_MMIO_ALIGN -} __attribute__((packed)); -#else -}; -#endif - -#endif /* __VIRTIO_MMIO_H__ */ diff --git a/components/drivers/virtio/virtio_net.c b/components/drivers/virtio/virtio_net.c deleted file mode 100644 index d92421b656..0000000000 --- a/components/drivers/virtio/virtio_net.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#include <rthw.h> -#include <rtthread.h> -#include <cpuport.h> -#include <mm_aspace.h> - -#ifdef RT_USING_VIRTIO_NET - -#include <virtio_net.h> - -static rt_err_t virtio_net_tx(rt_device_t dev, struct pbuf *p) -{ - rt_uint16_t id; - struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev; - struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev; - struct virtq *queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX]; - - id = (queue_tx->avail->idx * 2) % queue_tx->num; - - virtio_net_dev->info[id].hdr.flags = 0; - virtio_net_dev->info[id].hdr.gso_type = 0; - virtio_net_dev->info[id].hdr.hdr_len = 0; - virtio_net_dev->info[id].hdr.gso_size = 0; - virtio_net_dev->info[id].hdr.csum_start = 0; - virtio_net_dev->info[id].hdr.csum_offset = 0; - virtio_net_dev->info[id].hdr.num_buffers = 0; - - pbuf_copy_partial(p, virtio_net_dev->info[id].rx_buffer, p->tot_len, 0); - - virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id); - virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1); - - virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id, - VIRTIO_VA2PA(&virtio_net_dev->info[id].hdr), VIRTIO_NET_HDR_SIZE, VIRTQ_DESC_F_NEXT, id + 1); - - virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1, - VIRTIO_VA2PA(virtio_net_dev->info[id].rx_buffer), p->tot_len, 0, 0); - - virtio_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, id); - - virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_TX); - - virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX); - virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX); - - return RT_EOK; -} - -static struct pbuf *virtio_net_rx(rt_device_t dev) -{ - rt_uint16_t id; - rt_uint32_t len; - struct pbuf *p = RT_NULL; - struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev; - struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev; - struct virtq *queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX]; - - if (queue_rx->used_idx != queue_rx->used->idx) - { - id = (queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id + 1) % queue_rx->num; - len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len - VIRTIO_NET_HDR_SIZE; - - if (len > VIRTIO_NET_PAYLOAD_MAX_SIZE) - { - rt_kprintf("%s: Receive buffer's size = %u is too big!\n", virtio_net_dev->parent.parent.parent.name, len); - len = VIRTIO_NET_PAYLOAD_MAX_SIZE; - } - - p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); - - if (p != RT_NULL) - { - rt_memcpy(p->payload, (void *)queue_rx->desc[id].addr - PV_OFFSET, len); - - queue_rx->used_idx++; - - virtio_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_RX, id - 1); - - virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_RX); - } - } - - return p; -} - -static rt_err_t virtio_net_init(rt_device_t dev) -{ - int i; - rt_uint16_t idx[VIRTIO_NET_RTX_QUEUE_SIZE]; - struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev; - struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev; - struct virtq *queue_rx, *queue_tx; - - queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX]; - queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX]; - - virtio_alloc_desc_chain(virtio_dev, VIRTIO_NET_QUEUE_RX, queue_rx->num, idx); - virtio_alloc_desc_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, queue_tx->num, idx); - - for (i = 0; i < queue_rx->num; ++i) - { - rt_uint16_t id = (i * 2) % queue_rx->num; - void *addr = virtio_net_dev->info[i].tx_buffer; - - /* Descriptor for net_hdr */ - virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_RX, id, - VIRTIO_VA2PA(addr), VIRTIO_NET_HDR_SIZE, VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE, id + 1); - - /* Descriptor for data */ - virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_RX, id + 1, - VIRTIO_VA2PA(addr) + VIRTIO_NET_HDR_SIZE, VIRTIO_NET_MSS, VIRTQ_DESC_F_WRITE, 0); - - queue_rx->avail->ring[i] = id; - } - rt_hw_dsb(); - - queue_rx->avail->flags = 0; - queue_rx->avail->idx = queue_rx->num; - - queue_rx->used_idx = queue_rx->used->idx; - - queue_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT; - queue_tx->avail->idx = 0; - - virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_RX); - - return eth_device_linkchange(&virtio_net_dev->parent, RT_TRUE); -} - -static rt_err_t virtio_net_control(rt_device_t dev, int cmd, void *args) -{ - rt_err_t status = RT_EOK; - struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev; - - switch (cmd) - { - case NIOCTL_GADDR: - if (args == RT_NULL) - { - status = -RT_ERROR; - break; - } - - rt_memcpy(args, virtio_net_dev->config->mac, sizeof(virtio_net_dev->config->mac)); - break; - default: - status = -RT_EINVAL; - break; - } - - return status; -} - -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops virtio_net_ops = -{ - virtio_net_init, - RT_NULL, - RT_NULL, - RT_NULL, - RT_NULL, - virtio_net_control -}; -#endif - -static void virtio_net_isr(int irqno, void *param) -{ - struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)param; - struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev; - struct virtq *queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX]; - - virtio_interrupt_ack(virtio_dev); - rt_hw_dsb(); - - if (queue_rx->used_idx != queue_rx->used->idx) - { - rt_hw_dsb(); - - eth_device_ready(&virtio_net_dev->parent); - } -} - -rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq) -{ - static int dev_no = 0; - char dev_name[RT_NAME_MAX]; - struct virtio_device *virtio_dev; - struct virtio_net_device *virtio_net_dev; - - virtio_net_dev = rt_malloc(sizeof(struct virtio_net_device)); - - if (virtio_net_dev == RT_NULL) - { - goto _alloc_fail; - } - - virtio_dev = &virtio_net_dev->virtio_dev; - virtio_dev->irq = irq; - virtio_dev->mmio_base = mmio_base; - - virtio_net_dev->config = (struct virtio_net_config *)virtio_dev->mmio_config->config; - - virtio_reset_device(virtio_dev); - virtio_status_acknowledge_driver(virtio_dev); - - virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~( - (1 << VIRTIO_NET_F_CTRL_VQ) | - (1 << VIRTIO_F_RING_EVENT_IDX)); - - virtio_status_driver_ok(virtio_dev); - - if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK) - { - goto _alloc_fail; - } - - if (virtio_queue_init(virtio_dev, VIRTIO_NET_QUEUE_RX, VIRTIO_NET_RTX_QUEUE_SIZE) != RT_EOK) - { - goto _alloc_fail; - } - - if (virtio_queue_init(virtio_dev, VIRTIO_NET_QUEUE_TX, VIRTIO_NET_RTX_QUEUE_SIZE) != RT_EOK) - { - virtio_queue_destroy(virtio_dev, VIRTIO_NET_QUEUE_RX); - goto _alloc_fail; - } - - virtio_net_dev->parent.parent.type = RT_Device_Class_NetIf; -#ifdef RT_USING_DEVICE_OPS - virtio_net_dev->parent.parent.ops = &virtio_net_ops; -#else - virtio_net_dev->parent.parent.init = virtio_net_init; - virtio_net_dev->parent.parent.open = RT_NULL; - virtio_net_dev->parent.parent.close = RT_NULL; - virtio_net_dev->parent.parent.read = RT_NULL; - virtio_net_dev->parent.parent.write = RT_NULL; - virtio_net_dev->parent.parent.control = virtio_net_control; -#endif - virtio_net_dev->parent.eth_tx = virtio_net_tx; - virtio_net_dev->parent.eth_rx = virtio_net_rx; - - rt_snprintf(dev_name, RT_NAME_MAX, "virtio-net%d", dev_no++); - - rt_hw_interrupt_install(irq, virtio_net_isr, virtio_net_dev, dev_name); - rt_hw_interrupt_umask(irq); - - return eth_device_init(&virtio_net_dev->parent, dev_name); - -_alloc_fail: - - if (virtio_net_dev != RT_NULL) - { - virtio_queues_free(virtio_dev); - rt_free(virtio_net_dev); - } - return -RT_ENOMEM; -} -#endif /* RT_USING_VIRTIO_NET */ diff --git a/components/drivers/virtio/virtio_pci.c b/components/drivers/virtio/virtio_pci.c new file mode 100644 index 0000000000..d17b6ee97a --- /dev/null +++ b/components/drivers/virtio/virtio_pci.c @@ -0,0 +1,942 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-07 GuEe-GUI first version + */ + +#include <rtthread.h> + +#define DBG_TAG "virtio.pci" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include <mmu.h> + +#include <drivers/pic.h> +#include <drivers/pci.h> +#include <drivers/pci_msi.h> +#include <drivers/virtio.h> +#include <drivers/core/bus.h> + +#define VIRTIO_PCI_CAP_COMMON_CFG 1 /* Common configuration */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 /* Notifications */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 /* ISR Status */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 /* Device specific configuration */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 /* PCI configuration access */ +#define VIRTIO_PCI_CAP_SHARED_MEMORY_CFG 8 /* Shared memory region */ +#define VIRTIO_PCI_CAP_VENDOR_CFG 9 /* Vendor-specific data */ + +struct virtio_pci_cap +{ + rt_uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + rt_uint8_t cap_next; /* Generic PCI field: next ptr. */ + rt_uint8_t cap_len; /* Generic PCI field: capability length */ + rt_uint8_t cfg_type; /* Identifies the structure. */ + rt_uint8_t bar; /* Where to find it. */ + rt_uint8_t id; /* Multiple capabilities of the same type */ + rt_uint8_t padding[2]; /* Pad to full dword. */ + rt_le32_t offset; /* Offset within bar. */ + rt_le32_t length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_cap64 +{ + struct virtio_pci_cap cap; + rt_le32_t offset_hi; /* Most sig 32 bits of offset */ + rt_le32_t length_hi; /* Most sig 32 bits of length */ +}; + +struct virtio_pci_common_cfg +{ + /* About the whole device. */ + rt_le32_t device_feature_select; /* Read-write */ + rt_le32_t device_feature; /* Read-only for driver */ + rt_le32_t driver_feature_select; /* Read-write */ + rt_le32_t driver_feature; /* Read-write */ + rt_le16_t config_msix_vector; /* Read-write */ + rt_le16_t num_queues; /* Read-only for driver */ + rt_uint8_t device_status; /* Read-write */ + rt_uint8_t config_generation; /* Read-only for driver */ + + /* About a specific virtqueue. */ + rt_le16_t queue_select; /* Read-write */ + rt_le16_t queue_size; /* Read-write */ + rt_le16_t queue_msix_vector; /* Read-write */ + rt_le16_t queue_enable; /* Read-write */ + rt_le16_t queue_notify_off; /* Read-only for driver */ + rt_le32_t queue_desc_low; /* read-write */ + rt_le32_t queue_desc_high; /* read-write */ + rt_le32_t queue_avail_low; /* read-write */ + rt_le32_t queue_avail_high; /* read-write */ + rt_le32_t queue_used_low; /* read-write */ + rt_le32_t queue_used_high; /* read-write */ +}; + +struct virtio_pci_notify_cap +{ + struct virtio_pci_cap cap; + rt_le32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +struct virtio_pci_cfg_cap +{ + struct virtio_pci_cap cap; + rt_uint8_t pci_cfg_data[4]; /* Data for BAR access. */ +}; + +#define VIRTIO_PCI_VIRTQ_ALIGN 4096 +#define VIRTIO_PCI_ISR_QUEUE RT_BIT(0) +#define VIRTIO_PCI_ISR_CONFIG RT_BIT(1) +#define VIRTIO_MSI_NO_VECTOR 0xffff + +#define VIRTIO_PCI_DEVICE_START 0x1040 +#define VIRTIO_PCI_DEVICE_END 0x107f + +struct virtio_pci +{ + struct rt_virtio_device parent; + struct rt_pci_device *pdev; + + void *dev_regs; + void *isr_regs; + void *notify_regs; + struct virtio_pci_common_cfg *common; + + rt_size_t dev_regs_offset; + rt_size_t isr_regs_offset; + rt_size_t notify_regs_offset; + rt_size_t common_offset; + + rt_size_t notify_len; + rt_uint32_t notify_offset_multiplier; + + int nvectors; + struct rt_pci_msix_entry *msix_entries; +}; + +#define raw_to_virtio_pci(raw) rt_container_of(raw, struct virtio_pci, parent) + +rt_inline rt_uint32_t virtio_pci_read32(void *addr) +{ + return rt_cpu_to_le32(HWREG32(addr)); +} + +rt_inline void virtio_pci_write32(void *addr, rt_uint32_t value) +{ + HWREG32(addr) = rt_le32_to_cpu(value); +} + +rt_inline rt_uint16_t virtio_pci_read16(void *addr) +{ + return rt_cpu_to_le16(HWREG16(addr)); +} + +rt_inline void virtio_pci_write16(void *addr, rt_uint16_t value) +{ + HWREG16(addr) = rt_le16_to_cpu(value); +} + +rt_inline rt_uint8_t virtio_pci_read8(void *addr) +{ + return HWREG8(addr); +} + +rt_inline void virtio_pci_write8(void *addr, rt_uint8_t value) +{ + HWREG8(addr) = value; +} + +static void virtio_pci_vq_isr(int irqno, void *param) +{ + struct rt_virtqueue *vq = param; + + rt_virtqueue_isr(irqno, vq); +} + +static void virtio_pci_config_isr(int irqno, void *param) +{ + struct virtio_pci *vp = param; + + rt_virtio_device_config_changed(&vp->parent); +} + +static void virtio_pci_isr(int irqno, void *param) +{ + rt_uint8_t isr; + struct rt_virtqueue *vq; + struct virtio_pci *vp = param; + + isr = virtio_pci_read8(vp->isr_regs); + + if (!isr) + { + return; + } + + if (isr & VIRTIO_PCI_ISR_CONFIG) + { + virtio_pci_config_isr(irqno, param); + } + + if (isr & VIRTIO_PCI_ISR_QUEUE) + { + rt_list_for_each_entry(vq, &vp->parent.vq_node, list) + { + virtio_pci_vq_isr(irqno, vq); + } + } +} + +static rt_bool_t virtio_pci_notify(struct rt_virtqueue *vq) +{ + rt_uint16_t offset; + struct virtio_pci *vp = raw_to_virtio_pci(vq->vdev); + + virtio_pci_write16(&vp->common->queue_select, vq->index); + + offset = virtio_pci_read16(&vp->common->queue_notify_off); + offset *= vp->notify_offset_multiplier; + + /* We no config VIRTIO_F_NOTIFICATION_DATA, so it is only 16 bits */ + if (offset > vp->notify_len - sizeof(rt_uint16_t)) + { + return RT_FALSE; + } + + virtio_pci_write16(vp->notify_regs + offset, vq->index); + + return RT_TRUE; +} + +static rt_uint16_t virtio_pci_queue_vector(struct virtio_pci *vp, + rt_uint16_t index, rt_uint16_t vector) +{ + struct virtio_pci_common_cfg *cfg = vp->common; + + virtio_pci_write16(&cfg->queue_select, index); + virtio_pci_write16(&cfg->queue_msix_vector, vector); + + /* Flush the write out to device */ + return virtio_pci_read16(&cfg->queue_msix_vector); +} + +static rt_uint16_t virtio_pci_config_vector(struct virtio_pci *vp, + rt_uint16_t vector) +{ + struct virtio_pci_common_cfg *cfg = vp->common; + + virtio_pci_write16(&cfg->config_msix_vector, vector); + + /* Flush the write out to device */ + return virtio_pci_read16(&cfg->config_msix_vector); +} + +static rt_err_t virtio_pci_read_shm_region(struct virtio_pci *vp, + struct rt_virtio_shm_region *shm) +{ + int pos; + rt_uint8_t bar; + rt_uint64_t offset, len; + struct rt_pci_device *pdev = vp->pdev; + + for (pos = rt_pci_find_capability(pdev, PCIY_VENDOR); pos > 0; + pos = rt_pci_find_next_capability(pdev, pos, PCIY_VENDOR)) + { + rt_uint32_t value32; + rt_uint8_t type, cap_len, id; + + rt_pci_read_config_u8(pdev, + pos + rt_offsetof(struct virtio_pci_cap, cfg_type), &type); + + if (type != VIRTIO_PCI_CAP_SHARED_MEMORY_CFG) + { + continue; + } + + rt_pci_read_config_u8(pdev, + pos + rt_offsetof(struct virtio_pci_cap, cap_len), &cap_len); + + if (cap_len != sizeof(struct virtio_pci_cap64)) + { + LOG_E("%s: shm cap with bad size offset: %d size: %d", + rt_dm_dev_get_name(&pdev->parent), pos, cap_len); + + continue; + } + + rt_pci_read_config_u8(pdev, + pos + rt_offsetof(struct virtio_pci_cap, id), &id); + + if (id != shm->id) + { + continue; + } + + rt_pci_read_config_u8(pdev, + pos + rt_offsetof(struct virtio_pci_cap, bar), &bar); + + if (bar >= PCI_STD_NUM_BARS) + { + continue; + } + + rt_pci_read_config_u32(pdev, + pos + rt_offsetof(struct virtio_pci_cap, offset), &value32); + offset = value32; + + rt_pci_read_config_u32(pdev, + pos + rt_offsetof(struct virtio_pci_cap, length), &value32); + len = value32; + + rt_pci_read_config_u32(pdev, + pos + rt_offsetof(struct virtio_pci_cap64, offset_hi), &value32); + offset |= ((rt_uint64_t)value32) << 32; + + rt_pci_read_config_u32(pdev, + pos + rt_offsetof(struct virtio_pci_cap64, length_hi), &value32); + len |= ((rt_uint64_t)value32) << 32; + + break; + } + + if (!pos) + { + return -RT_EEMPTY; + } + + if (offset + len < offset) + { + LOG_E("%s: cap offset + len overflow detected", + rt_dm_dev_get_name(&pdev->parent)); + + return -RT_EIO; + } + + if (offset + len > pdev->resource[bar].size) + { + LOG_E("%s: bar shorter than cap offset + len", + rt_dm_dev_get_name(&pdev->parent)); + + return -RT_EIO; + } + + shm->base = pdev->resource[bar].base + offset; + shm->size = len; + + return RT_EOK; +} + +static rt_err_t virtio_pci_get_status(struct rt_virtio_device *vdev, + rt_uint8_t *out_status) +{ + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + *out_status = virtio_pci_read32(&vp->common->device_status); + + return RT_EOK; +} + +static rt_err_t virtio_pci_set_status(struct rt_virtio_device *vdev, + rt_uint8_t status) +{ + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + virtio_pci_write32(&vp->common->device_status, status); + + return RT_EOK; +} + +static rt_err_t virtio_pci_get_features(struct rt_virtio_device *vdev, + rt_uint64_t *out_features) +{ + rt_uint64_t features; + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + virtio_pci_write32(&vp->common->device_feature_select, 1); + features = virtio_pci_read32(&vp->common->device_feature); + features <<= 32; + + virtio_pci_write32(&vp->common->device_feature_select, 0); + features |= virtio_pci_read32(&vp->common->device_feature); + + *out_features = features; + + return RT_EOK; +} + +static rt_err_t virtio_pci_set_features(struct rt_virtio_device *vdev) +{ + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + virtio_pci_write32(&vp->common->driver_feature_select, 1); + virtio_pci_write32(&vp->common->driver_feature, (rt_uint32_t)(vdev->features >> 32)); + + virtio_pci_write32(&vp->common->driver_feature_select, 0); + virtio_pci_write32(&vp->common->driver_feature, (rt_uint32_t)vdev->features); + + return RT_EOK; +} + +static rt_err_t virtio_pci_get_config(struct rt_virtio_device *vdev, + rt_uint32_t offset, void *dst, int length) +{ + rt_uint8_t byte; + rt_le16_t word; + rt_le32_t dword; + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + switch (length) + { + case 4: + dword = virtio_pci_read32(vp->dev_regs + offset); + rt_memcpy(dst, &dword, sizeof(dword)); + break; + case 1: + byte = virtio_pci_read8(vp->dev_regs + offset); + rt_memcpy(dst, &byte, sizeof(byte)); + break; + case 2: + word = virtio_pci_read16(vp->dev_regs + offset); + rt_memcpy(dst, &word, sizeof(word)); + break; + case 8: + dword = virtio_pci_read32(vp->dev_regs + offset); + rt_memcpy(dst, &dword, sizeof(dword)); + dword = virtio_pci_read32(vp->dev_regs + offset + sizeof(dword)); + rt_memcpy(dst + sizeof(dword), &dword, sizeof(dword)); + break; + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t virtio_pci_set_config(struct rt_virtio_device *vdev, + rt_uint32_t offset, const void *src, int length) +{ + rt_uint8_t byte; + rt_le16_t word; + rt_le32_t dword; + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + switch (length) + { + case 4: + rt_memcpy(&dword, src, sizeof(dword)); + virtio_pci_write32(vp->dev_regs + offset, dword); + break; + case 1: + rt_memcpy(&byte, src, sizeof(byte)); + virtio_pci_write8(vp->dev_regs + offset, byte); + break; + case 2: + rt_memcpy(&word, src, sizeof(word)); + virtio_pci_write16(vp->dev_regs + offset, word); + break; + case 8: + rt_memcpy(&dword, src, sizeof(dword)); + virtio_pci_write32(vp->dev_regs + offset, dword); + rt_memcpy(&dword, src + sizeof(dword), sizeof(dword)); + virtio_pci_write32(vp->dev_regs + offset + sizeof(dword), dword); + break; + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +static struct rt_virtqueue *virtio_pci_install_vq(struct rt_virtio_device *vdev, + int index, const char *name, rt_virtqueue_callback cb, + struct rt_virtqueue_formula *formula) +{ + rt_uint64_t page; + rt_uint32_t num_max; + struct rt_virtqueue *vq; + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + struct virtio_pci_common_cfg *cfg = vp->common; + + if (index >= virtio_pci_read16(&cfg->num_queues)) + { + return RT_NULL; + } + + virtio_pci_write16(&cfg->queue_select, index); + + num_max = virtio_pci_read16(&cfg->queue_size); + + if (!num_max || virtio_pci_read16(&cfg->queue_enable)) + { + return RT_NULL; + } + + vq = rt_virtqueue_create(vdev, name, index, num_max, VIRTIO_PCI_VIRTQ_ALIGN, + virtio_pci_notify, cb, formula); + + if (!vq) + { + return vq; + } + + vq->num_max = num_max; + + virtio_pci_write16(&cfg->queue_size, rt_virtqueue_get_virtq_size(vq)); + + page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_desc_addr(vq)); + virtio_pci_write32(&cfg->queue_desc_low, (rt_uint32_t)page); + virtio_pci_write32(&cfg->queue_desc_high, (rt_uint32_t)(page >> 32)); + + page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_avail_addr(vq)); + virtio_pci_write32(&cfg->queue_avail_low, (rt_uint32_t)page); + virtio_pci_write32(&cfg->queue_avail_high, (rt_uint32_t)(page >> 32)); + + page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_used_addr(vq)); + virtio_pci_write32(&cfg->queue_used_low, (rt_uint32_t)page); + virtio_pci_write32(&cfg->queue_used_high, (rt_uint32_t)(page >> 32)); + + virtio_pci_write16(&cfg->queue_enable, 1); + + return vq; +} + +static rt_err_t virtio_pci_install_vqs(struct rt_virtio_device *vdev, int vqs_nr, + struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[]) +{ + void *isr; + rt_err_t err; + char name[RT_NAME_MAX]; + int nvectors = vqs_nr + 1, irq, cpuid = 0; + RT_IRQ_AFFINITY_DECLARE(affinity) = { 0 }; + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + vp->msix_entries = rt_malloc(nvectors * sizeof(*vp->msix_entries)); + + if (!vp->msix_entries) + { + return -RT_ENOMEM; + } + + rt_pci_msix_entry_index_linear(vp->msix_entries, nvectors); + + /* Try MSI-X with one vector per queue */ + if (rt_pci_msix_enable(vp->pdev, vp->msix_entries, nvectors) < 0) + { + nvectors = 2; + + /* Try MSI-X with one shared for queues, one vector for config */ + if (rt_pci_msix_enable(vp->pdev, vp->msix_entries, nvectors) < 0) + { + /* Only supported INTx */ + nvectors = 1; + + rt_free(vp->msix_entries); + vp->msix_entries = RT_NULL; + } + } + + for (int i = 0, vq_idx = 0; i < vqs_nr; ++i, ++vq_idx) + { + if (!names[i]) + { + vqs[i] = RT_NULL; + + continue; + } + + vqs[i] = virtio_pci_install_vq(vdev, vq_idx, names[i], cbs[i], RT_NULL); + + if (!vqs[i]) + { + err = -RT_ERROR; + goto _fail; + } + + if (nvectors >= 2 || (nvectors == 2 && vqs_nr == 1)) + { + int vec_idx = nvectors != 2 ? vq_idx : 0; + int msi_idx = nvectors != 2 ? i : 0; + + if (!cbs[i]) + { + virtio_pci_queue_vector(vp, vq_idx, VIRTIO_MSI_NO_VECTOR); + + continue; + } + + if (virtio_pci_queue_vector(vp, vq_idx, vec_idx) == VIRTIO_MSI_NO_VECTOR) + { + err = -RT_EBUSY; + goto _fail; + } + + irq = vp->msix_entries[msi_idx].irq; + + rt_snprintf(name, RT_NAME_MAX, "%s-%s-%d", + rt_dm_dev_get_name(&vdev->parent), names[i], vq_idx); + + RT_IRQ_AFFINITY_SET(affinity, cpuid % RT_CPUS_NR); + rt_pic_irq_set_affinity(irq, affinity); + RT_IRQ_AFFINITY_CLEAR(affinity, cpuid++ % RT_CPUS_NR); + + rt_hw_interrupt_install(irq, virtio_pci_vq_isr, vqs[i], name); + rt_hw_interrupt_umask(irq); + } + } + + if (nvectors >= 2) + { + rt_snprintf(name, RT_NAME_MAX, "%s-config", + rt_dm_dev_get_name(&vdev->parent)); + + isr = virtio_pci_config_isr; + irq = vp->msix_entries[nvectors - 1].irq; + + if (virtio_pci_config_vector(vp, nvectors - 1) == VIRTIO_MSI_NO_VECTOR) + { + err = -RT_EBUSY; + goto _fail; + } + + RT_IRQ_AFFINITY_SET(affinity, cpuid % RT_CPUS_NR); + rt_pic_irq_set_affinity(irq, affinity); + RT_IRQ_AFFINITY_CLEAR(affinity, cpuid++ % RT_CPUS_NR); + } + else + { + rt_snprintf(name, RT_NAME_MAX, "%s", rt_dm_dev_get_name(&vdev->parent)); + + isr = virtio_pci_isr; + irq = vp->pdev->irq; + + virtio_pci_config_vector(vp, VIRTIO_MSI_NO_VECTOR); + } + + rt_hw_interrupt_install(irq, isr, vp, name); + rt_hw_interrupt_umask(irq); + + vp->nvectors = nvectors; + + return RT_EOK; + +_fail: + rt_virtio_virtqueue_release(vdev); + + return err; +} + +static rt_err_t virtio_pci_release_vqs(struct rt_virtio_device *vdev) +{ + int irq; + struct rt_virtqueue *vq, *vq_next; + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + rt_list_for_each_entry_safe(vq, vq_next, &vp->parent.vq_node, list) + { + virtio_pci_write16(&vp->common->queue_select, vq->index); + + if (vp->nvectors >= 2) + { + virtio_pci_queue_vector(vp, vq->index, VIRTIO_MSI_NO_VECTOR); + + irq = vp->msix_entries[vq->index].irq; + + rt_hw_interrupt_mask(irq); + rt_pic_detach_irq(irq, vq); + } + + /* Select and deactivate the queue */ + virtio_pci_write16(&vp->common->queue_enable, 0); + + rt_virtqueue_delete(&vp->parent, vq); + } + + if (vp->nvectors >= 2) + { + irq = vp->msix_entries[vp->nvectors - 1].irq; + } + else + { + irq = vp->pdev->irq; + } + + rt_hw_interrupt_mask(irq); + rt_pic_detach_irq(irq, vp); + + return RT_EOK; +} + +static rt_err_t virtio_pci_control_vqs(struct rt_virtio_device *vdev, + rt_uint32_t cfg, void *data) +{ + rt_err_t err = RT_EOK; + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + switch (cfg) + { + case RT_VIRTQUEUE_CTL_IRQ_AFFINITY: + if (vp->nvectors == 1) + { + err = rt_pic_irq_set_affinity(vp->pdev->irq, (rt_bitmap_t *)data); + } + else + { + err = -RT_ENOSYS; + } + break; + + case RT_VIRTQUEUE_CTL_READ_SHM_REGION: + if (!data) + { + err = -RT_EINVAL; + break; + } + + err = virtio_pci_read_shm_region(vp, data); + break; + + default: + err = -RT_ENOSYS; + break; + } + + return err; +} + +static rt_err_t virtio_pci_generation(struct rt_virtio_device *vdev, + rt_uint32_t *out_counter) +{ + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + *out_counter = virtio_pci_read8(&vp->common->config_generation); + + return RT_EOK; +} + +static rt_err_t virtio_pci_reset(struct rt_virtio_device *vdev) +{ + struct virtio_pci *vp = raw_to_virtio_pci(vdev); + + virtio_pci_write8(&vp->common->device_status, 0); + + while (virtio_pci_read8(&vp->common->device_status)) + { + rt_thread_mdelay(1); + } + + return RT_EOK; +} + +static const struct rt_virtio_transport virtio_pci_trans = +{ + .get_status = virtio_pci_get_status, + .set_status = virtio_pci_set_status, + .get_features = virtio_pci_get_features, + .set_features = virtio_pci_set_features, + .get_config = virtio_pci_get_config, + .set_config = virtio_pci_set_config, + .install_vqs = virtio_pci_install_vqs, + .release_vqs = virtio_pci_release_vqs, + .control_vqs = virtio_pci_control_vqs, + .generation = virtio_pci_generation, + .reset = virtio_pci_reset, +}; + +static rt_uint32_t virtio_pci_find_capability(struct rt_pci_device *pdev, + rt_uint8_t cfg_type, rt_size_t cap_size, struct virtio_pci_cap *out_cap) +{ + int offset; + + for (rt_uint8_t pos = rt_pci_find_capability(pdev, PCIY_VENDOR); + pos > 0 && (PCI_REGMAX + 1) - cap_size >= pos; + pos = rt_pci_find_next_capability(pdev, pos, PCIY_VENDOR)) + { + offset = pos + rt_offsetof(struct virtio_pci_cap, cap_vndr); + rt_pci_read_config_u8(pdev, offset, &out_cap->cap_vndr); + offset = pos + rt_offsetof(struct virtio_pci_cap, cap_next); + rt_pci_read_config_u8(pdev, offset, &out_cap->cap_next); + offset = pos + rt_offsetof(struct virtio_pci_cap, cap_len); + rt_pci_read_config_u8(pdev, offset, &out_cap->cap_len); + offset = pos + rt_offsetof(struct virtio_pci_cap, cfg_type); + rt_pci_read_config_u8(pdev, offset, &out_cap->cfg_type); + offset = pos + rt_offsetof(struct virtio_pci_cap, bar); + rt_pci_read_config_u8(pdev, offset, &out_cap->bar); + offset = pos + rt_offsetof(struct virtio_pci_cap, offset); + rt_pci_read_config_u32(pdev, offset, &out_cap->offset); + offset = pos + rt_offsetof(struct virtio_pci_cap, length); + rt_pci_read_config_u32(pdev, offset, &out_cap->length); + + /* Ignore structures with reserved BAR values */ + if (out_cap->bar >= RT_PCI_BAR_NR_MAX) + { + continue; + } + + if (out_cap->cfg_type == cfg_type) + { + return pos; + } + } + + return 0; +} + +static void virtio_pci_free(struct virtio_pci *vp) +{ + if (vp->common) + { + rt_iounmap(vp->common - vp->common_offset); + } + if (vp->dev_regs) + { + rt_iounmap(vp->dev_regs - vp->dev_regs_offset); + } + if (vp->notify_regs) + { + rt_iounmap(vp->notify_regs - vp->notify_regs_offset); + } + if (vp->isr_regs) + { + rt_iounmap(vp->isr_regs - vp->isr_regs_offset); + } + + rt_free(vp); +} + +static rt_err_t virtio_pci_probe(struct rt_pci_device *pdev) +{ + rt_err_t err = RT_EOK; + rt_uint8_t common, notify, device, isr; + struct virtio_pci_cap common_cap, notify_cap, device_cap, isr_cap; + struct rt_virtio_device *vdev; + struct virtio_pci *vp; + + if (pdev->device < VIRTIO_PCI_DEVICE_START || + pdev->device > VIRTIO_PCI_DEVICE_END) + { + return -RT_EINVAL; + } + + if (!(vp = rt_calloc(1, sizeof(*vp)))) + { + return -RT_ENOMEM; + } + vp->pdev = pdev; + + if (!(common = virtio_pci_find_capability(pdev, VIRTIO_PCI_CAP_COMMON_CFG, + sizeof(struct virtio_pci_cap), &common_cap))) + { + err = -RT_EINVAL; + goto _fail; + } + + if (!(device = virtio_pci_find_capability(pdev, VIRTIO_PCI_CAP_DEVICE_CFG, + sizeof(struct virtio_pci_cap), &device_cap))) + { + err = -RT_EINVAL; + goto _fail; + } + + if (!(notify = virtio_pci_find_capability(pdev, VIRTIO_PCI_CAP_NOTIFY_CFG, + sizeof(struct virtio_pci_notify_cap), ¬ify_cap))) + { + err = -RT_EINVAL; + goto _fail; + } + + if (!(isr = virtio_pci_find_capability(pdev, VIRTIO_PCI_CAP_ISR_CFG, + sizeof(struct virtio_pci_cap), &isr_cap))) + { + err = -RT_EINVAL; + goto _fail; + } + + if (!(vp->common = rt_pci_iomap(pdev, common_cap.bar))) + { + err = -RT_EIO; + goto _fail; + } + vp->common_offset = common_cap.offset; + vp->common += vp->common_offset; + + if (!(vp->dev_regs = rt_pci_iomap(pdev, device_cap.bar))) + { + err = -RT_EIO; + goto _fail; + } + vp->dev_regs_offset = device_cap.offset; + vp->dev_regs += vp->dev_regs_offset; + + if (!(vp->notify_regs = rt_pci_iomap(pdev, notify_cap.bar))) + { + err = -RT_EIO; + goto _fail; + } + vp->notify_regs_offset = notify_cap.offset; + vp->notify_regs += vp->notify_regs_offset; + vp->notify_len = notify_cap.length; + + if (!(vp->isr_regs = rt_pci_iomap(pdev, isr_cap.bar))) + { + err = -RT_EIO; + goto _fail; + } + vp->isr_regs_offset = isr_cap.offset; + vp->isr_regs += vp->isr_regs_offset; + + rt_pci_read_config_u32(pdev, + notify + rt_offsetof(struct virtio_pci_notify_cap, notify_off_multiplier), + &vp->notify_offset_multiplier); + + vdev = &vp->parent; + vdev->id.device = pdev->device - VIRTIO_PCI_DEVICE_START; + rt_pci_read_config_u16(pdev, PCIR_SUBVEND_0, (rt_uint16_t *)&vdev->id.vendor); + + vdev->trans = &virtio_pci_trans; + vdev->parent.ofw_node = pdev->parent.ofw_node; + + if ((err = rt_virtio_device_register(vdev))) + { + goto _fail; + } + + pdev->parent.user_data = vp; + + return err; + +_fail: + virtio_pci_free(vp); + + return err; +} + +static rt_err_t virtio_pci_remove(struct rt_pci_device *pdev) +{ + struct virtio_pci *vp = pdev->parent.user_data; + + rt_bus_remove_device(&vp->parent.parent); + + virtio_pci_free(vp); + + return RT_EOK; +} + +static struct rt_pci_device_id virtio_pci_ids[] = +{ + { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_ANY_ID), }, + { /* sentinel */ } +}; + +static struct rt_pci_driver virtio_pci_driver = +{ + .name = "virtio-pci", + + .ids = virtio_pci_ids, + .probe = virtio_pci_probe, + .remove = virtio_pci_remove, +}; +RT_PCI_DRIVER_EXPORT(virtio_pci_driver); diff --git a/components/drivers/virtio/virtio_queue.c b/components/drivers/virtio/virtio_queue.c new file mode 100644 index 0000000000..1244fefb1f --- /dev/null +++ b/components/drivers/virtio/virtio_queue.c @@ -0,0 +1,1219 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include <rthw.h> +#include <rtthread.h> + +#define DBG_TAG "virtio.queue" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include <mm_aspace.h> + +#include <drivers/dma.h> +#include <drivers/virtq.h> +#include <drivers/virtio.h> + +#include "virtio_internal.h" + +struct virtq_buffer_shadow +{ + rt_ubase_t dma_handle; + void *dma_buf; + + rt_size_t size; + rt_size_t chain_num; +}; + +struct virtqueue_split +{ + struct virtq virtq; + rt_ubase_t virtq_dma; + + rt_uint16_t avail_idx_shadow; + rt_uint16_t avail_flags_shadow; + struct virtq_buffer_shadow buffer_shadow[0]; +}; + +struct virtqueue_packed +{ + struct virtq virtq; + rt_size_t virtq_size; + rt_ubase_t virtq_dma; + rt_ubase_t driver_event_dma; + rt_ubase_t device_event_dma; + + rt_uint16_t last_used_idx; + rt_uint16_t avail_used_flags; + rt_uint16_t avail_wrap_counter; + rt_uint16_t avail_flags_shadow; + rt_uint16_t event_flags_shadow; + struct virtq_buffer_shadow buffer_shadow[0]; +}; + +static struct rt_virtqueue *vq_split_create(struct rt_virtio_device *vdev, + const char *name, int index, int num, rt_uint32_t align, + rt_virtqueue_notifier notify, rt_virtqueue_callback callback, + struct rt_virtqueue_formula *formula) +{ + void *pages; + rt_size_t size; + struct virtqueue_split *vq_split; + struct rt_virtqueue *vq = RT_NULL; + struct virtq_buffer_shadow *buffer_shadow; + + /* + * Layout: + * +-----------------+ + * | rt_virtqueue | + * +-----------------+ + * | virtqueue_split | + * +-----------------+ + * | buffer_shadow | + * +-----------------+ + */ + vq = rt_malloc(sizeof(*vq) + + sizeof(struct virtqueue_split) + + sizeof(struct virtq_buffer_shadow) * num); + + if (!vq) + { + return RT_NULL; + } + + vq_split = (void *)vq + sizeof(*vq); + buffer_shadow = (void *)vq_split + sizeof(*vq_split); + rt_memset(buffer_shadow, 0, sizeof(*buffer_shadow) * num); + + /* + * +------------------+-----------+----------------------+ + * | Virtqueue Part | Alignment | Size | + * +------------------+-----------+----------------------+ + * | Descriptor Table | 16 | 16 * (Queue Size) | + * +------------------+-----------+----------------------+ + * | Available Ring | 2 | 6 + 2 * (Queue Size) | + * +------------------+-----------+----------------------+ + * | Used Ring | 4 | 6 + 8 * (Queue Size) | + * +------------------+-----------+----------------------+ + */ + size = virtq_size(RT_NULL, num, align); + + if (formula->page) + { + pages = formula->page; + } + else + { + pages = rt_dma_alloc(&vdev->parent, size, &vq_split->virtq_dma, RT_DMA_F_LINEAR); + + if (!pages) + { + rt_free(vq); + + return RT_NULL; + } + } + + rt_memset(pages, 0, size); + virtq_init(&vq_split->virtq, num, pages, align); + + vq_split->avail_idx_shadow = 0; + vq_split->avail_flags_shadow = 0; + + vq->name = name; + vq->index = index; + vq->num_free = num; + + vq->callback = callback; + + vq->vq_split = vq_split; + vq->packed_ring = RT_FALSE; + + vq->notify = notify; + vq->event = rt_virtio_has_feature(vdev, VIRTIO_F_RING_EVENT_IDX); + vq->event_triggered = RT_FALSE; + vq->free_head = 0; + vq->num_added = 0; + vq->last_used_idx = 0; + + vq->vdev = vdev; + + if (!vq->callback) + { + vq_split->avail_flags_shadow |= VIRTQ_AVAIL_F_NO_INTERRUPT; + + if (!vq->event) + { + vq_split->virtq.avail->flags = cpu_to_virtio16(vdev, + vq_split->avail_flags_shadow); + } + } + + rt_memcpy(&vq->formula, formula, sizeof(*formula)); + + return vq; +} + +static rt_err_t vq_split_delete(struct rt_virtqueue *vq) +{ + rt_err_t err = RT_EOK; + struct virtq *virtq; + struct virtqueue_split *vq_split = vq->vq_split; + struct rt_virtqueue_formula *formula = &vq->formula; + + if (!formula->page) + { + virtq = &vq_split->virtq; + rt_dma_free(&vq->vdev->parent, virtq_size(virtq, 0, 0), + (void *)virtq->desc, vq_split->virtq_dma, RT_DMA_F_LINEAR); + } + + rt_free(vq); + + return err; +} + +static rt_err_t vq_split_add_buf(struct rt_virtqueue *vq, + void *dma_buf, rt_size_t size, rt_bool_t is_out) +{ + rt_err_t err; + rt_uint16_t buf_id; + rt_ubase_t dma_addr; + rt_size_t virtq_num; + int head, next, flags; + struct virtq *virtq; + struct virtq_desc *desc; + struct virtqueue_split *vq_split; + struct virtq_buffer_shadow *buffer_shadow; + struct rt_virtio_device *vdev = vq->vdev; + + if (!vq->num_free) + { + LOG_D("%s.virtqueue[%s(%d)] add buffer.len = %d fail", + rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, size); + + /* Recvice buffer NOW! */ + if (is_out) + { + vq->notify(vq); + } + + return -RT_EFULL; + } + + err = rt_dma_sync_out_data(&vdev->parent, dma_buf, size, &dma_addr, RT_DMA_F_LINEAR); + + if (err) + { + return err; + } + + vq_split = vq->vq_split; + virtq = &vq_split->virtq; + virtq_num = virtq->num; + + head = vq->free_head++ & (virtq_num - 1); + rt_hw_dsb(); + + next = vq->free_head & (virtq_num - 1); + desc = &virtq->desc[head]; + buffer_shadow = &vq_split->buffer_shadow[head]; + + buffer_shadow->dma_handle = dma_addr; + buffer_shadow->dma_buf = dma_buf; + buffer_shadow->size = size; + + buf_id = (head - vq->num_added) & (virtq_num - 1); + vq_split->buffer_shadow[buf_id].chain_num = vq->num_added + 1; + + flags = VIRTQ_DESC_F_NEXT; + if (!is_out) + { + flags |= VIRTQ_DESC_F_WRITE; + } + + desc->addr = cpu_to_virtio64(vdev, dma_addr); + desc->len = cpu_to_virtio32(vdev, size); + desc->flags = cpu_to_virtio16(vdev, flags); + desc->next = cpu_to_virtio16(vdev, next); + + /* Update index */ + ++vq->num_added; + --vq->num_free; + + LOG_D("%s.virtqueue[%s(%d)] add buffer(%p, size = %d) head = %d", + rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, dma_buf, size, head); + + return RT_EOK; +} + +static rt_bool_t vq_split_submit(struct rt_virtqueue *vq) +{ + int head, prev; + rt_uint16_t avail, num_added; + struct rt_virtio_device *vdev = vq->vdev; + struct virtqueue_split *vq_split = vq->vq_split; + struct virtq *virtq = &vq_split->virtq; + rt_size_t virtq_num = virtq->num; + + num_added = vq->num_added; + head = vq->free_head; + prev = (head - 1) & (virtq_num - 1); + head = head - num_added; + + LOG_D("%s.virtqueue[%s(%d)] submit head = %d, num_added = %d, idx = %d", + rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, + head & (virtq_num - 1), num_added, virtq->avail->idx); + + /* Reset list info */ + vq->num_added = 0; + + /* Clear last "next" flags */ + virtq->desc[prev].flags &= ~cpu_to_virtio16(vdev, VIRTQ_DESC_F_NEXT); + virtq->desc[prev].next = 0; + + /* Tell the device the first index in our chain of descriptors */ + avail = vq_split->avail_idx_shadow & (virtq_num - 1); + virtq->avail->ring[avail] = cpu_to_virtio32(vdev, head & (virtq_num - 1)); + + /* Tell the device another avail ring entry is available */ + rt_hw_wmb(); + ++vq_split->avail_idx_shadow; + virtq->avail->idx = cpu_to_virtio16(vdev, vq_split->avail_idx_shadow); + + if (vq->event) + { + rt_uint16_t old = vq_split->avail_idx_shadow - num_added; + rt_uint16_t new = vq_split->avail_idx_shadow; + + return virtq_need_event(virtio16_to_cpu(vdev, + *virtq_avail_event(virtq)), new, old); + } + + return !(virtq->used->flags & cpu_to_virtio16(vdev, VIRTQ_USED_F_NO_NOTIFY)); +} + +static rt_bool_t vq_split_poll(struct rt_virtqueue *vq, rt_uint32_t last_used_idx) +{ + return (rt_uint16_t)last_used_idx != virtio16_to_cpu(vq->vdev, vq->vq_split->virtq.used->idx); +} + +rt_inline rt_bool_t vq_split_pending(struct rt_virtqueue *vq) +{ + return vq->last_used_idx != virtio16_to_cpu(vq->vdev, vq->vq_split->virtq.used->idx); +} + +static void vq_split_disable_callback(struct rt_virtqueue *vq) +{ + struct virtqueue_split *vq_split = vq->vq_split; + struct virtq *virtq = &vq_split->virtq; + + if (!(vq_split->avail_flags_shadow & VIRTQ_AVAIL_F_NO_INTERRUPT)) + { + vq_split->avail_flags_shadow |= VIRTQ_AVAIL_F_NO_INTERRUPT; + + if (vq->event) + { + *virtq_used_event(virtq) = 0; + } + else + { + virtq->avail->flags = cpu_to_virtio16(vq->vdev, vq_split->avail_flags_shadow); + } + } +} + +static rt_uint32_t vq_split_enable_callback(struct rt_virtqueue *vq) +{ + struct virtqueue_split *vq_split = vq->vq_split; + struct virtq *virtq = &vq_split->virtq; + rt_uint16_t last_used_idx = vq->last_used_idx; + + if (vq_split->avail_flags_shadow & VIRTQ_AVAIL_F_NO_INTERRUPT) + { + vq_split->avail_flags_shadow &= ~VIRTQ_AVAIL_F_NO_INTERRUPT; + + if (!vq->event) + { + virtq->avail->flags = cpu_to_virtio16(vq->vdev, vq_split->avail_flags_shadow); + } + } + + *virtq_used_event(virtq) = cpu_to_virtio16(vq->vdev, last_used_idx); + + return last_used_idx; +} + +static void *vq_split_read_buf(struct rt_virtqueue *vq, rt_size_t *out_len) +{ + void *buf; + rt_err_t err; + rt_uint32_t idx; + rt_uint16_t last_used, next; + rt_size_t chain_num; + struct virtq *virtq; + struct virtqueue_split *vq_split; + struct virtq_buffer_shadow *buffer_shadow; + struct rt_virtio_device *vdev = vq->vdev; + + if (!vq_split_pending(vq)) + { + LOG_D("%s.virtqueue[%s(%d)] read buffer empty", + rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index); + + return RT_NULL; + } + + vq_split = vq->vq_split; + virtq = &vq_split->virtq; + + last_used = vq->last_used_idx & (virtq->num - 1); + next = idx = virtio32_to_cpu(vdev, virtq->used->ring[last_used].id); + *out_len = virtio32_to_cpu(vdev, virtq->used->ring[last_used].len); + rt_hw_dsb(); + + buffer_shadow = &vq_split->buffer_shadow[idx]; + buf = buffer_shadow->dma_buf; + chain_num = buffer_shadow->chain_num; + + LOG_D("%s.virtqueue[%s(%d)] read head = %d, buffer(%p, size = %d)", + rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, idx, buf, *out_len); + + for (int i = 0; i < chain_num; ++i) + { + idx = next; + next = virtq->desc[idx].next; + + if (virtq->desc[idx].flags & VIRTQ_DESC_F_WRITE || + vdev->dma_dispatch) + { + buffer_shadow = &vq_split->buffer_shadow[idx]; + err = rt_dma_sync_in_data(&vdev->parent, + buffer_shadow->dma_buf, + buffer_shadow->size, + buffer_shadow->dma_handle, RT_DMA_F_LINEAR); + + if (err) + { + LOG_E("%s.virtqueue[%s(%d)] read head = %d sync error = %s", + rt_dm_dev_get_name(&vdev->parent), + vq->name, vq->index, idx, rt_strerror(err)); + } + } + } + + vq->num_free += chain_num; + ++vq->last_used_idx; + + if (!(vq_split->avail_flags_shadow & VIRTQ_AVAIL_F_NO_INTERRUPT)) + { + HWREG16(virtq_used_event(virtq)) = cpu_to_virtio16(vq->vdev, vq->last_used_idx); + rt_hw_dmb(); + } + + rt_hw_dsb(); + + return buf; +} + +static struct rt_virtqueue *vq_packed_create(struct rt_virtio_device *vdev, + const char *name, int index, int num, int align, + rt_virtqueue_notifier notify, rt_virtqueue_callback callback, + struct rt_virtqueue_formula *formula) +{ + rt_size_t size, event_size; + struct virtq *virtq; + struct virtqueue_packed *vq_packed; + struct rt_virtqueue *vq = RT_NULL; + struct virtq_buffer_shadow *buffer_shadow; + + /* + * Layout: + * +------------------------+ + * | rt_virtqueue | + * +------------------------+ + * | virtqueue_packed | + * +------------------------+ + * | buffer_shadow | + * +------------------------+ + */ + vq = rt_malloc(sizeof(*vq) + + sizeof(struct virtqueue_packed) + + sizeof(struct virtq_buffer_shadow) * num); + + if (!vq) + { + return RT_NULL; + } + + vq_packed = (void *)vq + sizeof(*vq); + buffer_shadow = (void *)vq_packed + sizeof(*vq_packed); + rt_memset(buffer_shadow, 0, sizeof(*buffer_shadow) * num); + + /* + * +--------------------------+-----------+-------------------+ + * | Virtqueue Part | Alignment | Size | + * +--------------------------+-----------+-------------------+ + * | Descriptor Ring | 16 | 16 * (Queue Size) | + * +--------------------------+-----------+-------------------+ + * | Device Event Suppression | 4 | 4 | + * +--------------------------+-----------+-------------------+ + * | Driver Event Suppression | 4 | 4 | + * +--------------------------+-----------+-------------------+ + */ + virtq = &vq_packed->virtq; + + size = num * sizeof(struct virtq_packed_desc); + size = RT_ALIGN(size, 4); + event_size = sizeof(struct virtq_packed_desc_event); + vq_packed->virtq_size = size + event_size * 2; + + if (formula->page) + { + virtq->desc_packed = formula->page; + } + else + { + virtq->desc_packed = rt_dma_alloc(&vdev->parent, + vq_packed->virtq_size, &vq_packed->virtq_dma, RT_DMA_F_LINEAR); + + if (!virtq->desc_packed) + { + rt_free(vq); + + return RT_NULL; + } + } + + virtq->driver_event = (void *)virtq->desc_packed + size; + vq_packed->driver_event_dma = vq_packed->virtq_dma + size; + + virtq->device_event = (void *)virtq->driver_event + event_size; + vq_packed->device_event_dma = vq_packed->driver_event_dma + event_size; + + rt_memset(virtq->desc_packed, 0, size); + rt_memset(virtq->driver_event, 0, event_size); + rt_memset(virtq->device_event, 0, event_size); + virtq->num = num; + virtq->align = align; + + vq_packed->avail_wrap_counter = 1; + vq_packed->event_flags_shadow = 0; + vq_packed->avail_used_flags = VIRTQ_DESC_F_AVAIL; + + vq->name = name; + vq->index = index; + vq->num_free = num; + + vq->callback = callback; + + vq->vq_packed = vq_packed; + vq->packed_ring = RT_TRUE; + + vq->notify = notify; + vq->event = rt_virtio_has_feature(vdev, VIRTIO_F_RING_EVENT_IDX); + vq->event_triggered = RT_FALSE; + vq->free_head = 0; + vq->num_added = 0; + vq->last_used_idx = 0 | RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR); + + vq->vdev = vdev; + + if (!vq->callback) + { + vq_packed->avail_flags_shadow = VIRTQ_PACKED_EVENT_FLAG_DISABLE; + vq_packed->virtq.avail->flags = rt_cpu_to_le16(vq_packed->avail_flags_shadow); + } + + rt_memcpy(&vq->formula, formula, sizeof(*formula)); + + return vq; +} + +static rt_err_t vq_packed_delete(struct rt_virtqueue *vq) +{ + rt_err_t err = RT_EOK; + struct virtq *virtq; + struct virtqueue_packed *vq_packed = vq->vq_packed; + struct rt_virtqueue_formula *formula = &vq->formula; + + virtq = &vq_packed->virtq; + + if (virtq->desc_packed && !formula->page) + { + rt_dma_free(&vq->vdev->parent, vq_packed->virtq_size, + (void *)virtq->desc_packed, vq_packed->virtq_dma, RT_DMA_F_LINEAR); + } + + rt_free(vq); + + return err; +} + +static rt_err_t vq_packed_add_buf(struct rt_virtqueue *vq, + void *dma_buf, rt_size_t size, rt_bool_t is_out) +{ + rt_err_t err; + rt_uint16_t buf_id; + rt_ubase_t dma_addr; + rt_size_t virtq_num; + int head, flags; + struct virtq *virtq; + struct virtqueue_packed *vq_packed; + struct virtq_packed_desc *desc_packed; + struct virtq_buffer_shadow *buffer_shadow; + struct rt_virtio_device *vdev = vq->vdev; + + if (!vq->num_free) + { + LOG_D("%s.virtqueue[%s(%d)] add buffer.len = %d fail", + rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, size); + + /* Recvice buffer NOW! */ + if (is_out) + { + vq->notify(vq); + } + + return -RT_EFULL; + } + + err = rt_dma_sync_out_data(&vdev->parent, dma_buf, size, &dma_addr, RT_DMA_F_LINEAR); + + if (err) + { + return err; + } + + vq_packed = vq->vq_packed; + virtq = &vq_packed->virtq; + virtq_num = virtq->num; + + head = vq->free_head++ & (virtq_num - 1); + rt_hw_dsb(); + + desc_packed = &virtq->desc_packed[head]; + buffer_shadow = &vq_packed->buffer_shadow[head]; + + buffer_shadow->dma_handle = dma_addr; + buffer_shadow->dma_buf = dma_buf; + buffer_shadow->size = size; + + buf_id = (head - vq->num_added) & (virtq_num - 1); + vq_packed->buffer_shadow[buf_id].chain_num = vq->num_added + 1; + + flags = VIRTQ_DESC_F_NEXT; + if (!is_out) + { + flags |= VIRTQ_DESC_F_WRITE; + } + + desc_packed->addr = rt_cpu_to_le64(dma_addr); + desc_packed->len = rt_cpu_to_le32(size); + desc_packed->id = rt_cpu_to_le16(buf_id); + desc_packed->flags = rt_cpu_to_le16(vq_packed->avail_used_flags | flags); + + /* Ready fot next */ + if (head + 1 >= virtq->num) + { + vq_packed->avail_used_flags ^= VIRTQ_DESC_F_AVAIL | VIRTQ_DESC_F_USED; + /* Toggle the wrap counter */ + vq_packed->avail_wrap_counter ^= 1; + } + + rt_hw_wmb(); + + /* Update index */ + ++vq->num_added; + --vq->num_free; + + LOG_D("%s.virtqueue[%s(%d)] add buffer(%p, size = %d) head = %d", + rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, dma_buf, size, head); + + return RT_EOK; +} + +static rt_bool_t vq_packed_submit(struct rt_virtqueue *vq) +{ + int head, prev; + rt_uint16_t off_wrap, flags, wrap_counter, event_idx; + struct virtq_packed_desc_event device_event; + struct virtqueue_packed *vq_packed = vq->vq_packed; + struct virtq *virtq = &vq_packed->virtq; + rt_size_t virtq_num = virtq->num; + + rt_hw_dmb(); + rt_memcpy(&device_event, virtq->device_event, sizeof(device_event)); + + head = vq->free_head; + prev = (head - 1) & (virtq_num - 1); + head = head - vq->num_added; + + LOG_D("%s.virtqueue[%s(%d)] submit head = %d, num_added = %d, idx = %d", + rt_dm_dev_get_name(&vq->vdev->parent), vq->name, vq->index, + head & (virtq_num - 1), vq->num_added, rt_le16_to_cpu(device_event.off_wrap) & + ~RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR)); + + /* Reset list info */ + vq->num_added = 0; + + /* Clear last "next" flags */ + virtq->desc_packed[prev].flags &= ~rt_cpu_to_le16(VIRTQ_DESC_F_NEXT); + + flags = rt_le16_to_cpu(device_event.flags); + + if (flags != VIRTQ_PACKED_EVENT_FLAG_DESC) + { + return (flags != VIRTQ_PACKED_EVENT_FLAG_DISABLE); + } + + off_wrap = rt_le16_to_cpu(device_event.off_wrap); + + wrap_counter = off_wrap >> VIRTQ_PACKED_EVENT_WRAP_CTR; + event_idx = off_wrap & ~RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR); + if (wrap_counter != vq_packed->avail_wrap_counter) + { + event_idx -= virtq->num; + } + + return virtq_need_event(event_idx, prev, head); +} + +rt_inline rt_bool_t is_used_desc_packed(const struct virtq *virtq, + rt_uint16_t idx, rt_bool_t used_wrap_counter) +{ + rt_uint16_t flags; + rt_bool_t avail, used; + + flags = rt_le16_to_cpu(virtq->desc_packed[idx].flags); + avail = !!(flags & VIRTQ_DESC_F_AVAIL); + used = !!(flags & VIRTQ_DESC_F_USED); + + return avail == used && used == used_wrap_counter; +} + +static rt_bool_t packed_used_wrap_counter(rt_uint16_t last_used_idx) +{ + return !!(last_used_idx & RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR)); +} + +static rt_uint16_t packed_last_used(rt_uint16_t last_used_idx) +{ + return last_used_idx & ~(-RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR)); +} + +static rt_bool_t vq_packed_poll(struct rt_virtqueue *vq, rt_uint32_t last_used_idx) +{ + rt_bool_t wrap_counter; + rt_uint16_t off_wrap = last_used_idx, used_idx; + + wrap_counter = off_wrap >> VIRTQ_PACKED_EVENT_WRAP_CTR; + used_idx = off_wrap & ~RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR); + + return is_used_desc_packed(&vq->vq_packed->virtq, used_idx, wrap_counter); +} + +rt_inline rt_bool_t vq_packed_pending(struct rt_virtqueue *vq) +{ + rt_bool_t wrap_counter; + rt_uint16_t last_used, last_used_idx; + + last_used_idx = HWREG16(&vq->last_used_idx); + last_used = packed_last_used(last_used_idx); + wrap_counter = packed_used_wrap_counter(last_used_idx); + return is_used_desc_packed(&vq->vq_packed->virtq, last_used, wrap_counter); +} + +static void vq_packed_disable_callback(struct rt_virtqueue *vq) +{ + struct virtqueue_packed *vq_packed = vq->vq_packed; + + if (vq_packed->event_flags_shadow != VIRTQ_PACKED_EVENT_FLAG_DISABLE) + { + vq_packed->event_flags_shadow = VIRTQ_PACKED_EVENT_FLAG_DISABLE; + + /* + * If device triggered an event already it won't trigger one again: + * no need to disable. + */ + if (vq->event_triggered) + { + return; + } + + vq_packed->virtq.driver_event->flags = rt_cpu_to_le16(vq_packed->event_flags_shadow); + } +} + +static rt_uint32_t vq_packed_enable_callback(struct rt_virtqueue *vq) +{ + struct virtqueue_packed *vq_packed = vq->vq_packed; + + if (vq->event) + { + vq_packed->virtq.driver_event->off_wrap = rt_cpu_to_le16(vq->last_used_idx); + + /* Update event offset and event wrap counter first before updating event flags. */ + rt_hw_wmb(); + } + + if (vq_packed->event_flags_shadow == VIRTQ_PACKED_EVENT_FLAG_DISABLE) + { + vq_packed->event_flags_shadow = vq->event ? + VIRTQ_PACKED_EVENT_FLAG_DESC : VIRTQ_PACKED_EVENT_FLAG_ENABLE; + vq_packed->virtq.driver_event->flags = + rt_cpu_to_le16(vq_packed->event_flags_shadow); + } + + return vq->last_used_idx; +} + +static void *vq_packed_read_buf(struct rt_virtqueue *vq, rt_size_t *out_len) +{ + void *buf; + rt_err_t err; + rt_bool_t wrap_counter; + rt_uint16_t last_used, last_used_idx, id; + rt_size_t chain_num; + struct virtq *virtq; + struct virtqueue_packed *vq_packed; + struct virtq_buffer_shadow *buffer_shadow; + struct rt_virtio_device *vdev = vq->vdev; + + if (!vq_packed_pending(vq)) + { + LOG_D("%s.virtqueue[%s(%d)] read buffer empty", + rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index); + + return RT_NULL; + } + + vq_packed = vq->vq_packed; + virtq = &vq_packed->virtq; + + rt_hw_rmb(); + + last_used_idx = HWREG16(&vq->last_used_idx); + wrap_counter = packed_used_wrap_counter(last_used_idx); + last_used = packed_last_used(last_used_idx); + id = rt_le16_to_cpu(virtq->desc_packed[last_used].id); + *out_len = rt_le32_to_cpu(virtq->desc_packed[last_used].len); + + buffer_shadow = &vq->vq_packed->buffer_shadow[id]; + buf = buffer_shadow->dma_buf; + chain_num = buffer_shadow->chain_num; + + LOG_D("%s.virtqueue[%s(%d)] read head = %d, buffer(%p, size = %d)", + rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, id, buf, *out_len); + + for (int i = 0; i < chain_num; ++i) + { + if (virtq->desc_packed[id].flags & VIRTQ_DESC_F_WRITE || + vdev->dma_dispatch) + { + buffer_shadow = &vq->vq_packed->buffer_shadow[id]; + err = rt_dma_sync_in_data(&vdev->parent, + buffer_shadow->dma_buf, + buffer_shadow->size, + buffer_shadow->dma_handle, RT_DMA_F_LINEAR); + + if (err) + { + LOG_E("%s.virtqueue[%s(%d)] read head = %d sync error = %s", + rt_dm_dev_get_name(&vdev->parent), + vq->name, vq->index, id, rt_strerror(err)); + } + } + + ++id; + } + + vq->num_free += chain_num; + last_used += chain_num; + + if (last_used >= virtq->num) + { + last_used -= virtq->num; + wrap_counter ^= 1; + } + + last_used |= (wrap_counter << VIRTQ_PACKED_EVENT_WRAP_CTR); + HWREG16(&vq->last_used_idx) = last_used; + + if (vq_packed->event_flags_shadow == VIRTQ_PACKED_EVENT_FLAG_DESC) + { + HWREG16(&virtq->driver_event->off_wrap) = rt_cpu_to_le16(vq->last_used_idx); + rt_hw_dmb(); + } + + return buf; +} + +rt_inline rt_bool_t virtqueue_pending(struct rt_virtqueue *vq) +{ + rt_bool_t res = RT_FALSE; + + if (vq->packed_ring) + { + res = vq_packed_pending(vq); + } + else + { + res = vq_split_pending(vq); + } + + return res; +} + +struct rt_virtqueue *rt_virtqueue_create(struct rt_virtio_device *vdev, + const char *name, int index, int num, rt_uint32_t align, + rt_virtqueue_notifier notify, rt_virtqueue_callback callback, + struct rt_virtqueue_formula *formula) +{ + struct rt_virtqueue *vq = RT_NULL; + struct rt_virtqueue_formula default_formula = {}; + + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(num != 0); + RT_ASSERT((num & (num - 1)) == 0); + RT_ASSERT(notify != RT_NULL); + RT_ASSERT(name != RT_NULL); + + formula = formula ? : &default_formula; + + if (rt_virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) + { + vq = vq_packed_create(vdev, name, index, num, align, notify, callback, formula); + } + else + { + vq = vq_split_create(vdev, name, index, num, align, notify, callback, formula); + } + + if (vq) + { + if (!callback) + { + rt_virtqueue_disable_callback(vq); + } + + rt_base_t level = rt_spin_lock_irqsave(&vdev->vq_lock); + + rt_list_init(&vq->list); + rt_list_init(&vq->user_list); + rt_list_insert_before(&vdev->vq_node, &vq->list); + + rt_spin_unlock_irqrestore(&vdev->vq_lock, level); + } + + return vq; +} + +rt_err_t rt_virtqueue_delete(struct rt_virtio_device *vdev, struct rt_virtqueue *vq) +{ + rt_ubase_t level; + rt_err_t err = RT_EOK; + + RT_ASSERT(vdev != RT_NULL); + RT_ASSERT(vq != RT_NULL); + + level = rt_spin_lock_irqsave(&vdev->vq_lock); + + while (virtqueue_pending(vq)) + { + rt_spin_unlock_irqrestore(&vdev->vq_lock, level); + + rt_thread_yield(); + + level = rt_spin_lock_irqsave(&vdev->vq_lock); + } + + rt_list_remove(&vq->list); + + rt_spin_unlock_irqrestore(&vdev->vq_lock, level); + + if (vq->packed_ring) + { + vq_packed_delete(vq); + } + else + { + vq_split_delete(vq); + } + + return err; +} + +rt_err_t rt_virtqueue_add_outbuf(struct rt_virtqueue *vq, void *dma_buf, rt_size_t size) +{ + rt_err_t err = -RT_ENOSYS; + + RT_ASSERT(vq != RT_NULL); + RT_ASSERT(dma_buf != RT_NULL); + RT_ASSERT(size != 0); + + if (vq->packed_ring) + { + err = vq_packed_add_buf(vq, dma_buf, size, RT_TRUE); + } + else + { + err = vq_split_add_buf(vq, dma_buf, size, RT_TRUE); + } + + return err; +} + +rt_err_t rt_virtqueue_add_inbuf(struct rt_virtqueue *vq, void *dma_buf, rt_size_t size) +{ + rt_err_t err = -RT_ENOSYS; + + RT_ASSERT(vq != RT_NULL); + RT_ASSERT(dma_buf != RT_NULL); + RT_ASSERT(size != 0); + + if (vq->packed_ring) + { + err = vq_packed_add_buf(vq, dma_buf, size, RT_FALSE); + } + else + { + err = vq_split_add_buf(vq, dma_buf, size, RT_FALSE); + } + + return err; +} + +rt_bool_t rt_virtqueue_prepare(struct rt_virtqueue *vq, rt_uint32_t nr) +{ + return vq->num_free >= nr; +} + +void rt_virtqueue_wait_prepare(struct rt_virtqueue *vq, rt_uint32_t nr) +{ + while (!rt_virtqueue_prepare(vq, nr)) + { + rt_thread_yield(); + rt_hw_cpu_relax(); + } +} + +rt_uint32_t rt_virtqueue_next_buf_index(struct rt_virtqueue *vq) +{ + RT_ASSERT(vq != RT_NULL); + + return vq->free_head % (vq->packed_ring ? + vq->vq_packed->virtq.num : vq->vq_split->virtq.num); +} + +rt_bool_t rt_virtqueue_submit(struct rt_virtqueue *vq) +{ + rt_bool_t res = RT_FALSE; + + RT_ASSERT(vq != RT_NULL); + + if (vq->packed_ring) + { + res = vq_packed_submit(vq); + } + else + { + res = vq_split_submit(vq); + } + + return res; +} + +rt_bool_t rt_virtqueue_notify(struct rt_virtqueue *vq) +{ + RT_ASSERT(vq != RT_NULL); + + if (!vq->notify(vq)) + { + return RT_FALSE; + } + + return RT_TRUE; +} + +rt_bool_t rt_virtqueue_kick(struct rt_virtqueue *vq) +{ + RT_ASSERT(vq != RT_NULL); + + if (rt_virtqueue_submit(vq)) + { + return rt_virtqueue_notify(vq); + } + + return RT_TRUE; +} + +void rt_virtqueue_isr(int irq, struct rt_virtqueue *vq) +{ + if (!virtqueue_pending(vq)) + { + LOG_D("%s.virtqueue[%s(%d)] no buffer pending in %s", + rt_dm_dev_get_name(&vq->vdev->parent), vq->name, vq->index, "isr"); + + return; + } + + if (vq->event) + { + vq->event_triggered = RT_TRUE; + } + + if (vq->callback) + { + vq->callback(vq); + } +} + +rt_bool_t rt_virtqueue_poll(struct rt_virtqueue *vq, rt_uint32_t last_used_idx) +{ + rt_bool_t res = RT_FALSE; + + RT_ASSERT(vq != RT_NULL); + + if (vq->packed_ring) + { + res = vq_packed_poll(vq, last_used_idx); + } + else + { + res = vq_split_poll(vq, last_used_idx); + } + + return res; +} + +void rt_virtqueue_disable_callback(struct rt_virtqueue *vq) +{ + if (vq->event_triggered) + { + return; + } + + if (vq->packed_ring) + { + vq_packed_disable_callback(vq); + } + else + { + vq_split_disable_callback(vq); + } +} + +rt_bool_t rt_virtqueue_enable_callback(struct rt_virtqueue *vq, + rt_uint32_t *out_last_used_idx) +{ + rt_uint32_t last_used_idx; + + if (vq->event_triggered) + { + vq->event_triggered = RT_FALSE; + } + + if (vq->packed_ring) + { + last_used_idx = vq_packed_enable_callback(vq); + } + else + { + last_used_idx = vq_split_enable_callback(vq); + } + + if (out_last_used_idx) + { + *out_last_used_idx = last_used_idx; + } + + return !rt_virtqueue_poll(vq, last_used_idx); +} + +void *rt_virtqueue_read_buf(struct rt_virtqueue *vq, rt_size_t *out_len) +{ + void *buf = RT_NULL; + rt_size_t len = 0; + + RT_ASSERT(vq != RT_NULL); + + if (vq->packed_ring) + { + buf = vq_packed_read_buf(vq, &len); + } + else + { + buf = vq_split_read_buf(vq, &len); + } + + if (len && out_len) + { + *out_len = len; + } + + return buf; +} + +rt_size_t rt_virtqueue_get_virtq_size(struct rt_virtqueue *vq) +{ + RT_ASSERT(vq != RT_NULL); + + if (vq->packed_ring) + { + return (rt_ubase_t)vq->vq_packed->virtq.num; + } + else + { + return (rt_ubase_t)vq->vq_split->virtq.num; + } +} + +rt_ubase_t rt_virtqueue_get_desc_addr(struct rt_virtqueue *vq) +{ + RT_ASSERT(vq != RT_NULL); + + if (vq->packed_ring) + { + return (rt_ubase_t)vq->vq_packed->virtq.desc; + } + else + { + return (rt_ubase_t)vq->vq_split->virtq.desc; + } +} + +rt_ubase_t rt_virtqueue_get_avail_addr(struct rt_virtqueue *vq) +{ + RT_ASSERT(vq != RT_NULL); + + if (vq->packed_ring) + { + return (rt_ubase_t)vq->vq_packed->virtq.driver_event; + } + else + { + return (rt_ubase_t)vq->vq_split->virtq.avail; + } +} + +rt_ubase_t rt_virtqueue_get_used_addr(struct rt_virtqueue *vq) +{ + RT_ASSERT(vq != RT_NULL); + + if (vq->packed_ring) + { + return (rt_ubase_t)vq->vq_packed->virtq.device_event; + } + else + { + return (rt_ubase_t)vq->vq_split->virtq.used; + } +} diff --git a/components/drivers/virtio/virtio_queue.h b/components/drivers/virtio/virtio_queue.h deleted file mode 100644 index b2b0bdcd32..0000000000 --- a/components/drivers/virtio/virtio_queue.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#ifndef __VIRTIO_QUEUE_H__ -#define __VIRTIO_QUEUE_H__ - -#include <rtdef.h> - -#define VIRTQ_DESC_F_NEXT 1 /* This marks a buffer as continuing via the next field. */ -#define VIRTQ_DESC_F_WRITE 2 /* This marks a buffer as write-only (otherwise read-only). */ -#define VIRTQ_DESC_F_INDIRECT 4 /* This means the buffer contains a list of buffer descriptors. */ - -/* - * The device uses this in used->flags to advise the driver: don't kick me - * when you add a buffer. It's unreliable, so it's simply an optimization. - */ -#define VIRTQ_USED_F_NO_NOTIFY 1 - -/* - * The driver uses this in avail->flags to advise the device: don't - * interrupt me when you consume a buffer. It's unreliable, so it's - * simply an optimization. - */ -#define VIRTQ_AVAIL_F_NO_INTERRUPT 1 - -/* Virtqueue descriptors: 16 bytes. These can chain together via "next". */ -struct virtq_desc -{ - rt_uint64_t addr; /* Address (guest-physical). */ - rt_uint32_t len; /* Length. */ - rt_uint16_t flags; /* The flags as indicated above. */ - rt_uint16_t next; /* We chain unused descriptors via this, too */ -}; - -struct virtq_avail -{ - rt_uint16_t flags; /* Notifications */ - rt_uint16_t idx; /* Where the driver would put the next descriptor entry in the ring (modulo the queue size) */ - rt_uint16_t ring[]; - - /* - * Only if VIRTIO_F_RING_EVENT_IDX - * rt_uint16_t used_event; - */ -}; - -struct virtq_used_elem -{ - rt_uint32_t id; /* Index of start of used descriptor chain. */ - rt_uint32_t len; /* Total length of the descriptor chain which was written to. */ -}; - -struct virtq_used -{ - rt_uint16_t flags; - rt_uint16_t idx; - struct virtq_used_elem ring[]; - - /* - * Only if VIRTIO_F_RING_EVENT_IDX - * rt_uint16_t avail_event; - */ -}; - -struct virtq -{ - rt_uint32_t num; - - struct virtq_desc *desc; - struct virtq_avail *avail; - struct virtq_used *used; - - /* Helper of driver */ - rt_uint16_t used_idx; - rt_bool_t *free; - rt_size_t free_count; -}; - -#define VIRTQ_DESC_TOTAL_SIZE(ring_size) (sizeof(struct virtq_desc) * (ring_size)) -/* flags, idx, used_event + ring * ring_size */ -#define VIRTQ_AVAIL_TOTAL_SIZE(ring_size) (sizeof(rt_uint16_t) * 3 + sizeof(rt_uint16_t) * (ring_size)) -/* flags, idx, avail_event + ring * ring_size */ -#define VIRTQ_USED_TOTAL_SIZE(ring_size) (sizeof(rt_uint16_t) * 3 + sizeof(struct virtq_used_elem) * (ring_size)) - -#define VIRTQ_AVAIL_RES_SIZE (sizeof(rt_uint16_t)) /* used_event */ -#define VIRTQ_USED_RES_SIZE (sizeof(rt_uint16_t)) /* avail_event */ - -#define VIRTQ_INVALID_DESC_ID RT_UINT16_MAX - -#endif /* __VIRTIO_QUEUE_H__ */ |
