brcm2708: update 4.1 patches
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-4.1 / 0149-dwc_otg-fiq_fsm-Make-high-speed-isochronous-strided-.patch
1 From 52db5f085001b191fb6ccdb8138ba947ba48ba73 Mon Sep 17 00:00:00 2001
2 From: P33M <P33M@github.com>
3 Date: Tue, 4 Aug 2015 01:15:20 +0100
4 Subject: [PATCH 149/222] dwc_otg: fiq_fsm: Make high-speed isochronous strided
5 transfers work properly
6
7 Certain low-bandwidth high-speed USB devices (specialist audio devices,
8 compressed-frame webcams) have packet intervals > 1 microframe.
9
10 Stride these transfers in the FIQ by using the start-of-frame interrupt
11 to restart the channel at the right time.
12 ---
13 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 17 +++++++++++++----
14 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 5 ++++-
15 drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 7 ++++++-
16 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 6 ++++--
17 4 files changed, 27 insertions(+), 8 deletions(-)
18
19 --- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
20 +++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
21 @@ -615,8 +615,11 @@ static int notrace noinline fiq_fsm_do_s
22 break;
23
24 case FIQ_HS_ISOC_SLEEPING:
25 - state->channel[n].fsm = FIQ_HS_ISOC_TURBO;
26 - fiq_fsm_restart_channel(state, n, 0);
27 + /* Is it time to wake this channel yet? */
28 + if (--state->channel[n].uframe_sleeps == 0) {
29 + state->channel[n].fsm = FIQ_HS_ISOC_TURBO;
30 + fiq_fsm_restart_channel(state, n, 0);
31 + }
32 break;
33
34 case FIQ_PER_SSPLIT_QUEUED:
35 @@ -624,7 +627,7 @@ static int notrace noinline fiq_fsm_do_s
36 break;
37 if(!fiq_fsm_tt_in_use(state, num_channels, n)) {
38 if (!fiq_fsm_too_late(state, n)) {
39 - fiq_print(FIQDBG_INT, st, "SOF GO %01d", n);
40 + fiq_print(FIQDBG_INT, state, "SOF GO %01d", n);
41 fiq_fsm_restart_channel(state, n, 0);
42 state->channel[n].fsm = FIQ_PER_SSPLIT_STARTED;
43 } else {
44 @@ -1069,8 +1072,14 @@ static int notrace noinline fiq_fsm_do_h
45 if (fiq_fsm_update_hs_isoc(state, n, hcint)) {
46 /* more transactions to come */
47 handled = 1;
48 - restart = 1;
49 fiq_print(FIQDBG_INT, state, "HSISO M ");
50 + /* For strided transfers, put ourselves to sleep */
51 + if (st->hs_isoc_info.stride > 1) {
52 + st->uframe_sleeps = st->hs_isoc_info.stride - 1;
53 + st->fsm = FIQ_HS_ISOC_SLEEPING;
54 + } else {
55 + restart = 1;
56 + }
57 } else {
58 st->fsm = FIQ_HS_ISOC_DONE;
59 fiq_print(FIQDBG_INT, state, "HSISO F ");
60 --- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
61 +++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
62 @@ -260,12 +260,13 @@ struct fiq_dma_blob {
63 * @iso_frame: Pointer to the array of OTG URB iso_frame_descs.
64 * @nrframes: Total length of iso_frame_desc array
65 * @index: Current index (FIQ-maintained)
66 - *
67 + * @stride: Interval in uframes between HS isoc transactions
68 */
69 struct fiq_hs_isoc_info {
70 struct dwc_otg_hcd_iso_packet_desc *iso_desc;
71 unsigned int nrframes;
72 unsigned int index;
73 + unsigned int stride;
74 };
75
76 /**
77 @@ -296,6 +297,8 @@ struct fiq_channel_state {
78 /* Hardware bug workaround: sometimes channel halt interrupts are
79 * delayed until the next SOF. Keep track of when we expected to get interrupted. */
80 unsigned int expected_uframe;
81 + /* number of uframes remaining (for interval > 1 HS isoc transfers) before next transfer */
82 + unsigned int uframe_sleeps;
83 /* in/out for communicating number of dma buffers used, or number of ISOC to do */
84 unsigned int nrpackets;
85 struct fiq_dma_info dma_info;
86 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
87 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
88 @@ -1678,6 +1678,9 @@ int fiq_fsm_queue_isoc_transaction(dwc_o
89 }
90 }
91
92 + st->hs_isoc_info.stride = qh->interval;
93 + st->uframe_sleeps = 0;
94 +
95 fiq_print(FIQDBG_INT, hcd->fiq_state, "FSMQ %01d ", hc->hc_num);
96 fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcchar_copy.d32);
97 fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hctsiz_copy.d32);
98 @@ -1692,9 +1695,11 @@ int fiq_fsm_queue_isoc_transaction(dwc_o
99 DWC_WRITE_REG32(&hc_regs->hcintmsk, st->hcintmsk_copy.d32);
100 if (hfnum.b.frrem < PERIODIC_FRREM_BACKOFF) {
101 /* Prevent queueing near EOF1. Bad things happen if a periodic
102 - * split transaction is queued very close to EOF.
103 + * split transaction is queued very close to EOF. SOF interrupt handler
104 + * will wake this channel at the next interrupt.
105 */
106 st->fsm = FIQ_HS_ISOC_SLEEPING;
107 + st->uframe_sleeps = 1;
108 } else {
109 st->fsm = FIQ_HS_ISOC_TURBO;
110 st->hcchar_copy.b.chen = 1;
111 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
112 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
113 @@ -2297,10 +2297,10 @@ void dwc_otg_fiq_unmangle_isoc(dwc_otg_h
114 dwc_urb->error_count++;
115 }
116 }
117 + qh->sched_frame = dwc_frame_num_inc(qh->sched_frame, qh->interval * (nr_frames - 1));
118 +
119 //printk_ratelimited(KERN_INFO "%s: HS isochronous of %d/%d frames with %d errors complete\n",
120 // __FUNCTION__, i, dwc_urb->packet_count, dwc_urb->error_count);
121 - hcd->fops->complete(hcd, dwc_urb->priv, dwc_urb, 0);
122 - release_channel(hcd, qh->channel, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
123 }
124
125 /**
126 @@ -2543,6 +2543,8 @@ void dwc_otg_hcd_handle_hc_fsm(dwc_otg_h
127 * fail.
128 */
129 dwc_otg_fiq_unmangle_isoc(hcd, qh, qtd, num);
130 + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
131 + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
132 break;
133
134 case FIQ_PER_SPLIT_LS_ABORTED: