Patchwork [v6,14/16] stream: Add flow control API

login
register
mail settings
Submitter Peter Crosthwaite
Date April 16, 2013, 12:27 a.m.
Message ID <ee6811c95e78acb831d280dd64f15e748e6a5e65.1366069170.git.peter.crosthwaite@xilinx.com>
Download mbox | patch
Permalink /patch/236787/
State New
Headers show

Comments

Peter Crosthwaite - April 16, 2013, 12:27 a.m.
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

Add basic flow control to stream. A stream slave may return short, indicating
that it is not capable of accepting any more data at the present time. Polling
or a callback can be used via the can_push() function to determine when the
slave can receive again.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---

 hw/core/stream.c        |   13 +++++++++++--
 hw/dma/xilinx_axidma.c  |    3 ++-
 hw/net/xilinx_axienet.c |    8 +++++---
 include/hw/stream.h     |   33 ++++++++++++++++++++++++++++++---
 4 files changed, 48 insertions(+), 9 deletions(-)

Patch

diff --git a/hw/core/stream.c b/hw/core/stream.c
index a07d6a5..5397a8d 100644
--- a/hw/core/stream.c
+++ b/hw/core/stream.c
@@ -1,11 +1,20 @@ 
 #include "hw/stream.h"
 
-void
+size_t
 stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app)
 {
     StreamSlaveClass *k =  STREAM_SLAVE_GET_CLASS(sink);
 
-    k->push(sink, buf, len, app);
+    return k->push(sink, buf, len, app);
+}
+
+bool
+stream_can_push(StreamSlave *sink, StreamCanPushNotifyFn notify,
+                void *notify_opaque)
+{
+    StreamSlaveClass *k =  STREAM_SLAVE_GET_CLASS(sink);
+
+    return k->can_push ? k->can_push(sink, notify, notify_opaque) : true;
 }
 
 static const TypeInfo stream_slave_info = {
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index 2bbfea1..80ce57f 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -381,7 +381,7 @@  static void xilinx_axidma_reset(DeviceState *dev)
     }
 }
 
-static void
+static size_t
 xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len,
                                uint32_t *app)
 {
@@ -393,6 +393,7 @@  xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len,
     }
     stream_process_s2mem(s, buf, len, app);
     stream_update_irq(s);
+    return len;
 }
 
 static uint64_t axidma_read(void *opaque, hwaddr addr,
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
index f4638b2..6d27546 100644
--- a/hw/net/xilinx_axienet.c
+++ b/hw/net/xilinx_axienet.c
@@ -815,7 +815,7 @@  static void eth_cleanup(NetClientState *nc)
     g_free(s);
 }
 
-static void
+static size_t
 xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size,
                                 uint32_t *hdr)
 {
@@ -824,13 +824,13 @@  xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size,
 
     /* TX enable ?  */
     if (!(s->tc & TC_TX)) {
-        return;
+        return size;
     }
 
     /* Jumbo or vlan sizes ?  */
     if (!(s->tc & TC_JUM)) {
         if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) {
-            return;
+            return size;
         }
     }
 
@@ -858,6 +858,8 @@  xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size,
     s->stats.tx_bytes += size;
     s->regs[R_IS] |= IS_TX_COMPLETE;
     enet_update_irq(s);
+
+    return size;
 }
 
 static NetClientInfo net_xilinx_enet_info = {
diff --git a/include/hw/stream.h b/include/hw/stream.h
index f6137d6..5bc47a9 100644
--- a/include/hw/stream.h
+++ b/include/hw/stream.h
@@ -18,14 +18,41 @@  typedef struct StreamSlave {
     Object Parent;
 } StreamSlave;
 
+typedef void (*StreamCanPushNotifyFn)(void *opaque);
+
 typedef struct StreamSlaveClass {
     InterfaceClass parent;
-
-    void (*push)(StreamSlave *obj, unsigned char *buf, size_t len,
+    /**
+     * can push - determine if a stream slave is capable of accepting at least
+     * one byte of data. Returns false if cannot accept. If not implemented, the
+     * slave is assumed to always be capable of recieveing.
+     * @notify: Optional callback that the slave will call when the slave is
+     * capable of recieving again. Only called if false is returned.
+     * @notify_opaque: opaque data to pass to notify call.
+     */
+    bool (*can_push)(StreamSlave *obj, StreamCanPushNotifyFn notify,
+                     void *notify_opaque);
+    /**
+     * push - push data to a Stream slave. The number of bytes pushed is
+     * returned. If the slave short returns, the master must wait before trying
+     * again, the slave may continue to just return 0 waiting for the vm time to
+     * advance. The can_push() function can be used to trap the point in time
+     * where the slave is ready to recieve again, otherwise polling on a QEMU
+     * timer will work.
+     * @obj: Stream slave to push to
+     * @buf: Data to write
+     * @len: Maximum number of bytes to write
+     */
+    size_t (*push)(StreamSlave *obj, unsigned char *buf, size_t len,
                                                     uint32_t *app);
 } StreamSlaveClass;
 
-void
+size_t
 stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app);
 
+bool
+stream_can_push(StreamSlave *sink, StreamCanPushNotifyFn notify,
+                void *notify_opaque);
+
+
 #endif /* STREAM_H */