From 94a6b8257206c2dc02828f2ca4c27e6dfdd33ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Mon, 21 Oct 2024 10:54:34 +0200 Subject: [PATCH] drivers: udc_dwc2: Handle IN events before OUT events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DWC2 otg OUT transfers are being used for SETUP DATA0, OUT Data Stage packets and OUT Status Stage ZLP. On High-Speed it is possible for IN Data Stage, OUT Status Stage ZLP and subsequent SETUP DATA0 to happen in very quick succession, making all the three events appear at the same time to the handler thread. The handler thread is picking up next endpoint to handle based on the least significant bit set. When OUT endpoints were on bits 0-15 and IN endpoints were on bits 16-31, the least significant bit policy favored OUT endpoints over IN endpoints. This caused problems in Completer mode (but suprisingly not in Buffer DMA mode) that lead to incorrect control transfer handling. The choice between least significant bit first or most significant bit first is arbitrary. Switching from least to most significant bit first would have resolved the issue. It would also favor higher numbered endpoints over lower numbered endpoints. Swap the order of endpoints in bitmaps to have IN on bits 0-15 and OUT on bits 16-31 to keep handling lower numbered endpoints first and resolve the control transfer handling in Completer mode. Signed-off-by: Tomasz Moń --- drivers/usb/udc/udc_dwc2.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c index 917910ad26d..00e4a370bac 100644 --- a/drivers/usb/udc/udc_dwc2.c +++ b/drivers/usb/udc/udc_dwc2.c @@ -99,9 +99,9 @@ struct udc_dwc2_data { struct k_thread thread_data; /* Main events the driver thread waits for */ struct k_event drv_evt; - /* Transfer triggers (OUT on bits 0-15, IN on bits 16-31) */ + /* Transfer triggers (IN on bits 0-15, OUT on bits 16-31) */ struct k_event xfer_new; - /* Finished transactions (OUT on bits 0-15, IN on bits 16-31) */ + /* Finished transactions (IN on bits 0-15, OUT on bits 16-31) */ struct k_event xfer_finished; struct dwc2_reg_backup backup; uint32_t ghwcfg1; @@ -1554,9 +1554,9 @@ static int udc_dwc2_ep_clear_halt(const struct device *dev, uint32_t ep_bit; if (USB_EP_DIR_IS_IN(cfg->addr)) { - ep_bit = BIT(16 + USB_EP_GET_IDX(cfg->addr)); - } else { ep_bit = BIT(USB_EP_GET_IDX(cfg->addr)); + } else { + ep_bit = BIT(16 + USB_EP_GET_IDX(cfg->addr)); } k_event_post(&priv->xfer_new, ep_bit); @@ -1579,9 +1579,9 @@ static int udc_dwc2_ep_enqueue(const struct device *dev, uint32_t ep_bit; if (USB_EP_DIR_IS_IN(cfg->addr)) { - ep_bit = BIT(16 + USB_EP_GET_IDX(cfg->addr)); - } else { ep_bit = BIT(USB_EP_GET_IDX(cfg->addr)); + } else { + ep_bit = BIT(16 + USB_EP_GET_IDX(cfg->addr)); } k_event_post(&priv->xfer_new, ep_bit); @@ -2346,7 +2346,7 @@ static inline void dwc2_handle_in_xfercompl(const struct device *dev, return; } - k_event_post(&priv->xfer_finished, BIT(16 + ep_idx)); + k_event_post(&priv->xfer_finished, BIT(ep_idx)); k_event_post(&priv->drv_evt, BIT(DWC2_DRV_EVT_EP_FINISHED)); } @@ -2452,7 +2452,7 @@ static inline void dwc2_handle_out_xfercompl(const struct device *dev, net_buf_tailroom(buf)) { dwc2_prep_rx(dev, buf, ep_cfg); } else { - k_event_post(&priv->xfer_finished, BIT(ep_idx)); + k_event_post(&priv->xfer_finished, BIT(16 + ep_idx)); k_event_post(&priv->drv_evt, BIT(DWC2_DRV_EVT_EP_FINISHED)); } } @@ -2803,9 +2803,9 @@ static uint8_t pull_next_ep_from_bitmap(uint32_t *bitmap) *bitmap &= ~BIT(bit); if (bit >= 16) { - return USB_EP_DIR_IN | (bit - 16); + return USB_EP_DIR_OUT | (bit - 16); } else { - return USB_EP_DIR_OUT | bit; + return USB_EP_DIR_IN | bit; } }