diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index 4e6939f9a2e6bcdd842b6ebb4af732ae1c78395d..21928f9f3f1279a8ff0abbebe25f9eb3e705af5a 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -196,12 +196,14 @@ static void mcf_fec_do_tx(mcf_fec_state *s) static void mcf_fec_enable_rx(mcf_fec_state *s) { + NetClientState *nc = qemu_get_queue(s->nic); mcf_fec_bd bd; mcf_fec_read_bd(&bd, s->rx_descriptor); s->rx_enabled = ((bd.flags & FEC_BD_E) != 0); - if (!s->rx_enabled) - DPRINTF("RX buffer full\n"); + if (s->rx_enabled) { + qemu_flush_queued_packets(nc); + } } static void mcf_fec_reset(mcf_fec_state *s) @@ -397,6 +399,32 @@ static void mcf_fec_write(void *opaque, hwaddr addr, mcf_fec_update(s); } +static int mcf_fec_have_receive_space(mcf_fec_state *s, size_t want) +{ + mcf_fec_bd bd; + uint32_t addr; + + /* Walk descriptor list to determine if we have enough buffer */ + addr = s->rx_descriptor; + while (want > 0) { + mcf_fec_read_bd(&bd, addr); + if ((bd.flags & FEC_BD_E) == 0) { + return 0; + } + if (want < s->emrbr) { + return 1; + } + want -= s->emrbr; + /* Advance to the next descriptor. */ + if ((bd.flags & FEC_BD_W) != 0) { + addr = s->erdsr; + } else { + addr += 8; + } + } + return 0; +} + static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t size) { mcf_fec_state *s = qemu_get_nic_opaque(nc); @@ -426,18 +454,14 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si if (size > (s->rcr >> 16)) { flags |= FEC_BD_LG; } + /* Check if we have enough space in current descriptors */ + if (!mcf_fec_have_receive_space(s, size)) { + return 0; + } addr = s->rx_descriptor; retsize = size; while (size > 0) { mcf_fec_read_bd(&bd, addr); - if ((bd.flags & FEC_BD_E) == 0) { - /* No descriptors available. Bail out. */ - /* FIXME: This is wrong. We should probably either save the - remainder for when more RX buffers are available, or - flag an error. */ - fprintf(stderr, "mcf_fec: Lost end of frame\n"); - break; - } buf_len = (size <= s->emrbr) ? size: s->emrbr; bd.length = buf_len; size -= buf_len; diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c index 19ecfc4ccf9b862d21c02d017761ab35a6ff3d58..d7cbfc1033d9c80ae93febe690c6a4698affd1b7 100644 --- a/hw/net/xen_nic.c +++ b/hw/net/xen_nic.c @@ -234,27 +234,6 @@ static void net_rx_response(struct XenNetDev *netdev, #define NET_IP_ALIGN 2 -static int net_rx_ok(NetClientState *nc) -{ - struct XenNetDev *netdev = qemu_get_nic_opaque(nc); - RING_IDX rc, rp; - - if (netdev->xendev.be_state != XenbusStateConnected) { - return 0; - } - - rc = netdev->rx_ring.req_cons; - rp = netdev->rx_ring.sring->req_prod; - xen_rmb(); - - if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) { - xen_be_printf(&netdev->xendev, 2, "%s: no rx buffers (%d/%d)\n", - __FUNCTION__, rc, rp); - return 0; - } - return 1; -} - static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size) { struct XenNetDev *netdev = qemu_get_nic_opaque(nc); @@ -271,8 +250,7 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) { - xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n"); - return -1; + return 0; } if (size > XC_PAGE_SIZE - NET_IP_ALIGN) { xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)", @@ -304,7 +282,6 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size static NetClientInfo net_xen_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = net_rx_ok, .receive = net_rx_packet, };