X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=qemu%2Froms%2FSLOF%2Flib%2Flibvirtio%2Fvirtio-net.c;h=fc620a201b27199f65a8344528771922864057fe;hb=a14b48d18a9ed03ec191cf16b162206998a895ce;hp=99c19d952d4a48dd762aaa65693cb4b4a81ab396;hpb=e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb;p=kvmfornfv.git diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-net.c b/qemu/roms/SLOF/lib/libvirtio/virtio-net.c index 99c19d952..fc620a201 100644 --- a/qemu/roms/SLOF/lib/libvirtio/virtio-net.c +++ b/qemu/roms/SLOF/lib/libvirtio/virtio-net.c @@ -26,6 +26,7 @@ #include #include "virtio.h" #include "virtio-net.h" +#include "virtio-internal.h" #undef DEBUG //#define DEBUG @@ -37,22 +38,13 @@ #define sync() asm volatile (" sync \n" ::: "memory") -/* PCI virtio header offsets */ -#define VIRTIOHDR_DEVICE_FEATURES 0 -#define VIRTIOHDR_GUEST_FEATURES 4 -#define VIRTIOHDR_QUEUE_ADDRESS 8 -#define VIRTIOHDR_QUEUE_SIZE 12 -#define VIRTIOHDR_QUEUE_SELECT 14 -#define VIRTIOHDR_QUEUE_NOTIFY 16 -#define VIRTIOHDR_DEVICE_STATUS 18 -#define VIRTIOHDR_ISR_STATUS 19 -#define VIRTIOHDR_DEVICE_CONFIG 20 -#define VIRTIOHDR_MAC_ADDRESS 20 +#define DRIVER_FEATURE_SUPPORT (VIRTIO_NET_F_MAC | VIRTIO_F_VERSION_1) struct virtio_device virtiodev; -struct vqs vq[2]; /* Information about virtqueues */ +static struct vqs vq_rx; /* Information about receive virtqueues */ +static struct vqs vq_tx; /* Information about transmit virtqueues */ -/* See Virtio Spec, appendix C, "Device Operation" */ +/* See Virtio Spec, appendix C, "Device Operation" */ struct virtio_net_hdr { uint8_t flags; uint8_t gso_type; @@ -63,6 +55,18 @@ struct virtio_net_hdr { // uint16_t num_buffers; /* Only if VIRTIO_NET_F_MRG_RXBUF */ }; +static unsigned int net_hdr_size; + +struct virtio_net_hdr_v1 { + uint8_t flags; + uint8_t gso_type; + le16 hdr_len; + le16 gso_size; + le16 csum_start; + le16 csum_offset; + le16 num_buffers; +}; + static uint16_t last_rx_idx; /* Last index in RX "used" ring */ /** @@ -72,15 +76,13 @@ static uint16_t last_rx_idx; /* Last index in RX "used" ring */ */ static int virtionet_init_pci(struct virtio_device *dev) { - int i; - dprintf("virtionet: doing virtionet_init_pci!\n"); if (!dev) return -1; - virtiodev.base = dev->base; - virtiodev.type = dev->type; + /* make a copy of the device structure */ + memcpy(&virtiodev, dev, sizeof(struct virtio_device)); /* Reset device */ virtio_reset_device(&virtiodev); @@ -90,29 +92,11 @@ static int virtionet_init_pci(struct virtio_device *dev) * second the transmit queue, and the forth is the control queue for * networking options. * We are only interested in the receive and transmit queue here. */ - - for (i=VQ_RX; i<=VQ_TX; i++) { - /* Select ring (0=RX, 1=TX): */ - vq[i].id = i-VQ_RX; - ci_write_16(virtiodev.base+VIRTIOHDR_QUEUE_SELECT, - cpu_to_le16(vq[i].id)); - - vq[i].size = le16_to_cpu(ci_read_16(virtiodev.base+VIRTIOHDR_QUEUE_SIZE)); - vq[i].desc = SLOF_alloc_mem_aligned(virtio_vring_size(vq[i].size), 4096); - if (!vq[i].desc) { - printf("memory allocation failed!\n"); - return -1; - } - memset(vq[i].desc, 0, virtio_vring_size(vq[i].size)); - ci_write_32(virtiodev.base+VIRTIOHDR_QUEUE_ADDRESS, - cpu_to_le32((long)vq[i].desc / 4096)); - vq[i].avail = (void*)vq[i].desc - + vq[i].size * sizeof(struct vring_desc); - vq[i].used = (void*)VQ_ALIGN((long)vq[i].avail - + vq[i].size * sizeof(struct vring_avail)); - - dprintf("%i: vq.id = %llx\nvq.size =%x\n vq.avail =%p\nvq.used=%p\n", - i, vq[i].id, vq[i].size, vq[i].avail, vq[i].used); + if (virtio_queue_init_vq(dev, &vq_rx, VQ_RX) || + virtio_queue_init_vq(dev, &vq_tx, VQ_TX)) { + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER + |VIRTIO_STAT_FAILED); + return -1; } /* Acknowledge device. */ @@ -129,6 +113,7 @@ static int virtionet_init_pci(struct virtio_device *dev) static int virtionet_init(net_driver_t *driver) { int i; + int status = VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER; dprintf("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n", driver->mac_addr[0], driver->mac_addr[1], @@ -139,60 +124,69 @@ static int virtionet_init(net_driver_t *driver) return 0; /* Tell HV that we know how to drive the device. */ - virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER); - - /* Device specific setup - we do not support special features right now */ - virtio_set_guest_features(&virtiodev, 0); + virtio_set_status(&virtiodev, status); + + /* Device specific setup */ + if (virtiodev.is_modern) { + if (virtio_negotiate_guest_features(&virtiodev, DRIVER_FEATURE_SUPPORT)) + goto dev_error; + net_hdr_size = sizeof(struct virtio_net_hdr_v1); + virtio_get_status(&virtiodev, &status); + } else { + net_hdr_size = sizeof(struct virtio_net_hdr); + virtio_set_guest_features(&virtiodev, 0); + } /* Allocate memory for one transmit an multiple receive buffers */ - vq[VQ_RX].buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr)) + vq_rx.buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+net_hdr_size) * RX_QUEUE_SIZE); - if (!vq[VQ_RX].buf_mem) { + if (!vq_rx.buf_mem) { printf("virtionet: Failed to allocate buffers!\n"); - virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED); - return -1; + goto dev_error; } /* Prepare receive buffer queue */ for (i = 0; i < RX_QUEUE_SIZE; i++) { - struct vring_desc *desc; + uint64_t addr = (uint64_t)vq_rx.buf_mem + + i * (BUFFER_ENTRY_SIZE+net_hdr_size); + uint32_t id = i*2; /* Descriptor for net_hdr: */ - desc = &vq[VQ_RX].desc[i*2]; - desc->addr = (uint64_t)vq[VQ_RX].buf_mem - + i * (BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr)); - desc->len = sizeof(struct virtio_net_hdr); - desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE; - desc->next = i*2+1; + virtio_fill_desc(&vq_rx.desc[id], virtiodev.is_modern, addr, net_hdr_size, + VRING_DESC_F_NEXT | VRING_DESC_F_WRITE, id + 1); /* Descriptor for data: */ - desc = &vq[VQ_RX].desc[i*2+1]; - desc->addr = vq[VQ_RX].desc[i*2].addr + sizeof(struct virtio_net_hdr); - desc->len = BUFFER_ENTRY_SIZE; - desc->flags = VRING_DESC_F_WRITE; - desc->next = 0; + virtio_fill_desc(&vq_rx.desc[id+1], virtiodev.is_modern, addr + net_hdr_size, + BUFFER_ENTRY_SIZE, VRING_DESC_F_WRITE, 0); - vq[VQ_RX].avail->ring[i] = i*2; + vq_rx.avail->ring[i] = virtio_cpu_to_modern16(&virtiodev, id); } sync(); - vq[VQ_RX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT; - vq[VQ_RX].avail->idx = RX_QUEUE_SIZE; - last_rx_idx = vq[VQ_RX].used->idx; + vq_rx.avail->flags = virtio_cpu_to_modern16(&virtiodev, VRING_AVAIL_F_NO_INTERRUPT); + vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, RX_QUEUE_SIZE); + + last_rx_idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx); - vq[VQ_TX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT; - vq[VQ_TX].avail->idx = 0; + vq_tx.avail->flags = virtio_cpu_to_modern16(&virtiodev, VRING_AVAIL_F_NO_INTERRUPT); + vq_tx.avail->idx = 0; /* Tell HV that setup succeeded */ - virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE - |VIRTIO_STAT_DRIVER - |VIRTIO_STAT_DRIVER_OK); + status |= VIRTIO_STAT_DRIVER_OK; + virtio_set_status(&virtiodev, status); /* Tell HV that RX queues are ready */ virtio_queue_notify(&virtiodev, VQ_RX); driver->running = 1; - + for(i = 0; i < (int)sizeof(driver->mac_addr); i++) { + driver->mac_addr[i] = virtio_get_config(&virtiodev, i, 1); + } return 0; + +dev_error: + status |= VIRTIO_STAT_FAILED; + virtio_set_status(&virtiodev, status); + return -1; } @@ -225,9 +219,10 @@ static int virtionet_term(net_driver_t *driver) */ static int virtionet_xmit(char *buf, int len) { - struct vring_desc *desc; - int id; - static struct virtio_net_hdr nethdr; + int id, idx; + static struct virtio_net_hdr_v1 nethdr_v1; + static struct virtio_net_hdr nethdr_legacy; + void *nethdr = &nethdr_legacy; if (len > BUFFER_ENTRY_SIZE) { printf("virtionet: Packet too big!\n"); @@ -236,28 +231,25 @@ static int virtionet_xmit(char *buf, int len) dprintf("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len); - memset(&nethdr, 0, sizeof(nethdr)); + if (virtiodev.is_modern) + nethdr = &nethdr_v1; + + memset(nethdr, 0, net_hdr_size); /* Determine descriptor index */ - id = (vq[VQ_TX].avail->idx * 2) % vq[VQ_TX].size; + idx = virtio_modern16_to_cpu(&virtiodev, vq_tx.avail->idx); + id = (idx * 2) % vq_tx.size; /* Set up virtqueue descriptor for header */ - desc = &vq[VQ_TX].desc[id]; - desc->addr = (uint64_t)&nethdr; - desc->len = sizeof(struct virtio_net_hdr); - desc->flags = VRING_DESC_F_NEXT; - desc->next = id + 1; + virtio_fill_desc(&vq_tx.desc[id], virtiodev.is_modern, (uint64_t)nethdr, + net_hdr_size, VRING_DESC_F_NEXT, id + 1); /* Set up virtqueue descriptor for data */ - desc = &vq[VQ_TX].desc[id+1]; - desc->addr = (uint64_t)buf; - desc->len = len; - desc->flags = 0; - desc->next = 0; + virtio_fill_desc(&vq_tx.desc[id+1], virtiodev.is_modern, (uint64_t)buf, len, 0, 0); - vq[VQ_TX].avail->ring[vq[VQ_TX].avail->idx % vq[VQ_TX].size] = id; + vq_tx.avail->ring[idx % vq_tx.size] = virtio_cpu_to_modern16(&virtiodev, id); sync(); - vq[VQ_TX].avail->idx += 1; + vq_tx.avail->idx = virtio_cpu_to_modern16(&virtiodev, idx + 1); sync(); /* Tell HV that TX queue is ready */ @@ -272,23 +264,24 @@ static int virtionet_xmit(char *buf, int len) */ static int virtionet_receive(char *buf, int maxlen) { - int len = 0; - int id; + uint32_t len = 0; + uint32_t id, idx; - if (last_rx_idx == vq[VQ_RX].used->idx) { + idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx); + + if (last_rx_idx == idx) { /* Nothing received yet */ return 0; } - id = (vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].id + 1) - % vq[VQ_RX].size; - len = vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].len - - sizeof(struct virtio_net_hdr); - - dprintf("virtionet_receive() last_rx_idx=%i, vq[VQ_RX].used->idx=%i," - " id=%i len=%i\n", last_rx_idx, vq[VQ_RX].used->idx, id, len); + id = (virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].id) + 1) + % vq_rx.size; + len = virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].len) + - net_hdr_size; + dprintf("virtionet_receive() last_rx_idx=%i, vq_rx.used->idx=%i," + " id=%i len=%i\n", last_rx_idx, vq_rx.used->idx, id, len); - if (len > maxlen) { + if (len > (uint32_t)maxlen) { printf("virtio-net: Receive buffer not big enough!\n"); len = maxlen; } @@ -298,7 +291,7 @@ static int virtionet_receive(char *buf, int maxlen) printf("\n"); int i; for (i=0; i<64; i++) { - printf(" %02x", *(uint8_t*)(vq[VQ_RX].desc[id].addr+i)); + printf(" %02x", *(uint8_t*)(vq_rx.desc[id].addr+i)); if ((i%16)==15) printf("\n"); } @@ -306,14 +299,14 @@ static int virtionet_receive(char *buf, int maxlen) #endif /* Copy data to destination buffer */ - memcpy(buf, (void*)vq[VQ_RX].desc[id].addr, len); + memcpy(buf, (void *)virtio_modern64_to_cpu(&virtiodev, vq_rx.desc[id].addr), len); /* Move indices to next entries */ last_rx_idx = last_rx_idx + 1; - vq[VQ_RX].avail->ring[vq[VQ_RX].avail->idx % vq[VQ_RX].size] = id - 1; + vq_rx.avail->ring[idx % vq_rx.size] = virtio_cpu_to_modern16(&virtiodev, id - 1); sync(); - vq[VQ_RX].avail->idx += 1; + vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, idx + 1); /* Tell HV that RX queue entry is ready */ virtio_queue_notify(&virtiodev, VQ_RX); @@ -321,7 +314,7 @@ static int virtionet_receive(char *buf, int maxlen) return len; } -net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev) +net_driver_t *virtionet_open(struct virtio_device *dev) { net_driver_t *driver; @@ -331,7 +324,6 @@ net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev) return NULL; } - memcpy(driver->mac_addr, mac_addr, 6); driver->running = 0; if (virtionet_init_pci(dev))