qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [QEMU RFC 1/2] cadence_gem: Throttle traffic using buffer s


From: Peter Crosthwaite
Subject: [Qemu-devel] [QEMU RFC 1/2] cadence_gem: Throttle traffic using buffer state
Date: Sat, 26 Jan 2013 12:18:30 -0800

Under heady RX traffic, GEM just keeps receiving packets and dropping them
as fast as possible. Throttle the traffic if GEM is incapable of receiving the
packet because there is no valid buffer.

This patch is a non-functional RFC please see the cover letter for discussion.

Signed-off-by: Peter Crosthwaite <address@hidden>

Conflicts:
        hw/cadence_gem.c
---
 hw/cadence_gem.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 63 insertions(+), 12 deletions(-)

diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c
index 0d83442..8c2be8b 100644
--- a/hw/cadence_gem.c
+++ b/hw/cadence_gem.c
@@ -27,6 +27,9 @@
 #include "sysbus.h"
 #include "net/net.h"
 #include "net/checksum.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+#include "sysemu/dma.h"
 
 #ifdef CADENCE_GEM_ERR_DEBUG
 #define DB_PRINT(...) do { \
@@ -318,6 +321,7 @@ static inline void rx_desc_set_length(unsigned *desc, 
unsigned len)
 typedef struct {
     SysBusDevice busdev;
     MemoryRegion iomem;
+    MemoryRegion rx_desc_snoop_mem;
     NICState *nic;
     NICConf conf;
     qemu_irq irq;
@@ -342,6 +346,7 @@ typedef struct {
     uint32_t rx_desc_addr;
     uint32_t tx_desc_addr;
 
+    uint8_t can_rx_state; /* Debug only */
 } GemState;
 
 /* The broadcast MAC address: 0xFFFFFFFFFFFF */
@@ -407,17 +412,44 @@ static void phy_update_link(GemState *s)
 
 static int gem_can_receive(NetClientState *nc)
 {
-    GemState *s;
-
-    s = DO_UPCAST(NICState, nc, nc)->opaque;
-
-    DB_PRINT("\n");
+    GemState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    unsigned    desc[2];
 
+    /* read current descriptor */
+    if (!s->rx_desc_addr) {
+        if (s->can_rx_state != 1) {
+            DB_PRINT("cant receive - no buffer descriptor\n");
+            s->can_rx_state = 1;
+        }
+        return 0;
+    }
+    dma_memory_read(&dma_context_memory, s->rx_desc_addr,
+                    (uint8_t *)&desc[0], sizeof(desc));
+    if (rx_desc_get_ownership(desc) == 1) {
+        memory_region_del_subregion(get_system_memory(), 
&s->rx_desc_snoop_mem);
+        memory_region_add_subregion(get_system_memory(),
+                                            s->rx_desc_addr,
+                                            &s->rx_desc_snoop_mem);
+        if (s->can_rx_state != 2) {
+            s->can_rx_state = 2;
+            DB_PRINT("cant receive - busy buffer descriptor 0x%x\n",
+                     s->rx_desc_addr);
+        }
+        return 0;
+    }
     /* Do nothing if receive is not enabled. */
     if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_RXENA)) {
+        if (s->can_rx_state != 3) {
+            s->can_rx_state = 3;
+            DB_PRINT("cant receive - noenable\n");
+        }
         return 0;
     }
 
+    if (s->can_rx_state != 0) {
+        s->can_rx_state = 0;
+        DB_PRINT("can receive 0x%x\n", s->rx_desc_addr);
+    }
     return 1;
 }
 
@@ -1078,15 +1110,14 @@ static void gem_write(void *opaque, hwaddr offset, 
uint64_t val,
 
     /* Squash bits which are read only in write value */
     val &= ~(s->regs_ro[offset]);
-    /* Preserve (only) bits which are read only in register */
-    readonly = s->regs[offset];
-    readonly &= s->regs_ro[offset];
-
-    /* Squash bits which are write 1 to clear */
-    val &= ~(s->regs_w1c[offset] & val);
+    /* Preserve (only) bits which are read only and wtc in register */
+    readonly = s->regs[offset] & (s->regs_ro[offset] | s->regs_w1c[offset]);
 
     /* Copy register write to backing store */
-    s->regs[offset] = val | readonly;
+    s->regs[offset] = (val & ~s->regs_w1c[offset]) | readonly;
+
+    /* do w1c */
+    s->regs[offset] &= ~(s->regs_w1c[offset] & val);
 
     /* Handle register write side effects */
     switch (offset) {
@@ -1102,6 +1133,9 @@ static void gem_write(void *opaque, hwaddr offset, 
uint64_t val,
             /* Reset to start of Q when receive disabled. */
             s->rx_desc_addr = s->regs[GEM_RXQBASE];
         }
+        if (gem_can_receive(&s->nic->nc)) {
+            qemu_flush_queued_packets(&s->nic->nc);
+        }
         break;
 
     case GEM_TXSTATUS:
@@ -1146,6 +1180,21 @@ static const MemoryRegionOps gem_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+static void gem_rx_desc_snoop_write(void *opaque, hwaddr offset, uint64_t val,
+        unsigned size)
+{
+        GemState *s = (GemState *)opaque;
+
+        if (gem_can_receive(&s->nic->nc)) {
+            qemu_flush_queued_packets(&s->nic->nc);
+        }
+};
+
+static const MemoryRegionOps gem_rx_desc_snoop_ops = {
+    .write = gem_rx_desc_snoop_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static void gem_cleanup(NetClientState *nc)
 {
     GemState *s = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -1178,6 +1227,8 @@ static int gem_init(SysBusDevice *dev)
     s = FROM_SYSBUS(GemState, dev);
     gem_init_register_masks(s);
     memory_region_init_io(&s->iomem, &gem_ops, s, "enet", sizeof(s->regs));
+    memory_region_init_io(&s->rx_desc_snoop_mem, &gem_rx_desc_snoop_ops, s,
+                          "enet_rx_snoop", sizeof(unsigned) * 2);
     sysbus_init_mmio(dev, &s->iomem);
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
-- 
1.7.12.1.396.g16eed7c





reply via email to

[Prev in Thread] Current Thread [Next in Thread]