OSDN Git Service

stream: Add flow control API
authorPeter Crosthwaite <peter.crosthwaite@xilinx.com>
Tue, 16 Apr 2013 00:27:16 +0000 (10:27 +1000)
committerEdgar E. Iglesias <edgar.iglesias@gmail.com>
Tue, 16 Apr 2013 08:04:23 +0000 (10:04 +0200)
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>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
hw/core/stream.c
hw/dma/xilinx_axidma.c
hw/net/xilinx_axienet.c
include/hw/stream.h

index a07d6a5..5397a8d 100644 (file)
@@ -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 = {
index 2bbfea1..80ce57f 100644 (file)
@@ -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,
index f4638b2..6d27546 100644 (file)
@@ -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 = {
index f6137d6..5bc47a9 100644 (file)
@@ -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 */