[bsp/qemu-virt64-aarch64] Update drivers' code (#6194)

* [bsp/qemu-virt64-aarch64] RTC add hard alarm support

* [bsp/qemu-virt64-aarch64] Fixup VirtIO-GPU init buffer fail by cpu out-of-order execution

* [bsp/qemu-virt64-aarch64] Fixup VirtIO-NET transmit payload split
Add Virtio-GPU cursor demo
This commit is contained in:
GUI 2022-07-30 14:04:25 +08:00 committed by GitHub
parent 9ee9b9205c
commit 747ed9b516
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 217 additions and 97 deletions

View File

@ -50,6 +50,15 @@ Use VirtIO-Console in new terminal by:
telnet 127.0.0.1 4321 telnet 127.0.0.1 4321
```` ````
If use tap net mode with tap0 card, modify qemu run script config
```
-netdev user,id=net0
```
to
```
-netdev tap,id=net0,ifname=tap0
```
## 4. Condition ## 4. Condition
| Driver | Condition | Remark | | Driver | Condition | Remark |

View File

@ -51,6 +51,15 @@ msh />
telnet 127.0.0.1 4321 telnet 127.0.0.1 4321
``` ```
如果使用tap网卡模式以设备tap0为例将qemu运行脚本
```
-netdev user,id=net0
```
修改为
```
-netdev tap,id=net0,ifname=tap0
```
## 4.支持情况 ## 4.支持情况
| 驱动 | 支持情况 | 备注 | | 驱动 | 支持情况 | 备注 |

View File

@ -24,6 +24,7 @@ static rt_uint32_t cur_points[2];
static rt_uint32_t cur_last_points[2]; static rt_uint32_t cur_last_points[2];
static rt_bool_t cur_event_sync; static rt_bool_t cur_event_sync;
static rt_uint32_t color[2] = { 0xff0000, 0x0000ff }; static rt_uint32_t color[2] = { 0xff0000, 0x0000ff };
static rt_uint8_t cursor[VIRTIO_GPU_CURSOR_IMG_SIZE] ALIGN(VIRTIO_PAGE_SIZE);
void tablet_event_handler(struct virtio_input_event event) void tablet_event_handler(struct virtio_input_event event)
{ {
@ -100,6 +101,8 @@ void graphic_thread(void *param)
if (graphic_info.framebuffer != RT_NULL) if (graphic_info.framebuffer != RT_NULL)
{ {
int i = 0;
rt_memset(graphic_info.framebuffer, 0xff, rt_memset(graphic_info.framebuffer, 0xff,
graphic_info.width * graphic_info.height * graphic_info.bits_per_pixel); graphic_info.width * graphic_info.height * graphic_info.bits_per_pixel);
@ -111,6 +114,16 @@ void graphic_thread(void *param)
rt_device_control(device, RTGRAPHIC_CTRL_RECT_UPDATE, &rect_info); rt_device_control(device, RTGRAPHIC_CTRL_RECT_UPDATE, &rect_info);
while (i < sizeof(cursor) / sizeof(rt_uint32_t))
{
/* R: 0x4c G: 0xaf B: 0x50 A: 0.8 */
((rt_uint32_t *)cursor)[i] = 0xcc4caf50;
++i;
}
rt_device_control(device, VIRTIO_DEVICE_CTRL_CURSOR_SETUP, cursor);
rt_device_control(device, VIRTIO_DEVICE_CTRL_CURSOR_MOVE, (rt_uint32_t[]){0, 0});
gpu_dev = device; gpu_dev = device;
} }
} }

View File

