diff options
author | Fam Zheng <famz@redhat.com> | 2015-07-15 18:19:13 +0800 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2015-07-27 14:12:18 +0100 |
commit | f9f7492ea4a9dda538fedeec31399fb940533a16 (patch) | |
tree | e9f392f667f0a3c63708ca15fce6db5b12559967 /hw/net/xilinx_axienet.c | |
parent | 4594f93a732f1f5936c3a5225481586e24bffa9e (diff) |
axienet: Flush queued packets when rx is done
eth_can_rx checks s->rxsize and returns false if it is non-zero. Because
of the .can_receive semantics change, this will make the incoming queue
disabled by peer, until it is explicitly flushed. So we should flush it
when s->rxsize is becoming zero.
Squash eth_can_rx semantics into etx_rx and drop .can_receive()
callback, also add flush when rx buffer becomes available again after a
packet gets queued.
The other conditions, "!axienet_rx_resetting(s) &&
axienet_rx_enabled(s)" are OK because enet_write already calls
qemu_flush_queued_packets when the register bits are changed.
Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Jason Wang <jasowang@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1436955553-22791-13-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'hw/net/xilinx_axienet.c')
-rw-r--r-- | hw/net/xilinx_axienet.c | 17 |
1 files changed, 13 insertions, 4 deletions
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, }; |