Skip to content

Commit 31a6784

Browse files
tmon-nordicgithub-actions[bot]
authored andcommitted
[nrf fromtree] drivers: udc_dwc2: Rework control endpoint feeding
In Completer mode SETUP data can always be received and therefore endpoint 0 should only be enabled for OUT Data Stage and OUT Status Stage. In Buffer DMA mode, SETUP can only be received when endpoint is enabled and therefore the software has to make sure that there is a buffer available to receive SETUP data. Rework the EP0 buffer feeding to adhere to DWC2 Programming Guide. Synchronize the accesses with driver mutex to avoid interrupt related race conditions. Signed-off-by: Tomasz Moń <[email protected]> (cherry picked from commit 8348d9a) (cherry picked from commit d0bef36)
1 parent e0deed4 commit 31a6784

File tree

1 file changed

+107
-65
lines changed

1 file changed

+107
-65
lines changed

drivers/usb/udc/udc_dwc2.c

Lines changed: 107 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ LOG_MODULE_REGISTER(udc_dwc2, CONFIG_UDC_DRIVER_LOG_LEVEL);
2525
#include "udc_dwc2_vendor_quirks.h"
2626

2727
enum dwc2_drv_event_type {
28+
/* USB connection speed determined after bus reset */
29+
DWC2_DRV_EVT_ENUM_DONE,
2830
/* Trigger next transfer, must not be used for control OUT */
2931
DWC2_DRV_EVT_XFER,
3032
/* Setup packet received */
@@ -383,6 +385,42 @@ static bool dwc2_ep_is_iso(struct udc_ep_config *const cfg)
383385
return (cfg->attributes & USB_EP_TRANSFER_TYPE_MASK) == USB_EP_TYPE_ISO;
384386
}
385387

