usb: cdnsp: Fix issue with detecting command completion event
authorPawel Laszczak <pawell@cadence.com>
Tue, 13 May 2025 05:30:09 +0000 (05:30 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 21 May 2025 11:12:10 +0000 (13:12 +0200)
In some cases, there is a small-time gap in which CMD_RING_BUSY can be
cleared by controller but adding command completion event to event ring
will be delayed. As the result driver will return error code.

This behavior has been detected on usbtest driver (test 9) with
configuration including ep1in/ep1out bulk and ep2in/ep2out isoc
endpoint.

Probably this gap occurred because controller was busy with adding some
other events to event ring.

The CMD_RING_BUSY is cleared to '0' when the Command Descriptor has been
executed and not when command completion event has been added to event
ring.

To fix this issue for this test the small delay is sufficient less than
10us) but to make sure the problem doesn't happen again in the future
the patch introduces 10 retries to check with delay about 20us before
returning error code.

Fixes: 3d82904559f4 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver")
Cc: stable <stable@kernel.org>
Signed-off-by: Pawel Laszczak <pawell@cadence.com>
Acked-by: Peter Chen <peter.chen@kernel.org>
Link: https://lore.kernel.org/r/PH7PR07MB9538AA45362ACCF1B94EE9B7DD96A@PH7PR07MB9538.namprd07.prod.outlook.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/cdns3/cdnsp-gadget.c

index cd1e00daf43f55c59fbfe98707beb64d84617781..55f95f41b3b4dd880c0aea0d1ab9eaeca2e93a45 100644 (file)
@@ -548,6 +548,7 @@ int cdnsp_wait_for_cmd_compl(struct cdnsp_device *pdev)
        dma_addr_t cmd_deq_dma;
        union cdnsp_trb *event;
        u32 cycle_state;
+       u32 retry = 10;
        int ret, val;
        u64 cmd_dma;
        u32  flags;
@@ -579,8 +580,23 @@ int cdnsp_wait_for_cmd_compl(struct cdnsp_device *pdev)
                flags = le32_to_cpu(event->event_cmd.flags);
 
                /* Check the owner of the TRB. */
-               if ((flags & TRB_CYCLE) != cycle_state)
+               if ((flags & TRB_CYCLE) != cycle_state) {
+                       /*
+                        * Give some extra time to get chance controller
+                        * to finish command before returning error code.
+                        * Checking CMD_RING_BUSY is not sufficient because
+                        * this bit is cleared to '0' when the Command
+                        * Descriptor has been executed by controller
+                        * and not when command completion event has
+                        * be added to event ring.
+                        */
+                       if (retry--) {
+                               udelay(20);
+                               continue;
+                       }
+
                        return -EINVAL;
+               }
 
                cmd_dma = le64_to_cpu(event->event_cmd.cmd_trb);