aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-07-27 14:53:42 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-07-27 14:53:42 +0100
commit122e7dab8ac549c8c5a9e1e13aa2464190e888de (patch)
tree110679c12752916fc4ae9b011b9d7fa98a2127ae /hw
parente40db4c6d391419c0039fe274c74df32a6ca1a28 (diff)
parentf9f7492ea4a9dda538fedeec31399fb940533a16 (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.c8
-rw-r--r--hw/net/eepro100.c11
-rw-r--r--hw/net/fsl_etsec/etsec.c20
-rw-r--r--hw/net/fsl_etsec/etsec.h4
-rw-r--r--hw/net/fsl_etsec/rings.c17
-rw-r--r--hw/net/lance.c1
-rw-r--r--hw/net/mcf_fec.c63
-rw-r--r--hw/net/milkymist-minimac2.c33
-rw-r--r--hw/net/mipsnet.c9
-rw-r--r--hw/net/pcnet-pci.c1
-rw-r--r--hw/net/pcnet.c9
-rw-r--r--hw/net/pcnet.h1
-rw-r--r--hw/net/stellaris_enet.c14
-rw-r--r--hw/net/xgmac.c8
-rw-r--r--hw/net/xilinx_axienet.c17
-rw-r--r--hw/usb/dev-network.c20
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,
};