diff options
Diffstat (limited to 'gpxe/src/drivers/net/virtio-net.c')
-rw-r--r-- | gpxe/src/drivers/net/virtio-net.c | 307 |
1 files changed, 0 insertions, 307 deletions
diff --git a/gpxe/src/drivers/net/virtio-net.c b/gpxe/src/drivers/net/virtio-net.c deleted file mode 100644 index 49fcc1c5..00000000 --- a/gpxe/src/drivers/net/virtio-net.c +++ /dev/null @@ -1,307 +0,0 @@ -/* virtio-net.c - etherboot driver for virtio network interface - * - * (c) Copyright 2008 Bull S.A.S. - * - * Author: Laurent Vivier <Laurent.Vivier@bull.net> - * - * some parts from Linux Virtio PCI driver - * - * Copyright IBM Corp. 2007 - * Authors: Anthony Liguori <aliguori@us.ibm.com> - * - * some parts from Linux Virtio Ring - * - * Copyright Rusty Russell IBM Corporation 2007 - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - * - */ - -#include "etherboot.h" -#include "nic.h" -#include "gpxe/virtio-ring.h" -#include "gpxe/virtio-pci.h" -#include "virtio-net.h" - -#define BUG() do { \ - printf("BUG: failure at %s:%d/%s()!\n", \ - __FILE__, __LINE__, __FUNCTION__); \ - while(1); \ -} while (0) -#define BUG_ON(condition) do { if (condition) BUG(); } while (0) - -/* Ethernet header */ - -struct eth_hdr { - unsigned char dst_addr[ETH_ALEN]; - unsigned char src_addr[ETH_ALEN]; - unsigned short type; -}; - -struct eth_frame { - struct eth_hdr hdr; - unsigned char data[ETH_FRAME_LEN]; -}; - -/* TX: virtio header and eth buffer */ - -static struct virtio_net_hdr tx_virtio_hdr; -static struct eth_frame tx_eth_frame; - -/* RX: virtio headers and buffers */ - -#define RX_BUF_NB 6 -static struct virtio_net_hdr rx_hdr[RX_BUF_NB]; -static unsigned char rx_buffer[RX_BUF_NB][ETH_FRAME_LEN]; - -/* virtio queues and vrings */ - -enum { - RX_INDEX = 0, - TX_INDEX, - QUEUE_NB -}; - -static struct vring_virtqueue virtqueue[QUEUE_NB]; - -/* - * virtnet_disable - * - * Turn off ethernet interface - * - */ - -static void virtnet_disable(struct nic *nic) -{ - int i; - - for (i = 0; i < QUEUE_NB; i++) { - vring_disable_cb(&virtqueue[i]); - vp_del_vq(nic->ioaddr, i); - } - vp_reset(nic->ioaddr); -} - -/* - * virtnet_poll - * - * Wait for a frame - * - * return true if there is a packet ready to read - * - * nic->packet should contain data on return - * nic->packetlen should contain length of data - * - */ -static int virtnet_poll(struct nic *nic, int retrieve) -{ - unsigned int len; - u16 token; - struct virtio_net_hdr *hdr; - struct vring_list list[2]; - - if (!vring_more_used(&virtqueue[RX_INDEX])) - return 0; - - if (!retrieve) - return 1; - - token = vring_get_buf(&virtqueue[RX_INDEX], &len); - - BUG_ON(len > sizeof(struct virtio_net_hdr) + ETH_FRAME_LEN); - - hdr = &rx_hdr[token]; /* FIXME: check flags */ - len -= sizeof(struct virtio_net_hdr); - - nic->packetlen = len; - memcpy(nic->packet, (char *)rx_buffer[token], nic->packetlen); - - /* add buffer to desc */ - - list[0].addr = (char*)&rx_hdr[token]; - list[0].length = sizeof(struct virtio_net_hdr); - list[1].addr = (char*)&rx_buffer[token]; - list[1].length = ETH_FRAME_LEN; - - vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, token, 0); - vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], 1); - - return 1; -} - -/* - * - * virtnet_transmit - * - * Transmit a frame - * - */ - -static void virtnet_transmit(struct nic *nic, const char *destaddr, - unsigned int type, unsigned int len, const char *data) -{ - struct vring_list list[2]; - - /* - * from http://www.etherboot.org/wiki/dev/devmanual : - * "You do not need more than one transmit buffer." - */ - - /* FIXME: initialize header according to vp_get_features() */ - - tx_virtio_hdr.flags = 0; - tx_virtio_hdr.csum_offset = 0; - tx_virtio_hdr.csum_start = 0; - tx_virtio_hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE; - tx_virtio_hdr.gso_size = 0; - tx_virtio_hdr.hdr_len = 0; - - /* add ethernet frame into vring */ - - BUG_ON(len > sizeof(tx_eth_frame.data)); - - memcpy(tx_eth_frame.hdr.dst_addr, destaddr, ETH_ALEN); - memcpy(tx_eth_frame.hdr.src_addr, nic->node_addr, ETH_ALEN); - tx_eth_frame.hdr.type = htons(type); - memcpy(tx_eth_frame.data, data, len); - - list[0].addr = (char*)&tx_virtio_hdr; - list[0].length = sizeof(struct virtio_net_hdr); - list[1].addr = (char*)&tx_eth_frame; - list[1].length = ETH_FRAME_LEN; - - vring_add_buf(&virtqueue[TX_INDEX], list, 2, 0, 0, 0); - - vring_kick(nic->ioaddr, &virtqueue[TX_INDEX], 1); - - /* - * http://www.etherboot.org/wiki/dev/devmanual - * - * "You should ensure the packet is fully transmitted - * before returning from this routine" - */ - - while (!vring_more_used(&virtqueue[TX_INDEX])) { - mb(); - udelay(10); - } - - /* free desc */ - - (void)vring_get_buf(&virtqueue[TX_INDEX], NULL); -} - -static void virtnet_irq(struct nic *nic __unused, irq_action_t action) -{ - switch ( action ) { - case DISABLE : - vring_disable_cb(&virtqueue[RX_INDEX]); - vring_disable_cb(&virtqueue[TX_INDEX]); - break; - case ENABLE : - vring_enable_cb(&virtqueue[RX_INDEX]); - vring_enable_cb(&virtqueue[TX_INDEX]); - break; - case FORCE : - break; - } -} - -static void provide_buffers(struct nic *nic) -{ - int i; - struct vring_list list[2]; - - for (i = 0; i < RX_BUF_NB; i++) { - list[0].addr = (char*)&rx_hdr[i]; - list[0].length = sizeof(struct virtio_net_hdr); - list[1].addr = (char*)&rx_buffer[i]; - list[1].length = ETH_FRAME_LEN; - vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, i, i); - } - - /* nofify */ - - vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], i); -} - -static struct nic_operations virtnet_operations = { - .connect = dummy_connect, - .poll = virtnet_poll, - .transmit = virtnet_transmit, - .irq = virtnet_irq, -}; - -/* - * virtnet_probe - * - * Look for a virtio network adapter - * - */ - -static int virtnet_probe(struct nic *nic, struct pci_device *pci) -{ - u32 features; - int i; - - /* Mask the bit that says "this is an io addr" */ - - nic->ioaddr = pci->ioaddr & ~3; - - /* Copy IRQ from PCI information */ - - nic->irqno = pci->irq; - - printf("I/O address 0x%08x, IRQ #%d\n", nic->ioaddr, nic->irqno); - - adjust_pci_device(pci); - - vp_reset(nic->ioaddr); - - features = vp_get_features(nic->ioaddr); - if (features & (1 << VIRTIO_NET_F_MAC)) { - vp_get(nic->ioaddr, offsetof(struct virtio_net_config, mac), - nic->node_addr, ETH_ALEN); - printf("MAC address "); - for (i = 0; i < ETH_ALEN; i++) { - printf("%02x%c", nic->node_addr[i], - (i == ETH_ALEN - 1) ? '\n' : ':'); - } - } - - /* initialize emit/receive queue */ - - for (i = 0; i < QUEUE_NB; i++) { - virtqueue[i].free_head = 0; - virtqueue[i].last_used_idx = 0; - memset((char*)&virtqueue[i].queue, 0, sizeof(virtqueue[i].queue)); - if (vp_find_vq(nic->ioaddr, i, &virtqueue[i]) == -1) - printf("Cannot register queue #%d\n", i); - } - - /* provide some receive buffers */ - - provide_buffers(nic); - - /* define NIC interface */ - - nic->nic_op = &virtnet_operations; - - /* driver is ready */ - - vp_set_features(nic->ioaddr, features & (1 << VIRTIO_NET_F_MAC)); - vp_set_status(nic->ioaddr, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); - - return 1; -} - -static struct pci_device_id virtnet_nics[] = { -PCI_ROM(0x1af4, 0x1000, "virtio-net", "Virtio Network Interface", 0), -}; - -PCI_DRIVER ( virtnet_driver, virtnet_nics, PCI_NO_CLASS ); - -DRIVER ( "VIRTIO-NET", nic_driver, pci_driver, virtnet_driver, - virtnet_probe, virtnet_disable ); |