drivers: udc_dwc2: Handle IN events before OUT events
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ń <tomasz.mon@nordicsemi.no>
This commit is contained in:
parent
aefda52e42
commit
94a6b82572
1 changed files with 10 additions and 10 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue