summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-08-26 09:11:58 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-08-26 09:11:58 -0600
commitd94a7d54fbfbd086c19f274b4657d9994d2b6db5 (patch)
tree3a047332bb42b831879e82cc5d7e99212e525c11
parentf239b84ba842e1b7937ac6c863e2df6bb39ced66 (diff)
downloadnuttx-d94a7d54fbfbd086c19f274b4657d9994d2b6db5.tar.gz
nuttx-d94a7d54fbfbd086c19f274b4657d9994d2b6db5.tar.bz2
nuttx-d94a7d54fbfbd086c19f274b4657d9994d2b6db5.zip
ENCX24J600: Use the ENC's SRAM from multiple TX packets. From Max Holtzberg
-rw-r--r--nuttx/ChangeLog4
-rw-r--r--nuttx/drivers/net/encx24j600.c172
-rw-r--r--nuttx/drivers/net/encx24j600.h2
3 files changed, 137 insertions, 41 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 3e29450a2..319c37703 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -5451,10 +5451,12 @@
* configs/olimex-stm32-p107: Incorporate ENCX24J600 support for the
Olimex STM32 P107 board. From Max Holtzberg (2013-8-25).
* fs/romfs/fs_romfsutil.c: Fix an error where long (>15) file names
- were read incorrectly from a ROMFS file system. From Mike Smit
+ were read incorrectly from a ROMFS file system. From Mike Smith
(2013-8-25).
* arch/arm/src/stm32/stm32_sdio.c: SourceForge bug #17 Fix if
CONFIG_SDIO_BLOCKSETUP defined, OS will crash". Generate an error
if CONFIG_SDIO_BLOCKSETUP is defined; that option is not yet supported
by the STM32 SDIO driver. From CCTSAO (2013-6-26)
+ * drivers/net/encx24j600.c and .h: Use the ENC's SRAM for multiple TX
+ packets. From Max Holtzberg (2013-6-26).
diff --git a/nuttx/drivers/net/encx24j600.c b/nuttx/drivers/net/encx24j600.c
index 6efef1a7a..f4d163a33 100644
--- a/nuttx/drivers/net/encx24j600.c
+++ b/nuttx/drivers/net/encx24j600.c
@@ -58,6 +58,7 @@
#include <debug.h>
#include <wdog.h>
#include <errno.h>
+#include <queue.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
@@ -158,11 +159,10 @@
/* Packet memory layout */
-#define ALIGNED_BUFSIZE ((CONFIG_NET_BUFSIZE + 1) & ~1) /* Address has to be even */
-#define PKTMEM_TX_START PKTMEM_START /* Start TX buffer at teh beginning of SRAM */
-#define PKTMEM_TX_ENDP1 ALIGNED_BUFSIZE /* Allow TX buffer for one frame */
-#define PKTMEM_RX_START PKTMEM_TX_ENDP1 /* Followed by RX buffer */
-#define PKTMEM_RX_END (PKTMEM_END - 1) /* RX buffer goes to the end of SRAM */
+#define PKTMEM_ALIGNED_BUFSIZE ((CONFIG_NET_BUFSIZE + 1) & ~1)
+#define PKTMEM_NDESCR ((PKTMEM_SIZE / 2) / PKTMEM_ALIGNED_BUFSIZE)
+#define PKTMEM_RX_START (PKTMEM_START + PKTMEM_SIZE / 2) /* Followed by RX buffer */
+#define PKTMEM_RX_END (PKTMEM_START + PKTMEM_SIZE - 2) /* RX buffer goes to the end of SRAM */
/* This is a helper pointer for accessing the contents of the Ethernet header */
@@ -194,9 +194,16 @@
enum enc_state_e
{
- ENCSTATE_UNINIT = 0, /* The interface is in an uninitialized state */
- ENCSTATE_DOWN, /* The interface is down */
- ENCSTATE_UP /* The interface is up */
+ ENCSTATE_UNINIT = 0, /* The interface is in an uninitialized state */
+ ENCSTATE_DOWN, /* The interface is down */
+ ENCSTATE_UP /* The interface is up */
+};
+
+struct enc_descr_s
+{
+ struct enc_descr_next *flink;
+ uint16_t addr;
+ uint16_t len;
};
/* The enc_driver_s encapsulates all state information for a single hardware
@@ -225,6 +232,10 @@ struct enc_driver_s
struct work_s towork; /* Tx timeout work queue support */
struct work_s pollwork; /* Poll timeout work queue support */
+ struct enc_descr_s descralloc[PKTMEM_NDESCR];
+ sq_queue_t freedescr; /* The free descriptor list */
+ sq_queue_t txqueue; /* Enqueued descriptors waiting for transmition */
+
/* This is the contained SPI driver intstance */
FAR struct spi_dev_s *spi;
@@ -297,6 +308,7 @@ static void enc_wrphy(FAR struct enc_driver_s *priv, uint8_t phyaddr,
/* Common TX logic */
+static int enc_txenqueue(FAR struct enc_driver_s *priv);
static int enc_transmit(FAR struct enc_driver_s *priv);
static int enc_uiptxpoll(struct uip_driver_s *dev);
@@ -361,7 +373,7 @@ static inline void enc_configspi(FAR struct spi_dev_s *spi)
SPI_SETMODE(spi, CONFIG_ENCX24J600_SPIMODE);
SPI_SETBITS(spi, 8);
- SPI_SETFREQUENCY(spi, CONFIG_ENCX24J600_FREQUENCY)
+ SPI_SETFREQUENCY(spi, CONFIG_ENCX24J600_FREQUENCY);
}
#endif
@@ -1021,13 +1033,13 @@ static void enc_wrphy(FAR struct enc_driver_s *priv, uint8_t phyaddr,
static int enc_transmit(FAR struct enc_driver_s *priv)
{
- /* Increment statistics */
+ struct enc_descr_s *descr;
- nllvdbg("Sending packet, pktlen: %d\n", priv->dev.d_len);
+ /* dequeue next packet to transmit */
-#ifdef CONFIG_ENCX24J600_STATS
- priv->stats.txrequests++;
-#endif
+ descr = (struct enc_descr_s*)sq_remfirst(&priv->txqueue);
+
+ DEBUGASSERT(descr != NULL);
/* Verify that the hardware is ready to send another packet. The driver
* starts a transmission process by setting ECON1.TXRTS. When the packet is
@@ -1041,19 +1053,10 @@ static int enc_transmit(FAR struct enc_driver_s *priv)
DEBUGASSERT((enc_rdreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0);
- /* Send the packet: address=priv->dev.d_buf, length=priv->dev.d_len */
-
- enc_dumppacket("Transmit Packet", priv->dev.d_buf, priv->dev.d_len);
-
- /* copy the packet into the transmit buffer */
-
- enc_cmd(priv, ENC_WGPWRPT, PKTMEM_TX_START);
- enc_wrbuffer(priv, priv->dev.d_buf, priv->dev.d_len);
-
- /* Set TX Len registers. TX Start is set in enc_reset */
-
- enc_wrreg(priv, ENC_ETXLEN, priv->dev.d_len);
+ /* Set TXStart and TXLen registers. */
+ enc_wrreg(priv, ENC_ETXST, descr->addr);
+ enc_wrreg(priv, ENC_ETXLEN, descr->len);
/* Set TXRTS to send the packet in the transmit buffer */
@@ -1064,17 +1067,91 @@ static int enc_transmit(FAR struct enc_driver_s *priv)
* the timer is started?
*/
- (void)wd_start(priv->txtimeout, ENC_TXTIMEOUT, enc_txtimeout, 1, (uint32_t)priv);
+ (void)wd_start(priv->txtimeout, ENC_TXTIMEOUT, enc_txtimeout, 1,
+ (uint32_t)priv);
+
+ /* free the descriptor */
+
+ sq_addlast((sq_entry_t*)descr, &priv->freedescr);
return OK;
}
/****************************************************************************
+ * Function: enc_txenqueue
+ *
+ * Description:
+ * Write packet from d_buf to the enc's SRAM if a free descriptor is available.
+ * The filled descriptor is enqueued for transmission.
+ *
+ * Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ * A packet is available in d_buf.
+ * Interrupts are enabled but the caller holds the uIP lock.
+ *
+ ****************************************************************************/
+
+static int enc_txenqueue(FAR struct enc_driver_s *priv)
+{
+ int ret = OK;
+ struct enc_descr_s *descr;
+
+ DEBUGASSERT(priv->dev.d_len > 0);
+
+ /* Increment statistics */
+
+#ifdef CONFIG_ENCX24J600_STATS
+ priv->stats.txrequests++;
+#endif
+
+ descr = (struct enc_descr_s*)sq_remfirst(&priv->freedescr);
+
+ if (descr != NULL)
+ {
+ enc_dumppacket("Write packet to enc SRAM", priv->dev.d_buf,
+ priv->dev.d_len);
+
+ /* copy the packet into the transmit buffer described by the current
+ * tx descriptor
+ */
+
+ enc_cmd(priv, ENC_WGPWRPT, descr->addr);
+ enc_wrbuffer(priv, priv->dev.d_buf, priv->dev.d_len);
+
+ /* store packet length */
+
+ descr->len = priv->dev.d_len;
+
+ /* enqueue packet */
+
+ sq_addlast((sq_entry_t*)descr, &priv->txqueue);
+
+ /* if currently no transmission is active, trigger the transmission */
+
+ if ((enc_rdreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0)
+ {
+ enc_transmit(priv);
+ }
+ }
+ else
+ {
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
* Function: enc_uiptxpoll
*
* Description:
- * The transmitter is available, check if uIP has any outgoing packets ready
- * to send. This is a callback from uip_poll(). uip_poll() may be called:
+ * Enqueues uIP packets if available.
+ * This is a callback from uip_poll(). uip_poll() may be called:
*
* 1. When the preceding TX packet send is complete,
* 2. When the preceding TX packet send timedout and the interface is reset
@@ -1094,27 +1171,26 @@ static int enc_transmit(FAR struct enc_driver_s *priv)
static int enc_uiptxpoll(struct uip_driver_s *dev)
{
FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private;
+ int ret = OK;
/* If the polling resulted in data that should be sent out on the network,
* the field d_len is set to a value > 0.
*/
nllvdbg("Poll result: d_len=%d\n", priv->dev.d_len);
+
if (priv->dev.d_len > 0)
{
uip_arp_out(&priv->dev);
- enc_transmit(priv);
-
- /* Stop the poll now because we can queue only one packet */
- return -EBUSY;
+ ret = enc_txenqueue(priv);
}
/* If zero is returned, the polling will continue until all connections have
* been examined.
*/
- return OK;
+ return ret;
}
/****************************************************************************
@@ -1182,9 +1258,18 @@ static void enc_linkstatus(FAR struct enc_driver_s *priv)
static void enc_txif(FAR struct enc_driver_s *priv)
{
- /* If no further xmits are pending, then cancel the TX timeout */
+ if (sq_empty(&priv->txqueue))
+ {
+ /* If no further xmits are pending, then cancel the TX timeout */
- wd_cancel(priv->txtimeout);
+ wd_cancel(priv->txtimeout);
+ }
+ else
+ {
+ /* process txqueue */
+
+ enc_transmit(priv);
+ }
/* Then poll uIP for new XMIT data */
@@ -1229,7 +1314,7 @@ static void enc_rxdispatch(FAR struct enc_driver_s *priv)
if (priv->dev.d_len > 0)
{
uip_arp_out(&priv->dev);
- enc_transmit(priv);
+ enc_txenqueue(priv);
}
}
else if (BUF->type == htons(UIP_ETHTYPE_ARP))
@@ -1243,7 +1328,7 @@ static void enc_rxdispatch(FAR struct enc_driver_s *priv)
if (priv->dev.d_len > 0)
{
- enc_transmit(priv);
+ enc_txenqueue(priv);
}
}
else
@@ -2180,6 +2265,7 @@ static void enc_setmacaddr(FAR struct enc_driver_s *priv)
static int enc_reset(FAR struct enc_driver_s *priv)
{
+ int i;
int ret;
uint16_t regval;
@@ -2229,12 +2315,20 @@ static int enc_reset(FAR struct enc_driver_s *priv)
priv->nextpkt = PKTMEM_RX_START;
enc_wrreg(priv, ENC_ERXST, PKTMEM_RX_START);
- enc_wrreg(priv, ENC_ETXST, PKTMEM_TX_START);
/* Program the Tail Pointer, ERXTAIL, to the last even address of the buffer */
enc_wrreg(priv, ENC_ERXTAIL, PKTMEM_RX_END);
+ sq_init(&priv->freedescr);
+ sq_init(&priv->txqueue);
+
+ for (i = 0; i < PKTMEM_NDESCR; i++)
+ {
+ priv->descralloc[i].addr = PKTMEM_START + PKTMEM_ALIGNED_BUFSIZE * i;
+ sq_addlast((sq_entry_t*)&priv->descralloc[i], &priv->freedescr);
+ }
+
/* "Typically, when using auto-negotiation, users should write 0x05E1 to PHANA
* to advertise flow control capability."
*/
diff --git a/nuttx/drivers/net/encx24j600.h b/nuttx/drivers/net/encx24j600.h
index f0343efba..4c38109d6 100644
--- a/nuttx/drivers/net/encx24j600.h
+++ b/nuttx/drivers/net/encx24j600.h
@@ -414,7 +414,7 @@
/* 24-Kbyte Transmit/Receive Packet Dual Port SRAM */
#define PKTMEM_START 0x0000
-#define PKTMEM_END 0x5fff
+#define PKTMEM_SIZE 0x6000
/* RX Status Bit Definitions ************************************************/