diff options
Diffstat (limited to 'recipes/linux/linux-omap-pm-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch')
-rw-r--r-- | recipes/linux/linux-omap-pm-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch new file mode 100644 index 0000000000..7115b152d9 --- /dev/null +++ b/recipes/linux/linux-omap-pm-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch @@ -0,0 +1,202 @@ +From 5424305125492a2417bde7c6d23ee4b84e25f6be Mon Sep 17 00:00:00 2001 +From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> +Date: Fri, 27 Mar 2009 12:52:43 -0700 +Subject: [PATCH] musb_gadget: fix unhandled endpoint 0 IRQs + +The gadget EP0 code routinely ignores an interrupt at end of +the data phase because of musb_g_ep0_giveback() resetting the +state machine to "idle, waiting for SETUP" phase prematurely. + +The driver also prematurely leaves the status phase on +receiving the SetupEnd interrupt. + +As there were still unhandled endpoint 0 interrupts happening +from time to time after fixing these issues, there turned to +be yet another culprit: two distinct gadget states collapsed +into one. + +The (missing) state that comes after STATUS IN/OUT states was +typically indiscernible from them since the corresponding +interrupts tend to happen within too little period of time +(due to only a zero-length status packet in between) and so +they got coalesced; yet this state is not the same as the next +one which is associated with the reception of a SETUP packet. + +Adding this extra state seems to have fixed the rest of the +unhandled interrupts that generic_interrupt() and +davinci_interrupt() hid by faking their result and only +emitting a debug message -- so, stop doing that. + +Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> +Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> +--- + drivers/usb/musb/davinci.c | 7 +---- + drivers/usb/musb/musb_core.c | 8 +----- + drivers/usb/musb/musb_core.h | 3 +- + drivers/usb/musb/musb_gadget_ep0.c | 45 +++++++++++++++++++++++++++++++---- + 4 files changed, 43 insertions(+), 20 deletions(-) + +diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c +index 2dc7606..399c435 100644 +--- a/drivers/usb/musb/davinci.c ++++ b/drivers/usb/musb/davinci.c +@@ -357,12 +357,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) + + spin_unlock_irqrestore(&musb->lock, flags); + +- /* REVISIT we sometimes get unhandled IRQs +- * (e.g. ep0). not clear why... +- */ +- if (retval != IRQ_HANDLED) +- DBG(5, "unhandled? %08x\n", tmp); +- return IRQ_HANDLED; ++ return retval; + } + + int musb_platform_set_mode(struct musb *musb, u8 mode) +diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c +index 3019725..a1de43b 100644 +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c +@@ -1481,13 +1481,7 @@ static irqreturn_t generic_interrupt(int irq, void *__hci) + + spin_unlock_irqrestore(&musb->lock, flags); + +- /* REVISIT we sometimes get spurious IRQs on g_ep0 +- * not clear why... +- */ +- if (retval != IRQ_HANDLED) +- DBG(5, "spurious?\n"); +- +- return IRQ_HANDLED; ++ return retval; + } + + #else +diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h +index adf1806..f56a56c 100644 +--- a/drivers/usb/musb/musb_core.h ++++ b/drivers/usb/musb/musb_core.h +@@ -171,7 +171,8 @@ enum musb_h_ep0_state { + + /* peripheral side ep0 states */ + enum musb_g_ep0_state { +- MUSB_EP0_STAGE_SETUP, /* idle, waiting for setup */ ++ MUSB_EP0_STAGE_IDLE, /* idle, waiting for SETUP */ ++ MUSB_EP0_STAGE_SETUP, /* received SETUP */ + MUSB_EP0_STAGE_TX, /* IN data */ + MUSB_EP0_STAGE_RX, /* OUT data */ + MUSB_EP0_STAGE_STATUSIN, /* (after OUT data) */ +diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c +index 3f5e30d..ec0e899 100644 +--- a/drivers/usb/musb/musb_gadget_ep0.c ++++ b/drivers/usb/musb/musb_gadget_ep0.c +@@ -4,6 +4,7 @@ + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2006-2007 Nokia Corporation ++ * Copyright (C) 2008-2009 MontaVista Software, Inc. <source-Igf4POYTYCDQT0dZR+AlfA@public.gmane.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License +@@ -58,7 +59,8 @@ + static char *decode_ep0stage(u8 stage) + { + switch (stage) { +- case MUSB_EP0_STAGE_SETUP: return "idle"; ++ case MUSB_EP0_STAGE_IDLE: return "idle"; ++ case MUSB_EP0_STAGE_SETUP: return "setup"; + case MUSB_EP0_STAGE_TX: return "in"; + case MUSB_EP0_STAGE_RX: return "out"; + case MUSB_EP0_STAGE_ACKWAIT: return "wait"; +@@ -628,7 +630,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) + musb_writew(regs, MUSB_CSR0, + csr & ~MUSB_CSR0_P_SENTSTALL); + retval = IRQ_HANDLED; +- musb->ep0_state = MUSB_EP0_STAGE_SETUP; ++ musb->ep0_state = MUSB_EP0_STAGE_IDLE; + csr = musb_readw(regs, MUSB_CSR0); + } + +@@ -636,7 +638,18 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) + if (csr & MUSB_CSR0_P_SETUPEND) { + musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND); + retval = IRQ_HANDLED; +- musb->ep0_state = MUSB_EP0_STAGE_SETUP; ++ /* Transition into the early status phase */ ++ switch (musb->ep0_state) { ++ case MUSB_EP0_STAGE_TX: ++ musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT; ++ break; ++ case MUSB_EP0_STAGE_RX: ++ musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; ++ break; ++ default: ++ ERR("SetupEnd came in a wrong ep0stage %s", ++ decode_ep0stage(musb->ep0_state)); ++ } + csr = musb_readw(regs, MUSB_CSR0); + /* NOTE: request may need completion */ + } +@@ -697,11 +710,31 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) + if (req) + musb_g_ep0_giveback(musb, req); + } ++ ++ /* ++ * In case when several interrupts can get coalesced, ++ * check to see if we've already received a SETUP packet... ++ */ ++ if (csr & MUSB_CSR0_RXPKTRDY) ++ goto setup; ++ ++ retval = IRQ_HANDLED; ++ musb->ep0_state = MUSB_EP0_STAGE_IDLE; ++ break; ++ ++ case MUSB_EP0_STAGE_IDLE: ++ /* ++ * This state is typically (but not always) indiscernible ++ * from the status states since the corresponding interrupts ++ * tend to happen within too little period of time (with only ++ * a zero-length packet in between) and so get coalesced... ++ */ + retval = IRQ_HANDLED; + musb->ep0_state = MUSB_EP0_STAGE_SETUP; + /* FALLTHROUGH */ + + case MUSB_EP0_STAGE_SETUP: ++setup: + if (csr & MUSB_CSR0_RXPKTRDY) { + struct usb_ctrlrequest setup; + int handled = 0; +@@ -783,7 +816,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) + stall: + DBG(3, "stall (%d)\n", handled); + musb->ackpend |= MUSB_CSR0_P_SENDSTALL; +- musb->ep0_state = MUSB_EP0_STAGE_SETUP; ++ musb->ep0_state = MUSB_EP0_STAGE_IDLE; + finish: + musb_writew(regs, MUSB_CSR0, + musb->ackpend); +@@ -803,7 +836,7 @@ finish: + /* "can't happen" */ + WARN_ON(1); + musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL); +- musb->ep0_state = MUSB_EP0_STAGE_SETUP; ++ musb->ep0_state = MUSB_EP0_STAGE_IDLE; + break; + } + +@@ -959,7 +992,7 @@ static int musb_g_ep0_halt(struct usb_ep *e, int value) + + csr |= MUSB_CSR0_P_SENDSTALL; + musb_writew(regs, MUSB_CSR0, csr); +- musb->ep0_state = MUSB_EP0_STAGE_SETUP; ++ musb->ep0_state = MUSB_EP0_STAGE_IDLE; + musb->ackpend = 0; + break; + default: +-- +1.6.0.4 + |