From 5f78f6998fc8b0cef89631fa7383bba7722011e1 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 24 Aug 2013 13:03:15 -0600 Subject: [PATCH] SAMA5: OHCI various bugfixes for interrupt handling --- arch/arm/src/sama5/sam_ohci.c | 59 +++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/arch/arm/src/sama5/sam_ohci.c b/arch/arm/src/sama5/sam_ohci.c index 55088e728b..a02d7a474b 100644 --- a/arch/arm/src/sama5/sam_ohci.c +++ b/arch/arm/src/sama5/sam_ohci.c @@ -1995,6 +1995,7 @@ static void sam_ohci_bottomhalf(void *arg) /* Now re-enable interrupts */ sam_putreg(OHCI_INT_MIE, SAM_USBHOST_INTEN); + sam_givesem(&g_ohci.exclsem); } /******************************************************************************* @@ -3264,41 +3265,53 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller) int sam_ohci_tophalf(int irq, FAR void *context) { uint32_t intst; - uint32_t regval; + uint32_t inten; uint32_t pending; /* Read Interrupt Status and mask out interrupts that are not enabled. */ intst = sam_getreg(SAM_USBHOST_INTST); - regval = sam_getreg(SAM_USBHOST_INTEN); - ullvdbg("INST: %08x INTEN: %08x\n", intst, regval); + inten = sam_getreg(SAM_USBHOST_INTEN); + ullvdbg("INST: %08x INTEN: %08x\n", intst, inten); - pending = intst & regval; - if (pending != 0) +#ifdef CONFIG_SAMA5_EHCI + /* Check the Master Interrupt Enable bit (MIE). It this function is called + * from the common UHPHS interrupt handler, there might be pending interrupts + * but with the overall interstate disabled. This could never happen if only + * OHCI were enabled because we would never get here. + */ + + if ((inten & OHCI_INT_MIE) != 0) +#endif { - /* Schedule interrupt handling work for the high priority worker thread - * so that we are not pressed for time and so that we can interrupt with - * other USB threads gracefully. - * - * The worker should be available now because we implement a handshake - * by controlling the OHCI interrupts. - */ + /* Mask out the interrupts that are not enabled */ + pending = intst & inten; + if (pending != 0) + { + /* Schedule interrupt handling work for the high priority worker + * thread so that we are not pressed for time and so that we can + * interrupt with other USB threads gracefully. + * + * The worker should be available now because we implement a + * handshake by controlling the OHCI interrupts. + */ - DEBUGASSERT(work_available(&g_ohci.work)); - DEBUGVERIFY(work_queue(HPWORK, &g_ohci.work, sam_ohci_bottomhalf, - (FAR void *)pending, 0)); + DEBUGASSERT(work_available(&g_ohci.work)); + DEBUGVERIFY(work_queue(HPWORK, &g_ohci.work, sam_ohci_bottomhalf, + (FAR void *)pending, 0)); - /* Disable further OHCI interrupts so that we do not overrun the work - * queue. - */ + /* Disable further OHCI interrupts so that we do not overrun the + * work queue. + */ - sam_putreg(OHCI_INT_MIE, SAM_USBHOST_INTDIS); + sam_putreg(OHCI_INT_MIE, SAM_USBHOST_INTDIS); - /* Clear all pending status bits by writing the value of the pending - * interrupt bits back to the status register. - */ + /* Clear all pending status bits by writing the value of the + * pending interrupt bits back to the status register. + */ - sam_putreg(intst, SAM_USBHOST_INTST); + sam_putreg(intst, SAM_USBHOST_INTST); + } } return OK;