In the existing implementation, multiple requests queued up on an endpoint are subject to getting evicted without transmission.
For both control and bulk endpoints, their respective logic found in usba_control_irq()/usba_ep_irq() guarantees that TX FIFO is empty before data is sent out, and that request_complete() gets called once the transaction has been finished. At this point however, if any additional requests are found on the endpoint queue, they will be processed by submit_next_request(), which makes no checks against the above conditions, trashing data on a busy FIFO and neglecting completion handlers. Fix the above issues by removing the calls to submit_next_request(), and thus forcing the pending requests to be processed on the next pass of the respective endpoint logic. While at it, remove a DBG message, as that branch becomes part of regular flow. This restores mass storage mode operation on Microchip ATSAMA5D27 SoC. Signed-off-by: Artur Rojek <ar...@conclusive.pl> --- drivers/usb/gadget/atmel_usba_udc.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 7d51821497b4..e6b458d940d8 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -57,13 +57,9 @@ static void submit_request(struct usba_ep *ep, struct usba_request *req) req->submitted = 1; next_fifo_transaction(ep, req); - if (req->last_transaction) { - usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); - } else { + if (ep_is_control(ep)) usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); - } + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); } static void submit_next_request(struct usba_ep *ep) @@ -889,7 +885,6 @@ restart: if (req) { list_del_init(&req->queue); request_complete(ep, req, 0); - submit_next_request(ep); } usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); ep->state = WAIT_FOR_SETUP; @@ -1036,7 +1031,6 @@ static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep) DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name); if (list_empty(&ep->queue)) { - DBG(DBG_INT, "ep_irq: queue empty\n"); usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); return; } @@ -1050,7 +1044,6 @@ static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep) if (req->last_transaction) { list_del_init(&req->queue); - submit_next_request(ep); request_complete(ep, req, 0); } -- 2.42.0