• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /* TX: virtio header and eth buffer */
49 
50 static struct virtio_net_hdr tx_virtio_hdr;
51 static struct eth_frame tx_eth_frame;
52 
53 /* RX: virtio headers and buffers */
54 
55 #define RX_BUF_NB  6
56 static struct virtio_net_hdr rx_hdr[RX_BUF_NB];
57 static unsigned char rx_buffer[RX_BUF_NB][ETH_FRAME_LEN];
58 
59 /* virtio queues and vrings */
60 
61 enum {
62    RX_INDEX = 0,
63    TX_INDEX,
64    QUEUE_NB
65 };
66 
67 static struct vring_virtqueue virtqueue[QUEUE_NB];
68 
69 /*
70  * virtnet_disable
71  *
72  * Turn off ethernet interface
73  *
74  */
75 
virtnet_disable(struct nic * nic)76 static void virtnet_disable(struct nic *nic)
77 {
78    int i;
79 
80    for (i = 0; i < QUEUE_NB; i++) {
81            vring_disable_cb(&virtqueue[i]);
82            vp_del_vq(nic->ioaddr, i);
83    }
84    vp_reset(nic->ioaddr);
85 }
86 
87 /*
88  * virtnet_poll
89  *
90  * Wait for a frame
91  *
92  * return true if there is a packet ready to read
93  *
94  * nic->packet should contain data on return
95  * nic->packetlen should contain length of data
96  *
97  */
virtnet_poll(struct nic * nic,int retrieve)98 static int virtnet_poll(struct nic *nic, int retrieve)
99 {
100    unsigned int len;
101    u16 token;
102    struct virtio_net_hdr *hdr;
103    struct vring_list list[2];
104 
105    if (!vring_more_used(&virtqueue[RX_INDEX]))
106            return 0;
107 
108    if (!retrieve)
109            return 1;
110 
111    token = vring_get_buf(&virtqueue[RX_INDEX], &len);
112 
113    BUG_ON(len > sizeof(struct virtio_net_hdr) + ETH_FRAME_LEN);
114 
115    hdr = &rx_hdr[token];   /* FIXME: check flags */
116    len -= sizeof(struct virtio_net_hdr);
117 
118    nic->packetlen = len;
119    memcpy(nic->packet, (char *)rx_buffer[token], nic->packetlen);
120 
121    /* add buffer to desc */
122 
123    list[0].addr = (char*)&rx_hdr[token];
124    list[0].length = sizeof(struct virtio_net_hdr);
125    list[1].addr = (char*)&rx_buffer[token];
126    list[1].length = ETH_FRAME_LEN;
127 
128    vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, token, 0);
129    vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], 1);
130 
131    return 1;
132 }
133 
134 /*
135  *
136  * virtnet_transmit
137  *
138  * Transmit a frame
139  *
140  */
141 
virtnet_transmit(struct nic * nic,const char * destaddr,unsigned int type,unsigned int len,const char * data)142 static void virtnet_transmit(struct nic *nic, const char *destaddr,
143         unsigned int type, unsigned int len, const char *data)
144 {
145    struct vring_list list[2];
146 
147    /*
148     * from http://www.etherboot.org/wiki/dev/devmanual :
149     *     "You do not need more than one transmit buffer."
150     */
151 
152    /* FIXME: initialize header according to vp_get_features() */
153 
154    tx_virtio_hdr.flags = 0;
155    tx_virtio_hdr.csum_offset = 0;
156    tx_virtio_hdr.csum_start = 0;
157    tx_virtio_hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE;
158    tx_virtio_hdr.gso_size = 0;
159    tx_virtio_hdr.hdr_len = 0;
160 
161    /* add ethernet frame into vring */
162 
163    BUG_ON(len > sizeof(tx_eth_frame.data));
164 
165    memcpy(tx_eth_frame.hdr.dst_addr, destaddr, ETH_ALEN);
166    memcpy(tx_eth_frame.hdr.src_addr, nic->node_addr, ETH_ALEN);
167    tx_eth_frame.hdr.type = htons(type);
168    memcpy(tx_eth_frame.data, data, len);
169 
170    list[0].addr = (char*)&tx_virtio_hdr;
171    list[0].length = sizeof(struct virtio_net_hdr);
172    list[1].addr = (char*)&tx_eth_frame;
173    list[1].length = ETH_FRAME_LEN;
174 
175    vring_add_buf(&virtqueue[TX_INDEX], list, 2, 0, 0, 0);
176 
177    vring_kick(nic->ioaddr, &virtqueue[TX_INDEX], 1);
178 
179    /*
180     * http://www.etherboot.org/wiki/dev/devmanual
181     *
182     *   "You should ensure the packet is fully transmitted
183     *    before returning from this routine"
184     */
185 
186    while (!vring_more_used(&virtqueue[TX_INDEX])) {
187            mb();
188            udelay(10);
189    }
190 
191    /* free desc */
192 
193    (void)vring_get_buf(&virtqueue[TX_INDEX], NULL);
194 }
195 
virtnet_irq(struct nic * nic __unused,irq_action_t action)196 static void virtnet_irq(struct nic *nic __unused, irq_action_t action)
197 {
198    switch ( action ) {
199    case DISABLE :
200            vring_disable_cb(&virtqueue[RX_INDEX]);
201            vring_disable_cb(&virtqueue[TX_INDEX]);
202            break;
203    case ENABLE :
204            vring_enable_cb(&virtqueue[RX_INDEX]);
205            vring_enable_cb(&virtqueue[TX_INDEX]);
206            break;
207    case FORCE :
208            break;
209    }
210 }
211 
provide_buffers(struct nic * nic)212 static void provide_buffers(struct nic *nic)
213 {
214    int i;
215    struct vring_list list[2];
216 
217    for (i = 0; i < RX_BUF_NB; i++) {
218            list[0].addr = (char*)&rx_hdr[i];
219            list[0].length = sizeof(struct virtio_net_hdr);
220            list[1].addr = (char*)&rx_buffer[i];
221            list[1].length = ETH_FRAME_LEN;
222            vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, i, i);
223    }
224 
225    /* nofify */
226 
227    vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], i);
228 }
229 
230 static struct nic_operations virtnet_operations = {
231 	.connect = dummy_connect,
232 	.poll = virtnet_poll,
233 	.transmit = virtnet_transmit,
234 	.irq = virtnet_irq,
235 };
236 
237 /*
238  * virtnet_probe
239  *
240  * Look for a virtio network adapter
241  *
242  */
243 
virtnet_probe(struct nic * nic,struct pci_device * pci)244 static int virtnet_probe(struct nic *nic, struct pci_device *pci)
245 {
246    u32 features;
247    int i;
248 
249    /* Mask the bit that says "this is an io addr" */
250 
251    nic->ioaddr = pci->ioaddr & ~3;
252 
253    /* Copy IRQ from PCI information */
254 
255    nic->irqno = pci->irq;
256 
257    printf("I/O address 0x%08x, IRQ #%d\n", nic->ioaddr, nic->irqno);
258 
259    adjust_pci_device(pci);
260 
261    vp_reset(nic->ioaddr);
262 
263    features = vp_get_features(nic->ioaddr);
264    if (features & (1 << VIRTIO_NET_F_MAC)) {
265            vp_get(nic->ioaddr, offsetof(struct virtio_net_config, mac),
266                   nic->node_addr, ETH_ALEN);
267            printf("MAC address ");
268 	   for (i = 0; i < ETH_ALEN; i++) {
269                    printf("%02x%c", nic->node_addr[i],
270                           (i == ETH_ALEN - 1) ? '\n' : ':');
271            }
272    }
273 
274    /* initialize emit/receive queue */
275 
276    for (i = 0; i < QUEUE_NB; i++) {
277            virtqueue[i].free_head = 0;
278            virtqueue[i].last_used_idx = 0;
279            memset((char*)&virtqueue[i].queue, 0, sizeof(virtqueue[i].queue));
280            if (vp_find_vq(nic->ioaddr, i, &virtqueue[i]) == -1)
281                    printf("Cannot register queue #%d\n", i);
282    }
283 
284    /* provide some receive buffers */
285 
286     provide_buffers(nic);
287 
288    /* define NIC interface */
289 
290     nic->nic_op = &virtnet_operations;
291 
292    /* driver is ready */
293 
294    vp_set_features(nic->ioaddr, features & (1 << VIRTIO_NET_F_MAC));
295    vp_set_status(nic->ioaddr, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
296 
297    return 1;
298 }
299 
300 static struct pci_device_id virtnet_nics[] = {
301 PCI_ROM(0x1af4, 0x1000, "virtio-net",              "Virtio Network Interface", 0),
302 };
303 
304 PCI_DRIVER ( virtnet_driver, virtnet_nics, PCI_NO_CLASS );
305 
306 DRIVER ( "VIRTIO-NET", nic_driver, pci_driver, virtnet_driver,
307 	 virtnet_probe, virtnet_disable );
308