388+
static int dwc2_ctrl_feed_dout(const struct device *dev, const size_t length)
389+
{
390+
struct udc_dwc2_data *const priv = udc_get_private(dev);
391+
struct udc_ep_config *ep_cfg = udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT);
392+
struct net_buf *buf;
393+
size_t alloc_len = length;
394+
395+
if (dwc2_in_buffer_dma_mode(dev)) {
396+
/* Control OUT buffers must be multiple of bMaxPacketSize0 */
397+
alloc_len = ROUND_UP(length, 64);
398+
}
399+
400+
buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, alloc_len);
401+
if (buf == NULL) {
402+
return -ENOMEM;
403+
}
404+
405+
udc_buf_put(ep_cfg, buf);
406+
k_event_post(&priv->xfer_new, BIT(16));
407+
k_event_post(&priv->drv_evt, BIT(DWC2_DRV_EVT_XFER));
408+
409+
return 0;
410+
}
411+
412+
static void dwc2_ensure_setup_ready(const struct device *dev)
413+
{
414+
if (dwc2_in_completer_mode(dev)) {
415+
/* In Completer mode EP0 can always receive SETUP data */
416+
return;
417+
}
418+
419+
if (!udc_buf_peek(dev, USB_CONTROL_EP_OUT)) {
420+
dwc2_ctrl_feed_dout(dev, 8);
421+
}
422+
}
423+
386424
static bool dwc2_dma_buffer_ok_to_use(const struct device *dev, void *buf,
387425
uint32_t xfersize, uint16_t mps)
388426
{
@@ -708,6 +746,26 @@ static void dwc2_handle_xfer_next(const struct device *dev,
708746
} else {
709747
int err = dwc2_tx_fifo_write(dev, cfg, buf);
710748

749+
if (cfg->addr == USB_CONTROL_EP_IN) {
750+
/* Feed a buffer for the next setup packet after arming
751+
* IN endpoint with the data. This is necessary both in
752+
* IN Data Stage (Control Read Transfer) and IN Status
753+
* Stage (Control Write Transfers and Control Transfers
754+
* without Data Stage).
755+
*
756+
* The buffer must be fed here in Buffer DMA mode to
757+
* allow receiving premature SETUP. This inevitably does
758+
* automatically arm the buffer for OUT Status Stage.
759+
*
760+
* The buffer MUST NOT be fed here in Completer mode to
761+
* avoid race condition where the next Control Write
762+
* Transfer Data Stage is received into the buffer.
763+
*/
764+
if (dwc2_in_buffer_dma_mode(dev)) {
765+
dwc2_ctrl_feed_dout(dev, 8);
766+
}
767+
}
768+
711769
if (err) {
712770
LOG_ERR("Failed to start write to TX FIFO, ep 0x%02x (err: %d)",
713771
cfg->addr, err);
@@ -724,39 +782,35 @@ static void dwc2_handle_xfer_next(const struct device *dev,
724782
udc_ep_set_busy(dev, cfg->addr, true);
725783
}
726784

727-
static int dwc2_ctrl_feed_dout(const struct device *dev, const size_t length)
785+
static int dwc2_handle_evt_setup(const struct device *dev)
728786
{
729787
struct udc_dwc2_data *const priv = udc_get_private(dev);
730-
struct udc_ep_config *ep_cfg = udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT);
731788
struct net_buf *buf;
732-
size_t alloc_len = length;
789+
int err;
733790

734-
if (dwc2_in_buffer_dma_mode(dev)) {
735-
/* Control OUT buffers must be multiple of bMaxPacketSize0 */
736-
alloc_len = ROUND_UP(length, 64);
737-
}
791+
/* In Completer mode SETUP data is received without preparing endpoint 0
792+
* transfer beforehand. In Buffer DMA the SETUP can be copied to any EP0
793+
* OUT buffer. If there is any buffer queued, it is obsolete now.
794+
*/
795+
k_event_clear(&priv->xfer_finished, BIT(0) | BIT(16));
738796

739-
buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, alloc_len);
740-
if (buf == NULL) {
741-
return -ENOMEM;
797+
buf = udc_buf_get_all(dev, USB_CONTROL_EP_OUT);
798+
if (buf) {
799+
net_buf_unref(buf);
742800
}
743801

744-
udc_buf_put(ep_cfg, buf);
745-
dwc2_prep_rx(dev, buf, ep_cfg);
746-
LOG_DBG("feed buf %p", buf);
747-
748-
return 0;
749-
}
802+
buf = udc_buf_get_all(dev, USB_CONTROL_EP_IN);
803+
if (buf) {
804+
net_buf_unref(buf);
805+
}
750806

751-
static int dwc2_handle_evt_setup(const struct device *dev)
752-
{
753-
struct udc_dwc2_data *const priv = udc_get_private(dev);
754-
struct net_buf *buf;
755-
int err;
807+
udc_ep_set_busy(dev, USB_CONTROL_EP_OUT, false);
808+
udc_ep_set_busy(dev, USB_CONTROL_EP_IN, false);
756809

757-
buf = udc_buf_get(dev, USB_CONTROL_EP_OUT);
810+
/* Allocate buffer and copy received SETUP for processing */
811+
buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, 8);
758812
if (buf == NULL) {
759-
LOG_ERR("No buffer queued for control ep");
813+
LOG_ERR("No buffer available for control ep");
760814
return -ENODATA;
761815
}
762816

@@ -773,30 +827,17 @@ static int dwc2_handle_evt_setup(const struct device *dev)
773827
/* Allocate and feed buffer for data OUT stage */
774828
LOG_DBG("s:%p|feed for -out-", buf);
775829

776-
/* Allocate at least 8 bytes in case the host decides to send
777-
* SETUP DATA instead of OUT DATA packet.
778-
*/
779-
err = dwc2_ctrl_feed_dout(dev, MAX(udc_data_stage_length(buf), 8));
830+
err = dwc2_ctrl_feed_dout(dev, udc_data_stage_length(buf));
780831
if (err == -ENOMEM) {
781832
err = udc_submit_ep_event(dev, buf, err);
782833
}
783834
} else if (udc_ctrl_stage_is_data_in(dev)) {
784835
LOG_DBG("s:%p|feed for -in-status", buf);
785836

786-
err = dwc2_ctrl_feed_dout(dev, 8);
787-
if (err == -ENOMEM) {
788-
err = udc_submit_ep_event(dev, buf, err);
789-
}
790-
791837
err = udc_ctrl_submit_s_in_status(dev);
792838
} else {
793839
LOG_DBG("s:%p|feed >setup", buf);
794840

795-
err = dwc2_ctrl_feed_dout(dev, 8);
796-
if (err == -ENOMEM) {
797-
err = udc_submit_ep_event(dev, buf, err);
798-
}
799-
800841
err = udc_ctrl_submit_s_status(dev);
801842
}
802843

@@ -806,6 +847,7 @@ static int dwc2_handle_evt_setup(const struct device *dev)
806847
static inline int dwc2_handle_evt_dout(const struct device *dev,
807848
struct udc_ep_config *const cfg)
808849
{
850+
struct udc_data *data = dev->data;
809851
struct net_buf *buf;
810852
int err = 0;
811853

@@ -822,25 +864,14 @@ static inline int dwc2_handle_evt_dout(const struct device *dev,
822864
/* s-in-status finished */
823865
LOG_DBG("dout:%p| status, feed >s", buf);
824866

825-
/* Feed a buffer for the next setup packet */
826-
err = dwc2_ctrl_feed_dout(dev, 8);
827-
if (err == -ENOMEM) {
828-
err = udc_submit_ep_event(dev, buf, err);
829-
}
830-
831867
/* Status stage finished, notify upper layer */
832868
udc_ctrl_submit_status(dev, buf);
833-
} else {
834-
/*
835-
* For all other cases we feed with a buffer
836-
* large enough for setup packet.
837-
*/
838-
LOG_DBG("dout:%p| data, feed >s", buf);
839869

840-
err = dwc2_ctrl_feed_dout(dev, 8);
841-
if (err == -ENOMEM) {
842-
err = udc_submit_ep_event(dev, buf, err);
870+
if (dwc2_in_buffer_dma_mode(dev)) {
871+
dwc2_ctrl_feed_dout(dev, 8);
843872
}
873+
} else {
874+
LOG_DBG("dout:%p| data, feed >s", buf);
844875
}
845876

846877
/* Update to next stage of control transfer */
@@ -849,6 +880,13 @@ static inline int dwc2_handle_evt_dout(const struct device *dev,
849880
if (udc_ctrl_stage_is_status_in(dev)) {
850881
err = udc_ctrl_submit_s_out_status(dev, buf);
851882
}
883+
884+
if (data->stage == CTRL_PIPE_STAGE_ERROR) {
885+
/* Allow receiving next SETUP. USB stack won't queue any
886+
* buffer because it has no clue about this transfer.
887+
*/
888+
dwc2_ensure_setup_ready(dev);
889+
}
852890
} else {
853891
err = udc_submit_ep_event(dev, buf, 0);
854892
}
@@ -892,10 +930,12 @@ static int dwc2_handle_evt_din(const struct device *dev,
892930
udc_ctrl_update_stage(dev, buf);
893931

894932
if (udc_ctrl_stage_is_status_out(dev)) {
895-
/*
896-
* IN transfer finished, release buffer,
897-
* control OUT buffer should be already fed.
898-
*/
933+
if (dwc2_in_completer_mode(dev)) {
934+
/* Allow OUT status stage */
935+
dwc2_ctrl_feed_dout(dev, 8);
936+
}
937+
938+
/* IN transfer finished, release buffer. */
899939
net_buf_unref(buf);
900940
}
901941

@@ -1322,13 +1362,7 @@ static int dwc2_ep_control_enable(const struct device *dev,
13221362
dxepctl0 |= USB_DWC2_DEPCTL_USBACTEP;
13231363

13241364
if (cfg->addr == USB_CONTROL_EP_OUT) {
1325-
int ret;
1326-
13271365
dwc2_flush_rx_fifo(dev);
1328-
ret = dwc2_ctrl_feed_dout(dev, 8);
1329-
if (ret) {
1330-
return ret;
1331-
}
13321366
} else {
13331367
dwc2_flush_tx_fifo(dev, 0);
13341368
}
@@ -1613,9 +1647,9 @@ static int udc_dwc2_ep_set_halt(const struct device *dev,
16131647
LOG_DBG("Set halt ep 0x%02x", cfg->addr);
16141648
if (ep_idx != 0) {
16151649
cfg->stat.halted = true;
1616-
} else if (!udc_buf_peek(dev, USB_CONTROL_EP_OUT)) {
1617-
/* Data stage is STALLed, allow receiving next SETUP */
1618-
dwc2_ctrl_feed_dout(dev, 8);
1650+
} else {
1651+
/* Data/Status stage is STALLed, allow receiving next SETUP */
1652+
dwc2_ensure_setup_ready(dev);
16191653
}
16201654

16211655
return 0;
@@ -2341,6 +2375,8 @@ static void dwc2_handle_enumdone(const struct device *dev)
23412375
dsts = sys_read32((mem_addr_t)&base->dsts);
23422376
priv->enumspd = usb_dwc2_get_dsts_enumspd(dsts);
23432377
priv->enumdone = 1;
2378+
2379+
k_event_post(&priv->drv_evt, BIT(DWC2_DRV_EVT_ENUM_DONE));
23442380
}
23452381

23462382
static inline int dwc2_read_fifo_setup(const struct device *dev, uint8_t ep,
@@ -3041,6 +3077,12 @@ static ALWAYS_INLINE void dwc2_thread_handler(void *const arg)
30413077
config->irq_enable_func(dev);
30423078
}
30433079

3080+
if (evt & BIT(DWC2_DRV_EVT_ENUM_DONE)) {
3081+
k_event_clear(&priv->drv_evt, BIT(DWC2_DRV_EVT_ENUM_DONE));
3082+
3083+
dwc2_ensure_setup_ready(dev);
3084+
}
3085+
30443086
udc_unlock_internal(dev);
30453087
}
30463088

0 commit comments

Comments
 (0)