[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 <2991707448@qq.com>
This commit is contained in:
GuEe-GUI
2026-06-15 10:00:57 +08:00
committed by Rbb666
parent 79e7d91909
commit 8517f2d086
58 changed files with 10548 additions and 507 deletions
+9 -10
View File
@@ -327,15 +327,6 @@ CONFIG_RT_USING_SOFT_RTC=y
# CONFIG_RT_USING_BLK is not set
# CONFIG_RT_USING_REGULATOR is not set
# CONFIG_RT_USING_POWER_SUPPLY is not set
CONFIG_RT_USING_VIRTIO=y
CONFIG_RT_USING_VIRTIO10=y
# CONFIG_RT_USING_VIRTIO_MMIO_ALIGN is not set
CONFIG_RT_USING_VIRTIO_BLK=y
CONFIG_RT_USING_VIRTIO_NET=y
CONFIG_RT_USING_VIRTIO_CONSOLE=y
CONFIG_RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR=4
CONFIG_RT_USING_VIRTIO_GPU=y
CONFIG_RT_USING_VIRTIO_INPUT=y
CONFIG_RT_USING_PIN=y
# CONFIG_RT_USING_CHERRYUSB is not set
# end of Device Drivers
@@ -1608,7 +1599,15 @@ CONFIG_RT_PAGE_MAX_ORDER=11
#
# RISC-V QEMU virt64 configs
#
CONFIG_BSP_USING_VIRTIO=y
CONFIG_RT_USING_LEGACY_VIRTIO=y
CONFIG_RT_USING_VIRTIO10=y
# CONFIG_RT_USING_VIRTIO_MMIO_ALIGN is not set
CONFIG_RT_USING_VIRTIO_BLK=y
CONFIG_RT_USING_VIRTIO_NET=y
CONFIG_RT_USING_VIRTIO_CONSOLE=y
CONFIG_RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR=4
CONFIG_RT_USING_VIRTIO_GPU=y
CONFIG_RT_USING_VIRTIO_INPUT=y
CONFIG_BSP_USING_VIRTIO_BLK=y
CONFIG_BSP_USING_VIRTIO_NET=y
CONFIG_BSP_USING_VIRTIO_CONSOLE=y
+5 -15
View File
@@ -1,43 +1,33 @@
menu "RISC-V QEMU virt64 configs"
config BSP_USING_VIRTIO
bool "Using VirtIO"
default y
depends on RT_USING_DEVICE_OPS
config BSP_USING_VIRTIO_BLK
bool "Using VirtIO BLK"
select RT_USING_VIRTIO
select RT_USING_LEGACY_VIRTIO
select RT_USING_VIRTIO_BLK
default y
depends on BSP_USING_VIRTIO
config BSP_USING_VIRTIO_NET
bool "Using VirtIO NET"
select RT_USING_VIRTIO
select RT_USING_LEGACY_VIRTIO
select RT_USING_VIRTIO_NET
default y
depends on BSP_USING_VIRTIO
config BSP_USING_VIRTIO_CONSOLE
bool "Using VirtIO Console"
select RT_USING_VIRTIO
select RT_USING_LEGACY_VIRTIO
select RT_USING_VIRTIO_CONSOLE
default y
depends on BSP_USING_VIRTIO
config BSP_USING_VIRTIO_GPU
bool "Using VirtIO GPU"
select RT_USING_VIRTIO
select RT_USING_LEGACY_VIRTIO
select RT_USING_VIRTIO_GPU
default y
depends on BSP_USING_VIRTIO
config BSP_USING_VIRTIO_INPUT
bool "Using VirtIO Input"
select RT_USING_VIRTIO
select RT_USING_LEGACY_VIRTIO
select RT_USING_VIRTIO_INPUT
default y
depends on BSP_USING_VIRTIO
endmenu
+2 -2
View File
@@ -11,7 +11,7 @@
#include <rtthread.h>
#include <virt.h>
#ifdef BSP_USING_VIRTIO
#ifdef RT_USING_LEGACY_VIRTIO
#include <virtio.h>
#ifdef BSP_USING_VIRTIO_BLK
@@ -97,4 +97,4 @@ int rt_virtio_devices_init(void)
return 0;
}
INIT_DEVICE_EXPORT(rt_virtio_devices_init);
#endif /* BSP_USING_VIRTIO */
#endif /* RT_USING_LEGACY_VIRTIO */
+1 -1
View File
@@ -1 +1 @@
RT_CPUS_NR = 8;
RT_CPUS_NR = 1;
+8 -9
View File
@@ -202,14 +202,6 @@
#define RT_USING_RANDOM
#define RT_USING_RTC
#define RT_USING_SOFT_RTC
#define RT_USING_VIRTIO
#define RT_USING_VIRTIO10
#define RT_USING_VIRTIO_BLK
#define RT_USING_VIRTIO_NET
#define RT_USING_VIRTIO_CONSOLE
#define RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR 4
#define RT_USING_VIRTIO_GPU
#define RT_USING_VIRTIO_INPUT
#define RT_USING_PIN
/* end of Device Drivers */
@@ -558,7 +550,14 @@
/* RISC-V QEMU virt64 configs */
#define BSP_USING_VIRTIO
#define RT_USING_LEGACY_VIRTIO
#define RT_USING_VIRTIO10
#define RT_USING_VIRTIO_BLK
#define RT_USING_VIRTIO_NET
#define RT_USING_VIRTIO_CONSOLE
#define RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR 4
#define RT_USING_VIRTIO_GPU
#define RT_USING_VIRTIO_INPUT
#define BSP_USING_VIRTIO_BLK
#define BSP_USING_VIRTIO_NET
#define BSP_USING_VIRTIO_CONSOLE
+8 -9
View File
@@ -341,14 +341,6 @@ CONFIG_RT_USING_SOFT_RTC=y
# CONFIG_RT_USING_BLK is not set
# CONFIG_RT_USING_REGULATOR is not set
# CONFIG_RT_USING_POWER_SUPPLY is not set
CONFIG_RT_USING_VIRTIO=y
CONFIG_RT_USING_VIRTIO10=y
# CONFIG_RT_USING_VIRTIO_MMIO_ALIGN is not set
CONFIG_RT_USING_VIRTIO_BLK=y
# CONFIG_RT_USING_VIRTIO_NET is not set
# CONFIG_RT_USING_VIRTIO_CONSOLE is not set
# CONFIG_RT_USING_VIRTIO_GPU is not set
# CONFIG_RT_USING_VIRTIO_INPUT is not set
CONFIG_RT_USING_PIN=y
# CONFIG_RT_USING_CHERRYUSB is not set
# end of Device Drivers
@@ -1562,7 +1554,14 @@ CONFIG_LWP_PTY_MAX_PARIS_LIMIT=64
#
# RISC-V QEMU virt64 configs
#
CONFIG_BSP_USING_VIRTIO=y
CONFIG_RT_USING_LEGACY_VIRTIO=y
CONFIG_RT_USING_VIRTIO10=y
# CONFIG_RT_USING_VIRTIO_MMIO_ALIGN is not set
CONFIG_RT_USING_VIRTIO_BLK=y
# CONFIG_RT_USING_VIRTIO_NET is not set
# CONFIG_RT_USING_VIRTIO_CONSOLE is not set
# CONFIG_RT_USING_VIRTIO_GPU is not set
# CONFIG_RT_USING_VIRTIO_INPUT is not set
CONFIG_BSP_USING_VIRTIO_BLK=y
# end of RISC-V QEMU virt64 configs
+1 -7
View File
@@ -1,15 +1,9 @@
menu "RISC-V QEMU virt64 configs"
config BSP_USING_VIRTIO
bool "Using VirtIO"
default y
depends on RT_USING_DEVICE_OPS
config BSP_USING_VIRTIO_BLK
bool "Using VirtIO BLK"
select RT_USING_VIRTIO
select RT_USING_LEGACY_VIRTIO
select RT_USING_VIRTIO_BLK
default y
depends on BSP_USING_VIRTIO
endmenu
+2 -2
View File
@@ -11,7 +11,7 @@
#include <rtthread.h>
#include <virt.h>
#ifdef BSP_USING_VIRTIO
#ifdef RT_USING_LEGACY_VIRTIO
#include <virtio.h>
#ifdef BSP_USING_VIRTIO_BLK
@@ -74,4 +74,4 @@ int rt_virtio_devices_init(void)
return 0;
}
INIT_DEVICE_EXPORT(rt_virtio_devices_init);
#endif /* BSP_USING_VIRTIO */
#endif /* RT_USING_LEGACY_VIRTIO */
+3 -4
View File
@@ -219,9 +219,6 @@
#define RT_USING_RANDOM
#define RT_USING_RTC
#define RT_USING_SOFT_RTC
#define RT_USING_VIRTIO
#define RT_USING_VIRTIO10
#define RT_USING_VIRTIO_BLK
#define RT_USING_PIN
/* end of Device Drivers */
@@ -527,7 +524,9 @@
/* RISC-V QEMU virt64 configs */
#define BSP_USING_VIRTIO
#define RT_USING_LEGACY_VIRTIO
#define RT_USING_VIRTIO10
#define RT_USING_VIRTIO_BLK
#define BSP_USING_VIRTIO_BLK
/* end of RISC-V QEMU virt64 configs */
#define BOARD_QEMU_VIRT_RV64
+282
View File
@@ -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__ */
+198
View File
@@ -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__ */
+5
View File
@@ -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
+87 -31
View File
@@ -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
+46 -6
View File
@@ -1,11 +1,51 @@
# RT-Thread building script for component
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = []
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_VIRTIO'], CPPPATH = CPPPATH)
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 = [''], CPPPATH = CPPPATH)
Return('group')
+188
View File
@@ -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);
+332
View File
@@ -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);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+300
View File
@@ -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);
+423
View File
@@ -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);
+191
View File
@@ -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);
+293
View File
@@ -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);
+322
View File
@@ -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);
File diff suppressed because it is too large Load Diff
@@ -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__ */
@@ -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__ */
@@ -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__ */
File diff suppressed because it is too large Load Diff
@@ -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__ */
@@ -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__ */
@@ -0,0 +1,82 @@
/*
* 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_NET_H__
#define __VIRTIO_NET_H__
#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 */
#define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS 2 /* Dynamic offload configuration */
#define VIRTIO_NET_F_MTU 3 /* Initial MTU advice */
#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address */
#define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in */
#define VIRTIO_NET_F_GUEST_TSO6 8 /* Guest can handle TSOv6 in */
#define VIRTIO_NET_F_GUEST_ECN 9 /* Guest can handle TSO[6] w/ ECN in */
#define VIRTIO_NET_F_GUEST_UFO 10 /* Guest can handle UFO in */
#define VIRTIO_NET_F_HOST_TSO4 11 /* Host can handle TSOv4 in */
#define VIRTIO_NET_F_HOST_TSO6 12 /* Host can handle TSOv6 in */
#define VIRTIO_NET_F_HOST_ECN 13 /* Host can handle TSO[6] w/ ECN in */
#define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in */
#define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */
#define VIRTIO_NET_F_STATUS 16 /* virtio_net_config.status available */
#define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */
#define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */
#define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */
#define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */
#define VIRTIO_NET_F_GUEST_ANNOUNCE 21 /* Guest can announce device on the network */
#define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow Steering */
#define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */
#define VIRTIO_NET_F_HASH_REPORT 57 /* Supports hash report */
#define VIRTIO_NET_F_RSS 60 /* Supports RSS RX steering */
#define VIRTIO_NET_F_RSC_EXT 61 /* Extended coalescing info */
#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 */
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
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;
});
#define VIRTIO_NET_MSS 1514
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;
rt_uint32_t speed;
rt_uint8_t duplex;
rt_uint8_t rss_max_key_size;
rt_uint16_t rss_max_indirection_table_length;
rt_uint32_t supported_hash_types;
});
#endif /* __VIRTIO_NET_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__ */
@@ -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__ */
+77
View File
@@ -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__ */
+112
View File
@@ -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__ */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1
View File
@@ -1,2 +1,3 @@
rsource "usb/Kconfig"
rsource "fdt/Kconfig"
rsource "virtio/Kconfig"
+1
View File
@@ -1,2 +1,3 @@
# RT-Thread Legacy
- virtio: virtio not DM support version, using by some qemu riscv BSPs
+44
View File
@@ -0,0 +1,44 @@
menuconfig RT_USING_LEGACY_VIRTIO
bool "Using VirtIO device drivers"
default n
depends on RT_USING_DEVICE_OPS
if RT_USING_LEGACY_VIRTIO
choice RT_USING_VIRTIO_VERSION
prompt "VirtIO Version"
default RT_USING_VIRTIO10
config RT_USING_VIRTIO10
bool "VirtIO v1.0"
endchoice
config RT_USING_VIRTIO_MMIO_ALIGN
bool "Using VirtIO MMIO alignment"
default y
config RT_USING_VIRTIO_BLK
bool "Using VirtIO BLK"
default y
config RT_USING_VIRTIO_NET
bool "Using VirtIO NET"
default y
menuconfig RT_USING_VIRTIO_CONSOLE
bool "Using VirtIO Console"
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_USING_VIRTIO_GPU
bool "Using VirtIO GPU"
default y
config RT_USING_VIRTIO_INPUT
bool "Using VirtIO Input"
default y
endif
+11
View File
@@ -0,0 +1,11 @@
# RT-Thread building script for component
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_LEGACY_VIRTIO'], CPPPATH = CPPPATH)
Return('group')
+473
View File
@@ -0,0 +1,473 @@
/*
* 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-10-12 fangjianzhou support SDL2
*/
#include <rtthread.h>
#include <cpuport.h>
#include <virtio.h>
rt_inline void _virtio_dev_check(struct virtio_device *dev)
{
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(dev->mmio_config != RT_NULL);
}
void virtio_reset_device(struct virtio_device *dev)
{
_virtio_dev_check(dev);
dev->mmio_config->status = 0;
}
void virtio_status_acknowledge_driver(struct virtio_device *dev)
{
_virtio_dev_check(dev);
dev->mmio_config->status |= VIRTIO_STATUS_ACKNOWLEDGE | VIRTIO_STATUS_DRIVER;
}
void virtio_status_driver_ok(struct virtio_device *dev)
{
_virtio_dev_check(dev);
dev->mmio_config->status |= VIRTIO_STATUS_FEATURES_OK | VIRTIO_STATUS_DRIVER_OK;
}
void virtio_interrupt_ack(struct virtio_device *dev)
{
rt_uint32_t status;
_virtio_dev_check(dev);
status = dev->mmio_config->interrupt_status;
if (status != 0)
{
dev->mmio_config->interrupt_ack = status;
}
}
rt_bool_t virtio_has_feature(struct virtio_device *dev, rt_uint32_t feature_bit)
{
_virtio_dev_check(dev);
return !!(dev->mmio_config->device_features & (1UL << feature_bit));
}
rt_err_t virtio_queues_alloc(struct virtio_device *dev, rt_size_t queues_num)
{
_virtio_dev_check(dev);
dev->queues = rt_malloc(sizeof(struct virtq) * queues_num);
if (dev->queues != RT_NULL)
{
dev->queues_num = queues_num;
return RT_EOK;
}
return -RT_ENOMEM;
}
void virtio_queues_free(struct virtio_device *dev)
{
if (dev->queues != RT_NULL)
{
dev->queues_num = 0;
rt_free(dev->queues);
}
}
rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t ring_size)
{
int i;
void *pages;
rt_size_t pages_total_size;
struct virtq *queue;
_virtio_dev_check(dev);
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);
/* 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);
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);
pages = rt_malloc_align(pages_total_size, VIRTIO_PAGE_SIZE);
if (pages == RT_NULL)
{
return -RT_ENOMEM;
}
queue->free = rt_malloc(sizeof(rt_bool_t) * ring_size);
if (queue->free == RT_NULL)
{
rt_free_align(pages);
return -RT_ENOMEM;
}
rt_memset(pages, 0, pages_total_size);
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;
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);
queue->used_idx = 0;
/* All descriptors start out unused */
for (i = 0; i < ring_size; ++i)
{
queue->free[i] = RT_TRUE;
}
queue->free_count = ring_size;
return RT_EOK;
}
void virtio_queue_destroy(struct virtio_device *dev, rt_uint32_t queue_index)
{
struct virtq *queue;
_virtio_dev_check(dev);
RT_ASSERT(queue_index < dev->queues_num);
/* 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);
queue = &dev->queues[queue_index];
RT_ASSERT(queue->num > 0);
rt_free(queue->free);
rt_free_align((void *)queue->desc);
dev->mmio_config->queue_pfn = RT_NULL;
queue->num = 0;
queue->desc = RT_NULL;
queue->avail = RT_NULL;
queue->used = RT_NULL;
}
void virtio_queue_notify(struct virtio_device *dev, rt_uint32_t queue_index)
{
_virtio_dev_check(dev);
dev->mmio_config->queue_notify = queue_index;
}
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;
_virtio_dev_check(dev);
queue = &dev->queues[queue_index];
ring_size = queue->num;
/* Tell the device the first index in our chain of descriptors */
queue->avail->ring[queue->avail->idx % ring_size] = desc_index;
rt_hw_dsb();
/* Tell the device another avail ring entry is available */
queue->avail->idx++;
rt_hw_dsb();
}
rt_uint16_t virtio_alloc_desc(struct virtio_device *dev, rt_uint32_t queue_index)
{
int i;
struct virtq *queue;
_virtio_dev_check(dev);
RT_ASSERT(queue_index < dev->queues_num);
queue = &dev->queues[queue_index];
if (queue->free_count > 0)
{
rt_size_t ring_size = queue->num;
for (i = 0; i < ring_size; ++i)
{
if (queue->free[i])
{
queue->free[i] = RT_FALSE;
queue->free_count--;
return (rt_uint16_t)i;
}
}
}
return VIRTQ_INVALID_DESC_ID;
}
void virtio_free_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index)
{
struct virtq *queue;
_virtio_dev_check(dev);
queue = &dev->queues[queue_index];
RT_ASSERT(queue_index < dev->queues_num);
RT_ASSERT(!queue->free[desc_index]);
queue->desc[desc_index].addr = 0;
queue->desc[desc_index].len = 0;
queue->desc[desc_index].flags = 0;
queue->desc[desc_index].next = 0;
queue->free[desc_index] = RT_TRUE;
queue->free_count++;
}
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;
_virtio_dev_check(dev);
RT_ASSERT(indexs != RT_NULL);
if (dev->queues[queue_index].free_count < count)
{
return -RT_ERROR;
}
for (i = 0; i < count; ++i)
{
indexs[i] = virtio_alloc_desc(dev, queue_index);
if (indexs[i] == VIRTQ_INVALID_DESC_ID)
{
for (j = 0; j < i; ++j)
{
virtio_free_desc(dev, queue_index, indexs[j]);
}
return -RT_ERROR;
}
}
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);
desc = &dev->queues[queue_index].desc[0];
for (;;)
{
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;
}
}
}
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];
desc->addr = addr;
desc->len = len;
desc->flags = flags;
desc->next = next;
}
#ifdef RT_USING_SMART
#ifdef RT_USING_VIRTIO_GPU
#include <virtio_gpu.h>
#include "drivers/lcd.h"
#include <dfs_file.h>
#include <lwp_user_mm.h>
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;
static rt_err_t fb_open(rt_device_t dev, rt_uint16_t oflag)
{
return RT_EOK;
}
static rt_err_t fb_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t fb_control(rt_device_t dev, int cmd, void *args)
{
switch(cmd)
{
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;
if(mmap2)
{
mmap2->ret = lwp_map_user_phy(lwp_self(), RT_NULL, rt_kmem_v2p(_graphic_info.framebuffer), mmap2->length, 1);
}
else
{
return -EIO;
}
break;
}
default:
break;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops fb_ops =
{
RT_NULL,
fb_open,
fb_close,
RT_NULL,
RT_NULL,
fb_control
};
#endif
static int fb_init()
{
_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;
}
_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;
}
INIT_COMPONENT_EXPORT(fb_init);
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More