Permalink
Browse files

softusb: remove rx_pending vs. rx_active race

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.
  • Loading branch information...
1 parent afd24aa commit 00c097c26778bab46050efacb34715eea9fe6ed1 @wpwrak wpwrak committed with sbourdeauducq Nov 29, 2011
Showing with 11 additions and 5 deletions.
  1. +1 −1 cores/softusb/rtl/softusb_sie.v
  2. +7 −3 softusb-input/main.c
  3. +3 −1 softusb-input/sie.h
@@ -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;
View
@@ -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)
View
@@ -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

0 comments on commit 00c097c

Please sign in to comment.