~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/SLOF/lib/libvirtio/virtio-net.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        uint16_t avail_idx;
 
270
 
 
271
        idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx);
 
272
 
 
273
        if (last_rx_idx == idx) {
 
274
                /* Nothing received yet */
 
275
                return 0;
 
276
        }
 
277
 
 
278
        id = (virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].id) + 1)
 
279
                % vq_rx.size;
 
280
        len = virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].len)
 
281
                - net_hdr_size;
 
282
        dprintf("virtionet_receive() last_rx_idx=%i, vq_rx.used->idx=%i,"
 
283
                " id=%i len=%i\n", last_rx_idx, vq_rx.used->idx, id, len);
 
284
 
 
285
        if (len > (uint32_t)maxlen) {
 
286
                printf("virtio-net: Receive buffer not big enough!\n");
 
287
                len = maxlen;
 
288
        }
 
289
 
 
290
#if 0
 
291
        /* Dump packet */
 
292
        printf("\n");
 
293
        int i;
 
294
        for (i=0; i<64; i++) {
 
295
                printf(" %02x", *(uint8_t*)(vq_rx.desc[id].addr+i));
 
296
                if ((i%16)==15)
 
297
                        printf("\n");
 
298
        }
 
299
        prinfk("\n");
 
300
#endif
 
301
 
 
302
        /* Copy data to destination buffer */
 
303
        memcpy(buf, (void *)virtio_modern64_to_cpu(&virtiodev, vq_rx.desc[id].addr), len);
 
304
 
 
305
        /* Move indices to next entries */
 
306
        last_rx_idx = last_rx_idx + 1;
 
307
 
 
308
        avail_idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.avail->idx);
 
309
        vq_rx.avail->ring[avail_idx % vq_rx.size] = virtio_cpu_to_modern16(&virtiodev, id - 1);
 
310
        sync();
 
311
        vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, avail_idx + 1);
 
312
 
 
313
        /* Tell HV that RX queue entry is ready */
 
314
        virtio_queue_notify(&virtiodev, VQ_RX);
 
315
 
 
316
        return len;
 
317
}
 
318
 
 
319
net_driver_t *virtionet_open(struct virtio_device *dev)
 
320
{
 
321
        net_driver_t *driver;
 
322
 
 
323
        driver = SLOF_alloc_mem(sizeof(*driver));
 
324
        if (!driver) {
 
325
                printf("Unable to allocate virtio-net driver\n");
 
326
                return NULL;
 
327
        }
 
328
 
 
329
        driver->running = 0;
 
330
 
 
331
        if (virtionet_init_pci(dev))
 
332
                goto FAIL;
 
333
 
 
334
        if (virtionet_init(driver))
 
335
                goto FAIL;
 
336
 
 
337
        return driver;
 
338
 
 
339
FAIL:   SLOF_free_mem(driver, sizeof(*driver));
 
340
        return NULL;
 
341
}
 
342
 
 
343
void virtionet_close(net_driver_t *driver)
 
344
{
 
345
        if (driver) {
 
346
                virtionet_term(driver);
 
347
                SLOF_free_mem(driver, sizeof(*driver));
 
348
        }
 
349
}
 
350
 
 
351
int virtionet_read(char *buf, int len)
 
352
{
 
353
        if (buf)
 
354
                return virtionet_receive(buf, len);
 
355
        return -1;
 
356
}
 
357
 
 
358
int virtionet_write(char *buf, int len)
 
359
{
 
360
        if (buf)
 
361
                return virtionet_xmit(buf, len);
 
362
        return -1;
 
363
}