@ -1,13 +1,15 @@
/* /*
* Copyright (c) 2006-2021, RT-Thread Development Team * Copyright (c) 2006-2022, RT-Thread Development Team
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
* Change Logs: * Change Logs:
* Date Author Notes * Date Author Notes
* 2021-11-4 GuEe-GUI first version * 2021-11-4 GuEe-GUI first version
* 2022-07-15 GuEe-GUI add alarm ops support
*/ */
#include <rthw.h>
#include <rtthread.h> #include <rtthread.h>
#include <rtdevice.h> #include <rtdevice.h>
#include <sys/time.h> #include <sys/time.h>
@ -28,8 +30,13 @@
#define RTC_CR_OPEN 1 #define RTC_CR_OPEN 1
#define RTC_CR_CLOSE 0 #define RTC_CR_CLOSE 0
#define RTC_BIT_AI (1 << 0) /* Alarm interrupt bit */
#define RTC_BIT_PI (1 << 1) /* Periodic interrupt bit. ST variants only. */
static struct hw_rtc_device rtc_device; static rt_rtc_dev_t _rtc_device;
#ifdef RT_USING_ALARM
static struct rt_rtc_wkalarm _wkalarm;
#endif
rt_inline rt_uint32_t pl031_read32(rt_ubase_t offset) rt_inline rt_uint32_t pl031_read32(rt_ubase_t offset)
{ {
@ -41,76 +48,157 @@ rt_inline void pl031_write32(rt_ubase_t offset, rt_uint32_t value)
(*((volatile unsigned int *)(PL031_RTC_BASE + offset))) = value; (*((volatile unsigned int *)(PL031_RTC_BASE + offset))) = value;
} }
static rt_err_t pl031_rtc_init(rt_device_t dev) static rt_err_t pl031_rtc_init(void)
{
return RT_EOK;
}
static rt_err_t pl031_rtc_open(rt_device_t dev, rt_uint16_t oflag)
{ {
pl031_write32(RTC_CR, RTC_CR_OPEN); pl031_write32(RTC_CR, RTC_CR_OPEN);
return RT_EOK; return RT_EOK;
} }
static rt_err_t pl031_rtc_close(rt_device_t dev) static rt_err_t pl031_get_secs(time_t *sec)
{ {
pl031_write32(RTC_CR, RTC_CR_CLOSE); if (sec != RT_NULL)
return RT_EOK;
}
static rt_err_t pl031_rtc_control(rt_device_t dev, int cmd, void *args)
{
RT_ASSERT(dev != RT_NULL);
switch (cmd)
{ {
case RT_DEVICE_CTRL_RTC_GET_TIME: *(rt_uint32_t *)sec = pl031_read32(RTC_DR);
*(rt_uint32_t *)args = pl031_read32(RTC_DR);
break; return RT_EOK;
case RT_DEVICE_CTRL_RTC_SET_TIME:
pl031_write32(RTC_LR, *(time_t *)args);
break;
default:
return RT_EINVAL;
} }
return RT_EOK;
return -RT_EINVAL;
} }
static rt_size_t pl031_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) static rt_err_t pl031_set_secs(time_t *sec)
{ {
pl031_rtc_control(dev, RT_DEVICE_CTRL_RTC_GET_TIME, buffer); if (sec != RT_NULL)
return size; {
pl031_write32(RTC_LR, *(rt_uint32_t *)sec);
return RT_EOK;
}
return -RT_EINVAL;
} }
static rt_size_t pl031_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) #ifdef RT_USING_ALARM
static rt_err_t pl031_set_alarm(struct rt_rtc_wkalarm *alarm)
{ {
pl031_rtc_control(dev, RT_DEVICE_CTRL_RTC_SET_TIME, (void *)buffer); if (alarm != RT_NULL)
return size; {
rt_uint32_t imsc, time;
_wkalarm.enable = alarm->enable;
_wkalarm.tm_hour = alarm->tm_hour;
_wkalarm.tm_min = alarm->tm_min;
_wkalarm.tm_sec = alarm->tm_sec;
time = pl031_read32(RTC_DR);
/* Back to 08:00 today */
time = time / (3600 * 24) * (3600 * 24);
/* Get alarm time */
time += alarm->tm_hour * 3600 + alarm->tm_min * 60 + alarm->tm_sec;
pl031_write32(RTC_MR, time);
/* Clear any pending alarm interrupts. */
pl031_write32(RTC_ICR, RTC_BIT_AI);
imsc = pl031_read32(RTC_IMSC);
if (alarm->enable)
{
pl031_write32(RTC_IMSC, imsc | RTC_BIT_AI);
}
else
{
pl031_write32(RTC_IMSC, imsc & ~RTC_BIT_AI);
}
return RT_EOK;
}
return -RT_EINVAL;
} }
const static struct rt_device_ops pl031_rtc_ops = static rt_err_t pl031_get_alarm(struct rt_rtc_wkalarm *alarm)
{ {
.init = pl031_rtc_init, if (alarm != RT_NULL)
.open = pl031_rtc_open, {
.close = pl031_rtc_close, *alarm = _wkalarm;
.read = pl031_rtc_read,
.write = pl031_rtc_write, return RT_EOK;
.control = pl031_rtc_control }
return -RT_EINVAL;
}
#endif /* RT_USING_ALARM */
static rt_err_t pl031_get_timeval(struct timeval *tv)
{
if (tv != RT_NULL)
{
tv->tv_sec = pl031_read32(RTC_DR);
return RT_EOK;
}
return -RT_EINVAL;
}
static rt_err_t pl031_set_timeval(struct timeval *tv)
{
if (tv != RT_NULL)
{
pl031_write32(RTC_LR, *(rt_uint32_t *)tv->tv_sec);
return RT_EOK;
}
return -RT_EINVAL;
}
static const struct rt_rtc_ops rtc_ops =
{
.init = pl031_rtc_init,
.get_secs = pl031_get_secs,
.set_secs = pl031_set_secs,
#ifdef RT_USING_ALARM
.get_alarm = pl031_get_alarm,
.set_alarm = pl031_set_alarm,
#else
.get_alarm = RT_NULL,
.set_alarm = RT_NULL,
#endif
.get_timeval = pl031_get_timeval,
.set_timeval = pl031_set_timeval,
}; };
#ifdef RT_USING_ALARM
static void rt_hw_rtc_isr(int irqno, void *param)
{
rt_uint32_t rtcmis = pl031_read32(RTC_MIS);
if (rtcmis & RTC_BIT_AI)
{
pl031_write32(RTC_ICR, RTC_BIT_AI);
rt_alarm_update(&_rtc_device.parent, 1);
}
}
#endif /* RT_USING_ALARM */
int rt_hw_rtc_init(void) int rt_hw_rtc_init(void)
{ {
rt_memset(&rtc_device, 0, sizeof(rtc_device)); _rtc_device.ops = &rtc_ops;
rtc_device.device.type = RT_Device_Class_RTC;
rtc_device.device.rx_indicate = RT_NULL;
rtc_device.device.tx_complete = RT_NULL;
rtc_device.device.ops = &pl031_rtc_ops;
rtc_device.device.user_data = RT_NULL;
/* register a rtc device */ /* register a rtc device */
rt_device_register(&rtc_device.device, "rtc", RT_DEVICE_FLAG_RDWR); rt_hw_rtc_register(&_rtc_device, "rtc", RT_DEVICE_FLAG_RDWR, RT_NULL);
#ifdef RT_USING_ALARM
rt_hw_interrupt_install(PL031_RTC_IRQNUM, rt_hw_rtc_isr, RT_NULL, "rtc");
rt_hw_interrupt_umask(PL031_RTC_IRQNUM);
#endif /* RT_USING_ALARM */
return 0; return 0;
} }

