usb: dwc2: host: Fix ISOC flow in DDMA mode
authorMinas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Wed, 13 Mar 2024 09:21:32 +0000 (09:21 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 26 Mar 2024 13:56:23 +0000 (14:56 +0100)
Fixed ISOC completion flow in DDMA mode. Added isoc
descriptor actual length value and update urb's start_frame
value.
Fixed initialization of ISOC DMA descriptors flow.

Fixes: 56f5b1cff22a ("staging: Core files for the DWC2 driver")
Fixes: 20f2eb9c4cf8 ("staging: dwc2: add microframe scheduler from downstream Pi kernel")
Fixes: c17b337c1ea4 ("usb: dwc2: host: program descriptor for next frame")
Fixes: dc4c76e7b22c ("staging: HCD descriptor DMA support for the DWC2 driver")
Fixes: 762d3a1a9cd7 ("usb: dwc2: host: process all completed urbs")
CC: stable@vger.kernel.org
Signed-off-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Link: https://lore.kernel.org/r/a8b1e1711cc6cabfb45d92ede12e35445c66f06c.1708944698.git.Minas.Harutyunyan@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd_ddma.c
drivers/usb/dwc2/hw.h

index 6de999c7513eb7d0717e3ba8aa36bc1c6c3509f5..70b389125f63560308dee3213f36e25e425f6f9e 100644 (file)
@@ -2701,8 +2701,11 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions(
                        hsotg->available_host_channels--;
                }
                qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
-               if (dwc2_assign_and_init_hc(hsotg, qh))
+               if (dwc2_assign_and_init_hc(hsotg, qh)) {
+                       if (hsotg->params.uframe_sched)
+                               hsotg->available_host_channels++;
                        break;
+               }
 
                /*
                 * Move the QH from the periodic ready schedule to the
@@ -2735,8 +2738,11 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions(
                        hsotg->available_host_channels--;
                }
 
-               if (dwc2_assign_and_init_hc(hsotg, qh))
+               if (dwc2_assign_and_init_hc(hsotg, qh)) {
+                       if (hsotg->params.uframe_sched)
+                               hsotg->available_host_channels++;
                        break;
+               }
 
                /*
                 * Move the QH from the non-periodic inactive schedule to the
@@ -4143,6 +4149,8 @@ void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
                         urb->actual_length);
 
        if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+               if (!hsotg->params.dma_desc_enable)
+                       urb->start_frame = qtd->qh->start_active_frame;
                urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb);
                for (i = 0; i < urb->number_of_packets; ++i) {
                        urb->iso_frame_desc[i].actual_length =
index 6b4d825e97a2d91bbafd04ada5fdce4a1ab52c0c..79582b102c7eda2eb72f6da3c293615cdad50b56 100644 (file)
@@ -559,7 +559,7 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
        idx = qh->td_last;
        inc = qh->host_interval;
        hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
-       cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
+       cur_idx = idx;
        next_idx = dwc2_desclist_idx_inc(qh->td_last, inc, qh->dev_speed);
 
        /*
@@ -866,6 +866,8 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
 {
        struct dwc2_dma_desc *dma_desc;
        struct dwc2_hcd_iso_packet_desc *frame_desc;
+       u16 frame_desc_idx;
+       struct urb *usb_urb = qtd->urb->priv;
        u16 remain = 0;
        int rc = 0;
 
@@ -878,8 +880,11 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
                                DMA_FROM_DEVICE);
 
        dma_desc = &qh->desc_list[idx];
+       frame_desc_idx = (idx - qtd->isoc_td_first) & (usb_urb->number_of_packets - 1);
 
-       frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
+       frame_desc = &qtd->urb->iso_descs[frame_desc_idx];
+       if (idx == qtd->isoc_td_first)
+               usb_urb->start_frame = dwc2_hcd_get_frame_number(hsotg);
        dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
        if (chan->ep_is_in)
                remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >>
@@ -900,7 +905,7 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
                frame_desc->status = 0;
        }
 
-       if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
+       if (++qtd->isoc_frame_index == usb_urb->number_of_packets) {
                /*
                 * urb->status is not used for isoc transfers here. The
                 * individual frame_desc status are used instead.
@@ -1005,11 +1010,11 @@ static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
                                return;
                        idx = dwc2_desclist_idx_inc(idx, qh->host_interval,
                                                    chan->speed);
-                       if (!rc)
+                       if (rc == 0)
                                continue;
 
-                       if (rc == DWC2_CMPL_DONE)
-                               break;
+                       if (rc == DWC2_CMPL_DONE || rc == DWC2_CMPL_STOP)
+                               goto stop_scan;
 
                        /* rc == DWC2_CMPL_STOP */
 
index 13abdd5f6752999cc20603fa404b02c3d84bac20..12f8c7f86dc980fc8fb754a7c6d82eab9f88bc7a 100644 (file)
 #define TXSTS_QTOP_TOKEN_MASK          (0x3 << 25)
 #define TXSTS_QTOP_TOKEN_SHIFT         25
 #define TXSTS_QTOP_TERMINATE           BIT(24)
-#define TXSTS_QSPCAVAIL_MASK           (0xff << 16)
+#define TXSTS_QSPCAVAIL_MASK           (0x7f << 16)
 #define TXSTS_QSPCAVAIL_SHIFT          16
 #define TXSTS_FSPCAVAIL_MASK           (0xffff << 0)
 #define TXSTS_FSPCAVAIL_SHIFT          0