From 6082c42751e8308a763aada8a3f9fa980efe18da Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 13 Dec 2011 19:58:24 +0000 Subject: 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 --- apps/ChangeLog.txt | 2 + apps/examples/nettest/Makefile | 11 ++- apps/examples/nettest/nettest.c | 14 +++- apps/examples/nettest/nettest_client.c | 7 +- nuttx/arch/arm/src/stm32/stm32_eth.c | 147 +++++++++++++++++++++++++++++---- 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. @@ -1179,6 +1201,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 * @@ -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. -- cgit v1.2.3