Jelajahi Sumber

[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
GUI 2 tahun lalu
induk
melakukan
747ed9b516

+ 9 - 0
bsp/qemu-virt64-aarch64/README.md

@@ -50,6 +50,15 @@ Use VirtIO-Console in new terminal by:
 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
 
 | Driver | Condition | Remark |

+ 9 - 0
bsp/qemu-virt64-aarch64/README_zh.md

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

+ 13 - 0
bsp/qemu-virt64-aarch64/applications/graphic.c

@@ -24,6 +24,7 @@ static rt_uint32_t cur_points[2];
 static rt_uint32_t cur_last_points[2];
 static rt_bool_t cur_event_sync;
 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)
 {
@@ -100,6 +101,8 @@ void graphic_thread(void *param)
 
         if (graphic_info.framebuffer != RT_NULL)
         {
+            int i = 0;
+
             rt_memset(graphic_info.framebuffer, 0xff,
                     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);
 
+            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;
         }
     }

+ 130 - 42
bsp/qemu-virt64-aarch64/driver/drv_rtc.c

@@ -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
  *
  * Change Logs:
  * Date           Author         Notes
  * 2021-11-4      GuEe-GUI       first version
+ * 2022-07-15     GuEe-GUI       add alarm ops support
  */
 
+#include <rthw.h>
 #include <rtthread.h>
 #include <rtdevice.h>
 #include <sys/time.h>
@@ -28,8 +30,13 @@
 
 #define RTC_CR_OPEN     1
 #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)
 {
@@ -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;
 }
 
-static rt_err_t pl031_rtc_init(rt_device_t dev)
+static rt_err_t pl031_rtc_init(void)
 {
+    pl031_write32(RTC_CR, RTC_CR_OPEN);
+
     return RT_EOK;
 }
 
-static rt_err_t pl031_rtc_open(rt_device_t dev, rt_uint16_t oflag)
+static rt_err_t pl031_get_secs(time_t *sec)
 {
-    pl031_write32(RTC_CR, RTC_CR_OPEN);
-    return RT_EOK;
+    if (sec != RT_NULL)
+    {
+        *(rt_uint32_t *)sec = pl031_read32(RTC_DR);
+
+        return RT_EOK;
+    }
+
+    return -RT_EINVAL;
 }
 
-static rt_err_t pl031_rtc_close(rt_device_t dev)
+static rt_err_t pl031_set_secs(time_t *sec)
 {
-    pl031_write32(RTC_CR, RTC_CR_CLOSE);
-    return RT_EOK;
+    if (sec != RT_NULL)
+    {
+        pl031_write32(RTC_LR, *(rt_uint32_t *)sec);
+
+        return RT_EOK;
+    }
+
+    return -RT_EINVAL;
 }
 
-static rt_err_t pl031_rtc_control(rt_device_t dev, int cmd, void *args)
+#ifdef RT_USING_ALARM
+static rt_err_t pl031_set_alarm(struct rt_rtc_wkalarm *alarm)
 {
+    if (alarm != RT_NULL)
+    {
+        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;
+    }
 
-    RT_ASSERT(dev != RT_NULL);
+    return -RT_EINVAL;
+}
 
-    switch (cmd)
+static rt_err_t pl031_get_alarm(struct rt_rtc_wkalarm *alarm)
+{
+    if (alarm != RT_NULL)
     {
-    case RT_DEVICE_CTRL_RTC_GET_TIME:
-        *(rt_uint32_t *)args = pl031_read32(RTC_DR);
-        break;
-    case RT_DEVICE_CTRL_RTC_SET_TIME:
-        pl031_write32(RTC_LR, *(time_t *)args);
-        break;
-    default:
-        return RT_EINVAL;
+        *alarm = _wkalarm;
+
+        return RT_EOK;
     }
-    return RT_EOK;
+
+    return -RT_EINVAL;
 }
+#endif /* RT_USING_ALARM */
 
