Skip to content

Commit 16bc054

Browse files
committed
dwc2: guard EP0 status completion with armed ZLP state
Track when an EP0 OUT zero-length transfer is actually armed and require that state before synthesizing a status-stage completion ahead of a co-reported SETUP event. This preserves the validated status-before-SETUP ordering fix while avoiding stale zero-length state from producing spurious EP0 OUT completions.
1 parent cfdab25 commit 16bc054

1 file changed

Lines changed: 21 additions & 0 deletions

File tree

src/portable/synopsys/dwc2/dcd_dwc2.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ static xfer_ctl_t xfer_status[DWC2_EP_MAX][2];
6262
typedef struct {
6363
// EP0 transfers are limited to 1 packet - larger sizes has to be split
6464
uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type
65+
bool ep0_out_zlp_armed; // EP0 OUT ZLP transfer is armed and waiting for completion
6566
uint16_t dfifo_top; // top free location in DFIFO in words
6667

6768
// Number of IN endpoints active
@@ -665,6 +666,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
665666
// EP0 can only handle one packet
666667
if (epnum == 0) {
667668
_dcd_data.ep0_pending[dir] = total_bytes;
669+
if (dir == TUSB_DIR_OUT) {
670+
_dcd_data.ep0_out_zlp_armed = (total_bytes == 0);
671+
}
668672
}
669673

670674
// Schedule packets to be sent within interrupt
@@ -744,6 +748,9 @@ static void handle_bus_reset(uint8_t rhport) {
744748

745749
tu_memclr(xfer_status, sizeof(xfer_status));
746750

751+
_dcd_data.ep0_pending[TUSB_DIR_OUT] = 0;
752+
_dcd_data.ep0_pending[TUSB_DIR_IN] = 0;
753+
_dcd_data.ep0_out_zlp_armed = false;
747754
_dcd_data.sof_en = false;
748755
_dcd_data.allocated_epin_count = 0;
749756

@@ -949,12 +956,16 @@ static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doe
949956
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
950957
const bool ep0_status_complete_before_setup = (epnum == 0) && doepint_bm.setup_phase_done &&
951958
doepint_bm.xfer_complete &&
959+
_dcd_data.ep0_out_zlp_armed &&
952960
(_dcd_data.ep0_pending[TUSB_DIR_OUT] == 0) &&
953961
(xfer->total_len == 0);
954962

955963
if (doepint_bm.setup_phase_done) {
956964
if (ep0_status_complete_before_setup) {
965+
_dcd_data.ep0_out_zlp_armed = false;
957966
dcd_event_xfer_complete(rhport, epnum, 0, XFER_RESULT_SUCCESS, true);
967+
} else if (epnum == 0) {
968+
_dcd_data.ep0_out_zlp_armed = false;
958969
}
959970

960971
// Cleanup previous pending EP0 IN transfer if any
@@ -976,6 +987,9 @@ static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doe
976987
// EP0 can only handle one packet, Schedule another packet to be received.
977988
edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT);
978989
} else {
990+
if (epnum == 0) {
991+
_dcd_data.ep0_out_zlp_armed = false;
992+
}
979993
dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
980994
}
981995
}
@@ -1017,12 +1031,16 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi
10171031
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
10181032
const bool ep0_status_complete_before_setup = (epnum == 0) && doepint_bm.setup_phase_done &&
10191033
doepint_bm.xfer_complete &&
1034+
_dcd_data.ep0_out_zlp_armed &&
10201035
(_dcd_data.ep0_pending[TUSB_DIR_OUT] == 0) &&
10211036
(xfer->total_len == 0);
10221037

10231038
if (doepint_bm.setup_phase_done) {
10241039
if (ep0_status_complete_before_setup) {
1040+
_dcd_data.ep0_out_zlp_armed = false;
10251041
dcd_event_xfer_complete(rhport, epnum, 0, XFER_RESULT_SUCCESS, true);
1042+
} else if (epnum == 0) {
1043+
_dcd_data.ep0_out_zlp_armed = false;
10261044
}
10271045

10281046
// Cleanup previous pending EP0 IN transfer if any
@@ -1058,6 +1076,9 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi
10581076
dma_setup_prepare(rhport);
10591077
}
10601078

1079+
if (epnum == 0) {
1080+
_dcd_data.ep0_out_zlp_armed = false;
1081+
}
10611082
dcd_dcache_invalidate(xfer->buffer, xfer->total_len);
10621083
dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
10631084
}

0 commit comments

Comments
 (0)