This moves the behavior of ne2000_can_receive to ne2000_receive. The logic is when the NIC is stopped we drop the packet, when the buffer is full we queue it and try flush later.
ne2000_buffer_full is determined by s->curpag, s->boundary, s->start and s->stop. Add a flush in ne2000_ioport_write as they are all updated there, except the advancing of s->curpag in ne2000_receive where ne2000_buffer_full is already false. Signed-off-by: Fam Zheng <f...@redhat.com> --- hw/net/ne2000-isa.c | 1 - hw/net/ne2000.c | 27 ++++++++++++++++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index 17e7199..18b0644 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -44,7 +44,6 @@ typedef struct ISANE2000State { static NetClientInfo net_ne2000_isa_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = ne2000_can_receive, .receive = ne2000_receive, }; diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 3492db3..182e7ca 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -165,15 +165,6 @@ static int ne2000_buffer_full(NE2000State *s) return 0; } -int ne2000_can_receive(NetClientState *nc) -{ - NE2000State *s = qemu_get_nic_opaque(nc); - - if (s->cmd & E8390_STOP) - return 1; - return !ne2000_buffer_full(s); -} - #define MIN_BUF_SIZE 60 ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_) @@ -190,8 +181,12 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_) printf("NE2000: received len=%d\n", size); #endif - if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) + if (s->cmd & E8390_STOP) { return -1; + } + if (ne2000_buffer_full(s)) { + return 0; + } /* XXX: check this */ if (s->rxcr & 0x10) { @@ -277,6 +272,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) { NE2000State *s = opaque; int offset, page, index; + bool try_flush = false; addr &= 0xf; #ifdef DEBUG_NE2000 @@ -309,19 +305,25 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->cmd &= ~E8390_TRANS; ne2000_update_irq(s); } + } else { + try_flush = true; } + } else { page = s->cmd >> 6; offset = addr | (page << 4); switch(offset) { case EN0_STARTPG: s->start = val << 8; + try_flush = true; break; case EN0_STOPPG: s->stop = val << 8; + try_flush = true; break; case EN0_BOUNDARY: s->boundary = val; + try_flush = true; break; case EN0_IMR: s->imr = val; @@ -363,12 +365,16 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case EN1_CURPAG: s->curpag = val; + try_flush = true; break; case EN1_MULT ... EN1_MULT + 7: s->mult[offset - EN1_MULT] = val; break; } } + if (try_flush && !ne2000_buffer_full(s)) { + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } } static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) @@ -705,7 +711,6 @@ void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size) static NetClientInfo net_ne2000_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = ne2000_can_receive, .receive = ne2000_receive, }; -- 2.4.5