-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_get_timeval(struct timeval *tv)
 {
-    pl031_rtc_control(dev, RT_DEVICE_CTRL_RTC_GET_TIME, buffer);
-    return size;
+    if (tv != RT_NULL)
+    {
+        tv->tv_sec = pl031_read32(RTC_DR);
+
+        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)
+static rt_err_t pl031_set_timeval(struct timeval *tv)
 {
-    pl031_rtc_control(dev, RT_DEVICE_CTRL_RTC_SET_TIME, (void *)buffer);
-    return size;
+    if (tv != RT_NULL)
+    {
+        pl031_write32(RTC_LR, *(rt_uint32_t *)tv->tv_sec);
+
+        return RT_EOK;
+    }
+
+    return -RT_EINVAL;
 }
 
-const static struct rt_device_ops pl031_rtc_ops =
+static const struct rt_rtc_ops rtc_ops =
 {
-    .init = pl031_rtc_init,
-    .open = pl031_rtc_open,
-    .close = pl031_rtc_close,
-    .read = pl031_rtc_read,
-    .write = pl031_rtc_write,
-    .control = pl031_rtc_control
+    .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,
 };
 
-int rt_hw_rtc_init(void)
+#ifdef RT_USING_ALARM
+static void rt_hw_rtc_isr(int irqno, void *param)
 {
-    rt_memset(&rtc_device, 0, sizeof(rtc_device));
+    rt_uint32_t rtcmis = pl031_read32(RTC_MIS);
 
-    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;
+    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)
+{
+    _rtc_device.ops = &rtc_ops;
 
     /* 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;
 }

+ 2 - 4
bsp/qemu-virt64-aarch64/driver/virtio/virtio_gpu.c

@@ -84,10 +84,6 @@ static void virtio_gpu_ctrl_send_command(struct virtio_gpu_device *virtio_gpu_de
 #endif
     }
 
-    rt_hw_dsb();
-
-    virtio_gpu_dev->info[idx[0]].ctrl_valid = RT_TRUE;
-
     rt_memcpy(&virtio_gpu_dev->gpu_request, cmd, cmd_len);
 
     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);
 
+    virtio_gpu_dev->info[idx[0]].ctrl_valid = RT_TRUE;
+
     virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]);
 
     virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CTRL);

+ 28 - 39
bsp/qemu-virt64-aarch64/driver/virtio/virtio_net.c

@@ -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 virtq *queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX];
 
-    while (p != RT_NULL)
-    {
 #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
-        id = (queue_tx->avail->idx * 2) % queue_tx->num;
 
-        virtio_net_dev->info[id].hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
-        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);
+    id = (queue_tx->avail->idx * 2) % queue_tx->num;
+
+    virtio_net_dev->info[id].hdr.flags = 0;
+    virtio_net_dev->info[id].hdr.gso_type = 0;
+    virtio_net_dev->info[id].hdr.hdr_len = 0;
+    virtio_net_dev->info[id].hdr.gso_size = 0;
+    virtio_net_dev->info[id].hdr.csum_start = 0;
+    virtio_net_dev->info[id].hdr.csum_offset = 0;
+    virtio_net_dev->info[id].hdr.num_buffers = 0;
 
-        virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
-        virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1);
+    pbuf_copy_partial(p, virtio_net_dev->info[id].rx_buffer, p->tot_len, 0);
 
-        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_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
+    virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1);
 
-        virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1,
-                VIRTIO_VA2PA(p->payload), p->tot_len, 0, 0);
+    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_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
+    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_queue_notify(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_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
-        rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+    rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
 #endif
-        p = p->next;
-    }
 
     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)
     {
         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 */
         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;
         }
 
-        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;
     default:
         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)
 {
-    int i;
     static int dev_no = 0;
     char dev_name[RT_NAME_MAX];
     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->mmio_base = mmio_base;
 
+    virtio_net_dev->config = (struct virtio_net_config *)virtio_dev->mmio_config->config;
+
 #ifdef RT_USING_SMP
     rt_spin_lock_init(&virtio_dev->spinlock);
 #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 & ~(
             (1 << VIRTIO_NET_F_CTRL_VQ) |
-            (1 << VIRTIO_NET_F_GUEST_TSO4) |
-            (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);
+            (1 << VIRTIO_F_RING_EVENT_IDX));
 
     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;
     }
 
-    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.ops  = &virtio_net_ops;
     virtio_net_dev->parent.eth_tx = virtio_net_tx;

+ 19 - 5
bsp/qemu-virt64-aarch64/driver/virtio/virtio_net.h

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