Annotation of qemu/roms/SLOF/board-qemu/virtio-net/virtio-net.c, revision 1.1

1.1     ! root        1: /******************************************************************************
        !             2:  * Copyright (c) 2011 IBM Corporation
        !             3:  * All rights reserved.
        !             4:  * This program and the accompanying materials
        !             5:  * are made available under the terms of the BSD License
        !             6:  * which accompanies this distribution, and is available at
        !             7:  * http://www.opensource.org/licenses/bsd-license.php
        !             8:  *
        !             9:  * Contributors:
        !            10:  *     IBM Corporation - initial implementation
        !            11:  *****************************************************************************/
        !            12: 
        !            13: /*
        !            14:  * This is the implementation for the Virtio network device driver. Details
        !            15:  * about the virtio-net interface can be found in Rusty Russel's "Virtio PCI
        !            16:  * Card Specification v0.8.10", appendix C, which can be found here:
        !            17:  *
        !            18:  *        http://ozlabs.org/~rusty/virtio-spec/virtio-spec.pdf
        !            19:  */
        !            20: 
        !            21: #include <stdint.h>
        !            22: #include "netdriver_int.h"
        !            23: #include <libhvcall.h>
        !            24: #include <virtio.h>
        !            25: #include <string.h>
        !            26: #include "virtio-net.h"
        !            27: 
        !            28: 
        !            29: #define sync()  asm volatile (" sync \n" ::: "memory")
        !            30: 
        !            31: 
        !            32: struct virtio_device virtiodev;
        !            33: struct vqs vq[2];     /* Information about virtqueues */
        !            34: 
        !            35: 
        !            36: /* See Virtio Spec, appendix C, "Device Operation" */ 
        !            37: struct virtio_net_hdr {
        !            38:        uint8_t  flags;
        !            39:        uint8_t  gso_type;
        !            40:        uint16_t  hdr_len;
        !            41:        uint16_t  gso_size;
        !            42:        uint16_t  csum_start;
        !            43:        uint16_t  csum_offset;
        !            44:        // uint16_t  num_buffers;       /* Only if VIRTIO_NET_F_MRG_RXBUF */
        !            45: };
        !            46: 
        !            47: static uint16_t last_rx_idx;   /* Last index in RX "used" ring */
        !            48: 
        !            49: 
        !            50: /**
        !            51:  * Initialize the virtio-net device.
        !            52:  * See the Virtio Spec, chapter 2.2.1 and Appendix C "Device Initialization"
        !            53:  * for details.
        !            54:  */
        !            55: static int virtionet_init(void)
        !            56: {
        !            57:        int i;
        !            58: 
        !            59:        dprintk("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n",
        !            60:                snk_module_interface->mac_addr[0], snk_module_interface->mac_addr[1],
        !            61:                snk_module_interface->mac_addr[2], snk_module_interface->mac_addr[3],
        !            62:                snk_module_interface->mac_addr[4], snk_module_interface->mac_addr[5]);
        !            63: 
        !            64:        if (snk_module_interface->running != 0)
        !            65:                return 0;
        !            66: 
        !            67:        /* Tell HV that we know how to drive the device. */
        !            68:        virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
        !            69: 
        !            70:        /* Device specific setup - we do not support special features right now */
        !            71:        virtio_set_guest_features(&virtiodev,  0);
        !            72: 
        !            73:        /* Allocate memory for one transmit an multiple receive buffers */
        !            74:        vq[VQ_RX].buf_mem = malloc((BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr))
        !            75:                                   * RX_QUEUE_SIZE);
        !            76:        if (!vq[VQ_RX].buf_mem) {
        !            77:                printk("virtionet: Failed to allocate buffers!\n");
        !            78:                virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED);
        !            79:                return -1;
        !            80:        }
        !            81: 
        !            82:        /* Prepare receive buffer queue */
        !            83:        for (i = 0; i < RX_QUEUE_SIZE; i++) {
        !            84:                struct vring_desc *desc;
        !            85:                /* Descriptor for net_hdr: */
        !            86:                desc = &vq[VQ_RX].desc[i*2];
        !            87:                desc->addr = (uint64_t)vq[VQ_RX].buf_mem
        !            88:                             + i * (BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr));
        !            89:                // printk("RX buf %i addr = 0x%llx\n", i, desc->addr);
        !            90:                desc->len = sizeof(struct virtio_net_hdr);
        !            91:                desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
        !            92:                desc->next = i*2+1;
        !            93: 
        !            94:                /* Descriptor for data: */
        !            95:                desc = &vq[VQ_RX].desc[i*2+1];
        !            96:                desc->addr = vq[VQ_RX].desc[i*2].addr + sizeof(struct virtio_net_hdr);
        !            97:                desc->len = BUFFER_ENTRY_SIZE;
        !            98:                desc->flags = VRING_DESC_F_WRITE;
        !            99:                desc->next = 0;
        !           100: 
        !           101:                vq[VQ_RX].avail->ring[i] = i*2;
        !           102:        }
        !           103:        sync();
        !           104:        vq[VQ_RX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
        !           105:        vq[VQ_RX].avail->idx = RX_QUEUE_SIZE;
        !           106: 
        !           107:        last_rx_idx = vq[VQ_RX].used->idx;
        !           108: 
        !           109:        vq[VQ_TX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
        !           110:        vq[VQ_TX].avail->idx = 0;
        !           111: 
        !           112:        /* Tell HV that setup succeeded */
        !           113:        virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE
        !           114:                                      |VIRTIO_STAT_DRIVER
        !           115:                                      |VIRTIO_STAT_DRIVER_OK);
        !           116: 
        !           117:        /* Tell HV that RX queues are ready */
        !           118:        virtio_queue_notify(&virtiodev, VQ_RX);
        !           119: 
        !           120:        snk_module_interface->running = 1;
        !           121: 
        !           122:        return 0;
        !           123: }
        !           124: 
        !           125: 
        !           126: /**
        !           127:  * Shutdown driver.
        !           128:  * We've got to make sure that the hosts stops all transfers since the buffers
        !           129:  * in our main memory will become invalid after this module has been terminated.
        !           130:  */
        !           131: static int virtionet_term(void)
        !           132: {
        !           133:        dprintk("virtionet_term()\n");
        !           134: 
        !           135:        if (snk_module_interface->running == 0)
        !           136:                return 0;
        !           137: 
        !           138:        /* Quiesce device */
        !           139:        virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED);
        !           140: 
        !           141:        /* Reset device */
        !           142:        virtio_reset_device(&virtiodev);
        !           143: 
        !           144:        snk_module_interface->running = 0;
        !           145: 
        !           146:        return 0;
        !           147: }
        !           148: 
        !           149: 
        !           150: /**
        !           151:  * Transmit a packet
        !           152:  */
        !           153: static int virtionet_xmit(char *buf, int len)
        !           154: {
        !           155:        struct vring_desc *desc;
        !           156:        int id;
        !           157:        static struct virtio_net_hdr nethdr = {
        !           158:                0, 0, sizeof(struct virtio_net_hdr),
        !           159:                0, 0, 0
        !           160:        };
        !           161: 
        !           162:        if (len > BUFFER_ENTRY_SIZE) {
        !           163:                printk("virtionet: Packet too big!\n");
        !           164:                return 0;
        !           165:        }
        !           166: 
        !           167:        dprintk("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len);
        !           168: 
        !           169:        /* Determine descriptor index */
        !           170:        id = (vq[VQ_TX].avail->idx * 2) % vq[VQ_TX].size;
        !           171: 
        !           172:        /* Set up virtqueue descriptor for header */
        !           173:        desc = &vq[VQ_TX].desc[id];
        !           174:        desc->addr = (uint64_t)&nethdr;
        !           175:        desc->len = sizeof(struct virtio_net_hdr);
        !           176:        desc->flags = VRING_DESC_F_NEXT;
        !           177:        desc->next = id + 1;
        !           178: 
        !           179:        /* Set up virtqueue descriptor for data */
        !           180:        desc = &vq[VQ_TX].desc[id+1];
        !           181:        desc->addr = (uint64_t)buf;
        !           182:        desc->len = len;
        !           183:        desc->flags = 0;
        !           184:        desc->next = 0;
        !           185: 
        !           186:        vq[VQ_TX].avail->ring[vq[VQ_TX].avail->idx % vq[VQ_TX].size] = id;
        !           187:        sync();
        !           188:        vq[VQ_TX].avail->idx += 1;
        !           189: 
        !           190:        /* Tell HV that TX queue is ready */
        !           191:        virtio_queue_notify(&virtiodev, VQ_TX);
        !           192: 
        !           193:        return len;
        !           194: }
        !           195: 
        !           196: 
        !           197: /**
        !           198:  * Receive a packet
        !           199:  */
        !           200: static int virtionet_receive(char *buf, int maxlen)
        !           201: {
        !           202:        int len = 0;
        !           203:        int id;
        !           204: 
        !           205:        if (last_rx_idx == vq[VQ_RX].used->idx) {
        !           206:                /* Nothing received yet */
        !           207:                return 0;
        !           208:        }
        !           209: 
        !           210:        id = (vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].id + 1)
        !           211:             % vq[VQ_RX].size;
        !           212:        len = vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].len
        !           213:              - sizeof(struct virtio_net_hdr);
        !           214: 
        !           215:        dprintk("virtionet_receive() last_rx_idx=%i, vq[VQ_RX].used->idx=%i,"
        !           216:                " id=%i len=%i\n", last_rx_idx, vq[VQ_RX].used->idx, id, len);
        !           217: 
        !           218:        if (len > maxlen) {
        !           219:                printk("virtio-net: Receive buffer not big enough!\n");
        !           220:                len = maxlen;
        !           221:        }
        !           222: 
        !           223: #if 0
        !           224:        /* Dump packet */
        !           225:        printk("\n");
        !           226:        int i;
        !           227:        for (i=0; i<64; i++) {
        !           228:                printk(" %02x", *(uint8_t*)(vq[VQ_RX].desc[id].addr+i));
        !           229:                if ((i%16)==15)
        !           230:                        printk("\n");
        !           231:        }
        !           232:        printk("\n");
        !           233: #endif
        !           234: 
        !           235:        /* Copy data to destination buffer */
        !           236:        memcpy(buf, (void*)vq[VQ_RX].desc[id].addr, len);
        !           237: 
        !           238:        /* Move indices to next entries */
        !           239:        last_rx_idx = last_rx_idx + 1;
        !           240: 
        !           241:        vq[VQ_RX].avail->ring[vq[VQ_RX].avail->idx % vq[VQ_RX].size] = id - 1;
        !           242:        sync();
        !           243:        vq[VQ_RX].avail->idx += 1;
        !           244: 
        !           245:        /* Tell HV that RX queue entry is ready */
        !           246:        virtio_queue_notify(&virtiodev, VQ_RX);
        !           247: 
        !           248:        return len;
        !           249: }
        !           250: 
        !           251: 
        !           252: /**
        !           253:  * Network IO control function - not implemented.
        !           254:  */
        !           255: static int virtionet_ioctl(int request, void* data)
        !           256: {
        !           257:        dprintk("virtionet_ioctl()\n");
        !           258: 
        !           259:        return -1;
        !           260: }
        !           261: 
        !           262: 
        !           263: /**
        !           264:  * Module definition
        !           265:  */
        !           266: snk_module_t virtionet_interface = {
        !           267:        .version = 1,
        !           268:        .type    = MOD_TYPE_NETWORK,
        !           269:        .running = 0,
        !           270:        .init    = virtionet_init,
        !           271:        .term    = virtionet_term,
        !           272:        .write   = virtionet_xmit,
        !           273:        .read    = virtionet_receive,
        !           274:        .ioctl   = virtionet_ioctl
        !           275: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.