Message ID | 1499423224-23060-8-git-send-email-thuth@redhat.com |
---|---|
State | New |
Headers | show |
On Fri, 7 Jul 2017 12:27:03 +0200 Thomas Huth <thuth@redhat.com> wrote: > The driver provides the recv() and send() functions which will > be required by SLOF's libnet code for receiving and sending > packets. No thorough review yet, only some things I noticed. > > Signed-off-by: Thomas Huth <thuth@redhat.com> > --- > pc-bios/s390-ccw/netboot.mak | 2 +- > pc-bios/s390-ccw/virtio-net.c | 130 ++++++++++++++++++++++++++++++++++++++++++ > pc-bios/s390-ccw/virtio.c | 9 ++- > pc-bios/s390-ccw/virtio.h | 13 ++++- > 4 files changed, 149 insertions(+), 5 deletions(-) > create mode 100644 pc-bios/s390-ccw/virtio-net.c > > diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c > new file mode 100644 > index 0000000..290b018 > --- /dev/null > +++ b/pc-bios/s390-ccw/virtio-net.c > @@ -0,0 +1,130 @@ > +/* > + * Virtio-net driver for the s390-ccw firmware > + * > + * Copyright 2017 Thomas Huth, Red Hat Inc. > + * > + * This code is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + */ > + > +#include <stdint.h> > +#include <stdbool.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <sys/socket.h> > +#include <ethernet.h> > +#include "s390-ccw.h" > +#include "virtio.h" > + > +#ifndef DEBUG_VIRTIO_NET > +#define DEBUG_VIRTIO_NET 0 > +#endif > + > +#define VQ_RX 0 /* Receive queue */ > +#define VQ_TX 1 /* Transmit queue */ > + > +struct VirtioNetHdr { > + uint8_t flags; > + uint8_t gso_type; > + uint16_t hdr_len; > + uint16_t gso_size; > + uint16_t csum_start; > + uint16_t csum_offset; > + /*uint16_t num_buffers;*/ /* Only with VIRTIO_NET_F_MRG_RXBUF or VIRTIO1 */ > +}; > +typedef struct VirtioNetHdr VirtioNetHdr; > + > +static uint16_t rx_last_idx; /* Last index in receive queue "used" ring */ > + > +int virtio_net_init(void *mac_addr) > +{ > + VDev *vdev = virtio_get_device(); > + VRing *rxvq = &vdev->vrings[VQ_RX]; > + void *buf; > + int i; > + > + virtio_setup_ccw(vdev); > + > + memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN); The mac address in the config space is only valid if the mac feature flag has been negotiated (although the field always exists). > + > + for (i = 0; i < 64; i++) { > + buf = malloc(ETH_MTU_SIZE + sizeof(VirtioNetHdr)); > + IPL_assert(buf != NULL, "Can not allocate memory for receive buffers"); > + vring_send_buf(rxvq, buf, ETH_MTU_SIZE + sizeof(VirtioNetHdr), > + VRING_DESC_F_WRITE); > + } > + vring_notify(rxvq); > + > + return 0; > +} > + > +int send(int fd, const void *buf, int len, int flags) > +{ > + VirtioNetHdr tx_hdr; > + VDev *vdev = virtio_get_device(); > + VRing *txvq = &vdev->vrings[VQ_TX]; > + > + /* Set up header - we do not use anything special, so simply clear it */ > + memset(&tx_hdr, 0, sizeof(tx_hdr)); > + > + vring_send_buf(txvq, &tx_hdr, sizeof(tx_hdr), VRING_DESC_F_NEXT); > + vring_send_buf(txvq, (void *)buf, len, VRING_HIDDEN_IS_CHAIN); > + while (!vr_poll(txvq)) { > + yield(); > + } > + if (drain_irqs(txvq->schid)) { > + puts("send: drain irqs failed"); > + return -1; Does the caller try again later? drain_irqs() errors may be transient. > + } > + > + return len; > +} > + > +int recv(int fd, void *buf, int maxlen, int flags) > +{ > + VDev *vdev = virtio_get_device(); > + VRing *rxvq = &vdev->vrings[VQ_RX]; > + int len, id; > + uint8_t *pkt; > + > + if (rx_last_idx == rxvq->used->idx) { > + return 0; > + } > + > + len = rxvq->used->ring[rx_last_idx % rxvq->num].len - sizeof(VirtioNetHdr); > + if (len > maxlen) { > + puts("virtio-net: Receive buffer too small"); > + len = maxlen; > + } > + id = rxvq->used->ring[rx_last_idx % rxvq->num].id % rxvq->num; > + pkt = (uint8_t *)(rxvq->desc[id].addr + sizeof(VirtioNetHdr)); > + > +#if DEBUG_VIRTIO_NET /* Dump packet */ > + int i; > + printf("\nbuf %p: len=%i\n", (void *)rxvq->desc[id].addr, len); > + for (i = 0; i < 64; i++) { > + printf(" %02x", pkt[i]); > + if ((i % 16) == 15) { > + printf("\n"); > + } > + } > + printf("\n"); > +#endif > + > + /* Copy data to destination buffer */ > + memcpy(buf, pkt, len); > + > + /* Mark buffer as available to the host again */ > + rxvq->avail->ring[rxvq->avail->idx % rxvq->num] = id; > + rxvq->avail->idx = rxvq->avail->idx + 1; > + vring_notify(rxvq); > + > + /* Move index to next entry */ > + rx_last_idx = rx_last_idx + 1; > + > + return len; > +} > diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c > index 09ab291..729d926 100644 > --- a/pc-bios/s390-ccw/virtio.c > +++ b/pc-bios/s390-ccw/virtio.c > @@ -149,7 +149,7 @@ static void vring_init(VRing *vr, VqInfo *info) > debug_print_addr("init vr", vr); > } > > -static bool vring_notify(VRing *vr) > +bool vring_notify(VRing *vr) > { > vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie); > return vr->cookie >= 0; > @@ -188,7 +188,7 @@ ulong get_second(void) > return (get_clock() >> 12) / 1000000; > } > > -static int vr_poll(VRing *vr) > +int vr_poll(VRing *vr) > { > if (vr->used->idx == vr->used_idx) { > vring_notify(vr); > @@ -261,6 +261,11 @@ void virtio_setup_ccw(VDev *vdev) > run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0); > > switch (vdev->senseid.cu_model) { > + case VIRTIO_ID_NET: > + vdev->nr_vqs = 3; I think this should be 2, as you don't negotiate for the control vq. > + vdev->cmd_vr_idx = 0; > + cfg_size = sizeof(vdev->config.net); > + break; > case VIRTIO_ID_BLOCK: > vdev->nr_vqs = 1; > vdev->cmd_vr_idx = 0; > diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h > index d743919..d6af022 100644 > --- a/pc-bios/s390-ccw/virtio.h > +++ b/pc-bios/s390-ccw/virtio.h > @@ -11,8 +11,6 @@ > #ifndef VIRTIO_H > #define VIRTIO_H > > -#include "s390-ccw.h" > - > /* Status byte for guest to report progress, and synchronize features. */ > /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ > #define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 > @@ -254,6 +252,12 @@ struct ScsiDevice { > }; > typedef struct ScsiDevice ScsiDevice; > > +struct VirtioNetConfig { > + uint8_t mac[6]; > + uint16_t status; I don't think status exists if you don't negotiate the respective feature bit. > +}; > +typedef struct VirtioNetConfig VirtioNetConfig; > + > struct VDev { > int nr_vqs; > VRing *vrings; > @@ -266,6 +270,7 @@ struct VDev { > union { > VirtioBlkConfig blk; > VirtioScsiConfig scsi; > + VirtioNetConfig net; > } config; > ScsiDevice *scsi_device; > bool is_cdrom; > @@ -291,10 +296,14 @@ struct VirtioCmd { > }; > typedef struct VirtioCmd VirtioCmd; > > +bool vring_notify(VRing *vr); > int drain_irqs(SubChannelId schid); > void vring_send_buf(VRing *vr, void *p, int len, int flags); > +int vr_poll(VRing *vr); > int vring_wait_reply(void); > int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd); > void virtio_setup_ccw(VDev *vdev); > > +int virtio_net_init(void *mac_addr); > + > #endif /* VIRTIO_H */
On 07.07.2017 14:37, Cornelia Huck wrote: > On Fri, 7 Jul 2017 12:27:03 +0200 > Thomas Huth <thuth@redhat.com> wrote: > >> The driver provides the recv() and send() functions which will >> be required by SLOF's libnet code for receiving and sending >> packets. [...] >> +int virtio_net_init(void *mac_addr) >> +{ >> + VDev *vdev = virtio_get_device(); >> + VRing *rxvq = &vdev->vrings[VQ_RX]; >> + void *buf; >> + int i; >> + >> + virtio_setup_ccw(vdev); >> + >> + memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN); > > The mac address in the config space is only valid if the mac feature > flag has been negotiated (although the field always exists). QEMU seems to always set it ... but yes, let's better negotiate VIRTIO_NET_F_MAC here. >> + >> + for (i = 0; i < 64; i++) { >> + buf = malloc(ETH_MTU_SIZE + sizeof(VirtioNetHdr)); >> + IPL_assert(buf != NULL, "Can not allocate memory for receive buffers"); >> + vring_send_buf(rxvq, buf, ETH_MTU_SIZE + sizeof(VirtioNetHdr), >> + VRING_DESC_F_WRITE); >> + } >> + vring_notify(rxvq); >> + >> + return 0; >> +} >> + >> +int send(int fd, const void *buf, int len, int flags) >> +{ >> + VirtioNetHdr tx_hdr; >> + VDev *vdev = virtio_get_device(); >> + VRing *txvq = &vdev->vrings[VQ_TX]; >> + >> + /* Set up header - we do not use anything special, so simply clear it */ >> + memset(&tx_hdr, 0, sizeof(tx_hdr)); >> + >> + vring_send_buf(txvq, &tx_hdr, sizeof(tx_hdr), VRING_DESC_F_NEXT); >> + vring_send_buf(txvq, (void *)buf, len, VRING_HIDDEN_IS_CHAIN); >> + while (!vr_poll(txvq)) { >> + yield(); >> + } >> + if (drain_irqs(txvq->schid)) { >> + puts("send: drain irqs failed"); >> + return -1; > > Does the caller try again later? drain_irqs() errors may be transient. Yes, the TFTP code retries to send packets after a certain amount of time (since the packets could also be lost in the network somewhere). >> diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c >> index 09ab291..729d926 100644 >> --- a/pc-bios/s390-ccw/virtio.c >> +++ b/pc-bios/s390-ccw/virtio.c >> @@ -149,7 +149,7 @@ static void vring_init(VRing *vr, VqInfo *info) >> debug_print_addr("init vr", vr); >> } >> >> -static bool vring_notify(VRing *vr) >> +bool vring_notify(VRing *vr) >> { >> vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie); >> return vr->cookie >= 0; >> @@ -188,7 +188,7 @@ ulong get_second(void) >> return (get_clock() >> 12) / 1000000; >> } >> >> -static int vr_poll(VRing *vr) >> +int vr_poll(VRing *vr) >> { >> if (vr->used->idx == vr->used_idx) { >> vring_notify(vr); >> @@ -261,6 +261,11 @@ void virtio_setup_ccw(VDev *vdev) >> run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0); >> >> switch (vdev->senseid.cu_model) { >> + case VIRTIO_ID_NET: >> + vdev->nr_vqs = 3; > > I think this should be 2, as you don't negotiate for the control vq. OK. >> + vdev->cmd_vr_idx = 0; >> + cfg_size = sizeof(vdev->config.net); >> + break; >> case VIRTIO_ID_BLOCK: >> vdev->nr_vqs = 1; >> vdev->cmd_vr_idx = 0; >> diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h >> index d743919..d6af022 100644 >> --- a/pc-bios/s390-ccw/virtio.h >> +++ b/pc-bios/s390-ccw/virtio.h >> @@ -11,8 +11,6 @@ >> #ifndef VIRTIO_H >> #define VIRTIO_H >> >> -#include "s390-ccw.h" >> - >> /* Status byte for guest to report progress, and synchronize features. */ >> /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ >> #define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 >> @@ -254,6 +252,12 @@ struct ScsiDevice { >> }; >> typedef struct ScsiDevice ScsiDevice; >> >> +struct VirtioNetConfig { >> + uint8_t mac[6]; >> + uint16_t status; > > I don't think status exists if you don't negotiate the respective > feature bit. OK. >> +}; >> +typedef struct VirtioNetConfig VirtioNetConfig; >> + >> struct VDev { >> int nr_vqs; >> VRing *vrings; >> @@ -266,6 +270,7 @@ struct VDev { >> union { >> VirtioBlkConfig blk; >> VirtioScsiConfig scsi; >> + VirtioNetConfig net; >> } config; >> ScsiDevice *scsi_device; >> bool is_cdrom; >> @@ -291,10 +296,14 @@ struct VirtioCmd { >> }; >> typedef struct VirtioCmd VirtioCmd; >> >> +bool vring_notify(VRing *vr); >> int drain_irqs(SubChannelId schid); >> void vring_send_buf(VRing *vr, void *p, int len, int flags); >> +int vr_poll(VRing *vr); >> int vring_wait_reply(void); >> int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd); >> void virtio_setup_ccw(VDev *vdev); >> >> +int virtio_net_init(void *mac_addr); >> + >> #endif /* VIRTIO_H */ > Thanks for the review! Thomas
On Mon, 10 Jul 2017 13:23:07 +0200 Thomas Huth <thuth@redhat.com> wrote: > On 07.07.2017 14:37, Cornelia Huck wrote: > > On Fri, 7 Jul 2017 12:27:03 +0200 > > Thomas Huth <thuth@redhat.com> wrote: > > > >> The driver provides the recv() and send() functions which will > >> be required by SLOF's libnet code for receiving and sending > >> packets. > [...] > >> +int virtio_net_init(void *mac_addr) > >> +{ > >> + VDev *vdev = virtio_get_device(); > >> + VRing *rxvq = &vdev->vrings[VQ_RX]; > >> + void *buf; > >> + int i; > >> + > >> + virtio_setup_ccw(vdev); > >> + > >> + memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN); > > > > The mac address in the config space is only valid if the mac feature > > flag has been negotiated (although the field always exists). > > QEMU seems to always set it ... but yes, let's better negotiate > VIRTIO_NET_F_MAC here. Ah, feature negotiation in the bios, nice :) > > >> + > >> + for (i = 0; i < 64; i++) { > >> + buf = malloc(ETH_MTU_SIZE + sizeof(VirtioNetHdr)); > >> + IPL_assert(buf != NULL, "Can not allocate memory for receive buffers"); > >> + vring_send_buf(rxvq, buf, ETH_MTU_SIZE + sizeof(VirtioNetHdr), > >> + VRING_DESC_F_WRITE); > >> + } > >> + vring_notify(rxvq); > >> + > >> + return 0; > >> +} > >> + > >> +int send(int fd, const void *buf, int len, int flags) > >> +{ > >> + VirtioNetHdr tx_hdr; > >> + VDev *vdev = virtio_get_device(); > >> + VRing *txvq = &vdev->vrings[VQ_TX]; > >> + > >> + /* Set up header - we do not use anything special, so simply clear it */ > >> + memset(&tx_hdr, 0, sizeof(tx_hdr)); > >> + > >> + vring_send_buf(txvq, &tx_hdr, sizeof(tx_hdr), VRING_DESC_F_NEXT); > >> + vring_send_buf(txvq, (void *)buf, len, VRING_HIDDEN_IS_CHAIN); > >> + while (!vr_poll(txvq)) { > >> + yield(); > >> + } > >> + if (drain_irqs(txvq->schid)) { > >> + puts("send: drain irqs failed"); > >> + return -1; > > > > Does the caller try again later? drain_irqs() errors may be transient. > > Yes, the TFTP code retries to send packets after a certain amount of > time (since the packets could also be lost in the network somewhere). Sounds good. (Not that I expect many errors in drain_irqs()...)
diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak index 1eaa0d8..dd9119a 100644 --- a/pc-bios/s390-ccw/netboot.mak +++ b/pc-bios/s390-ccw/netboot.mak @@ -1,7 +1,7 @@ SLOF_DIR := $(SRC_PATH)/roms/SLOF -NETOBJS := start.o sclp.o virtio.o netmain.o sbrk.o libc.a +NETOBJS := start.o sclp.o virtio.o virtio-net.o netmain.o sbrk.o libc.a LIBC_INC := -I$(SLOF_DIR)/lib/libc/include LIBNET_INC := -I$(SLOF_DIR)/lib/libnet diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c new file mode 100644 index 0000000..290b018 --- /dev/null +++ b/pc-bios/s390-ccw/virtio-net.c @@ -0,0 +1,130 @@ +/* + * Virtio-net driver for the s390-ccw firmware + * + * Copyright 2017 Thomas Huth, Red Hat Inc. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <ethernet.h> +#include "s390-ccw.h" +#include "virtio.h" + +#ifndef DEBUG_VIRTIO_NET +#define DEBUG_VIRTIO_NET 0 +#endif + +#define VQ_RX 0 /* Receive queue */ +#define VQ_TX 1 /* Transmit queue */ + +struct VirtioNetHdr { + uint8_t flags; + uint8_t gso_type; + uint16_t hdr_len; + uint16_t gso_size; + uint16_t csum_start; + uint16_t csum_offset; + /*uint16_t num_buffers;*/ /* Only with VIRTIO_NET_F_MRG_RXBUF or VIRTIO1 */ +}; +typedef struct VirtioNetHdr VirtioNetHdr; + +static uint16_t rx_last_idx; /* Last index in receive queue "used" ring */ + +int virtio_net_init(void *mac_addr) +{ + VDev *vdev = virtio_get_device(); + VRing *rxvq = &vdev->vrings[VQ_RX]; + void *buf; + int i; + + virtio_setup_ccw(vdev); + + memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN); + + for (i = 0; i < 64; i++) { + buf = malloc(ETH_MTU_SIZE + sizeof(VirtioNetHdr)); + IPL_assert(buf != NULL, "Can not allocate memory for receive buffers"); + vring_send_buf(rxvq, buf, ETH_MTU_SIZE + sizeof(VirtioNetHdr), + VRING_DESC_F_WRITE); + } + vring_notify(rxvq); + + return 0; +} + +int send(int fd, const void *buf, int len, int flags) +{ + VirtioNetHdr tx_hdr; + VDev *vdev = virtio_get_device(); + VRing *txvq = &vdev->vrings[VQ_TX]; + + /* Set up header - we do not use anything special, so simply clear it */ + memset(&tx_hdr, 0, sizeof(tx_hdr)); + + vring_send_buf(txvq, &tx_hdr, sizeof(tx_hdr), VRING_DESC_F_NEXT); + vring_send_buf(txvq, (void *)buf, len, VRING_HIDDEN_IS_CHAIN); + while (!vr_poll(txvq)) { + yield(); + } + if (drain_irqs(txvq->schid)) { + puts("send: drain irqs failed"); + return -1; + } + + return len; +} + +int recv(int fd, void *buf, int maxlen, int flags) +{ + VDev *vdev = virtio_get_device(); + VRing *rxvq = &vdev->vrings[VQ_RX]; + int len, id; + uint8_t *pkt; + + if (rx_last_idx == rxvq->used->idx) { + return 0; + } + + len = rxvq->used->ring[rx_last_idx % rxvq->num].len - sizeof(VirtioNetHdr); + if (len > maxlen) { + puts("virtio-net: Receive buffer too small"); + len = maxlen; + } + id = rxvq->used->ring[rx_last_idx % rxvq->num].id % rxvq->num; + pkt = (uint8_t *)(rxvq->desc[id].addr + sizeof(VirtioNetHdr)); + +#if DEBUG_VIRTIO_NET /* Dump packet */ + int i; + printf("\nbuf %p: len=%i\n", (void *)rxvq->desc[id].addr, len); + for (i = 0; i < 64; i++) { + printf(" %02x", pkt[i]); + if ((i % 16) == 15) { + printf("\n"); + } + } + printf("\n"); +#endif + + /* Copy data to destination buffer */ + memcpy(buf, pkt, len); + + /* Mark buffer as available to the host again */ + rxvq->avail->ring[rxvq->avail->idx % rxvq->num] = id; + rxvq->avail->idx = rxvq->avail->idx + 1; + vring_notify(rxvq); + + /* Move index to next entry */ + rx_last_idx = rx_last_idx + 1; + + return len; +} diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index 09ab291..729d926 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -149,7 +149,7 @@ static void vring_init(VRing *vr, VqInfo *info) debug_print_addr("init vr", vr); } -static bool vring_notify(VRing *vr) +bool vring_notify(VRing *vr) { vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie); return vr->cookie >= 0; @@ -188,7 +188,7 @@ ulong get_second(void) return (get_clock() >> 12) / 1000000; } -static int vr_poll(VRing *vr) +int vr_poll(VRing *vr) { if (vr->used->idx == vr->used_idx) { vring_notify(vr); @@ -261,6 +261,11 @@ void virtio_setup_ccw(VDev *vdev) run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0); switch (vdev->senseid.cu_model) { + case VIRTIO_ID_NET: + vdev->nr_vqs = 3; + vdev->cmd_vr_idx = 0; + cfg_size = sizeof(vdev->config.net); + break; case VIRTIO_ID_BLOCK: vdev->nr_vqs = 1; vdev->cmd_vr_idx = 0; diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h index d743919..d6af022 100644 --- a/pc-bios/s390-ccw/virtio.h +++ b/pc-bios/s390-ccw/virtio.h @@ -11,8 +11,6 @@ #ifndef VIRTIO_H #define VIRTIO_H -#include "s390-ccw.h" - /* Status byte for guest to report progress, and synchronize features. */ /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ #define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 @@ -254,6 +252,12 @@ struct ScsiDevice { }; typedef struct ScsiDevice ScsiDevice; +struct VirtioNetConfig { + uint8_t mac[6]; + uint16_t status; +}; +typedef struct VirtioNetConfig VirtioNetConfig; + struct VDev { int nr_vqs; VRing *vrings; @@ -266,6 +270,7 @@ struct VDev { union { VirtioBlkConfig blk; VirtioScsiConfig scsi; + VirtioNetConfig net; } config; ScsiDevice *scsi_device; bool is_cdrom; @@ -291,10 +296,14 @@ struct VirtioCmd { }; typedef struct VirtioCmd VirtioCmd; +bool vring_notify(VRing *vr); int drain_irqs(SubChannelId schid); void vring_send_buf(VRing *vr, void *p, int len, int flags); +int vr_poll(VRing *vr); int vring_wait_reply(void); int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd); void virtio_setup_ccw(VDev *vdev); +int virtio_net_init(void *mac_addr); + #endif /* VIRTIO_H */
The driver provides the recv() and send() functions which will be required by SLOF's libnet code for receiving and sending packets. Signed-off-by: Thomas Huth <thuth@redhat.com> --- pc-bios/s390-ccw/netboot.mak | 2 +- pc-bios/s390-ccw/virtio-net.c | 130 ++++++++++++++++++++++++++++++++++++++++++ pc-bios/s390-ccw/virtio.c | 9 ++- pc-bios/s390-ccw/virtio.h | 13 ++++- 4 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 pc-bios/s390-ccw/virtio-net.c