]>
Commit | Line | Data |
---|---|---|
30daf967 GKH |
1 | From b258e42688501cadb1a6dd658d6f015df9f32d8f Mon Sep 17 00:00:00 2001 |
2 | From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com> | |
3 | Date: Wed, 13 Mar 2024 09:21:32 +0000 | |
4 | Subject: usb: dwc2: host: Fix ISOC flow in DDMA mode | |
5 | ||
6 | From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com> | |
7 | ||
8 | commit b258e42688501cadb1a6dd658d6f015df9f32d8f upstream. | |
9 | ||
10 | Fixed ISOC completion flow in DDMA mode. Added isoc | |
11 | descriptor actual length value and update urb's start_frame | |
12 | value. | |
13 | Fixed initialization of ISOC DMA descriptors flow. | |
14 | ||
15 | Fixes: 56f5b1cff22a ("staging: Core files for the DWC2 driver") | |
16 | Fixes: 20f2eb9c4cf8 ("staging: dwc2: add microframe scheduler from downstream Pi kernel") | |
17 | Fixes: c17b337c1ea4 ("usb: dwc2: host: program descriptor for next frame") | |
18 | Fixes: dc4c76e7b22c ("staging: HCD descriptor DMA support for the DWC2 driver") | |
19 | Fixes: 762d3a1a9cd7 ("usb: dwc2: host: process all completed urbs") | |
20 | CC: stable@vger.kernel.org | |
21 | Signed-off-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com> | |
22 | Link: https://lore.kernel.org/r/a8b1e1711cc6cabfb45d92ede12e35445c66f06c.1708944698.git.Minas.Harutyunyan@synopsys.com | |
23 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
24 | --- | |
25 | drivers/usb/dwc2/hcd.c | 12 ++++++++++-- | |
26 | drivers/usb/dwc2/hcd_ddma.c | 17 +++++++++++------ | |
27 | drivers/usb/dwc2/hw.h | 2 +- | |
28 | 3 files changed, 22 insertions(+), 9 deletions(-) | |
29 | ||
30 | --- a/drivers/usb/dwc2/hcd.c | |
31 | +++ b/drivers/usb/dwc2/hcd.c | |
32 | @@ -2736,8 +2736,11 @@ enum dwc2_transaction_type dwc2_hcd_sele | |
33 | hsotg->available_host_channels--; | |
34 | } | |
35 | qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry); | |
36 | - if (dwc2_assign_and_init_hc(hsotg, qh)) | |
37 | + if (dwc2_assign_and_init_hc(hsotg, qh)) { | |
38 | + if (hsotg->params.uframe_sched) | |
39 | + hsotg->available_host_channels++; | |
40 | break; | |
41 | + } | |
42 | ||
43 | /* | |
44 | * Move the QH from the periodic ready schedule to the | |
45 | @@ -2770,8 +2773,11 @@ enum dwc2_transaction_type dwc2_hcd_sele | |
46 | hsotg->available_host_channels--; | |
47 | } | |
48 | ||
49 | - if (dwc2_assign_and_init_hc(hsotg, qh)) | |
50 | + if (dwc2_assign_and_init_hc(hsotg, qh)) { | |
51 | + if (hsotg->params.uframe_sched) | |
52 | + hsotg->available_host_channels++; | |
53 | break; | |
54 | + } | |
55 | ||
56 | /* | |
57 | * Move the QH from the non-periodic inactive schedule to the | |
58 | @@ -4125,6 +4131,8 @@ void dwc2_host_complete(struct dwc2_hsot | |
59 | urb->actual_length); | |
60 | ||
61 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { | |
62 | + if (!hsotg->params.dma_desc_enable) | |
63 | + urb->start_frame = qtd->qh->start_active_frame; | |
64 | urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb); | |
65 | for (i = 0; i < urb->number_of_packets; ++i) { | |
66 | urb->iso_frame_desc[i].actual_length = | |
67 | --- a/drivers/usb/dwc2/hcd_ddma.c | |
68 | +++ b/drivers/usb/dwc2/hcd_ddma.c | |
69 | @@ -589,7 +589,7 @@ static void dwc2_init_isoc_dma_desc(stru | |
70 | idx = qh->td_last; | |
71 | inc = qh->host_interval; | |
72 | hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg); | |
73 | - cur_idx = dwc2_frame_list_idx(hsotg->frame_number); | |
74 | + cur_idx = idx; | |
75 | next_idx = dwc2_desclist_idx_inc(qh->td_last, inc, qh->dev_speed); | |
76 | ||
77 | /* | |
78 | @@ -896,6 +896,8 @@ static int dwc2_cmpl_host_isoc_dma_desc( | |
79 | { | |
80 | struct dwc2_dma_desc *dma_desc; | |
81 | struct dwc2_hcd_iso_packet_desc *frame_desc; | |
82 | + u16 frame_desc_idx; | |
83 | + struct urb *usb_urb = qtd->urb->priv; | |
84 | u16 remain = 0; | |
85 | int rc = 0; | |
86 | ||
87 | @@ -908,8 +910,11 @@ static int dwc2_cmpl_host_isoc_dma_desc( | |
88 | DMA_FROM_DEVICE); | |
89 | ||
90 | dma_desc = &qh->desc_list[idx]; | |
91 | + frame_desc_idx = (idx - qtd->isoc_td_first) & (usb_urb->number_of_packets - 1); | |
92 | ||
93 | - frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last]; | |
94 | + frame_desc = &qtd->urb->iso_descs[frame_desc_idx]; | |
95 | + if (idx == qtd->isoc_td_first) | |
96 | + usb_urb->start_frame = dwc2_hcd_get_frame_number(hsotg); | |
97 | dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset); | |
98 | if (chan->ep_is_in) | |
99 | remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >> | |
100 | @@ -930,7 +935,7 @@ static int dwc2_cmpl_host_isoc_dma_desc( | |
101 | frame_desc->status = 0; | |
102 | } | |
103 | ||
104 | - if (++qtd->isoc_frame_index == qtd->urb->packet_count) { | |
105 | + if (++qtd->isoc_frame_index == usb_urb->number_of_packets) { | |
106 | /* | |
107 | * urb->status is not used for isoc transfers here. The | |
108 | * individual frame_desc status are used instead. | |
109 | @@ -1035,11 +1040,11 @@ static void dwc2_complete_isoc_xfer_ddma | |
110 | return; | |
111 | idx = dwc2_desclist_idx_inc(idx, qh->host_interval, | |
112 | chan->speed); | |
113 | - if (!rc) | |
114 | + if (rc == 0) | |
115 | continue; | |
116 | ||
117 | - if (rc == DWC2_CMPL_DONE) | |
118 | - break; | |
119 | + if (rc == DWC2_CMPL_DONE || rc == DWC2_CMPL_STOP) | |
120 | + goto stop_scan; | |
121 | ||
122 | /* rc == DWC2_CMPL_STOP */ | |
123 | ||
124 | --- a/drivers/usb/dwc2/hw.h | |
125 | +++ b/drivers/usb/dwc2/hw.h | |
126 | @@ -727,7 +727,7 @@ | |
127 | #define TXSTS_QTOP_TOKEN_MASK (0x3 << 25) | |
128 | #define TXSTS_QTOP_TOKEN_SHIFT 25 | |
129 | #define TXSTS_QTOP_TERMINATE BIT(24) | |
130 | -#define TXSTS_QSPCAVAIL_MASK (0xff << 16) | |
131 | +#define TXSTS_QSPCAVAIL_MASK (0x7f << 16) | |
132 | #define TXSTS_QSPCAVAIL_SHIFT 16 | |
133 | #define TXSTS_FSPCAVAIL_MASK (0xffff << 0) | |
134 | #define TXSTS_FSPCAVAIL_SHIFT 0 |