View File

@ -84,10 +84,6 @@ static void virtio_gpu_ctrl_send_command(struct virtio_gpu_device *virtio_gpu_de
#endif #endif
} }
rt_hw_dsb();
virtio_gpu_dev->info[idx[0]].ctrl_valid = RT_TRUE;
rt_memcpy(&virtio_gpu_dev->gpu_request, cmd, cmd_len); rt_memcpy(&virtio_gpu_dev->gpu_request, cmd, cmd_len);
virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0], virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0],
@ -98,6 +94,8 @@ static void virtio_gpu_ctrl_send_command(struct virtio_gpu_device *virtio_gpu_de
rt_memset(ret_res, 0, res_len); rt_memset(ret_res, 0, res_len);
virtio_gpu_dev->info[idx[0]].ctrl_valid = RT_TRUE;
virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]); virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]);
virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CTRL); virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CTRL);

View File

@ -23,41 +23,41 @@ static rt_err_t virtio_net_tx(rt_device_t dev, struct pbuf *p)
struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev; struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
struct virtq *queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX]; struct virtq *queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX];
while (p != RT_NULL)
{
#ifdef RT_USING_SMP #ifdef RT_USING_SMP
rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock); rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
#endif #endif
id = (queue_tx->avail->idx * 2) % queue_tx->num;
virtio_net_dev->info[id].hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; id = (queue_tx->avail->idx * 2) % queue_tx->num;
virtio_net_dev->info[id].hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE;
virtio_net_dev->info[id].hdr.hdr_len = 0;
virtio_net_dev->info[id].hdr.gso_size = 0;
virtio_net_dev->info[id].hdr.csum_start = 0;
virtio_net_dev->info[id].hdr.csum_offset = p->tot_len + sizeof(virtio_net_dev->info[id].hdr);
virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id); virtio_net_dev->info[id].hdr.flags = 0;
virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1); virtio_net_dev->info[id].hdr.gso_type = 0;
virtio_net_dev->info[id].hdr.hdr_len = 0;
virtio_net_dev->info[id].hdr.gso_size = 0;
virtio_net_dev->info[id].hdr.csum_start = 0;
virtio_net_dev->info[id].hdr.csum_offset = 0;
virtio_net_dev->info[id].hdr.num_buffers = 0;
virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id, pbuf_copy_partial(p, virtio_net_dev->info[id].rx_buffer, p->tot_len, 0);
VIRTIO_VA2PA(&virtio_net_dev->info[id].hdr), VIRTIO_NET_HDR_SIZE, VIRTQ_DESC_F_NEXT, id + 1);
virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1, virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
VIRTIO_VA2PA(p->payload), p->tot_len, 0, 0); virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1);
virtio_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, id); virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id,
VIRTIO_VA2PA(&virtio_net_dev->info[id].hdr), VIRTIO_NET_HDR_SIZE, VIRTQ_DESC_F_NEXT, id + 1);
virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_TX); virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1,
VIRTIO_VA2PA(virtio_net_dev->info[id].rx_buffer), p->tot_len, 0, 0);
virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX); virtio_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX);
virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_TX);
virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX);
virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX);
#ifdef RT_USING_SMP #ifdef RT_USING_SMP
rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level); rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
#endif #endif
p = p->next;
}
return RT_EOK; return RT_EOK;
} }
@ -144,7 +144,7 @@ static rt_err_t virtio_net_init(rt_device_t dev)
for (i = 0; i < queue_rx->num; ++i) for (i = 0; i < queue_rx->num; ++i)
{ {
rt_uint16_t id = (i * 2) % queue_rx->num; rt_uint16_t id = (i * 2) % queue_rx->num;
void *addr = virtio_net_dev->info[i].buffer; void *addr = virtio_net_dev->info[i].tx_buffer;
/* Descriptor for net_hdr */ /* Descriptor for net_hdr */
virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_RX, id, virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_RX, id,
@ -185,7 +185,7 @@ static rt_err_t virtio_net_control(rt_device_t dev, int cmd, void *args)
break; break;
} }
rt_memcpy(args, virtio_net_dev->mac, sizeof(virtio_net_dev->mac)); rt_memcpy(args, virtio_net_dev->config->mac, sizeof(virtio_net_dev->config->mac));
break; break;
default: default:
status = -RT_EINVAL; status = -RT_EINVAL;
@ -232,7 +232,6 @@ static void virtio_net_isr(int irqno, void *param)
rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq) rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
{ {
int i;
static int dev_no = 0; static int dev_no = 0;
char dev_name[RT_NAME_MAX]; char dev_name[RT_NAME_MAX];
struct virtio_device *virtio_dev; struct virtio_device *virtio_dev;
@ -249,6 +248,8 @@ rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
virtio_dev->irq = irq; virtio_dev->irq = irq;
virtio_dev->mmio_base = mmio_base; virtio_dev->mmio_base = mmio_base;
virtio_net_dev->config = (struct virtio_net_config *)virtio_dev->mmio_config->config;
#ifdef RT_USING_SMP #ifdef RT_USING_SMP
rt_spin_lock_init(&virtio_dev->spinlock); rt_spin_lock_init(&virtio_dev->spinlock);
#endif #endif
@ -258,14 +259,7 @@ rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~( virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
(1 << VIRTIO_NET_F_CTRL_VQ) | (1 << VIRTIO_NET_F_CTRL_VQ) |
(1 << VIRTIO_NET_F_GUEST_TSO4) | (1 << VIRTIO_F_RING_EVENT_IDX));
(1 << VIRTIO_NET_F_GUEST_TSO6) |
(1 << VIRTIO_NET_F_GUEST_UFO) |
(1 << VIRTIO_NET_F_MRG_RXBUF) |
(1 << VIRTIO_F_RING_EVENT_IDX)) &
(1 << VIRTIO_NET_F_CSUM) &
(1 << VIRTIO_NET_F_GUEST_CSUM) &
(1 << VIRTIO_NET_F_MAC);
virtio_status_driver_ok(virtio_dev); virtio_status_driver_ok(virtio_dev);
@ -285,11 +279,6 @@ rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
goto _alloc_fail; goto _alloc_fail;
} }
for (i = 0; i < sizeof(virtio_net_dev->mac) / sizeof(virtio_net_dev->mac[0]); ++i)
{
virtio_net_dev->mac[i] = virtio_dev->mmio_config->config[i];
}
virtio_net_dev->parent.parent.type = RT_Device_Class_NetIf; virtio_net_dev->parent.parent.type = RT_Device_Class_NetIf;
virtio_net_dev->parent.parent.ops = &virtio_net_ops; virtio_net_dev->parent.parent.ops = &virtio_net_ops;
virtio_net_dev->parent.eth_tx = virtio_net_tx; virtio_net_dev->parent.eth_tx = virtio_net_tx;

