浏览代码

Fixup VirtIO-NET transmit payload split
Update VirtIO drivers and example code

GuEe_GUI 3 年之前
父节点
当前提交
0da47822e3

+ 9 - 0
bsp/qemu-virt64-aarch64/README.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. 支持情况
 
 | 驱动 | 支持情况  |  备注  |

+ 48 - 0
bsp/qemu-virt64-aarch64/applications/console.c

@@ -10,6 +10,10 @@
 
 #include <rtthread.h>
 
+#ifdef RT_USING_POSIX
+#include <console.h>
+#endif
+
 #include <virtio_console.h>
 
 static int console_init()
@@ -31,3 +35,47 @@ static int console_init()
     return status;
 }
 INIT_ENV_EXPORT(console_init);
+
+#ifdef FINSH_USING_MSH
+
+static int console(int argc, char **argv)
+{
+    rt_err_t result = RT_EOK;
+
+    if (argc > 1)
+    {
+        if (!rt_strcmp(argv[1], "set"))
+        {
+            rt_kprintf("console change to %s\n", argv[2]);
+            rt_console_set_device(argv[2]);
+
+        #ifdef RT_USING_POSIX
+            {
+                rt_device_t dev = rt_device_find(argv[2]);
+
+                if (dev != RT_NULL)
+                {
+                    console_set_iodev(dev);
+                }
+            }
+        #else
+            finsh_set_device(argv[2]);
+        #endif /* RT_USING_POSIX */
+        }
+        else
+        {
+            rt_kprintf("Unknown command. Please enter 'console' for help\n");
+            result = -RT_ERROR;
+        }
+    }
+    else
+    {
+        rt_kprintf("Usage: \n");
+        rt_kprintf("console set <name>   - change console by name\n");
+        result = -RT_ERROR;
+    }
+    return result;
+}
+MSH_CMD_EXPORT(console, set console name);
+
+#endif /* FINSH_USING_MSH */

+ 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) / 4)
+            {
+                /* 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;
         }
     }

+ 22 - 9
components/drivers/virtio/virtio_console.c

@@ -34,6 +34,8 @@ struct port_device
     struct rt_spinlock spinlock_rx, spinlock_tx;
 #endif
 
+    struct rt_device_notify rx_notify_helper;
+
     struct
     {
         char rx_char, tx_char;
@@ -234,12 +236,6 @@ static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag)
 {
     struct port_device *port_dev = (struct port_device *)dev;
 
-    /* Can't use by others, just support only one */
-    if (port_dev->parent.ref_count > 1)
-    {
-        return -RT_EBUSY;
-    }
-
     if (port_dev->port_id == 0 && virtio_has_feature(&port_dev->console->virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
     {
         /* Port0 is reserve in multiport */
@@ -383,6 +379,14 @@ static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args
 
     switch (cmd)
     {
+    case RT_DEVICE_CTRL_NOTIFY_SET:
+        if (args == RT_NULL)
+        {
+            status = -RT_ERROR;
+            break;
+        }
+        rt_memcpy(&port_dev->rx_notify_helper, args, sizeof(port_dev->rx_notify_helper));
+        break;
     case RT_DEVICE_CTRL_CLR_INT:
         /* Disable RX */
         port_dev->rx_notify = RT_FALSE;
@@ -606,13 +610,22 @@ static void virtio_console_isr(int irqno, void *param)
             id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
             len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
 
-            if (port_dev->parent.rx_indicate != RT_NULL && port_dev->rx_notify)
+            if (port_dev->rx_notify)
             {
             #ifdef RT_USING_SMP
                 rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
             #endif
-                /* rx_indicate call virtio_console_port_read to inc used_idx */
-                port_dev->parent.rx_indicate(&port_dev->parent, len);
+                /* Will call virtio_console_port_read to inc used_idx */
+
+                if (port_dev->parent.rx_indicate != RT_NULL)
+                {
+                    port_dev->parent.rx_indicate(&port_dev->parent, len);
+                }
+
+                if (port_dev->rx_notify_helper.notify != RT_NULL)
+                {
+                    port_dev->rx_notify_helper.notify(port_dev->rx_notify_helper.dev);
+                }
 
             #ifdef RT_USING_SMP
                 level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);

+ 2 - 4
components/drivers/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
components/drivers/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;
@@ -234,7 +234,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;
@@ -251,6 +250,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
@@ -260,14 +261,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);
 
@@ -287,11 +281,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;
 #ifdef RT_USING_DEVICE_OPS
     virtio_net_dev->parent.parent.ops  = &virtio_net_ops;

+ 19 - 5
components/drivers/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];
 };