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