1 /******************************************************************************
2 * Copyright (c) 2011 IBM Corporation
3 * All rights reserved.
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
8 *
9 * Contributors:
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
12
13 /*
14 * This is the implementation for the Virtio network device driver. Details
15 * about the virtio-net interface can be found in Rusty Russel's "Virtio PCI
16 * Card Specification v0.8.10", appendix C, which can be found here:
17 *
18 * http://ozlabs.org/~rusty/virtio-spec/virtio-spec.pdf
19 */
20
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <helpers.h>
25 #include <cache.h>
26 #include <byteorder.h>
27 #include "virtio-net.h"
28 #include "virtio-internal.h"
29
30 #undef DEBUG
31 //#define DEBUG
32 #ifdef DEBUG
33 # define dprintf(fmt...) do { printf(fmt); } while(0)
34 #else
35 # define dprintf(fmt...)
36 #endif
37
38 #define sync() asm volatile (" sync \n" ::: "memory")
39
40 #define DRIVER_FEATURE_SUPPORT (VIRTIO_NET_F_MAC | VIRTIO_F_VERSION_1)
41
42 /* See Virtio Spec, appendix C, "Device Operation" */
43 struct virtio_net_hdr {
44 uint8_t flags;
45 uint8_t gso_type;
46 uint16_t hdr_len;
47 uint16_t gso_size;
48 uint16_t csum_start;
49 uint16_t csum_offset;
50 // uint16_t num_buffers; /* Only if VIRTIO_NET_F_MRG_RXBUF */
51 };
52
53 static unsigned int net_hdr_size;
54
55 struct virtio_net_hdr_v1 {
56 uint8_t flags;
57 uint8_t gso_type;
58 le16 hdr_len;
59 le16 gso_size;
60 le16 csum_start;
61 le16 csum_offset;
62 le16 num_buffers;
63 };
64
65 static uint16_t last_rx_idx; /* Last index in RX "used" ring */
66
67 /**
68 * Module init for virtio via PCI.
69 * Checks whether we're reponsible for the given device and set up
70 * the virtqueue configuration.
71 */
virtionet_init_pci(struct virtio_net * vnet,struct virtio_device * dev)72 static int virtionet_init_pci(struct virtio_net *vnet, struct virtio_device *dev)
73 {
74 struct virtio_device *vdev = &vnet->vdev;
75
76 dprintf("virtionet: doing virtionet_init_pci!\n");
77
78 if (!dev)
79 return -1;
80
81 /* make a copy of the device structure */
82 memcpy(vdev, dev, sizeof(struct virtio_device));
83
84 /* Reset device */
85 virtio_reset_device(vdev);
86
87 /* Acknowledge device. */
88 virtio_set_status(vdev, VIRTIO_STAT_ACKNOWLEDGE);
89
90 return 0;
91 }
92
93 /**
94 * Initialize the virtio-net device.
95 * See the Virtio Spec, chapter 2.2.1 and Appendix C "Device Initialization"
96 * for details.
97 */
virtionet_init(struct virtio_net * vnet)98 static int virtionet_init(struct virtio_net *vnet)
99 {
100 int i;
101 int status = VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER;
102 struct virtio_device *vdev = &vnet->vdev;
103 net_driver_t *driver = &vnet->driver;
104 struct vqs *vq_tx, *vq_rx;
105
106 dprintf("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n",
107 driver->mac_addr[0], driver->mac_addr[1],
108 driver->mac_addr[2], driver->mac_addr[3],
109 driver->mac_addr[4], driver->mac_addr[5]);
110
111 if (driver->running != 0)
112 return 0;
113
114 /* Tell HV that we know how to drive the device. */
115 virtio_set_status(vdev, status);
116
117 /* Device specific setup */
118 if (vdev->features & VIRTIO_F_VERSION_1) {
119 if (virtio_negotiate_guest_features(vdev, DRIVER_FEATURE_SUPPORT))
120 goto dev_error;
121 net_hdr_size = sizeof(struct virtio_net_hdr_v1);
122 virtio_get_status(vdev, &status);
123 } else {
124 net_hdr_size = sizeof(struct virtio_net_hdr);
125 virtio_set_guest_features(vdev, 0);
126 }
127
128 /* The queue information can be retrieved via the virtio header that
129 * can be found in the I/O BAR. First queue is the receive queue,
130 * second the transmit queue, and the forth is the control queue for
131 * networking options.
132 * We are only interested in the receive and transmit queue here. */
133 vq_rx = virtio_queue_init_vq(vdev, VQ_RX);
134 vq_tx = virtio_queue_init_vq(vdev, VQ_TX);
135 if (!vq_rx || !vq_tx) {
136 virtio_set_status(vdev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
137 |VIRTIO_STAT_FAILED);
138 return -1;
139 }
140
141 /* Allocate memory for one transmit an multiple receive buffers */
142 vq_rx->buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+net_hdr_size)
143 * RX_QUEUE_SIZE);
144 if (!vq_rx->buf_mem) {
145 printf("virtionet: Failed to allocate buffers!\n");
146 goto dev_error;
147 }
148
149 /* Prepare receive buffer queue */
150 for (i = 0; i < RX_QUEUE_SIZE; i++) {
151 uint64_t addr = (uint64_t)vq_rx->buf_mem
152 + i * (BUFFER_ENTRY_SIZE+net_hdr_size);
153 uint32_t id = i*2;
154 /* Descriptor for net_hdr: */
155 virtio_fill_desc(vq_rx, id, vdev->features, addr, net_hdr_size,
156 VRING_DESC_F_NEXT | VRING_DESC_F_WRITE, id + 1);
157
158 /* Descriptor for data: */
159 virtio_fill_desc(vq_rx, id + 1, vdev->features, addr + net_hdr_size,
160 BUFFER_ENTRY_SIZE, VRING_DESC_F_WRITE, 0);
161
162 vq_rx->avail->ring[i] = virtio_cpu_to_modern16(vdev, id);
163 }
164 sync();
165
166 vq_rx->avail->flags = virtio_cpu_to_modern16(vdev, VRING_AVAIL_F_NO_INTERRUPT);
167 vq_rx->avail->idx = virtio_cpu_to_modern16(vdev, RX_QUEUE_SIZE);
168
169 last_rx_idx = virtio_modern16_to_cpu(vdev, vq_rx->used->idx);
170
171 vq_tx->avail->flags = virtio_cpu_to_modern16(vdev, VRING_AVAIL_F_NO_INTERRUPT);
172 vq_tx->avail->idx = 0;
173
174 /* Tell HV that setup succeeded */
175 status |= VIRTIO_STAT_DRIVER_OK;
176 virtio_set_status(vdev, status);
177
178 /* Tell HV that RX queues are ready */
179 virtio_queue_notify(vdev, VQ_RX);
180
181 driver->running = 1;
182 for(i = 0; i < (int)sizeof(driver->mac_addr); i++) {
183 driver->mac_addr[i] = virtio_get_config(vdev, i, 1);
184 }
185 return 0;
186
187 dev_error:
188 status |= VIRTIO_STAT_FAILED;
189 virtio_set_status(vdev, status);
190 return -1;
191 }
192
193
194 /**
195 * Shutdown driver.
196 * We've got to make sure that the hosts stops all transfers since the buffers
197 * in our main memory will become invalid after this module has been terminated.
198 */
virtionet_term(struct virtio_net * vnet)199 static int virtionet_term(struct virtio_net *vnet)
200 {
201 struct virtio_device *vdev = &vnet->vdev;
202 net_driver_t *driver = &vnet->driver;
203 struct vqs *vq_tx = &vnet->vdev.vq[VQ_TX];
204 struct vqs *vq_rx = &vnet->vdev.vq[VQ_RX];
205
206 dprintf("virtionet_term()\n");
207
208 if (driver->running == 0)
209 return 0;
210
211 /* Quiesce device */
212 virtio_set_status(vdev, VIRTIO_STAT_FAILED);
213
214 /* Reset device */
215 virtio_reset_device(vdev);
216
217 driver->running = 0;
218
219 SLOF_free_mem(vq_rx->buf_mem,
220 (BUFFER_ENTRY_SIZE+net_hdr_size) * RX_QUEUE_SIZE);
221 vq_rx->buf_mem = NULL;
222
223 virtio_queue_term_vq(vdev, vq_rx, VQ_RX);
224 virtio_queue_term_vq(vdev, vq_tx, VQ_TX);
225
226 return 0;
227 }
228
229
230 /**
231 * Transmit a packet
232 */
virtionet_xmit(struct virtio_net * vnet,char * buf,int len)233 static int virtionet_xmit(struct virtio_net *vnet, char *buf, int len)
234 {
235 int id, idx;
236 static struct virtio_net_hdr_v1 nethdr_v1;
237 static struct virtio_net_hdr nethdr_legacy;
238 void *nethdr = &nethdr_legacy;
239 struct virtio_device *vdev = &vnet->vdev;
240 struct vqs *vq_tx = &vdev->vq[VQ_TX];
241
242 if (len > BUFFER_ENTRY_SIZE) {
243 printf("virtionet: Packet too big!\n");
244 return 0;
245 }
246
247 dprintf("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len);
248
249 if (vdev->features & VIRTIO_F_VERSION_1)
250 nethdr = &nethdr_v1;
251
252 memset(nethdr, 0, net_hdr_size);
253
254 /* Determine descriptor index */
255 idx = virtio_modern16_to_cpu(vdev, vq_tx->avail->idx);
256 id = (idx * 2) % vq_tx->size;
257
258 virtio_free_desc(vq_tx, id, vdev->features);
259 virtio_free_desc(vq_tx, id + 1, vdev->features);
260
261 /* Set up virtqueue descriptor for header */
262 virtio_fill_desc(vq_tx, id, vdev->features, (uint64_t)nethdr,
263 net_hdr_size, VRING_DESC_F_NEXT, id + 1);
264
265 /* Set up virtqueue descriptor for data */
266 virtio_fill_desc(vq_tx, id + 1, vdev->features, (uint64_t)buf, len, 0, 0);
267
268 vq_tx->avail->ring[idx % vq_tx->size] = virtio_cpu_to_modern16(vdev, id);
269 sync();
270 vq_tx->avail->idx = virtio_cpu_to_modern16(vdev, idx + 1);
271 sync();
272
273 /* Tell HV that TX queue is ready */
274 virtio_queue_notify(vdev, VQ_TX);
275
276 return len;
277 }
278
279
280 /**
281 * Receive a packet
282 */
virtionet_receive(struct virtio_net * vnet,char * buf,int maxlen)283 static int virtionet_receive(struct virtio_net *vnet, char *buf, int maxlen)
284 {
285 uint32_t len = 0;
286 uint32_t id, idx;
287 uint16_t avail_idx;
288 struct virtio_device *vdev = &vnet->vdev;
289 struct vqs *vq_rx = &vnet->vdev.vq[VQ_RX];
290
291 idx = virtio_modern16_to_cpu(vdev, vq_rx->used->idx);
292
293 if (last_rx_idx == idx) {
294 /* Nothing received yet */
295 return 0;
296 }
297
298 id = (virtio_modern32_to_cpu(vdev, vq_rx->used->ring[last_rx_idx % vq_rx->size].id) + 1)
299 % vq_rx->size;
300 len = virtio_modern32_to_cpu(vdev, vq_rx->used->ring[last_rx_idx % vq_rx->size].len)
301 - net_hdr_size;
302 dprintf("virtionet_receive() last_rx_idx=%i, vq_rx->used->idx=%i,"
303 " id=%i len=%i\n", last_rx_idx, vq_rx->used->idx, id, len);
304
305 if (len > (uint32_t)maxlen) {
306 printf("virtio-net: Receive buffer not big enough!\n");
307 len = maxlen;
308 }
309
310 #if 0
311 /* Dump packet */
312 printf("\n");
313 int i;
314 for (i=0; i<64; i++) {
315 printf(" %02x", *(uint8_t*)(vq_rx->desc[id].addr+i));
316 if ((i%16)==15)
317 printf("\n");
318 }
319 prinfk("\n");
320 #endif
321
322 /* Copy data to destination buffer */
323 memcpy(buf, virtio_desc_addr(vdev, VQ_RX, id), len);
324
325 /* Move indices to next entries */
326 last_rx_idx = last_rx_idx + 1;
327
328 avail_idx = virtio_modern16_to_cpu(vdev, vq_rx->avail->idx);
329 vq_rx->avail->ring[avail_idx % vq_rx->size] = virtio_cpu_to_modern16(vdev, id - 1);
330 sync();
331 vq_rx->avail->idx = virtio_cpu_to_modern16(vdev, avail_idx + 1);
332
333 /* Tell HV that RX queue entry is ready */
334 virtio_queue_notify(vdev, VQ_RX);
335
336 return len;
337 }
338
virtionet_open(struct virtio_device * dev)339 struct virtio_net *virtionet_open(struct virtio_device *dev)
340 {
341 struct virtio_net *vnet;
342
343 vnet = SLOF_alloc_mem(sizeof(*vnet));
344 if (!vnet) {
345 printf("Unable to allocate virtio-net driver\n");
346 return NULL;
347 }
348
349 vnet->driver.running = 0;
350
351 if (virtionet_init_pci(vnet, dev))
352 goto FAIL;
353
354 if (virtionet_init(vnet))
355 goto FAIL;
356
357 return vnet;
358
359 FAIL:
360 SLOF_free_mem(vnet, sizeof(*vnet));
361 return NULL;
362 }
363
virtionet_close(struct virtio_net * vnet)364 void virtionet_close(struct virtio_net *vnet)
365 {
366 if (vnet) {
367 virtionet_term(vnet);
368 SLOF_free_mem(vnet, sizeof(*vnet));
369 }
370 }
371
virtionet_read(struct virtio_net * vnet,char * buf,int len)372 int virtionet_read(struct virtio_net *vnet, char *buf, int len)
373 {
374 if (vnet && buf)
375 return virtionet_receive(vnet, buf, len);
376 return -1;
377 }
378
virtionet_write(struct virtio_net * vnet,char * buf,int len)379 int virtionet_write(struct virtio_net *vnet, char *buf, int len)
380 {
381 if (vnet && buf)
382 return virtionet_xmit(vnet, buf, len);
383 return -1;
384 }
385