qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

virtio-net.c (3676B)


      1 /*
      2  * Virtio-net driver for the s390-ccw firmware
      3  *
      4  * Copyright 2017 Thomas Huth, Red Hat Inc.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License as published by the
      8  * Free Software Foundation; either version 2 of the License, or (at your
      9  * option) any later version.
     10  */
     11 
     12 #include <stdint.h>
     13 #include <stdbool.h>
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 #include <unistd.h>
     18 #include <sys/socket.h>
     19 #include <ethernet.h>
     20 #include "s390-ccw.h"
     21 #include "virtio.h"
     22 #include "s390-time.h"
     23 #include "helper.h"
     24 
     25 #ifndef DEBUG_VIRTIO_NET
     26 #define DEBUG_VIRTIO_NET 0
     27 #endif
     28 
     29 #define VIRTIO_NET_F_MAC_BIT  (1 << 5)
     30 
     31 #define VQ_RX 0         /* Receive queue */
     32 #define VQ_TX 1         /* Transmit queue */
     33 
     34 struct VirtioNetHdr {
     35     uint8_t flags;
     36     uint8_t gso_type;
     37     uint16_t hdr_len;
     38     uint16_t gso_size;
     39     uint16_t csum_start;
     40     uint16_t csum_offset;
     41     /*uint16_t num_buffers;*/ /* Only with VIRTIO_NET_F_MRG_RXBUF or VIRTIO1 */
     42 };
     43 typedef struct VirtioNetHdr VirtioNetHdr;
     44 
     45 static uint16_t rx_last_idx;  /* Last index in receive queue "used" ring */
     46 
     47 int virtio_net_init(void *mac_addr)
     48 {
     49     VDev *vdev = virtio_get_device();
     50     VRing *rxvq = &vdev->vrings[VQ_RX];
     51     void *buf;
     52     int i;
     53 
     54     vdev->guest_features[0] = VIRTIO_NET_F_MAC_BIT;
     55     virtio_setup_ccw(vdev);
     56 
     57     IPL_assert(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT,
     58                "virtio-net device does not support the MAC address feature");
     59     memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN);
     60 
     61     for (i = 0; i < 64; i++) {
     62         buf = malloc(ETH_MTU_SIZE + sizeof(VirtioNetHdr));
     63         IPL_assert(buf != NULL, "Can not allocate memory for receive buffers");
     64         vring_send_buf(rxvq, buf, ETH_MTU_SIZE + sizeof(VirtioNetHdr),
     65                        VRING_DESC_F_WRITE);
     66     }
     67     vring_notify(rxvq);
     68 
     69     return 0;
     70 }
     71 
     72 int send(int fd, const void *buf, int len, int flags)
     73 {
     74     VirtioNetHdr tx_hdr;
     75     VDev *vdev = virtio_get_device();
     76     VRing *txvq = &vdev->vrings[VQ_TX];
     77 
     78     /* Set up header - we do not use anything special, so simply clear it */
     79     memset(&tx_hdr, 0, sizeof(tx_hdr));
     80 
     81     vring_send_buf(txvq, &tx_hdr, sizeof(tx_hdr), VRING_DESC_F_NEXT);
     82     vring_send_buf(txvq, (void *)buf, len, VRING_HIDDEN_IS_CHAIN);
     83     while (!vr_poll(txvq)) {
     84         yield();
     85     }
     86     if (drain_irqs(txvq->schid)) {
     87         puts("send: drain irqs failed");
     88         return -1;
     89     }
     90 
     91     return len;
     92 }
     93 
     94 int recv(int fd, void *buf, int maxlen, int flags)
     95 {
     96     VDev *vdev = virtio_get_device();
     97     VRing *rxvq = &vdev->vrings[VQ_RX];
     98     int len, id;
     99     uint8_t *pkt;
    100 
    101     if (rx_last_idx == rxvq->used->idx) {
    102         return 0;
    103     }
    104 
    105     len = rxvq->used->ring[rx_last_idx % rxvq->num].len - sizeof(VirtioNetHdr);
    106     if (len > maxlen) {
    107         puts("virtio-net: Receive buffer too small");
    108         len = maxlen;
    109     }
    110     id = rxvq->used->ring[rx_last_idx % rxvq->num].id % rxvq->num;
    111     pkt = (uint8_t *)(rxvq->desc[id].addr + sizeof(VirtioNetHdr));
    112 
    113 #if DEBUG_VIRTIO_NET   /* Dump packet */
    114     int i;
    115     printf("\nbuf %p: len=%i\n", (void *)rxvq->desc[id].addr, len);
    116     for (i = 0; i < 64; i++) {
    117         printf(" %02x", pkt[i]);
    118         if ((i % 16) == 15) {
    119             printf("\n");
    120         }
    121     }
    122     printf("\n");
    123 #endif
    124 
    125     /* Copy data to destination buffer */
    126     memcpy(buf, pkt, len);
    127 
    128     /* Mark buffer as available to the host again */
    129     rxvq->avail->ring[rxvq->avail->idx % rxvq->num] = id;
    130     rxvq->avail->idx = rxvq->avail->idx + 1;
    131     vring_notify(rxvq);
    132 
    133     /* Move index to next entry */
    134     rx_last_idx = rx_last_idx + 1;
    135 
    136     return len;
    137 }