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