Skip to content

Commit

Permalink
usb: dwc2: host: Fix ISOC flow in DDMA mode
Browse files Browse the repository at this point in the history
commit b258e42 upstream.

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: 56f5b1c ("staging: Core files for the DWC2 driver")
Fixes: 20f2eb9 ("staging: dwc2: add microframe scheduler from downstream Pi kernel")
Fixes: c17b337 ("usb: dwc2: host: program descriptor for next frame")
Fixes: dc4c76e ("staging: HCD descriptor DMA support for the DWC2 driver")
Fixes: 762d3a1 ("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>
  • Loading branch information
Minas Harutyunyan authored and gregkh committed Apr 3, 2024
1 parent 582c00e commit c4046e7
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 9 deletions.
12 changes: 10 additions & 2 deletions drivers/usb/dwc2/hcd.c
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 =
Expand Down
17 changes: 11 additions & 6 deletions drivers/usb/dwc2/hcd_ddma.c
Expand Up @@ -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);

/*
Expand Down Expand Up @@ -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;

Expand All @@ -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) >>
Expand All @@ -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.
Expand Down Expand Up @@ -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 */

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/dwc2/hw.h
Expand Up @@ -698,7 +698,7 @@
#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
Expand Down

0 comments on commit c4046e7

Please sign in to comment.