diff options
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.patch | 202 |
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 @@ | |||
1 | From 5424305125492a2417bde7c6d23ee4b84e25f6be Mon Sep 17 00:00:00 2001 | ||
2 | From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> | ||
3 | Date: Fri, 27 Mar 2009 12:52:43 -0700 | ||
4 | Subject: [PATCH] musb_gadget: fix unhandled endpoint 0 IRQs | ||
5 | |||
6 | The gadget EP0 code routinely ignores an interrupt at end of | ||
7 | the data phase because of musb_g_ep0_giveback() resetting the | ||
8 | state machine to "idle, waiting for SETUP" phase prematurely. | ||
9 | |||
10 | The driver also prematurely leaves the status phase on | ||
11 | receiving the SetupEnd interrupt. | ||
12 | |||
13 | As there were still unhandled endpoint 0 interrupts happening | ||
14 | from time to time after fixing these issues, there turned to | ||
15 | be yet another culprit: two distinct gadget states collapsed | ||
16 | into one. | ||
17 | |||
18 | The (missing) state that comes after STATUS IN/OUT states was | ||
19 | typically indiscernible from them since the corresponding | ||
20 | interrupts tend to happen within too little period of time | ||
21 | (due to only a zero-length status packet in between) and so | ||
22 | they got coalesced; yet this state is not the same as the next | ||
23 | one which is associated with the reception of a SETUP packet. | ||
24 | |||
25 | Adding this extra state seems to have fixed the rest of the | ||
26 | unhandled interrupts that generic_interrupt() and | ||
27 | davinci_interrupt() hid by faking their result and only | ||
28 | emitting a debug message -- so, stop doing that. | ||
29 | |||
30 | Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> | ||
31 | Signed-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 | |||
39 | diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c | ||
40 | index 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) | ||
57 | diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c | ||
58 | index 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 | ||
76 | diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h | ||
77 | index 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) */ | ||
90 | diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c | ||
91 | index 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 | -- | ||
201 | 1.6.0.4 | ||
202 | |||