diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-07-27 14:53:42 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-07-27 14:53:42 +0100 |
commit | 122e7dab8ac549c8c5a9e1e13aa2464190e888de (patch) | |
tree | 110679c12752916fc4ae9b011b9d7fa98a2127ae /hw | |
parent | e40db4c6d391419c0039fe274c74df32a6ca1a28 (diff) | |
parent | f9f7492ea4a9dda538fedeec31399fb940533a16 (diff) |
Merge remote-tracking branch 'remotes/stefanha/tags/net-pull-request' into staging
Pull request
Here are NIC fixes from Fam Zheng that prevent rx hangs (caused by NIC models
where .can_receive() stops rx but qemu_flush_queued_packets() isn't called).
# gpg: Signature made Mon Jul 27 14:51:48 2015 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>"
* remotes/stefanha/tags/net-pull-request:
axienet: Flush queued packets when rx is done
dp8393x: Flush packets when link comes up
stellaris_enet: Flush queued packets when read done
mipsnet: Flush queued packets when receiving is enabled
milkymist-minimac2: Flush queued packets when link comes up
mcf_fec: Drop mcf_fec_can_receive
etsec: Flush queue when rx buffer is consumed
etsec: Move etsec_can_receive into etsec_receive
usbnet: Drop usbnet_can_receive
eepro100: Drop nic_can_receive
pcnet: Drop pcnet_can_receive
xgmac: Drop packets with eth_can_rx is false.
hw/net: fix mcf_fec driver receiver
hw/net: add simple phy support to mcf_fec driver
hw/net: add ANLPAR bit definitions to generic mii
hw/net: create common collection of MII definitions
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/net/dp8393x.c | 8 | ||||
-rw-r--r-- | hw/net/eepro100.c | 11 | ||||
-rw-r--r-- | hw/net/fsl_etsec/etsec.c | 20 | ||||
-rw-r--r-- | hw/net/fsl_etsec/etsec.h | 4 | ||||
-rw-r--r-- | hw/net/fsl_etsec/rings.c | 17 | ||||
-rw-r--r-- | hw/net/lance.c | 1 | ||||
-rw-r--r-- | hw/net/mcf_fec.c | 63 | ||||
-rw-r--r-- | hw/net/milkymist-minimac2.c | 33 | ||||
-rw-r--r-- | hw/net/mipsnet.c | 9 | ||||
-rw-r--r-- | hw/net/pcnet-pci.c | 1 | ||||
-rw-r--r-- | hw/net/pcnet.c | 9 | ||||
-rw-r--r-- | hw/net/pcnet.h | 1 | ||||
-rw-r--r-- | hw/net/stellaris_enet.c | 14 | ||||
-rw-r--r-- | hw/net/xgmac.c | 8 | ||||
-rw-r--r-- | hw/net/xilinx_axienet.c | 17 | ||||
-rw-r--r-- | hw/usb/dev-network.c | 20 |
16 files changed, 133 insertions, 103 deletions
diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index cd889bce86..451ff72e50 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -327,9 +327,14 @@ static void dp8393x_do_stop_timer(dp8393xState *s) dp8393x_update_wt_regs(s); } +static int dp8393x_can_receive(NetClientState *nc); + static void dp8393x_do_receiver_enable(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS; + if (dp8393x_can_receive(s->nic->ncs)) { + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } } static void dp8393x_do_receiver_disable(dp8393xState *s) @@ -569,6 +574,9 @@ static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data, dp8393x_do_read_rra(s); } dp8393x_update_irq(s); + if (dp8393x_can_receive(s->nic->ncs)) { + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } break; /* Ignore least significant bit */ case SONIC_RSA: diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index c374c1a251..60333b7fcc 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -1617,16 +1617,6 @@ static const MemoryRegionOps eepro100_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static int nic_can_receive(NetClientState *nc) -{ - EEPRO100State *s = qemu_get_nic_opaque(nc); - TRACE(RXTX, logout("%p\n", s)); - return get_ru_state(s) == ru_ready; -#if 0 - return !eepro100_buffer_full(s); -#endif -} - static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) { /* TODO: @@ -1844,7 +1834,6 @@ static void pci_nic_uninit(PCIDevice *pci_dev) static NetClientInfo net_eepro100_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = nic_can_receive, .receive = nic_receive, }; diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index c57365fdec..0f5cf4477b 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -338,25 +338,26 @@ static void etsec_reset(DeviceState *d) MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS; } -static int etsec_can_receive(NetClientState *nc) -{ - eTSEC *etsec = qemu_get_nic_opaque(nc); - - return etsec->rx_buffer_len == 0; -} - static ssize_t etsec_receive(NetClientState *nc, const uint8_t *buf, size_t size) { + ssize_t ret; eTSEC *etsec = qemu_get_nic_opaque(nc); #if defined(HEX_DUMP) fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size); qemu_hexdump(buf, stderr, "", size); #endif - etsec_rx_ring_write(etsec, buf, size); - return size; + /* Flush is unnecessary as are already in receiving path */ + etsec->need_flush = false; + ret = etsec_rx_ring_write(etsec, buf, size); + if (ret == 0) { + /* The packet will be queued, let's flush it when buffer is avilable + * again. */ + etsec->need_flush = true; + } + return ret; } @@ -370,7 +371,6 @@ static void etsec_set_link_status(NetClientState *nc) static NetClientInfo net_etsec_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = etsec_can_receive, .receive = etsec_receive, .link_status_changed = etsec_set_link_status, }; diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h index 78d2c57ed3..e7dc0a4b90 100644 --- a/hw/net/fsl_etsec/etsec.h +++ b/hw/net/fsl_etsec/etsec.h @@ -144,6 +144,8 @@ typedef struct eTSEC { QEMUBH *bh; struct ptimer_state *ptimer; + /* Whether we should flush the rx queue when buffer becomes available. */ + bool need_flush; } eTSEC; #define TYPE_ETSEC_COMMON "eTSEC" @@ -162,7 +164,7 @@ DeviceState *etsec_create(hwaddr base, void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr); void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr); -void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size); +ssize_t etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size); void etsec_write_miim(eTSEC *etsec, eTSEC_Register *reg, diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index d4a494f6a3..68e7b6d16b 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -481,40 +481,42 @@ static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size) etsec->rx_buffer_len, etsec->rx_padding); } -void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size) +ssize_t etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size) { int ring_nbr = 0; /* Always use ring0 (no filer) */ if (etsec->rx_buffer_len != 0) { RING_DEBUG("%s: We can't receive now," " a buffer is already in the pipe\n", __func__); - return; + return 0; } if (etsec->regs[RSTAT].value & 1 << (23 - ring_nbr)) { RING_DEBUG("%s: The ring is halted\n", __func__); - return; + return -1; } if (etsec->regs[DMACTRL].value & DMACTRL_GRS) { RING_DEBUG("%s: Graceful receive stop\n", __func__); - return; + return -1; } if (!(etsec->regs[MACCFG1].value & MACCFG1_RX_EN)) { RING_DEBUG("%s: MAC Receive not enabled\n", __func__); - return; + return -1; } if ((etsec->regs[RCTRL].value & RCTRL_RSF) && (size < 60)) { /* CRC is not in the packet yet, so short frame is below 60 bytes */ RING_DEBUG("%s: Drop short frame\n", __func__); - return; + return -1; } rx_init_frame(etsec, buf, size); etsec_walk_rx_ring(etsec, ring_nbr); + + return size; } void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr) @@ -644,6 +646,9 @@ void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr) } else { etsec->rx_buffer_len = 0; etsec->rx_buffer = NULL; + if (etsec->need_flush) { + qemu_flush_queued_packets(qemu_get_queue(etsec->nic)); + } } RING_DEBUG("eTSEC End of ring_write: remaining_data:%zu\n", remaining_data); diff --git a/hw/net/lance.c b/hw/net/lance.c index 4baa0169e6..780b39d65a 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -94,7 +94,6 @@ static const MemoryRegionOps lance_mem_ops = { static NetClientInfo net_lance_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = pcnet_can_receive, .receive = pcnet_receive, .link_status_changed = pcnet_set_link_status, }; diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index 0255612f10..4e6939f9a2 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -8,6 +8,7 @@ #include "hw/hw.h" #include "net/net.h" #include "hw/m68k/mcf.h" +#include "hw/net/mii.h" /* For crc32 */ #include <zlib.h> #include "exec/address-spaces.h" @@ -216,6 +217,51 @@ static void mcf_fec_reset(mcf_fec_state *s) s->rfsr = 0x500; } +#define MMFR_WRITE_OP (1 << 28) +#define MMFR_READ_OP (2 << 28) +#define MMFR_PHYADDR(v) (((v) >> 23) & 0x1f) +#define MMFR_REGNUM(v) (((v) >> 18) & 0x1f) + +static uint64_t mcf_fec_read_mdio(mcf_fec_state *s) +{ + uint64_t v; + + if (s->mmfr & MMFR_WRITE_OP) + return s->mmfr; + if (MMFR_PHYADDR(s->mmfr) != 1) + return s->mmfr |= 0xffff; + + switch (MMFR_REGNUM(s->mmfr)) { + case MII_BMCR: + v = MII_BMCR_SPEED | MII_BMCR_AUTOEN | MII_BMCR_FD; + break; + case MII_BMSR: + v = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD | + MII_BMSR_10T_HD | MII_BMSR_MFPS | MII_BMSR_AN_COMP | + MII_BMSR_AUTONEG | MII_BMSR_LINK_ST; + break; + case MII_PHYID1: + v = DP83848_PHYID1; + break; + case MII_PHYID2: + v = DP83848_PHYID2; + break; + case MII_ANAR: + v = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD | + MII_ANAR_10 | MII_ANAR_CSMACD; + break; + case MII_ANLPAR: + v = MII_ANLPAR_ACK | MII_ANLPAR_TXFD | MII_ANLPAR_TX | + MII_ANLPAR_10FD | MII_ANLPAR_10 | MII_ANLPAR_CSMACD; + break; + default: + v = 0xffff; + break; + } + s->mmfr = (s->mmfr & ~0xffff) | v; + return s->mmfr; +} + static uint64_t mcf_fec_read(void *opaque, hwaddr addr, unsigned size) { @@ -226,7 +272,7 @@ static uint64_t mcf_fec_read(void *opaque, hwaddr addr, case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */ case 0x014: return 0; /* TDAR */ case 0x024: return s->ecr; - case 0x040: return s->mmfr; + case 0x040: return mcf_fec_read_mdio(s); case 0x044: return s->mscr; case 0x064: return 0; /* MIBC */ case 0x084: return s->rcr; @@ -287,8 +333,8 @@ static void mcf_fec_write(void *opaque, hwaddr addr, } break; case 0x040: - /* TODO: Implement MII. */ s->mmfr = value; + s->eir |= FEC_INT_MII; break; case 0x044: s->mscr = value & 0xfe; @@ -351,12 +397,6 @@ static void mcf_fec_write(void *opaque, hwaddr addr, mcf_fec_update(s); } -static int mcf_fec_can_receive(NetClientState *nc) -{ - mcf_fec_state *s = qemu_get_nic_opaque(nc); - return s->rx_enabled; -} - static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t size) { mcf_fec_state *s = qemu_get_nic_opaque(nc); @@ -367,10 +407,11 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si uint32_t buf_addr; uint8_t *crc_ptr; unsigned int buf_len; + size_t retsize; DPRINTF("do_rx len %d\n", size); if (!s->rx_enabled) { - fprintf(stderr, "mcf_fec_receive: Unexpected packet\n"); + return -1; } /* 4 bytes for the CRC. */ size += 4; @@ -386,6 +427,7 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si flags |= FEC_BD_LG; } addr = s->rx_descriptor; + retsize = size; while (size > 0) { mcf_fec_read_bd(&bd, addr); if ((bd.flags & FEC_BD_E) == 0) { @@ -430,7 +472,7 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si s->rx_descriptor = addr; mcf_fec_enable_rx(s); mcf_fec_update(s); - return size; + return retsize; } static const MemoryRegionOps mcf_fec_ops = { @@ -442,7 +484,6 @@ static const MemoryRegionOps mcf_fec_ops = { static NetClientInfo net_mcf_fec_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = mcf_fec_can_receive, .receive = mcf_fec_receive, }; diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c index f06afaa581..5d1cf08517 100644 --- a/hw/net/milkymist-minimac2.c +++ b/hw/net/milkymist-minimac2.c @@ -303,8 +303,7 @@ static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size) r_state = R_STATE1; rx_buf = s->rx1_buf; } else { - trace_milkymist_minimac2_drop_rx_frame(buf); - return size; + return 0; } /* assemble frame */ @@ -354,6 +353,18 @@ minimac2_read(void *opaque, hwaddr addr, unsigned size) return r; } +static int minimac2_can_rx(MilkymistMinimac2State *s) +{ + if (s->regs[R_STATE0] == STATE_LOADED) { + return 1; + } + if (s->regs[R_STATE1] == STATE_LOADED) { + return 1; + } + + return 0; +} + static void minimac2_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) @@ -387,6 +398,9 @@ minimac2_write(void *opaque, hwaddr addr, uint64_t value, case R_STATE1: s->regs[addr] = value; update_rx_interrupt(s); + if (minimac2_can_rx(s)) { + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } break; case R_SETUP: case R_COUNT0: @@ -411,20 +425,6 @@ static const MemoryRegionOps minimac2_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int minimac2_can_rx(NetClientState *nc) -{ - MilkymistMinimac2State *s = qemu_get_nic_opaque(nc); - - if (s->regs[R_STATE0] == STATE_LOADED) { - return 1; - } - if (s->regs[R_STATE1] == STATE_LOADED) { - return 1; - } - - return 0; -} - static void milkymist_minimac2_reset(DeviceState *d) { MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(d); @@ -445,7 +445,6 @@ static void milkymist_minimac2_reset(DeviceState *d) static NetClientInfo net_milkymist_minimac2_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = minimac2_can_rx, .receive = minimac2_rx, }; diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c index c813e0caa8..f261011a27 100644 --- a/hw/net/mipsnet.c +++ b/hw/net/mipsnet.c @@ -80,7 +80,7 @@ static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t si trace_mipsnet_receive(size); if (!mipsnet_can_receive(nc)) - return -1; + return 0; s->busy = 1; @@ -134,6 +134,9 @@ static uint64_t mipsnet_ioport_read(void *opaque, hwaddr addr, if (s->rx_count) { s->rx_count--; ret = s->rx_buffer[s->rx_read++]; + if (mipsnet_can_receive(s->nic->ncs)) { + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } } break; /* Reads as zero. */ @@ -170,6 +173,9 @@ static void mipsnet_ioport_write(void *opaque, hwaddr addr, } s->busy = !!s->intctl; mipsnet_update_irq(s); + if (mipsnet_can_receive(s->nic->ncs)) { + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } break; case MIPSNET_TX_DATA_BUFFER: s->tx_buffer[s->tx_written++] = val; @@ -214,7 +220,6 @@ static const VMStateDescription vmstate_mipsnet = { static NetClientInfo net_mipsnet_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = mipsnet_can_receive, .receive = mipsnet_receive, }; diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index 8305d1bdf2..b4d60b8123 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -273,7 +273,6 @@ static void pci_pcnet_uninit(PCIDevice *dev) static NetClientInfo net_pci_pcnet_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = pcnet_can_receive, .receive = pcnet_receive, .link_status_changed = pcnet_set_link_status, }; diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index 68b9981983..34373767d9 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -995,15 +995,6 @@ static int pcnet_tdte_poll(PCNetState *s) return !!(CSR_CXST(s) & 0x8000); } -int pcnet_can_receive(NetClientState *nc) -{ - PCNetState *s = qemu_get_nic_opaque(nc); - if (CSR_STOP(s) || CSR_SPND(s)) - return 0; - - return sizeof(s->buffer)-16; -} - #define MIN_BUF_SIZE 60 ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) diff --git a/hw/net/pcnet.h b/hw/net/pcnet.h index 79c4c84f07..dec8de834c 100644 --- a/hw/net/pcnet.h +++ b/hw/net/pcnet.h @@ -60,7 +60,6 @@ uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr); void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val); uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr); uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); -int pcnet_can_receive(NetClientState *nc); ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_); void pcnet_set_link_status(NetClientState *nc); void pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info); diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index 278a6545c3..21a47735d2 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -228,8 +228,7 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si if ((s->rctl & SE_RCTL_RXEN) == 0) return -1; if (s->np >= 31) { - DPRINTF("Packet dropped\n"); - return -1; + return 0; } DPRINTF("Received packet len=%zu\n", size); @@ -260,13 +259,8 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si return size; } -static int stellaris_enet_can_receive(NetClientState *nc) +static int stellaris_enet_can_receive(stellaris_enet_state *s) { - stellaris_enet_state *s = qemu_get_nic_opaque(nc); - - if ((s->rctl & SE_RCTL_RXEN) == 0) - return 1; - return (s->np < 31); } @@ -307,6 +301,9 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset, s->next_packet = 0; s->np--; DPRINTF("RX done np=%d\n", s->np); + if (!s->np && stellaris_enet_can_receive(s)) { + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } } return val; } @@ -454,7 +451,6 @@ static void stellaris_enet_reset(stellaris_enet_state *s) static NetClientInfo net_stellaris_enet_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = stellaris_enet_can_receive, .receive = stellaris_enet_receive, }; diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index b068f3a0d6..15fb681946 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -312,10 +312,8 @@ static const MemoryRegionOps enet_mem_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static int eth_can_rx(NetClientState *nc) +static int eth_can_rx(XgmacState *s) { - XgmacState *s = qemu_get_nic_opaque(nc); - /* RX enabled? */ return s->regs[DMA_CONTROL] & DMA_CONTROL_SR; } @@ -329,6 +327,9 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) struct desc bd; ssize_t ret; + if (!eth_can_rx(s)) { + return -1; + } unicast = ~buf[0] & 0x1; broadcast = memcmp(buf, sa_bcast, 6) == 0; multicast = !unicast && !broadcast; @@ -371,7 +372,6 @@ out: static NetClientInfo net_xgmac_enet_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = eth_can_rx, .receive = eth_rx, }; diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 92057707e0..d63c423247 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -401,6 +401,9 @@ struct XilinxAXIEnet { uint8_t rxapp[CONTROL_PAYLOAD_SIZE]; uint32_t rxappsize; + + /* Whether axienet_eth_rx_notify should flush incoming queue. */ + bool need_flush; }; static void axienet_rx_reset(XilinxAXIEnet *s) @@ -658,10 +661,8 @@ static const MemoryRegionOps enet_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static int eth_can_rx(NetClientState *nc) +static int eth_can_rx(XilinxAXIEnet *s) { - XilinxAXIEnet *s = qemu_get_nic_opaque(nc); - /* RX enabled? */ return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s); } @@ -701,6 +702,10 @@ static void axienet_eth_rx_notify(void *opaque) s->rxpos += ret; if (!s->rxsize) { s->regs[R_IS] |= IS_RX_COMPLETE; + if (s->need_flush) { + s->need_flush = false; + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } } } enet_update_irq(s); @@ -721,6 +726,11 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) DENET(qemu_log("%s: %zd bytes\n", __func__, size)); + if (!eth_can_rx(s)) { + s->need_flush = true; + return 0; + } + unicast = ~buf[0] & 0x1; broadcast = memcmp(buf, sa_bcast, 6) == 0; multicast = !unicast && !broadcast; @@ -925,7 +935,6 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size) static NetClientInfo net_xilinx_enet_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = eth_can_rx, .receive = eth_rx, }; diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 5eeb4c6b06..7800ceea5b 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1268,6 +1268,10 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz uint8_t *in_buf = s->in_buf; size_t total_size = size; + if (!s->dev.config) { + return -1; + } + if (is_rndis(s)) { if (s->rndis_state != RNDIS_DATA_INITIALIZED) { return -1; @@ -1309,21 +1313,6 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz return size; } -static int usbnet_can_receive(NetClientState *nc) -{ - USBNetState *s = qemu_get_nic_opaque(nc); - - if (!s->dev.config) { - return 0; - } - - if (is_rndis(s) && s->rndis_state != RNDIS_DATA_INITIALIZED) { - return 1; - } - - return !s->in_len; -} - static void usbnet_cleanup(NetClientState *nc) { USBNetState *s = qemu_get_nic_opaque(nc); @@ -1343,7 +1332,6 @@ static void usb_net_handle_destroy(USBDevice *dev) static NetClientInfo net_usbnet_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = usbnet_can_receive, .receive = usbnet_receive, .cleanup = usbnet_cleanup, }; |