* [Qemu-devel] [PULL for-2.4 1/2] hw/net: handle flow control in mcf_fec driver receiver
2015-07-28 12:26 [Qemu-devel] [PULL for-2.4 0/2] Net patches Stefan Hajnoczi
@ 2015-07-28 12:26 ` Stefan Hajnoczi
2015-07-28 12:26 ` [Qemu-devel] [PULL for-2.4 2/2] xen: Drop net_rx_ok Stefan Hajnoczi
2015-07-28 20:09 ` [Qemu-devel] [PULL for-2.4 0/2] Net patches Peter Maydell
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Hajnoczi @ 2015-07-28 12:26 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Greg Ungerer
From: Greg Ungerer <gerg@uclinux.org>
The network mcf_fec driver emulated receive side method is not dealing
with network queue flow control properly.
Modify the receive side to check if we have enough space in the
descriptors to store the current packet. If not we process none of it
and return 0. When the guest frees up some buffers through its descriptors
we signal the qemu net layer to send more packets.
[Fixed coding style: 4-space indent and curly braces on if statement.
--Stefan]
Signed-off-by: Greg Ungerer <gerg@uclinux.org>
Message-id: 1438045374-10358-1-git-send-email-gerg@uclinux.org
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
hw/net/mcf_fec.c | 44 ++++++++++++++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 10 deletions(-)
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
index 4e6939f..21928f9 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;
--
2.4.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PULL for-2.4 2/2] xen: Drop net_rx_ok
2015-07-28 12:26 [Qemu-devel] [PULL for-2.4 0/2] Net patches Stefan Hajnoczi
2015-07-28 12:26 ` [Qemu-devel] [PULL for-2.4 1/2] hw/net: handle flow control in mcf_fec driver receiver Stefan Hajnoczi
@ 2015-07-28 12:26 ` Stefan Hajnoczi
2015-07-28 20:09 ` [Qemu-devel] [PULL for-2.4 0/2] Net patches Peter Maydell
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Hajnoczi @ 2015-07-28 12:26 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Fam Zheng, Stefan Hajnoczi
From: Fam Zheng <famz@redhat.com>
Let net_rx_packet() (which checks the same conditions) drops the packet
if the device is not ready. Drop net_xen_info.can_receive and update the
return value for the buffer full case.
We rely on the qemu_flush_queued_packets() in net_event() to wake up
the peer when the buffer becomes available again.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1438077176-378-1-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
hw/net/xen_nic.c | 25 +------------------------
1 file changed, 1 insertion(+), 24 deletions(-)
diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c
index 19ecfc4..d7cbfc1 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,
};
--
2.4.3
^ permalink raw reply related [flat|nested] 4+ messages in thread