summaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch')
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch202
1 files changed, 202 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch
new file mode 100644
index 0000000000..7115b152d9
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch
@@ -0,0 +1,202 @@
1From 5424305125492a2417bde7c6d23ee4b84e25f6be Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Fri, 27 Mar 2009 12:52:43 -0700
4Subject: [PATCH] musb_gadget: fix unhandled endpoint 0 IRQs
5
6The gadget EP0 code routinely ignores an interrupt at end of
7the data phase because of musb_g_ep0_giveback() resetting the
8state machine to "idle, waiting for SETUP" phase prematurely.
9
10The driver also prematurely leaves the status phase on
11receiving the SetupEnd interrupt.
12
13As there were still unhandled endpoint 0 interrupts happening
14from time to time after fixing these issues, there turned to
15be yet another culprit: two distinct gadget states collapsed
16into one.
17
18The (missing) state that comes after STATUS IN/OUT states was
19typically indiscernible from them since the corresponding
20interrupts tend to happen within too little period of time
21(due to only a zero-length status packet in between) and so
22they got coalesced; yet this state is not the same as the next
23one which is associated with the reception of a SETUP packet.
24
25Adding this extra state seems to have fixed the rest of the
26unhandled interrupts that generic_interrupt() and
27davinci_interrupt() hid by faking their result and only
28emitting a debug message -- so, stop doing that.
29
30Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
31Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
32---
33 drivers/usb/musb/davinci.c | 7 +----
34 drivers/usb/musb/musb_core.c | 8 +-----
35 drivers/usb/musb/musb_core.h | 3 +-
36 drivers/usb/musb/musb_gadget_ep0.c | 45 +++++++++++++++++++++++++++++++----
37 4 files changed, 43 insertions(+), 20 deletions(-)
38
39diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
40index 2dc7606..399c435 100644
41--- a/drivers/usb/musb/davinci.c
42+++ b/drivers/usb/musb/davinci.c
43@@ -357,12 +357,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
44
45 spin_unlock_irqrestore(&musb->lock, flags);
46
47- /* REVISIT we sometimes get unhandled IRQs
48- * (e.g. ep0). not clear why...
49- */
50- if (retval != IRQ_HANDLED)
51- DBG(5, "unhandled? %08x\n", tmp);
52- return IRQ_HANDLED;
53+ return retval;
54 }
55
56 int musb_platform_set_mode(struct musb *musb, u8 mode)
57diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
58index 3019725..a1de43b 100644
59--- a/drivers/usb/musb/musb_core.c
60+++ b/drivers/usb/musb/musb_core.c
61@@ -1481,13 +1481,7 @@ static irqreturn_t generic_interrupt(int irq, void *__hci)
62
63 spin_unlock_irqrestore(&musb->lock, flags);
64
65- /* REVISIT we sometimes get spurious IRQs on g_ep0
66- * not clear why...
67- */
68- if (retval != IRQ_HANDLED)
69- DBG(5, "spurious?\n");
70-
71- return IRQ_HANDLED;
72+ return retval;
73 }
74
75 #else
76diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
77index adf1806..f56a56c 100644
78--- a/drivers/usb/musb/musb_core.h
79+++ b/drivers/usb/musb/musb_core.h
80@@ -171,7 +171,8 @@ enum musb_h_ep0_state {
81
82 /* peripheral side ep0 states */
83 enum musb_g_ep0_state {
84- MUSB_EP0_STAGE_SETUP, /* idle, waiting for setup */
85+ MUSB_EP0_STAGE_IDLE, /* idle, waiting for SETUP */
86+ MUSB_EP0_STAGE_SETUP, /* received SETUP */
87 MUSB_EP0_STAGE_TX, /* IN data */
88 MUSB_EP0_STAGE_RX, /* OUT data */
89 MUSB_EP0_STAGE_STATUSIN, /* (after OUT data) */
90diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
91index 3f5e30d..ec0e899 100644
92--- a/drivers/usb/musb/musb_gadget_ep0.c
93+++ b/drivers/usb/musb/musb_gadget_ep0.c
94@@ -4,6 +4,7 @@
95 * Copyright 2005 Mentor Graphics Corporation
96 * Copyright (C) 2005-2006 by Texas Instruments
97 * Copyright (C) 2006-2007 Nokia Corporation
98+ * Copyright (C) 2008-2009 MontaVista Software, Inc. <source-Igf4POYTYCDQT0dZR+AlfA@public.gmane.org>
99 *
100 * This program is free software; you can redistribute it and/or
101 * modify it under the terms of the GNU General Public License
102@@ -58,7 +59,8 @@
103 static char *decode_ep0stage(u8 stage)
104 {
105 switch (stage) {
106- case MUSB_EP0_STAGE_SETUP: return "idle";
107+ case MUSB_EP0_STAGE_IDLE: return "idle";
108+ case MUSB_EP0_STAGE_SETUP: return "setup";
109 case MUSB_EP0_STAGE_TX: return "in";
110 case MUSB_EP0_STAGE_RX: return "out";
111 case MUSB_EP0_STAGE_ACKWAIT: return "wait";
112@@ -628,7 +630,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
113 musb_writew(regs, MUSB_CSR0,
114 csr & ~MUSB_CSR0_P_SENTSTALL);
115 retval = IRQ_HANDLED;
116- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
117+ musb->ep0_state = MUSB_EP0_STAGE_IDLE;
118 csr = musb_readw(regs, MUSB_CSR0);
119 }
120
121@@ -636,7 +638,18 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
122 if (csr & MUSB_CSR0_P_SETUPEND) {
123 musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND);
124 retval = IRQ_HANDLED;
125- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
126+ /* Transition into the early status phase */
127+ switch (musb->ep0_state) {
128+ case MUSB_EP0_STAGE_TX:
129+ musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT;
130+ break;
131+ case MUSB_EP0_STAGE_RX:
132+ musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
133+ break;
134+ default:
135+ ERR("SetupEnd came in a wrong ep0stage %s",
136+ decode_ep0stage(musb->ep0_state));
137+ }
138 csr = musb_readw(regs, MUSB_CSR0);
139 /* NOTE: request may need completion */
140 }
141@@ -697,11 +710,31 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
142 if (req)
143 musb_g_ep0_giveback(musb, req);
144 }
145+
146+ /*
147+ * In case when several interrupts can get coalesced,
148+ * check to see if we've already received a SETUP packet...
149+ */
150+ if (csr & MUSB_CSR0_RXPKTRDY)
151+ goto setup;
152+
153+ retval = IRQ_HANDLED;
154+ musb->ep0_state = MUSB_EP0_STAGE_IDLE;
155+ break;
156+
157+ case MUSB_EP0_STAGE_IDLE:
158+ /*
159+ * This state is typically (but not always) indiscernible
160+ * from the status states since the corresponding interrupts
161+ * tend to happen within too little period of time (with only
162+ * a zero-length packet in between) and so get coalesced...
163+ */
164 retval = IRQ_HANDLED;
165 musb->ep0_state = MUSB_EP0_STAGE_SETUP;
166 /* FALLTHROUGH */
167
168 case MUSB_EP0_STAGE_SETUP:
169+setup:
170 if (csr & MUSB_CSR0_RXPKTRDY) {
171 struct usb_ctrlrequest setup;
172 int handled = 0;
173@@ -783,7 +816,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
174 stall:
175 DBG(3, "stall (%d)\n", handled);
176 musb->ackpend |= MUSB_CSR0_P_SENDSTALL;
177- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
178+ musb->ep0_state = MUSB_EP0_STAGE_IDLE;
179 finish:
180 musb_writew(regs, MUSB_CSR0,
181 musb->ackpend);
182@@ -803,7 +836,7 @@ finish:
183 /* "can't happen" */
184 WARN_ON(1);
185 musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL);
186- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
187+ musb->ep0_state = MUSB_EP0_STAGE_IDLE;
188 break;
189 }
190
191@@ -959,7 +992,7 @@ static int musb_g_ep0_halt(struct usb_ep *e, int value)
192
193 csr |= MUSB_CSR0_P_SENDSTALL;
194 musb_writew(regs, MUSB_CSR0, csr);
195- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
196+ musb->ep0_state = MUSB_EP0_STAGE_IDLE;
197 musb->ackpend = 0;
198 break;
199 default:
200--
2011.6.0.4
202