summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-12-13 19:58:24 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-12-13 19:58:24 +0000
commit6082c42751e8308a763aada8a3f9fa980efe18da (patch)
tree2625b8515c0e63363689070b22d20073b21a2014
parent80c5e02241fa0e4275079f45f45372795a3474dd (diff)
downloadnuttx-6082c42751e8308a763aada8a3f9fa980efe18da.tar.gz
nuttx-6082c42751e8308a763aada8a3f9fa980efe18da.tar.bz2
nuttx-6082c42751e8308a763aada8a3f9fa980efe18da.zip
Fix more STM32 ethernet bugs; Fix some build issues with examples/nettest
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4171 42af7a65-404d-4744-a932-0658087f49c3
-rwxr-xr-xapps/ChangeLog.txt2
-rw-r--r--apps/examples/nettest/Makefile11
-rw-r--r--apps/examples/nettest/nettest.c14
-rw-r--r--apps/examples/nettest/nettest_client.c7
-rwxr-xr-xnuttx/arch/arm/src/stm32/stm32_eth.c147
5 files changed, 157 insertions, 24 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt
index e71b99a2e..fe03dae6a 100755
--- a/apps/ChangeLog.txt
+++ b/apps/ChangeLog.txt
@@ -142,3 +142,5 @@
where network addresses expected (and vice versa).
* apps/examples/nettest: May now be built as an NSH built-in application
by setting CONFIG_NSH_BUILTIN_APPS.
+ * apps/examples/nettest: Correct some build issues with the nettest is
+ built for performance evaluation.
diff --git a/apps/examples/nettest/Makefile b/apps/examples/nettest/Makefile
index 9f9d79c77..ac07665ab 100644
--- a/apps/examples/nettest/Makefile
+++ b/apps/examples/nettest/Makefile
@@ -66,6 +66,11 @@ ifeq ($(CONFIG_EXAMPLE_NETTEST_SERVER),y)
HOSTCFLAGS += -DCONFIG_EXAMPLE_NETTEST_SERVER=1 \
-DCONFIG_EXAMPLE_NETTEST_CLIENTIP="$(CONFIG_EXAMPLE_NETTEST_CLIENTIP)"
endif
+ifeq ($(CONFIG_EXAMPLE_NETTEST_PERFORMANCE),y)
+HOSTCFLAGS += -DCONFIG_EXAMPLE_NETTEST_PERFORMANCE=1
+endif
+
+
HOST_SRCS = host.c
ifeq ($(CONFIG_EXAMPLE_NETTEST_SERVER),y)
@@ -89,7 +94,7 @@ STACKSIZE = 2048
VPATH =
-all: .built
+all: .built $(HOST_BIN)
.PHONY: clean depend disclean
$(TARG_AOBJS): %$(OBJEXT): %.S
@@ -106,9 +111,9 @@ $(HOST_BIN): $(HOST_OBJS)
@echo "LD: $@"
@$(HOSTCC) $(HOSTLDFLAGS) $(HOST_OBJS) -o $@
-.built: $(HOST_BIN) $(TARG_OBJS)
+.built: $(TARG_OBJS)
@( for obj in $(TARG_OBJS) ; do \
- $(call ARCHIVE, $@, $${obj}); \
+ $(call ARCHIVE, $(TARG_BIN), $${obj}); \
done ; )
@touch .built
diff --git a/apps/examples/nettest/nettest.c b/apps/examples/nettest/nettest.c
index 8ce44e54a..7160e693a 100644
--- a/apps/examples/nettest/nettest.c
+++ b/apps/examples/nettest/nettest.c
@@ -53,6 +53,18 @@
* Definitions
****************************************************************************/
+/* If CONFIG_NSH_BUILTIN_APPS is defined, then it is assumed that you want
+ * to execute the DHCPD daemon as an NSH built-in task.
+ */
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+# define MAIN_NAME nettest_main
+# define MAIN_NAME_STRING "nettest_main"
+#else
+# define MAIN_NAME user_start
+# define MAIN_NAME_STRING "user_start"
+#endif
+
/****************************************************************************
* Private Data
****************************************************************************/
@@ -65,7 +77,7 @@
* user_start
****************************************************************************/
-int user_start(int argc, char *argv[])
+int MAIN_NAME(int argc, char *argv[])
{
struct in_addr addr;
#ifdef CONFIG_EXAMPLE_NETTEST_NOMAC
diff --git a/apps/examples/nettest/nettest_client.c b/apps/examples/nettest/nettest_client.c
index 23036d581..2e54f1f9b 100644
--- a/apps/examples/nettest/nettest_client.c
+++ b/apps/examples/nettest/nettest_client.c
@@ -127,15 +127,16 @@ void send_client(void)
for (;;)
{
- nbytessent = send(sockfd, outbuf, 512, 0);
+ nbytessent = send(sockfd, outbuf, SENDSIZE, 0);
if (nbytessent < 0)
{
message("client: send failed: %d\n", errno);
goto errout_with_socket;
}
- else if (nbytessent != 512)
+ else if (nbytessent != SENDSIZE)
{
- message("client: Bad send length=%d: %d\n", nbytessent);
+ message("client: Bad send length=%d: %d of \n",
+ nbytessent, SENDSIZE);
goto errout_with_socket;
}
}
diff --git a/nuttx/arch/arm/src/stm32/stm32_eth.c b/nuttx/arch/arm/src/stm32/stm32_eth.c
index 6023108d9..2368b3030 100755
--- a/nuttx/arch/arm/src/stm32/stm32_eth.c
+++ b/nuttx/arch/arm/src/stm32/stm32_eth.c
@@ -563,6 +563,9 @@ static void stm32_dopoll(FAR struct stm32_ethmac_s *priv);
/* Interrupt handling */
+static void stm32_enableint(FAR struct stm32_ethmac_s *priv, uint32_t ierbit);
+static void stm32_disableint(FAR struct stm32_ethmac_s *priv, uint32_t ierbit);
+
static void stm32_freesegment(FAR struct stm32_ethmac_s *priv,
FAR struct eth_rxdesc_s *rxfirst, int segments);
static int stm32_recvframe(FAR struct stm32_ethmac_s *priv);
@@ -868,7 +871,6 @@ static int stm32_transmit(FAR struct stm32_ethmac_s *priv)
{
struct eth_txdesc_s *txdesc;
struct eth_txdesc_s *txfirst;
- uint32_t regval;
/* The internal uIP buffer size may be configured to be larger than the
* Ethernet buffer size.
@@ -1019,6 +1021,16 @@ static int stm32_transmit(FAR struct stm32_ethmac_s *priv)
nllvdbg("txhead: %p txtail: %p inflight: %d\n",
priv->txhead, priv->txtail, priv->inflight);
+ /* If all TX descriptors are in-flight, then we have to disable receive interrupts
+ * too. This is because receive events can trigger more un-stoppable transmit
+ * events.
+ */
+
+ if (priv->inflight >= CONFIG_STM32_ETH_NTXDESC)
+ {
+ stm32_disableint(priv, ETH_DMAINT_RI);
+ }
+
/* Check if the TX Buffer unavailable flag is set */
if ((stm32_getreg(STM32_ETH_DMASR) & ETH_DMAINT_TBUI) != 0)
@@ -1034,9 +1046,7 @@ static int stm32_transmit(FAR struct stm32_ethmac_s *priv)
/* Enable TX interrupts */
- regval = stm32_getreg(STM32_ETH_DMAIER);
- regval |= ETH_DMAINT_XMIT_ENABLE;
- stm32_putreg(regval, STM32_ETH_DMAIER);
+ stm32_enableint(priv, ETH_DMAINT_TI);
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
@@ -1089,9 +1099,15 @@ static int stm32_uiptxpoll(struct uip_driver_s *dev)
/* Check if the next TX descriptor is owned by the Ethernet DMA or CPU. We
* cannot perform the TX poll if we are unable to accept another packet for
* transmission.
+ *
+ * In a race condition, ETH_TDES0_OWN may be cleared BUT still not available
+ * because stm32_freeframe() has not yet run. If stm32_freeframe() has run,
+ * the buffer1 pointer (tdes2) will be nullified (and inflight should be <
+ * CONFIG_STM32_ETH_NTXDESC).
*/
- if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0)
+ if ((priv->txhead->tdes0 & ETH_TDES0_OWN) != 0 ||
+ priv->txhead->tdes2 != 0)
{
/* We have to terminate the poll if we have no more descriptors
* available for another transfer.
@@ -1148,9 +1164,15 @@ static void stm32_dopoll(FAR struct stm32_ethmac_s *priv)
/* Check if the next TX descriptor is owned by the Ethernet DMA or
* CPU. We cannot perform the TX poll if we are unable to accept
* another packet for transmission.
+ *
+ * In a race condition, ETH_TDES0_OWN may be cleared BUT still not available
+ * because stm32_freeframe() has not yet run. If stm32_freeframe() has run,
+ * the buffer1 pointer (tdes2) will be nullified (and inflight should be <
+ * CONFIG_STM32_ETH_NTXDESC).
*/
- if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0)
+ if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0 &&
+ priv->txhead->tdes2 == 0)
{
/* If we have the descriptor, then poll uIP for new XMIT data.
* Allocate a buffer for the poll.
@@ -1180,6 +1202,72 @@ static void stm32_dopoll(FAR struct stm32_ethmac_s *priv)
}
/****************************************************************************
+ * Function: stm32_enableint
+ *
+ * Description:
+ * Enable a "normal" interrupt
+ *
+ * Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void stm32_enableint(FAR struct stm32_ethmac_s *priv, uint32_t ierbit)
+{
+ uint32_t regval;
+
+ /* Enable the specified "normal" interrupt */
+
+ regval = stm32_getreg(STM32_ETH_DMAIER);
+ regval |= (ETH_DMAINT_NIS | ierbit);
+ stm32_putreg(regval, STM32_ETH_DMAIER);
+}
+
+/****************************************************************************
+ * Function: stm32_disableint
+ *
+ * Description:
+ * Disable a normal interrupt.
+ *
+ * Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void stm32_disableint(FAR struct stm32_ethmac_s *priv, uint32_t ierbit)
+{
+ uint32_t regval;
+
+ /* Disable the "normal" interrupt */
+
+ regval = stm32_getreg(STM32_ETH_DMAIER);
+ regval &= ~ierbit;
+
+ /* Are all "normal" interrupts now disabled? */
+
+ if ((regval & ETH_DMAINT_NORMAL) == 0)
+ {
+ /* Yes.. disable normal interrupts */
+
+ regval &= ~ETH_DMAINT_NIS;
+ }
+
+ stm32_putreg(regval, STM32_ETH_DMAIER);
+}
+
+/****************************************************************************
* Function: stm32_freesegment
*
* Description:
@@ -1274,11 +1362,23 @@ static int stm32_recvframe(FAR struct stm32_ethmac_s *priv)
return -ENOMEM;
}
- /* Scan descriptors owned by the CPU */
+ /* Scan descriptors owned by the CPU. Scan until:
+ *
+ * 1) We find a descriptor still owned by the DMA,
+ * 2) We have examined all of the RX descriptors, or
+ * 3) All of the TX descriptors are in flight.
+ *
+ * This last case is obscure. It is due to that fact that each packet
+ * that we receive can generate and unstoppable transmisson. So we have
+ * to stop receiving when we can not longer transmit. In this case, the
+ * transmit logic should also have disabled further RX interrupts.
+ */
rxdesc = priv->rxhead;
for (i = 0;
- (rxdesc->rdes0 & ETH_RDES0_OWN) == 0 && i < CONFIG_STM32_ETH_NRXDESC;
+ (rxdesc->rdes0 & ETH_RDES0_OWN) == 0 &&
+ i < CONFIG_STM32_ETH_NRXDESC &&
+ priv->inflight < CONFIG_STM32_ETH_NTXDESC;
i++)
{
/* Check if this is the first segment in the frame */
@@ -1523,6 +1623,9 @@ static void stm32_freeframe(FAR struct stm32_ethmac_s *priv)
* TX descriptors.
*/
+ nllvdbg("txtail: %p tdes0: %08x tdes2: %08x tdes3: %08x\n",
+ txdesc, txdesc->tdes0, txdesc->tdes2, txdesc->tdes3);
+
DEBUGASSERT(txdesc->tdes2 != 0);
/* Check if this is the first segment of a TX frame. */
@@ -1542,11 +1645,19 @@ static void stm32_freeframe(FAR struct stm32_ethmac_s *priv)
if ((txdesc->tdes0 & ETH_TDES0_FS) != 0)
{
- /* Yes.. Decrement the number of frames "in-flight".
- * If there are no more frames in-flight, then bail.
+ /* Yes.. Decrement the number of frames "in-flight". */
+
+ priv->inflight--;
+
+ /* If all of the TX descriptors were in-flight, then RX interrupts
+ * may have been disabled... we can re-enable them now.
*/
- if (--priv->inflight <= 0)
+ stm32_enableint(priv, ETH_DMAINT_RI);
+
+ /* If there are no more frames in-flight, then bail. */
+
+ if (priv->inflight <= 0)
{
priv->txtail = NULL;
priv->inflight = 0;
@@ -1589,8 +1700,6 @@ static void stm32_freeframe(FAR struct stm32_ethmac_s *priv)
static void stm32_txdone(FAR struct stm32_ethmac_s *priv)
{
- uint32_t regval;
-
DEBUGASSERT(priv->txtail != NULL);
/* Scan the TX desciptor change, returning buffers to free list */
@@ -1605,9 +1714,7 @@ static void stm32_txdone(FAR struct stm32_ethmac_s *priv)
/* And disable further TX interrupts. */
- regval = stm32_getreg(STM32_ETH_DMAIER);
- regval &= ~ETH_DMAINT_XMIT_DISABLE;
- stm32_putreg(regval, STM32_ETH_DMAIER);
+ stm32_disableint(priv, ETH_DMAINT_TI);
}
/* Then poll uIP for new XMIT data */
@@ -1775,9 +1882,15 @@ static void stm32_polltimer(int argc, uint32_t arg, ...)
* cannot perform the timer poll if we are unable to accept another packet
* for transmission. Hmmm.. might be bug here. Does this mean if there is
* a transmit in progress, we will missing TCP time state updates?
+ *
+ * In a race condition, ETH_TDES0_OWN may be cleared BUT still not available
+ * because stm32_freeframe() has not yet run. If stm32_freeframe() has run,
+ * the buffer1 pointer (tdes2) will be nullified (and inflight should be <
+ * CONFIG_STM32_ETH_NTXDESC).
*/
- if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0)
+ if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0 &&
+ priv->txhead->tdes2 == 0)
{
/* If we have the descriptor, then perform the timer poll. Allocate a
* buffer for the poll.