From 020ad47bb004cb01e2c7834a34d74da66cef3532 Mon Sep 17 00:00:00 2001 From: Gavin Li Date: Mon, 5 Oct 2020 22:40:00 -0700 Subject: [PATCH] stm32: fix ISTR and CTR_RX/TX race conditions --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 18 +++++++++++------- .../st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h | 8 ++++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 32179874..033d7cbd 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -203,6 +203,11 @@ static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) { *reg = (uint16_t)(*reg & ~mask); } +// Bits in ISTR are cleared upon writing 0 +static inline void clear_istr_bits(uint16_t mask) { + USB->ISTR = ~mask; +} + void dcd_init (uint8_t rhport) { /* Clocks should already be enabled */ @@ -231,7 +236,7 @@ void dcd_init (uint8_t rhport) USB->BTABLE = DCD_STM32_BTABLE_BASE; - reg16_clear_bits(&USB->ISTR, USB_ISTR_ALL_EVENTS); // Clear pending interrupts + USB->ISTR = 0; // Clear pending interrupts // Reset endpoints to disabled for(uint32_t i=0; iISTR, USB_ISTR_RESET); + clear_istr_bits(USB_ISTR_RESET); dcd_handle_bus_reset(); dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); return; // Don't do the rest of the things here; perhaps they've been cleared? @@ -523,14 +528,13 @@ void dcd_int_handler(uint8_t rhport) { /* servicing of the endpoint correct transfer interrupt */ /* clear of the CTR flag into the sub */ dcd_ep_ctr_handler(); - reg16_clear_bits(&USB->ISTR, USB_ISTR_CTR); } if (int_status & USB_ISTR_WKUP) { reg16_clear_bits(&USB->CNTR, USB_CNTR_LPMODE); reg16_clear_bits(&USB->CNTR, USB_CNTR_FSUSP); - reg16_clear_bits(&USB->ISTR, USB_ISTR_WKUP); + clear_istr_bits(USB_ISTR_WKUP); dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); } @@ -544,13 +548,13 @@ void dcd_int_handler(uint8_t rhport) { USB->CNTR |= USB_CNTR_LPMODE; /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - reg16_clear_bits(&USB->ISTR, USB_ISTR_SUSP); + clear_istr_bits(USB_ISTR_SUSP); dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } #if USE_SOF if(int_status & USB_ISTR_SOF) { - reg16_clear_bits(&USB->ISTR, USB_ISTR_SOF); + clear_istr_bits(USB_ISTR_SOF); dcd_event_bus_signal(0, DCD_EVENT_SOF, true); } #endif @@ -564,7 +568,7 @@ void dcd_int_handler(uint8_t rhport) { { remoteWakeCountdown--; } - reg16_clear_bits(&USB->ISTR, USB_ISTR_ESOF); + clear_istr_bits(USB_ISTR_ESOF); } } diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h index 4f2b2294..d26c700d 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h @@ -143,13 +143,17 @@ static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpNum) static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum) { uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); - regVal &= 0x7FFFu & USB_EPREG_MASK; + regVal &= USB_EPREG_MASK; + regVal &= ~USB_EP_CTR_RX; + regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0) pcd_set_endpoint(USBx, bEpNum, regVal); } static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum) { uint32_t regVal = pcd_get_endpoint(USBx, bEpNum); - regVal &= regVal & 0xFF7FU & USB_EPREG_MASK; + regVal &= USB_EPREG_MASK; + regVal &= ~USB_EP_CTR_TX; + regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0) pcd_set_endpoint(USBx, bEpNum,regVal); } /**