ENCX24J600: Use the ENC's SRAM from multiple TX packets. From Max Holtzberg
This commit is contained in:
parent
03ad60426d
commit
463c40c42e
@ -5451,10 +5451,12 @@
|
|||||||
* configs/olimex-stm32-p107: Incorporate ENCX24J600 support for the
|
* configs/olimex-stm32-p107: Incorporate ENCX24J600 support for the
|
||||||
Olimex STM32 P107 board. From Max Holtzberg (2013-8-25).
|
Olimex STM32 P107 board. From Max Holtzberg (2013-8-25).
|
||||||
* fs/romfs/fs_romfsutil.c: Fix an error where long (>15) file names
|
* 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).
|
(2013-8-25).
|
||||||
* arch/arm/src/stm32/stm32_sdio.c: SourceForge bug #17 Fix if
|
* arch/arm/src/stm32/stm32_sdio.c: SourceForge bug #17 Fix if
|
||||||
CONFIG_SDIO_BLOCKSETUP defined, OS will crash". Generate an error
|
CONFIG_SDIO_BLOCKSETUP defined, OS will crash". Generate an error
|
||||||
if CONFIG_SDIO_BLOCKSETUP is defined; that option is not yet supported
|
if CONFIG_SDIO_BLOCKSETUP is defined; that option is not yet supported
|
||||||
by the STM32 SDIO driver. From CCTSAO (2013-6-26)
|
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).
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <wdog.h>
|
#include <wdog.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <queue.h>
|
||||||
|
|
||||||
#include <nuttx/irq.h>
|
#include <nuttx/irq.h>
|
||||||
#include <nuttx/arch.h>
|
#include <nuttx/arch.h>
|
||||||
@ -158,11 +159,10 @@
|
|||||||
|
|
||||||
/* Packet memory layout */
|
/* Packet memory layout */
|
||||||
|
|
||||||
#define ALIGNED_BUFSIZE ((CONFIG_NET_BUFSIZE + 1) & ~1) /* Address has to be even */
|
#define PKTMEM_ALIGNED_BUFSIZE ((CONFIG_NET_BUFSIZE + 1) & ~1)
|
||||||
#define PKTMEM_TX_START PKTMEM_START /* Start TX buffer at teh beginning of SRAM */
|
#define PKTMEM_NDESCR ((PKTMEM_SIZE / 2) / PKTMEM_ALIGNED_BUFSIZE)
|
||||||
#define PKTMEM_TX_ENDP1 ALIGNED_BUFSIZE /* Allow TX buffer for one frame */
|
#define PKTMEM_RX_START (PKTMEM_START + PKTMEM_SIZE / 2) /* Followed by RX buffer */
|
||||||
#define PKTMEM_RX_START PKTMEM_TX_ENDP1 /* Followed by RX buffer */
|
#define PKTMEM_RX_END (PKTMEM_START + PKTMEM_SIZE - 2) /* RX buffer goes to the end of SRAM */
|
||||||
#define PKTMEM_RX_END (PKTMEM_END - 1) /* RX buffer goes to the end of SRAM */
|
|
||||||
|
|
||||||
/* This is a helper pointer for accessing the contents of the Ethernet header */
|
/* This is a helper pointer for accessing the contents of the Ethernet header */
|
||||||
|
|
||||||
@ -199,6 +199,13 @@ enum enc_state_e
|
|||||||
ENCSTATE_UP /* The interface is up */
|
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
|
/* The enc_driver_s encapsulates all state information for a single hardware
|
||||||
* interface
|
* interface
|
||||||
*/
|
*/
|
||||||
@ -225,6 +232,10 @@ struct enc_driver_s
|
|||||||
struct work_s towork; /* Tx timeout work queue support */
|
struct work_s towork; /* Tx timeout work queue support */
|
||||||
struct work_s pollwork; /* Poll 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 */
|
/* This is the contained SPI driver intstance */
|
||||||
|
|
||||||
FAR struct spi_dev_s *spi;
|
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 */
|
/* 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_transmit(FAR struct enc_driver_s *priv);
|
||||||
static int enc_uiptxpoll(struct uip_driver_s *dev);
|
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_SETMODE(spi, CONFIG_ENCX24J600_SPIMODE);
|
||||||
SPI_SETBITS(spi, 8);
|
SPI_SETBITS(spi, 8);
|
||||||
SPI_SETFREQUENCY(spi, CONFIG_ENCX24J600_FREQUENCY)
|
SPI_SETFREQUENCY(spi, CONFIG_ENCX24J600_FREQUENCY);
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
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
|
descr = (struct enc_descr_s*)sq_remfirst(&priv->txqueue);
|
||||||
priv->stats.txrequests++;
|
|
||||||
#endif
|
DEBUGASSERT(descr != NULL);
|
||||||
|
|
||||||
/* Verify that the hardware is ready to send another packet. The driver
|
/* Verify that the hardware is ready to send another packet. The driver
|
||||||
* starts a transmission process by setting ECON1.TXRTS. When the packet is
|
* 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);
|
DEBUGASSERT((enc_rdreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0);
|
||||||
|
|
||||||
/* Send the packet: address=priv->dev.d_buf, length=priv->dev.d_len */
|
/* Set TXStart and TXLen registers. */
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
enc_wrreg(priv, ENC_ETXST, descr->addr);
|
||||||
|
enc_wrreg(priv, ENC_ETXLEN, descr->len);
|
||||||
|
|
||||||
/* Set TXRTS to send the packet in the transmit buffer */
|
/* 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?
|
* 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;
|
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
|
* Function: enc_uiptxpoll
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* The transmitter is available, check if uIP has any outgoing packets ready
|
* Enqueues uIP packets if available.
|
||||||
* to send. This is a callback from uip_poll(). uip_poll() may be called:
|
* This is a callback from uip_poll(). uip_poll() may be called:
|
||||||
*
|
*
|
||||||
* 1. When the preceding TX packet send is complete,
|
* 1. When the preceding TX packet send is complete,
|
||||||
* 2. When the preceding TX packet send timedout and the interface is reset
|
* 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)
|
static int enc_uiptxpoll(struct uip_driver_s *dev)
|
||||||
{
|
{
|
||||||
FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private;
|
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,
|
/* If the polling resulted in data that should be sent out on the network,
|
||||||
* the field d_len is set to a value > 0.
|
* the field d_len is set to a value > 0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
nllvdbg("Poll result: d_len=%d\n", priv->dev.d_len);
|
nllvdbg("Poll result: d_len=%d\n", priv->dev.d_len);
|
||||||
|
|
||||||
if (priv->dev.d_len > 0)
|
if (priv->dev.d_len > 0)
|
||||||
{
|
{
|
||||||
uip_arp_out(&priv->dev);
|
uip_arp_out(&priv->dev);
|
||||||
enc_transmit(priv);
|
|
||||||
|
|
||||||
/* Stop the poll now because we can queue only one packet */
|
ret = enc_txenqueue(priv);
|
||||||
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If zero is returned, the polling will continue until all connections have
|
/* If zero is returned, the polling will continue until all connections have
|
||||||
* been examined.
|
* been examined.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return OK;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -1181,10 +1257,19 @@ static void enc_linkstatus(FAR struct enc_driver_s *priv)
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void enc_txif(FAR struct enc_driver_s *priv)
|
static void enc_txif(FAR struct enc_driver_s *priv)
|
||||||
|
{
|
||||||
|
if (sq_empty(&priv->txqueue))
|
||||||
{
|
{
|
||||||
/* If no further xmits are pending, then cancel the TX timeout */
|
/* 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 */
|
/* 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)
|
if (priv->dev.d_len > 0)
|
||||||
{
|
{
|
||||||
uip_arp_out(&priv->dev);
|
uip_arp_out(&priv->dev);
|
||||||
enc_transmit(priv);
|
enc_txenqueue(priv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (BUF->type == htons(UIP_ETHTYPE_ARP))
|
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)
|
if (priv->dev.d_len > 0)
|
||||||
{
|
{
|
||||||
enc_transmit(priv);
|
enc_txenqueue(priv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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)
|
static int enc_reset(FAR struct enc_driver_s *priv)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
uint16_t regval;
|
uint16_t regval;
|
||||||
|
|
||||||
@ -2229,12 +2315,20 @@ static int enc_reset(FAR struct enc_driver_s *priv)
|
|||||||
|
|
||||||
priv->nextpkt = PKTMEM_RX_START;
|
priv->nextpkt = PKTMEM_RX_START;
|
||||||
enc_wrreg(priv, ENC_ERXST, 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 */
|
/* Program the Tail Pointer, ERXTAIL, to the last even address of the buffer */
|
||||||
|
|
||||||
enc_wrreg(priv, ENC_ERXTAIL, PKTMEM_RX_END);
|
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
|
/* "Typically, when using auto-negotiation, users should write 0x05E1 to PHANA
|
||||||
* to advertise flow control capability."
|
* to advertise flow control capability."
|
||||||
*/
|
*/
|
||||||
|
@ -414,7 +414,7 @@
|
|||||||
/* 24-Kbyte Transmit/Receive Packet Dual Port SRAM */
|
/* 24-Kbyte Transmit/Receive Packet Dual Port SRAM */
|
||||||
|
|
||||||
#define PKTMEM_START 0x0000
|
#define PKTMEM_START 0x0000
|
||||||
#define PKTMEM_END 0x5fff
|
#define PKTMEM_SIZE 0x6000
|
||||||
|
|
||||||
/* RX Status Bit Definitions ************************************************/
|
/* RX Status Bit Definitions ************************************************/
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user