Skip to content

Commit 96bb174

Browse files
dianderstzuwen_chang
authored andcommitted
UPSTREAM: usb: dwc2: host: fix split transfer schedule sequence
We're supposed to keep outstanding splits in order. Keep track of a list of the order of splits and process channel interrupts in that order. Without this change and the following setup: * Rockchip rk3288 Chromebook, using port ff540000 -> Pluggable 7-port Hub with Charging (powered) -> Microsoft Wireless Keyboard 2000 in port 1. -> Das Keyboard in port 2. ...I find that I get dropped keys on the Microsoft keyboard (I'm sure there are other combinations that fail, but this documents my test). Specifically I've been typing "hahahahahahaha" on the keyboard and often see keys dropped or repeated. After this change the above setup works properly. This patch is based on a previous patch proposed by Yunzhi Li ("usb: dwc2: hcd: fix periodic transfer schedule sequence") Change-Id: I1d461d73c21a117de86de2863c0412b4980a16d8 Acked-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Yunzhi Li <lyz@rock-chips.com> Reviewed-by: Kever Yang <kever.yang@rock-chips.com> Tested-by: Heiko Stuebner <heiko@sntech.de> Tested-by: Kever Yang <kever.yang@rock-chips.com> Tested-by: Stefan Wahren <stefan.wahren@i2se.com> Signed-off-by: Felipe Balbi <balbi@kernel.org> (cherry picked from commit c9c8ac0150df2b75b25683cd3df3cb56877e4e52)
1 parent a927218 commit 96bb174

5 files changed

Lines changed: 31 additions & 0 deletions

File tree

drivers/usb/dwc2/core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,8 @@ void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
15591559

15601560
chan->xfer_started = 0;
15611561

1562+
list_del_init(&chan->split_order_list_entry);
1563+
15621564
/*
15631565
* Clear channel interrupt enables and any unhandled channel interrupt
15641566
* conditions

drivers/usb/dwc2/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ struct dwc2_hregs_backup {
672672
* periodic_sched_ready because it must be rescheduled for
673673
* the next frame. Otherwise, the item moves to
674674
* periodic_sched_inactive.
675+
* @split_order: List keeping track of channels doing splits, in order.
675676
* @periodic_usecs: Total bandwidth claimed so far for periodic transfers.
676677
* This value is in microseconds per (micro)frame. The
677678
* assumption is that all periodic transfers may occur in
@@ -792,6 +793,7 @@ struct dwc2_hsotg {
792793
struct list_head periodic_sched_ready;
793794
struct list_head periodic_sched_assigned;
794795
struct list_head periodic_sched_queued;
796+
struct list_head split_order;
795797
u16 periodic_usecs;
796798
u16 frame_usecs[8];
797799
u16 frame_number;

drivers/usb/dwc2/hcd.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,11 @@ static int dwc2_queue_transaction(struct dwc2_hsotg *hsotg,
10061006
{
10071007
int retval = 0;
10081008

1009+
if (chan->do_split)
1010+
/* Put ourselves on the list to keep order straight */
1011+
list_move_tail(&chan->split_order_list_entry,
1012+
&hsotg->split_order);
1013+
10091014
if (hsotg->core_params->dma_enable > 0) {
10101015
if (hsotg->core_params->dma_desc_enable > 0) {
10111016
if (!chan->xfer_started ||
@@ -3081,6 +3086,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
30813086
INIT_LIST_HEAD(&hsotg->periodic_sched_assigned);
30823087
INIT_LIST_HEAD(&hsotg->periodic_sched_queued);
30833088

3089+
INIT_LIST_HEAD(&hsotg->split_order);
3090+
30843091
/*
30853092
* Create a host channel descriptor for each host channel implemented
30863093
* in the controller. Initialize the channel descriptor array.
@@ -3094,6 +3101,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
30943101
if (channel == NULL)
30953102
goto error3;
30963103
channel->hc_num = i;
3104+
INIT_LIST_HEAD(&channel->split_order_list_entry);
30973105
hsotg->hc_ptr_array[i] = channel;
30983106
}
30993107

drivers/usb/dwc2/hcd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ struct dwc2_qh;
107107
* @qh: QH for the transfer being processed by this channel
108108
* @hc_list_entry: For linking to list of host channels
109109
* @desc_list_addr: Current QH's descriptor list DMA address
110+
* @split_order_list_entry: List entry for keeping track of the order of splits
110111
*
111112
* This structure represents the state of a single host channel when acting in
112113
* host mode. It contains the data items needed to transfer packets to an
@@ -159,6 +160,7 @@ struct dwc2_host_chan {
159160
struct dwc2_qh *qh;
160161
struct list_head hc_list_entry;
161162
dma_addr_t desc_list_addr;
163+
struct list_head split_order_list_entry;
162164
};
163165

164166
struct dwc2_hcd_pipe_info {

drivers/usb/dwc2/hcd_intr.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,7 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
21152115
{
21162116
u32 haint;
21172117
int i;
2118+
struct dwc2_host_chan *chan, *chan_tmp;
21182119

21192120
haint = dwc2_readl(hsotg->regs + HAINT);
21202121
if (dbg_perio()) {
@@ -2123,6 +2124,22 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
21232124
dev_vdbg(hsotg->dev, "HAINT=%08x\n", haint);
21242125
}
21252126

2127+
/*
2128+
* According to USB 2.0 spec section 11.18.8, a host must
2129+
* issue complete-split transactions in a microframe for a
2130+
* set of full-/low-speed endpoints in the same relative
2131+
* order as the start-splits were issued in a microframe for.
2132+
*/
2133+
list_for_each_entry_safe(chan, chan_tmp, &hsotg->split_order,
2134+
split_order_list_entry) {
2135+
int hc_num = chan->hc_num;
2136+
2137+
if (haint & (1 << hc_num)) {
2138+
dwc2_hc_n_intr(hsotg, hc_num);
2139+
haint &= ~(1 << hc_num);
2140+
}
2141+
}
2142+
21262143
for (i = 0; i < hsotg->core_params->host_channels; i++) {
21272144
if (haint & (1 << i))
21282145
dwc2_hc_n_intr(hsotg, i);

0 commit comments

Comments
 (0)