summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-09-25 14:22:35 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-09-25 14:22:35 -0600
commit692abfd2a26f86a32eb8f5d08f9fa13e41d7a9e1 (patch)
treefa26e94edc97d6dd05d6d683134d44991c58f8f5
parentf4b2fb4edcd986fbe0ade28a048d7bf955d51062 (diff)
downloadnuttx-692abfd2a26f86a32eb8f5d08f9fa13e41d7a9e1.tar.gz
nuttx-692abfd2a26f86a32eb8f5d08f9fa13e41d7a9e1.tar.bz2
nuttx-692abfd2a26f86a32eb8f5d08f9fa13e41d7a9e1.zip
SAMA5 EMAC: Need to pace RX and TX because and RX can result in a TX; Process TX interrupt events before TX interrupt events for the same reason
-rw-r--r--nuttx/ChangeLog2
-rw-r--r--nuttx/arch/arm/src/sama5/sam_emac.c151
2 files changed, 93 insertions, 60 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index f2c9fc831..67d50634b 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -5627,4 +5627,6 @@
by common stack monitoring logic (2013-9-24).
* drivers/net/Kconfig: Move CONFIG_NET_DUMPPACKET out of LPC17
and STM32 Kconfigs into the common network driver Kconfig (2013-9-25).
+ * arch/arm/src/sam_emac.c: EMAC driver is basically functional. More
+ testing is needed (as always) (2013-9-25).
diff --git a/nuttx/arch/arm/src/sama5/sam_emac.c b/nuttx/arch/arm/src/sama5/sam_emac.c
index 0a4f3a3d2..be0df5d2e 100644
--- a/nuttx/arch/arm/src/sama5/sam_emac.c
+++ b/nuttx/arch/arm/src/sama5/sam_emac.c
@@ -323,8 +323,8 @@ static uint8_t g_rxbuffer[CONFIG_SAMA5_EMAC_NRXBUFFERS * EMAC_RX_UNITSIZE]
/* Register operations ******************************************************/
#if defined(CONFIG_SAMA5_EMAC_REGDEBUG) && defined(CONFIG_DEBUG)
-static bool sasm_checkreg(struct sam_emac_s *priv, bool wr,
- uint32_t regval, uintptr_t address);
+static bool sam_checkreg(struct sam_emac_s *priv, bool wr,
+ uint32_t regval, uintptr_t address);
static uint32_t sam_getreg(struct sam_emac_s *priv, uintptr_t addr);
static void sam_putreg(struct sam_emac_s *priv, uintptr_t addr, uint32_t val);
#else
@@ -763,6 +763,26 @@ static int sam_transmit(struct sam_emac_s *priv)
(void)wd_start(priv->txtimeout, SAM_TXTIMEOUT, sam_txtimeout, 1,
(uint32_t)priv);
+
+ /* Set d_len to zero meaning that the d_buf[] packet buffer is again
+ * available.
+ */
+
+ dev->d_len = 0;
+
+ /* If we have no more available TX descriptors, then we must disable the
+ * RCOMP interrupt to stop further RX processing. Why? Because EACH RX
+ * packet that is dispatch is also an opportunity to replay with the a TX
+ * packet. So, if we cannot handle an RX packet replay, then we disable
+ * all RX packet processing.
+ */
+
+ if (sam_txfree(priv) < 1)
+ {
+ nllvdbg("Disabling RX interrupts\n");
+ sam_putreg(priv, SAM_EMAC_IDR, EMAC_INT_RCOMP);
+ }
+
return OK;
}
@@ -1234,8 +1254,17 @@ static void sam_txdone(struct sam_emac_s *priv)
if (++priv->txtail >= CONFIG_SAMA5_EMAC_NTXBUFFERS)
{
+ /* Wrap to the beginning of the TX descriptor list */
+
priv->txtail = 0;
}
+
+ /* At least one TX descriptor is available. Re-enable RX interrupts.
+ * RX interrupts may previously have been disabled when we ran out of
+ * TX desciptors (see commits in sam_transmit()).
+ */
+
+ sam_putreg(priv, SAM_EMAC_IER, EMAC_INT_RCOMP);
}
/* Then poll uIP for new XMIT data */
@@ -1279,61 +1308,9 @@ static int sam_emac_interrupt(int irq, void *context)
pending = isr & ~(imr | 0xffc300);
nllvdbg("isr: %08x pending: %08x\n", isr, pending);
- /* Check for the receipt of an RX packet.
- *
- * RXCOMP indicates that a packet has been received and stored in memory.
- * The RXCOMP bit is cleared whent he interrupt status register was read.
- * RSR:REC indicates that one or more frames have been received and placed
- * in memory. This indication is cleared by writing a one to this bit.
- */
-
- if ((pending & EMAC_INT_RCOMP) != 0 || (rsr & EMAC_RSR_REC) != 0)
- {
- clrbits = EMAC_RSR_REC;
-
- /* Check for Receive Overrun.
- *
- * RSR:RXOVR will be set if the RX FIFO is not able to store the
- * receive frame due to a FIFO overflow, or if the receive status
- * was not taken at the end of the frame. This bit is also set in
- * DMA packet buffer mode if the packet buffer overflows. For DMA
- * operation, the buffer will be recovered if an overrun occurs. This
- * bit is cleared when set to 1.
- */
-
- if ((rsr & EMAC_RSR_OVR) != 0)
- {
- nlldbg("ERROR: Receiver overrun RSR: %08x\n", rsr);
- clrbits |= EMAC_RSR_OVR;
- }
-
- /* Check for buffer not available (BNA)
- *
- * RSR:BNA means that an attempt was made to get a new buffer and the
- * pointer indicated that it was owned by the processor. The DMA will
- * reread the pointer each time an end of frame is received until a
- * valid pointer is found. This bit is set following each descriptor
- * read attempt that fails, even if consecutive pointers are
- * unsuccessful and software has in the mean time cleared the status
- * flag. Cleared by writing a one to this bit.
- */
-
- if ((rsr & EMAC_RSR_BNA) != 0)
- {
- nlldbg("ERROR: Buffer not available RSR: %08x\n", rsr);
- clrbits |= EMAC_RSR_BNA;
- }
-
- /* Clear status */
-
- sam_putreg(priv, SAM_EMAC_RSR, clrbits);
-
- /* Handle the received packet */
-
- sam_receive(priv);
- }
-
- /* Check for the completion of a transmission
+ /* Check for the completion of a transmission. This should be done before
+ * checking for received data (because receiving can cause another transmission
+ * before we had a chance to handle the last one).
*
* ISR:TCOMP is set when a frame has been transmitted. Cleared on read.
* TSR:COMP is set when a frame has been transmitted. Cleared by writing a
@@ -1402,6 +1379,60 @@ static int sam_emac_interrupt(int irq, void *context)
sam_txdone(priv);
}
+ /* Check for the receipt of an RX packet.
+ *
+ * RXCOMP indicates that a packet has been received and stored in memory.
+ * The RXCOMP bit is cleared whent he interrupt status register was read.
+ * RSR:REC indicates that one or more frames have been received and placed
+ * in memory. This indication is cleared by writing a one to this bit.
+ */
+
+ if ((pending & EMAC_INT_RCOMP) != 0 || (rsr & EMAC_RSR_REC) != 0)
+ {
+ clrbits = EMAC_RSR_REC;
+
+ /* Check for Receive Overrun.
+ *
+ * RSR:RXOVR will be set if the RX FIFO is not able to store the
+ * receive frame due to a FIFO overflow, or if the receive status
+ * was not taken at the end of the frame. This bit is also set in
+ * DMA packet buffer mode if the packet buffer overflows. For DMA
+ * operation, the buffer will be recovered if an overrun occurs. This
+ * bit is cleared when set to 1.
+ */
+
+ if ((rsr & EMAC_RSR_OVR) != 0)
+ {
+ nlldbg("ERROR: Receiver overrun RSR: %08x\n", rsr);
+ clrbits |= EMAC_RSR_OVR;
+ }
+
+ /* Check for buffer not available (BNA)
+ *
+ * RSR:BNA means that an attempt was made to get a new buffer and the
+ * pointer indicated that it was owned by the processor. The DMA will
+ * reread the pointer each time an end of frame is received until a
+ * valid pointer is found. This bit is set following each descriptor
+ * read attempt that fails, even if consecutive pointers are
+ * unsuccessful and software has in the mean time cleared the status
+ * flag. Cleared by writing a one to this bit.
+ */
+
+ if ((rsr & EMAC_RSR_BNA) != 0)
+ {
+ nlldbg("ERROR: Buffer not available RSR: %08x\n", rsr);
+ clrbits |= EMAC_RSR_BNA;
+ }
+
+ /* Clear status */
+
+ sam_putreg(priv, SAM_EMAC_RSR, clrbits);
+
+ /* Handle the received packet */
+
+ sam_receive(priv);
+ }
+
#ifdef CONFIG_DEBUG_NET
/* Check for PAUSE Frame recieved (PFRE).
*
@@ -2525,7 +2556,7 @@ static void sam_txreset(struct sam_emac_s *priv)
{
bufaddr = (uint32_t)(&(txbuffer[ndx * EMAC_TX_UNITSIZE]));
- /* Set the buffer address and mark the descriptor as used */
+ /* Set the buffer address and mark the descriptor as in used by firmware */
physaddr = sam_physramaddr(bufaddr);
txdesc[ndx].addr = physaddr;
@@ -2539,7 +2570,7 @@ static void sam_txreset(struct sam_emac_s *priv)
/* Set the Transmit Buffer Queue Pointer Register */
- physaddr = sam_physramaddr((uint32_t)txdesc);
+ physaddr = sam_physramaddr((uintptr_t)txdesc);
sam_putreg(priv, SAM_EMAC_TBQP, physaddr);
}
@@ -2603,7 +2634,7 @@ static void sam_rxreset(struct sam_emac_s *priv)
/* Set the Receive Buffer Queue Pointer Register */
- physaddr = sam_physramaddr((uint32_t)rxdesc);
+ physaddr = sam_physramaddr((uintptr_t)rxdesc);
sam_putreg(priv, SAM_EMAC_RBQP, physaddr);
}