[uri] Special case NULL in churi()
[gpxe.git] / src / drivers / net / virtio-net.c
blob49fcc1c51afeca89654b714dabc718add01e9509
1 /* virtio-net.c - etherboot driver for virtio network interface
3 * (c) Copyright 2008 Bull S.A.S.
5 * Author: Laurent Vivier <Laurent.Vivier@bull.net>
7 * some parts from Linux Virtio PCI driver
9 * Copyright IBM Corp. 2007
10 * Authors: Anthony Liguori <aliguori@us.ibm.com>
12 * some parts from Linux Virtio Ring
14 * Copyright Rusty Russell IBM Corporation 2007
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.
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"
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)
35 /* Ethernet header */
37 struct eth_hdr {
38 unsigned char dst_addr[ETH_ALEN];
39 unsigned char src_addr[ETH_ALEN];
40 unsigned short type;
43 struct eth_frame {
44 struct eth_hdr hdr;
45 unsigned char data[ETH_FRAME_LEN];
48 /* TX: virtio header and eth buffer */
50 static struct virtio_net_hdr tx_virtio_hdr;
51 static struct eth_frame tx_eth_frame;
53 /* RX: virtio headers and buffers */
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];
59 /* virtio queues and vrings */
61 enum {
62 RX_INDEX = 0,
63 TX_INDEX,
64 QUEUE_NB
67 static struct vring_virtqueue virtqueue[QUEUE_NB];
70 * virtnet_disable
72 * Turn off ethernet interface
76 static void virtnet_disable(struct nic *nic)
78 int i;
80 for (i = 0; i < QUEUE_NB; i++) {
81 vring_disable_cb(&virtqueue[i]);
82 vp_del_vq(nic->ioaddr, i);
84 vp_reset(nic->ioaddr);
88 * virtnet_poll
90 * Wait for a frame
92 * return true if there is a packet ready to read
94 * nic->packet should contain data on return
95 * nic->packetlen should contain length of data
98 static int virtnet_poll(struct nic *nic, int retrieve)
100 unsigned int len;
101 u16 token;
102 struct virtio_net_hdr *hdr;
103 struct vring_list list[2];
105 if (!vring_more_used(&virtqueue[RX_INDEX]))
106 return 0;
108 if (!retrieve)
109 return 1;
111 token = vring_get_buf(&virtqueue[RX_INDEX], &len);
113 BUG_ON(len > sizeof(struct virtio_net_hdr) + ETH_FRAME_LEN);
115 hdr = &rx_hdr[token]; /* FIXME: check flags */
116 len -= sizeof(struct virtio_net_hdr);
118 nic->packetlen = len;
119 memcpy(nic->packet, (char *)rx_buffer[token], nic->packetlen);
121 /* add buffer to desc */
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;
128 vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, token, 0);
129 vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], 1);
131 return 1;
136 * virtnet_transmit
138 * Transmit a frame
142 static void virtnet_transmit(struct nic *nic, const char *destaddr,
143 unsigned int type, unsigned int len, const char *data)
145 struct vring_list list[2];
148 * from http://www.etherboot.org/wiki/dev/devmanual :
149 * "You do not need more than one transmit buffer."
152 /* FIXME: initialize header according to vp_get_features() */
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;
161 /* add ethernet frame into vring */
163 BUG_ON(len > sizeof(tx_eth_frame.data));
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);
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;
175 vring_add_buf(&virtqueue[TX_INDEX], list, 2, 0, 0, 0);
177 vring_kick(nic->ioaddr, &virtqueue[TX_INDEX], 1);
180 * http://www.etherboot.org/wiki/dev/devmanual
182 * "You should ensure the packet is fully transmitted
183 * before returning from this routine"
186 while (!vring_more_used(&virtqueue[TX_INDEX])) {
187 mb();
188 udelay(10);
191 /* free desc */
193 (void)vring_get_buf(&virtqueue[TX_INDEX], NULL);
196 static void virtnet_irq(struct nic *nic __unused, irq_action_t action)
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;
212 static void provide_buffers(struct nic *nic)
214 int i;
215 struct vring_list list[2];
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);
225 /* nofify */
227 vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], i);
230 static struct nic_operations virtnet_operations = {
231 .connect = dummy_connect,
232 .poll = virtnet_poll,
233 .transmit = virtnet_transmit,
234 .irq = virtnet_irq,
238 * virtnet_probe
240 * Look for a virtio network adapter
244 static int virtnet_probe(struct nic *nic, struct pci_device *pci)
246 u32 features;
247 int i;
249 /* Mask the bit that says "this is an io addr" */
251 nic->ioaddr = pci->ioaddr & ~3;
253 /* Copy IRQ from PCI information */
255 nic->irqno = pci->irq;
257 printf("I/O address 0x%08x, IRQ #%d\n", nic->ioaddr, nic->irqno);
259 adjust_pci_device(pci);
261 vp_reset(nic->ioaddr);
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' : ':');
274 /* initialize emit/receive queue */
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);
284 /* provide some receive buffers */
286 provide_buffers(nic);
288 /* define NIC interface */
290 nic->nic_op = &virtnet_operations;
292 /* driver is ready */
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);
297 return 1;
300 static struct pci_device_id virtnet_nics[] = {
301 PCI_ROM(0x1af4, 0x1000, "virtio-net", "Virtio Network Interface", 0),
304 PCI_DRIVER ( virtnet_driver, virtnet_nics, PCI_NO_CLASS );
306 DRIVER ( "VIRTIO-NET", nic_driver, pci_driver, virtnet_driver,
307 virtnet_probe, virtnet_disable );