View File

@ -71,28 +71,42 @@ struct virtio_net_hdr
rt_uint16_t gso_size; rt_uint16_t gso_size;
rt_uint16_t csum_start; rt_uint16_t csum_start;
rt_uint16_t csum_offset; rt_uint16_t csum_offset;
rt_uint16_t num_buffers; /* Only if VIRTIO_NET_F_MRG_RXBUF */ rt_uint16_t num_buffers;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define VIRTIO_NET_MSS 1514 #define VIRTIO_NET_MSS 1514
/* Disable VIRTIO_NET_F_MRG_RXBUF */ #define VIRTIO_NET_HDR_SIZE (sizeof(struct virtio_net_hdr))
#define VIRTIO_NET_HDR_SIZE (sizeof(struct virtio_net_hdr) - sizeof(rt_uint16_t))
#define VIRTIO_NET_PAYLOAD_MAX_SIZE (VIRTIO_NET_HDR_SIZE + VIRTIO_NET_MSS) #define VIRTIO_NET_PAYLOAD_MAX_SIZE (VIRTIO_NET_HDR_SIZE + VIRTIO_NET_MSS)
struct virtio_net_config
{
rt_uint8_t mac[6];
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;
} __attribute__((packed));
struct virtio_net_device struct virtio_net_device
{ {
struct eth_device parent; struct eth_device parent;
struct virtio_device virtio_dev; struct virtio_device virtio_dev;
rt_uint8_t mac[6]; struct virtio_net_config *config;
struct struct
{ {
/* Transmit hdr */ /* Transmit hdr */
struct virtio_net_hdr hdr; struct virtio_net_hdr hdr;
/* Transmit buffer */
rt_uint8_t tx_buffer[VIRTIO_NET_PAYLOAD_MAX_SIZE];
/* Receive buffer */ /* Receive buffer */
rt_uint8_t buffer[VIRTIO_NET_PAYLOAD_MAX_SIZE]; rt_uint8_t rx_buffer[VIRTIO_NET_PAYLOAD_MAX_SIZE];
} info[VIRTIO_NET_RTX_QUEUE_SIZE]; } info[VIRTIO_NET_RTX_QUEUE_SIZE];
}; };