[virtio] Consolidate vring_get_buf() by using a buffer list to add to the vring
[people/mcb30/gpxe.git] / src / drivers / net / virtio-net.c
1 /* virtio-net.c - etherboot driver for virtio network interface
2  *
3  * (c) Copyright 2008 Bull S.A.S.
4  *
5  *  Author: Laurent Vivier <Laurent.Vivier@bull.net>
6  *
7  * some parts from Linux Virtio PCI driver
8  *
9  *  Copyright IBM Corp. 2007
10  *  Authors: Anthony Liguori  <aliguori@us.ibm.com>
11  *
12  *  some parts from Linux Virtio Ring
13  *
14  *  Copyright Rusty Russell IBM Corporation 2007
15  *
16  * This work is licensed under the terms of the GNU GPL, version 2 or later.
17  * See the COPYING file in the top-level directory.
18  *
19  *
20  */
21
22 #include "etherboot.h"
23 #include "nic.h"
24 #include "gpxe/virtio-ring.h"
25 #include "gpxe/virtio-pci.h"
26 #include "virtio-net.h"
27
28 #define BUG() do { \
29    printf("BUG: failure at %s:%d/%s()!\n", \
30           __FILE__, __LINE__, __FUNCTION__); \
31    while(1); \
32 } while (0)
33 #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
34
35 /* Ethernet header */
36
37 struct eth_hdr {
38    unsigned char dst_addr[ETH_ALEN];
39    unsigned char src_addr[ETH_ALEN];
40    unsigned short type;
41 };
42
43 struct eth_frame {
44    struct eth_hdr hdr;
45    unsigned char data[ETH_FRAME_LEN];
46 };
47
48 typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)];
49
50 /* TX: virtio header and eth buffer */
51
52 static struct virtio_net_hdr tx_virtio_hdr;
53 static struct eth_frame tx_eth_frame;
54
55 /* RX: virtio headers and buffers */
56
57 #define RX_BUF_NB  6
58 static struct virtio_net_hdr rx_hdr[RX_BUF_NB];
59 static unsigned char rx_buffer[RX_BUF_NB][ETH_FRAME_LEN];
60
61 /* virtio queues and vrings */
62
63 enum {
64    RX_INDEX = 0,
65    TX_INDEX,
66    QUEUE_NB
67 };
68
69 static virtio_queue_t queue[QUEUE_NB];
70 static struct vring vring[QUEUE_NB];
71 static u16 free_head[QUEUE_NB];
72 static u16 last_used_idx[QUEUE_NB];
73 static u16 vdata[QUEUE_NB][MAX_QUEUE_NUM];
74
75 /*
76  * Virtio PCI interface
77  *
78  */
79
80 static int vp_find_vq(struct nic *nic, int queue_index)
81 {
82    struct vring * vr = &vring[queue_index];
83    u16 num;
84
85    /* select the queue */
86
87    outw(queue_index, nic->ioaddr + VIRTIO_PCI_QUEUE_SEL);
88
89    /* check if the queue is available */
90
91    num = inw(nic->ioaddr + VIRTIO_PCI_QUEUE_NUM);
92    if (!num) {
93            printf("ERROR: queue size is 0\n");
94            return -1;
95    }
96
97    if (num > MAX_QUEUE_NUM) {
98            printf("ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
99            return -1;
100    }
101
102    /* check if the queue is already active */
103
104    if (inl(nic->ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
105            printf("ERROR: queue already active\n");
106            return -1;
107    }
108
109    /* initialize the queue */
110
111    vring_init(vr, num, (unsigned char*)&queue[queue_index]);
112
113    /* activate the queue
114     *
115     * NOTE: vr->desc is initialized by vring_init()
116     */
117
118    outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
119         nic->ioaddr + VIRTIO_PCI_QUEUE_PFN);
120
121    return num;
122 }
123
124 /*
125  * Virtual ring management
126  *
127  */
128
129 static void vring_enable_cb(int queue_index)
130 {
131    vring[queue_index].avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
132 }
133
134 static void vring_disable_cb(int queue_index)
135 {
136    vring[queue_index].avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
137 }
138
139 /*
140  * vring_free
141  *
142  * put at the begin of the free list the current desc[head]
143  */
144
145 static void vring_detach(int queue_index, unsigned int head)
146 {
147    struct vring *vr = &vring[queue_index];
148         unsigned int i;
149
150         /* find end of given descriptor */
151
152    i = head;
153    while (vr->desc[i].flags & VRING_DESC_F_NEXT)
154            i = vr->desc[i].next;
155
156    /* link it with free list and point to it */
157
158    vr->desc[i].next = free_head[queue_index];
159    wmb();
160    free_head[queue_index] = head;
161 }
162
163 /*
164  * vring_more_used
165  *
166  * is there some used buffers ?
167  *
168  */
169
170 static inline int vring_more_used(int queue_index)
171 {
172    wmb();
173    return last_used_idx[queue_index] != vring[queue_index].used->idx;
174 }
175
176 /*
177  * vring_get_buf
178  *
179  * get a buffer from the used list
180  *
181  */
182
183 static int vring_get_buf(int queue_index, unsigned int *len)
184 {
185    struct vring *vr = &vring[queue_index];
186    struct vring_used_elem *elem;
187    u32 id;
188    int ret;
189
190    BUG_ON(!vring_more_used(queue_index));
191
192    elem = &vr->used->ring[last_used_idx[queue_index] % vr->num];
193    wmb();
194    id = elem->id;
195    if (len != NULL)
196            *len = elem->len;
197
198    ret = vdata[queue_index][id];
199
200    vring_detach(queue_index, id);
201
202    last_used_idx[queue_index]++;
203
204    return ret;
205 }
206
207 static void vring_add_buf(int queue_index,
208                           struct vring_list list[],
209                           unsigned int out, unsigned int in,
210                           int index, int num_added)
211 {
212    struct vring *vr = &vring[queue_index];
213    int i, avail, head, prev;
214
215    BUG_ON(queue_index >= QUEUE_NB);
216    BUG_ON(out + in == 0);
217
218    prev = 0;
219    head = free_head[queue_index];
220    for (i = head; out; i = vr->desc[i].next, out--) {
221
222            vr->desc[i].flags = VRING_DESC_F_NEXT;
223            vr->desc[i].addr = (u64)virt_to_phys(list->addr);
224            vr->desc[i].len = list->length;
225            prev = i;
226            list++;
227    }
228    for ( ; in; i = vr->desc[i].next, in--) {
229
230            vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
231            vr->desc[i].addr = (u64)virt_to_phys(list->addr);
232            vr->desc[i].len = list->length;
233            prev = i;
234            list++;
235    }
236    vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
237
238    free_head[queue_index] = i;
239
240    vdata[queue_index][head] = index;
241
242    avail = (vr->avail->idx + num_added) % vr->num;
243    vr->avail->ring[avail] = head;
244    wmb();
245 }
246
247 static void vring_kick(struct nic *nic, int queue_index, int num_added)
248 {
249    struct vring *vr = &vring[queue_index];
250
251    wmb();
252    vr->avail->idx += num_added;
253
254    mb();
255    if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
256            vp_notify(nic, queue_index);
257 }
258
259 /*
260  * virtnet_disable
261  *
262  * Turn off ethernet interface
263  *
264  */
265
266 static void virtnet_disable(struct nic *nic)
267 {
268    int i;
269
270    for (i = 0; i < QUEUE_NB; i++) {
271            vring_disable_cb(i);
272            vp_del_vq(nic, i);
273    }
274    vp_reset(nic);
275 }
276
277 /*
278  * virtnet_poll
279  *
280  * Wait for a frame
281  *
282  * return true if there is a packet ready to read
283  *
284  * nic->packet should contain data on return
285  * nic->packetlen should contain length of data
286  *
287  */
288 static int virtnet_poll(struct nic *nic, int retrieve)
289 {
290    unsigned int len;
291    u16 token;
292    struct virtio_net_hdr *hdr;
293    struct vring_list list[2];
294
295    if (!vring_more_used(RX_INDEX))
296            return 0;
297
298    if (!retrieve)
299            return 1;
300
301    token = vring_get_buf(RX_INDEX, &len);
302
303    BUG_ON(len > sizeof(struct virtio_net_hdr) + ETH_FRAME_LEN);
304
305    hdr = &rx_hdr[token];   /* FIXME: check flags */
306    len -= sizeof(struct virtio_net_hdr);
307
308    nic->packetlen = len;
309    memcpy(nic->packet, (char *)rx_buffer[token], nic->packetlen);
310
311    /* add buffer to desc */
312
313    list[0].addr = (char*)&rx_hdr[token];
314    list[0].length = sizeof(struct virtio_net_hdr);
315    list[1].addr = (char*)&rx_buffer[token];
316    list[1].length = ETH_FRAME_LEN;
317
318    vring_add_buf(RX_INDEX, list, 0, 2, token, 0);
319    vring_kick(nic, RX_INDEX, 1);
320
321    return 1;
322 }
323
324 /*
325  *
326  * virtnet_transmit
327  *
328  * Transmit a frame
329  *
330  */
331
332 static void virtnet_transmit(struct nic *nic, const char *destaddr,
333         unsigned int type, unsigned int len, const char *data)
334 {
335    struct vring_list list[2];
336
337    /*
338     * from http://www.etherboot.org/wiki/dev/devmanual :
339     *     "You do not need more than one transmit buffer."
340     */
341
342    /* FIXME: initialize header according to vp_get_features() */
343
344    tx_virtio_hdr.flags = 0;
345    tx_virtio_hdr.csum_offset = 0;
346    tx_virtio_hdr.csum_start = 0;
347    tx_virtio_hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE;
348    tx_virtio_hdr.gso_size = 0;
349    tx_virtio_hdr.hdr_len = 0;
350
351    /* add ethernet frame into vring */
352
353    BUG_ON(len > sizeof(tx_eth_frame.data));
354
355    memcpy(tx_eth_frame.hdr.dst_addr, destaddr, ETH_ALEN);
356    memcpy(tx_eth_frame.hdr.src_addr, nic->node_addr, ETH_ALEN);
357    tx_eth_frame.hdr.type = htons(type);
358    memcpy(tx_eth_frame.data, data, len);
359
360    list[0].addr = (char*)&tx_virtio_hdr;
361    list[0].length = sizeof(struct virtio_net_hdr);
362    list[1].addr = (char*)&tx_eth_frame;
363    list[1].length = ETH_FRAME_LEN;
364
365    vring_add_buf(TX_INDEX, list, 2, 0, 0, 0);
366
367    vring_kick(nic, TX_INDEX, 1);
368
369    /*
370     * http://www.etherboot.org/wiki/dev/devmanual
371     *
372     *   "You should ensure the packet is fully transmitted
373     *    before returning from this routine"
374     */
375
376    while (!vring_more_used(TX_INDEX)) {
377            mb();
378            udelay(10);
379    }
380
381    /* free desc */
382
383    (void)vring_get_buf(TX_INDEX, NULL);
384 }
385
386 static void virtnet_irq(struct nic *nic __unused, irq_action_t action)
387 {
388    switch ( action ) {
389    case DISABLE :
390            vring_disable_cb(RX_INDEX);
391            vring_disable_cb(TX_INDEX);
392            break;
393    case ENABLE :
394            vring_enable_cb(RX_INDEX);
395            vring_enable_cb(TX_INDEX);
396            break;
397    case FORCE :
398            break;
399    }
400 }
401
402 static void provide_buffers(struct nic *nic)
403 {
404    int i;
405    struct vring_list list[2];
406
407    for (i = 0; i < RX_BUF_NB; i++) {
408            list[0].addr = (char*)&rx_hdr[i];
409            list[0].length = sizeof(struct virtio_net_hdr);
410            list[1].addr = (char*)&rx_buffer[i];
411            list[1].length = ETH_FRAME_LEN;
412            vring_add_buf(RX_INDEX, list, 0, 2, i, i);
413    }
414
415    /* nofify */
416
417    vring_kick(nic, RX_INDEX, i);
418 }
419
420 static struct nic_operations virtnet_operations = {
421         .connect = dummy_connect,
422         .poll = virtnet_poll,
423         .transmit = virtnet_transmit,
424         .irq = virtnet_irq,
425 };
426
427 /*
428  * virtnet_probe
429  *
430  * Look for a virtio network adapter
431  *
432  */
433
434 static int virtnet_probe(struct nic *nic, struct pci_device *pci)
435 {
436    u32 features;
437    int i;
438
439    /* Mask the bit that says "this is an io addr" */
440
441    nic->ioaddr = pci->ioaddr & ~3;
442
443    /* Copy IRQ from PCI information */
444
445    nic->irqno = pci->irq;
446
447    printf("I/O address 0x%08x, IRQ #%d\n", nic->ioaddr, nic->irqno);
448
449    adjust_pci_device(pci);
450
451    vp_reset(nic);
452
453    features = vp_get_features(nic);
454    if (features & (1 << VIRTIO_NET_F_MAC)) {
455            vp_get(nic, offsetof(struct virtio_net_config, mac),
456                   nic->node_addr, ETH_ALEN);
457            printf("MAC address ");
458            for (i = 0; i < ETH_ALEN; i++) {
459                    printf("%02x%c", nic->node_addr[i],
460                           (i == ETH_ALEN - 1) ? '\n' : ':');
461            }
462    }
463
464    /* initialize emit/receive queue */
465
466    for (i = 0; i < QUEUE_NB; i++) {
467            free_head[i] = 0;
468            last_used_idx[i] = 0;
469            memset((char*)&queue[i], 0, sizeof(queue[i]));
470            if (vp_find_vq(nic, i) == -1)
471                    printf("Cannot register queue #%d\n", i);
472    }
473
474    /* provide some receive buffers */
475
476     provide_buffers(nic);
477
478    /* define NIC interface */
479
480     nic->nic_op = &virtnet_operations;
481
482    /* driver is ready */
483
484    vp_set_features(nic, features & (1 << VIRTIO_NET_F_MAC));
485    vp_set_status(nic, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
486
487    return 1;
488 }
489
490 static struct pci_device_id virtnet_nics[] = {
491 PCI_ROM(0x1af4, 0x1000, "virtio-net",              "Virtio Network Interface"),
492 };
493
494 PCI_DRIVER ( virtnet_driver, virtnet_nics, PCI_NO_CLASS );
495
496 DRIVER ( "VIRTIO-NET", nic_driver, pci_driver, virtnet_driver,
497          virtnet_probe, virtnet_disable );