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"
24 #include "gpxe/virtio-ring.h"
25 #include "gpxe/virtio-pci.h"
26 #include "virtio-net.h"
29 printf("BUG: failure at %s:%d/%s()!\n", \
30 __FILE__, __LINE__, __FUNCTION__); \
33 #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
38 unsigned char dst_addr
[ETH_ALEN
];
39 unsigned char src_addr
[ETH_ALEN
];
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 */
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 */
67 static struct vring_virtqueue virtqueue
[QUEUE_NB
];
72 * Turn off ethernet interface
76 static void virtnet_disable(struct nic
*nic
)
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
);
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
)
102 struct virtio_net_hdr
*hdr
;
103 struct vring_list list
[2];
105 if (!vring_more_used(&virtqueue
[RX_INDEX
]))
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);
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
])) {
193 (void)vring_get_buf(&virtqueue
[TX_INDEX
], NULL
);
196 static void virtnet_irq(struct nic
*nic __unused
, irq_action_t action
)
200 vring_disable_cb(&virtqueue
[RX_INDEX
]);
201 vring_disable_cb(&virtqueue
[TX_INDEX
]);
204 vring_enable_cb(&virtqueue
[RX_INDEX
]);
205 vring_enable_cb(&virtqueue
[TX_INDEX
]);
212 static void provide_buffers(struct nic
*nic
)
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
);
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
,
240 * Look for a virtio network adapter
244 static int virtnet_probe(struct nic
*nic
, struct pci_device
*pci
)
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
);
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
);