When testing rx_pending and rx_active in a loop, the following race
can have happened:

- we test rx_pending and find it clear
- the packet's last byte finishes and rx_pending is set
- the EOP is detected and rx_active is cleared
- we test rx_active and conclude that the packet has terminated

Thus, we don't reach the test of rx_pending and miss the packet's
last byte.

This patch changes the SIE_RX_PENDING register such that it allows
both rx_active and rx_pending to be retrieved atomically.
---
 cores/softusb/rtl/softusb_sie.v |    2 +-
 softusb-input/main.c            |   10 +++++++---
 softusb-input/sie.h             |    4 +++-
 3 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/cores/softusb/rtl/softusb_sie.v b/cores/softusb/rtl/softusb_sie.v
index 7e09d1a..531aea2 100644
--- a/cores/softusb/rtl/softusb_sie.v
+++ b/cores/softusb/rtl/softusb_sie.v
@@ -96,7 +96,7 @@ always @(posedge usb_clk) begin
                                if(io_re)
                                        rx_pending <= 1'b0;
                        end
-                       6'h0a: io_do <= rx_pending;
+                       6'h0a: io_do <= { rx_pending, rx_active };
                        6'h0b: io_do <= rx_active;
                        6'h0c: begin
                                io_do <= rx_error_pending;
diff --git a/softusb-input/main.c b/softusb-input/main.c
index 1bb6bf8..bb052a1 100644
--- a/softusb-input/main.c
+++ b/softusb-input/main.c
@@ -137,13 +137,17 @@ static const char bitstuff_error[] PROGMEM = "RX bitstuff 
error\n";
 #define        WAIT_RX(end)                                            \
        do {                                                    \
                unsigned timeout = 0x200;                       \
-               while(!rio8(SIE_RX_PENDING)) {                  \
+               unsigned char status;                           \
+               while(1) {                                      \
+                       status = rio8(SIE_RX_STATUS);           \
+                       if(status & RX_PENDING)                 \
+                               break;                          \
+                       if(!(status & RX_ACTIVE))               \
+                               goto end;                       \
                        if(!--timeout)                          \
                                goto timeout;                   \
                        if(rio8(SIE_RX_ERROR))                  \
                                goto error;                     \
-                       if(!rio8(SIE_RX_ACTIVE))                \
-                               goto end;                       \
                }                                               \
        } while (0)
 
diff --git a/softusb-input/sie.h b/softusb-input/sie.h
index bdd4f4d..12cb29f 100644
--- a/softusb-input/sie.h
+++ b/softusb-input/sie.h
@@ -33,7 +33,9 @@
 #define SIE_TX_BUSRESET                0x08
 
 #define SIE_RX_DATA            0x09
-#define SIE_RX_PENDING         0x0a
+#define SIE_RX_STATUS          0x0a
+#define                RX_PENDING      0x02
+#define                RX_ACTIVE       0x01
 #define SIE_RX_ACTIVE          0x0b
 #define SIE_RX_ERROR           0x0c
 
-- 
1.7.1

_______________________________________________
http://lists.milkymist.org/listinfo.cgi/devel-milkymist.org
IRC: #milkymist@Freenode

Reply via email to