1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-11-11     GuEe-GUI     the first version
9  */
10 
11 #include <rthw.h>
12 #include <rtthread.h>
13 #include <cpuport.h>
14 #include <mm_aspace.h>
15 
16 #ifdef RT_USING_VIRTIO_NET
17 
18 #include <virtio_net.h>
19 
virtio_net_tx(rt_device_t dev,struct pbuf * p)20 static rt_err_t virtio_net_tx(rt_device_t dev, struct pbuf *p)
21 {
22     rt_uint16_t id;
23     struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
24     struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
25     struct virtq *queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX];
26 
27     id = (queue_tx->avail->idx * 2) % queue_tx->num;
28 
29     virtio_net_dev->info[id].hdr.flags = 0;
30     virtio_net_dev->info[id].hdr.gso_type = 0;
31     virtio_net_dev->info[id].hdr.hdr_len = 0;
32     virtio_net_dev->info[id].hdr.gso_size = 0;
33     virtio_net_dev->info[id].hdr.csum_start = 0;
34     virtio_net_dev->info[id].hdr.csum_offset = 0;
35     virtio_net_dev->info[id].hdr.num_buffers = 0;
36 
37     pbuf_copy_partial(p, virtio_net_dev->info[id].rx_buffer, p->tot_len, 0);
38 
39     virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
40     virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1);
41 
42     virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id,
43             VIRTIO_VA2PA(&virtio_net_dev->info[id].hdr), VIRTIO_NET_HDR_SIZE, VIRTQ_DESC_F_NEXT, id + 1);
44 
45     virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1,
46             VIRTIO_VA2PA(virtio_net_dev->info[id].rx_buffer), p->tot_len, 0, 0);
47 
48     virtio_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
49 
50     virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_TX);
51 
52     virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX);
53     virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX);
54 
55     return RT_EOK;
56 }
57 
virtio_net_rx(rt_device_t dev)58 static struct pbuf *virtio_net_rx(rt_device_t dev)
59 {
60     rt_uint16_t id;
61     rt_uint32_t len;
62     struct pbuf *p = RT_NULL;
63     struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
64     struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
65     struct virtq *queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX];
66 
67     if (queue_rx->used_idx != queue_rx->used->idx)
68     {
69         id = (queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id + 1) % queue_rx->num;
70         len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len - VIRTIO_NET_HDR_SIZE;
71 
72         if (len > VIRTIO_NET_PAYLOAD_MAX_SIZE)
73         {
74             rt_kprintf("%s: Receive buffer's size = %u is too big!\n", virtio_net_dev->parent.parent.parent.name, len);
75             len = VIRTIO_NET_PAYLOAD_MAX_SIZE;
76         }
77 
78         p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
79 
80         if (p != RT_NULL)
81         {
82             rt_memcpy(p->payload, (void *)queue_rx->desc[id].addr - PV_OFFSET, len);
83 
84             queue_rx->used_idx++;
85 
86             virtio_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_RX, id - 1);
87 
88             virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_RX);
89         }
90     }
91 
92     return p;
93 }
94 
virtio_net_init(rt_device_t dev)95 static rt_err_t virtio_net_init(rt_device_t dev)
96 {
97     int i;
98     rt_uint16_t idx[VIRTIO_NET_RTX_QUEUE_SIZE];
99     struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
100     struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
101     struct virtq *queue_rx, *queue_tx;
102 
103     queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX];
104     queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX];
105 
106     virtio_alloc_desc_chain(virtio_dev, VIRTIO_NET_QUEUE_RX, queue_rx->num, idx);
107     virtio_alloc_desc_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, queue_tx->num, idx);
108 
109     for (i = 0; i < queue_rx->num; ++i)
110     {
111         rt_uint16_t id = (i * 2) % queue_rx->num;
112         void *addr = virtio_net_dev->info[i].tx_buffer;
113 
114         /* Descriptor for net_hdr */
115         virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_RX, id,
116                 VIRTIO_VA2PA(addr), VIRTIO_NET_HDR_SIZE, VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE, id + 1);
117 
118         /* Descriptor for data */
119         virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_RX, id + 1,
120                 VIRTIO_VA2PA(addr) + VIRTIO_NET_HDR_SIZE, VIRTIO_NET_MSS, VIRTQ_DESC_F_WRITE, 0);
121 
122         queue_rx->avail->ring[i] = id;
123     }
124     rt_hw_dsb();
125 
126     queue_rx->avail->flags = 0;
127     queue_rx->avail->idx = queue_rx->num;
128 
129     queue_rx->used_idx = queue_rx->used->idx;
130 
131     queue_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
132     queue_tx->avail->idx = 0;
133 
134     virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_RX);
135 
136     return eth_device_linkchange(&virtio_net_dev->parent, RT_TRUE);
137 }
138 
virtio_net_control(rt_device_t dev,int cmd,void * args)139 static rt_err_t virtio_net_control(rt_device_t dev, int cmd, void *args)
140 {
141     rt_err_t status = RT_EOK;
142     struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
143 
144     switch (cmd)
145     {
146     case NIOCTL_GADDR:
147         if (args == RT_NULL)
148         {
149             status = -RT_ERROR;
150             break;
151         }
152 
153         rt_memcpy(args, virtio_net_dev->config->mac, sizeof(virtio_net_dev->config->mac));
154         break;
155     default:
156         status = -RT_EINVAL;
157         break;
158     }
159 
160     return status;
161 }
162 
163 #ifdef RT_USING_DEVICE_OPS
164 const static struct rt_device_ops virtio_net_ops =
165 {
166     virtio_net_init,
167     RT_NULL,
168     RT_NULL,
169     RT_NULL,
170     RT_NULL,
171     virtio_net_control
172 };
173 #endif
174 
virtio_net_isr(int irqno,void * param)175 static void virtio_net_isr(int irqno, void *param)
176 {
177     struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)param;
178     struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
179     struct virtq *queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX];
180 
181     virtio_interrupt_ack(virtio_dev);
182     rt_hw_dsb();
183 
184     if (queue_rx->used_idx != queue_rx->used->idx)
185     {
186         rt_hw_dsb();
187 
188         eth_device_ready(&virtio_net_dev->parent);
189     }
190 }
191 
rt_virtio_net_init(rt_ubase_t * mmio_base,rt_uint32_t irq)192 rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
193 {
194     static int dev_no = 0;
195     char dev_name[RT_NAME_MAX];
196     struct virtio_device *virtio_dev;
197     struct virtio_net_device *virtio_net_dev;
198 
199     virtio_net_dev = rt_malloc(sizeof(struct virtio_net_device));
200 
201     if (virtio_net_dev == RT_NULL)
202     {
203         goto _alloc_fail;
204     }
205 
206     virtio_dev = &virtio_net_dev->virtio_dev;
207     virtio_dev->irq = irq;
208     virtio_dev->mmio_base = mmio_base;
209 
210     virtio_net_dev->config = (struct virtio_net_config *)virtio_dev->mmio_config->config;
211 
212     virtio_reset_device(virtio_dev);
213     virtio_status_acknowledge_driver(virtio_dev);
214 
215     virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
216             (1 << VIRTIO_NET_F_CTRL_VQ) |
217             (1 << VIRTIO_F_RING_EVENT_IDX));
218 
219     virtio_status_driver_ok(virtio_dev);
220 
221     if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK)
222     {
223         goto _alloc_fail;
224     }
225 
226     if (virtio_queue_init(virtio_dev, VIRTIO_NET_QUEUE_RX, VIRTIO_NET_RTX_QUEUE_SIZE) != RT_EOK)
227     {
228         goto _alloc_fail;
229     }
230 
231     if (virtio_queue_init(virtio_dev, VIRTIO_NET_QUEUE_TX, VIRTIO_NET_RTX_QUEUE_SIZE) != RT_EOK)
232     {
233         virtio_queue_destroy(virtio_dev, VIRTIO_NET_QUEUE_RX);
234         goto _alloc_fail;
235     }
236 
237     virtio_net_dev->parent.parent.type = RT_Device_Class_NetIf;
238 #ifdef RT_USING_DEVICE_OPS
239     virtio_net_dev->parent.parent.ops  = &virtio_net_ops;
240 #else
241     virtio_net_dev->parent.parent.init      = virtio_net_init;
242     virtio_net_dev->parent.parent.open      = RT_NULL;
243     virtio_net_dev->parent.parent.close     = RT_NULL;
244     virtio_net_dev->parent.parent.read      = RT_NULL;
245     virtio_net_dev->parent.parent.write     = RT_NULL;
246     virtio_net_dev->parent.parent.control   = virtio_net_control;
247 #endif
248     virtio_net_dev->parent.eth_tx = virtio_net_tx;
249     virtio_net_dev->parent.eth_rx = virtio_net_rx;
250 
251     rt_snprintf(dev_name, RT_NAME_MAX, "virtio-net%d", dev_no++);
252 
253     rt_hw_interrupt_install(irq, virtio_net_isr, virtio_net_dev, dev_name);
254     rt_hw_interrupt_umask(irq);
255 
256     return eth_device_init(&virtio_net_dev->parent, dev_name);
257 
258 _alloc_fail:
259 
260     if (virtio_net_dev != RT_NULL)
261     {
262         virtio_queues_free(virtio_dev);
263         rt_free(virtio_net_dev);
264     }
265     return -RT_ENOMEM;
266 }
267 #endif /* RT_USING_VIRTIO_NET */
268