summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-08-24 13:03:15 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-08-24 13:03:15 -0600
commitc072e1d1b7c1c6d2f0fffae0b75bc07d2b688baf (patch)
treea990329025c80bd44bce37e1a251e11f2e8db2b1
parentcb9ed2733015b48819a34ed4357e5e916216636a (diff)
downloadnuttx-c072e1d1b7c1c6d2f0fffae0b75bc07d2b688baf.tar.gz
nuttx-c072e1d1b7c1c6d2f0fffae0b75bc07d2b688baf.tar.bz2
nuttx-c072e1d1b7c1c6d2f0fffae0b75bc07d2b688baf.zip
SAMA5: OHCI various bugfixes for interrupt handling
-rw-r--r--nuttx/arch/arm/src/sama5/sam_ohci.c59
1 files changed, 36 insertions, 23 deletions
diff --git a/nuttx/arch/arm/src/sama5/sam_ohci.c b/nuttx/arch/arm/src/sama5/sam_ohci.c
index 55088e728..a02d7a474 100644
--- a/nuttx/arch/arm/src/sama5/sam_ohci.c
+++ b/nuttx/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);
+
+#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.
+ */
- pending = intst & regval;
- if (pending != 0)
+ 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;