Home | History | Annotate | Download | only in net
      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 (at) bull.net>
      6  *
      7  * some parts from Linux Virtio PCI driver
      8  *
      9  *  Copyright IBM Corp. 2007
     10  *  Authors: Anthony Liguori  <aliguori (at) 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 
     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  */
     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 
    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 
    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 
    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 
    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