mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-08-18 02:46:30 +08:00
[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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 @@
|
||||
RT_CPUS_NR = 8;
|
||||
RT_CPUS_NR = 1;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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);
|
||||
@@ -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
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
+299
-411
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__ */
|
||||
@@ -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__ */
|
||||
@@ -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,2 +1,3 @@
|
||||
rsource "usb/Kconfig"
|
||||
rsource "fdt/Kconfig"
|
||||
rsource "virtio/Kconfig"
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
# RT-Thread Legacy
|
||||
|
||||
- virtio: virtio not DM support version, using by some qemu riscv BSPs
|
||||
|
||||
@@ -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
|
||||
@@ -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')
|
||||
@@ -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
Reference in New Issue
Block a user