Completes coding of the STM32 F4 Ethernet driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4161 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
8c1436b4a6
commit
0d20925085
@ -2252,3 +2252,4 @@
|
||||
because CodeSourcery doesn't support hard flowing point!)
|
||||
* arch/arm/src/stm32/chip/stm32_eth.h: Add Ethernet register definitions
|
||||
for the STM32 F4.
|
||||
* arch/arm/srcm/stm32/stm32_eth.c: Adds an Ethernet driver for the STM32 F4.
|
||||
|
@ -149,6 +149,11 @@
|
||||
#ifndef CONFIG_STM32_ETH_BUFSIZE
|
||||
# define CONFIG_STM32_ETH_BUFSIZE CONFIG_NET_BUFSIZE
|
||||
#endif
|
||||
|
||||
#if CONFIG_STM32_ETH_BUFSIZE > ETH_TDES1_TBS1_MASK
|
||||
# error "CONFIG_STM32_ETH_BUFSIZE is too large"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_STM32_ETH_NRXDESC
|
||||
# define CONFIG_STM32_ETH_NRXDESC 8
|
||||
#endif
|
||||
@ -156,11 +161,9 @@
|
||||
# define CONFIG_STM32_ETH_NTXDESC 4
|
||||
#endif
|
||||
|
||||
#if CONFIG_STM32_ETH_NTXDESC > 2
|
||||
# define STM32_ETH_NFREEBUFFERS CONFIG_STM32_ETH_NTXDESC
|
||||
#else
|
||||
# define STM32_ETH_NFREEBUFFERS 2
|
||||
#endif
|
||||
/* We need at least one more free buffer than transmit buffers */
|
||||
|
||||
#define STM32_ETH_NFREEBUFFERS (CONFIG_STM32_ETH_NTXDESC+1)
|
||||
|
||||
/* Clocking *****************************************************************/
|
||||
/* Set MACMIIAR CR bits depending on HCLK setting */
|
||||
@ -396,9 +399,9 @@
|
||||
* ETH_DMABMR_DSL Bits 2-6: Descriptor skip length
|
||||
* ETH_DMABMR_EDFE Bit 7: Enhanced descriptor format enable
|
||||
* ETH_DMABMR_PBL Bits 8-13: Programmable burst length
|
||||
* ETH_DMABMR_RTPR Bits 14-15: Rx Tx priority ratio
|
||||
* ETH_DMABMR_RTPR Bits 14-15: RX TX priority ratio
|
||||
* ETH_DMABMR_FB Bit 16: Fixed burst
|
||||
* ETH_DMABMR_RDP Bits 17-22: Rx DMA PBL
|
||||
* ETH_DMABMR_RDP Bits 17-22: RX DMA PBL
|
||||
* ETH_DMABMR_USP Bit 23: Use separate PBL
|
||||
* ETH_DMABMR_FPM Bit 24: 4xPBL mode
|
||||
* ETH_DMABMR_AAB Bit 25: Address-aligned beats
|
||||
@ -418,9 +421,9 @@
|
||||
* ETH_DMABMR_DSL Descriptor skip length 0
|
||||
* ETH_DMABMR_EDFE Enhanced descriptor format enable Depends on CONFIG_STM32_ETH_ENHANCEDDESC
|
||||
* ETH_DMABMR_PBL Programmable burst length 32 beats
|
||||
* ETH_DMABMR_RTPR Rx Tx priority ratio 2:1
|
||||
* ETH_DMABMR_RTPR RX TX priority ratio 2:1
|
||||
* ETH_DMABMR_FB Fixed burst 1 (enabled)
|
||||
* ETH_DMABMR_RDP Rx DMA PBL 32 beats
|
||||
* ETH_DMABMR_RDP RX DMA PBL 32 beats
|
||||
* ETH_DMABMR_USP Use separate PBL 1 (enabled)
|
||||
* ETH_DMABMR_FPM 4xPBL mode 0 (disabled)
|
||||
* ETH_DMABMR_AAB Address-aligned beats 1 (enabled)
|
||||
@ -489,10 +492,13 @@ struct stm32_ethmac_s
|
||||
|
||||
/* Used to track transmit and receive descriptors */
|
||||
|
||||
struct eth_txdesc_s *txdesc; /* Next TX descriptor */
|
||||
struct eth_rxdesc_s *rxdesc; /* Next RX descriptor */
|
||||
struct eth_rxdesc_s *rxfirst; /* First RX descriptor of the segment */
|
||||
uint32_t segcount; /* Segment count */
|
||||
struct eth_txdesc_s *txhead; /* Next available TX descriptor */
|
||||
struct eth_rxdesc_s *rxhead; /* Next available RX descriptor */
|
||||
|
||||
struct eth_txdesc_s *txtail; /* First "in_flight" TX descriptor */
|
||||
struct eth_rxdesc_s *rxcurr; /* First RX descriptor of the segment */
|
||||
uint16_t segments; /* RX segment count */
|
||||
uint16_t inflight; /* Number of TX transfers "in_flight" */
|
||||
sq_queue_t freeb; /* The free buffer list */
|
||||
|
||||
/* Descriptor allocations */
|
||||
@ -530,9 +536,10 @@ static int stm32_uiptxpoll(struct uip_driver_s *dev);
|
||||
/* Interrupt handling */
|
||||
|
||||
static void stm32_freesegment(FAR struct stm32_ethmac_s *priv,
|
||||
FAR struct eth_rxdesc_s *rxfirst, int nsegments);
|
||||
FAR struct eth_rxdesc_s *rxfirst, int segments);
|
||||
static int stm32_recvframe(FAR struct stm32_ethmac_s *priv);
|
||||
static void stm32_receive(FAR struct stm32_ethmac_s *priv);
|
||||
static void stm32_freeframe(FAR struct stm32_ethmac_s *priv);
|
||||
static void stm32_txdone(FAR struct stm32_ethmac_s *priv);
|
||||
static int stm32_interrupt(int irq, FAR void *context);
|
||||
|
||||
@ -543,12 +550,12 @@ static void stm32_txtimeout(int argc, uint32_t arg, ...);
|
||||
|
||||
/* NuttX callback functions */
|
||||
|
||||
static int stm32_ifup(struct uip_driver_s *dev);
|
||||
static int stm32_ifdown(struct uip_driver_s *dev);
|
||||
static int stm32_txavail(struct uip_driver_s *dev);
|
||||
static int stm32_ifup(struct uip_driver_s *dev);
|
||||
static int stm32_ifdown(struct uip_driver_s *dev);
|
||||
static int stm32_txavail(struct uip_driver_s *dev);
|
||||
#ifdef CONFIG_NET_IGMP
|
||||
static int stm32_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac);
|
||||
static int stm32_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac);
|
||||
static int stm32_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac);
|
||||
static int stm32_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac);
|
||||
#endif
|
||||
|
||||
/* Descriptor Initialization */
|
||||
@ -558,17 +565,18 @@ static void stm32_rxdescinit(FAR struct stm32_ethmac_s *priv);
|
||||
|
||||
/* PHY Initialization */
|
||||
|
||||
static int stm32_phyread(uint16_t phydevaddr, uint16_t phyregaddr, uint16_t *value);
|
||||
static int stm32_phywrite(uint16_t phydevaddr, uint16_t phyregaddr, uint16_t value);
|
||||
static int stm32_phyinit(FAR struct stm32_ethmac_s *priv);
|
||||
static int stm32_phyread(uint16_t phydevaddr, uint16_t phyregaddr, uint16_t *value);
|
||||
static int stm32_phywrite(uint16_t phydevaddr, uint16_t phyregaddr, uint16_t value);
|
||||
static int stm32_phyinit(FAR struct stm32_ethmac_s *priv);
|
||||
|
||||
/* MAC/DMA Initialization */
|
||||
|
||||
static inline void stm32_ethgpioconfig(FAR struct stm32_ethmac_s *priv);
|
||||
static void stm32_ethreset(FAR struct stm32_ethmac_s *priv);
|
||||
static int stm32_macconfig(FAR struct stm32_ethmac_s *priv);
|
||||
static int stm32_macenable(FAR struct stm32_ethmac_s *priv);
|
||||
static int stm32_ethconfig(FAR struct stm32_ethmac_s *priv);
|
||||
static int stm32_macconfig(FAR struct stm32_ethmac_s *priv);
|
||||
static void stm32_macaddress(FAR struct stm32_ethmac_s *priv);
|
||||
static int stm32_macenable(FAR struct stm32_ethmac_s *priv);
|
||||
static int stm32_ethconfig(FAR struct stm32_ethmac_s *priv);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -701,18 +709,149 @@ static inline bool stm32_isfreebuffer(FAR struct stm32_ethmac_s *priv)
|
||||
|
||||
static int stm32_transmit(FAR struct stm32_ethmac_s *priv)
|
||||
{
|
||||
struct eth_txdesc_s *txdesc;
|
||||
uint32_t regval;
|
||||
|
||||
/* The internal uIP buffer size may be configured to be larger than the
|
||||
* Ethernet buffer size.
|
||||
*/
|
||||
|
||||
#if CONFIG_NET_BUFSIZE > CONFIG_STM32_ETH_BUFSIZE
|
||||
struct eth_txdesc_s *txnext;
|
||||
uint8_t *buffer;
|
||||
int bufcount;
|
||||
int lastsize;
|
||||
int i;
|
||||
#endif
|
||||
|
||||
/* Verify that the hardware is ready to send another packet. If we get
|
||||
* here, then we are committed to sending a packet; Higher level logic
|
||||
* must have assured that there is no transmission in progress.
|
||||
*/
|
||||
|
||||
/* Increment statistics */
|
||||
txdesc = priv->txhead;
|
||||
DEBUGASSERT(txdesc && (txdesc->tdes0 & ETH_TDES0_OWN) == 0);
|
||||
|
||||
/* Send the packet: address=priv->dev.d_buf, length=priv->dev.d_len */
|
||||
/* Is the size to be sent greater than the size of the Ethernet buffer? */
|
||||
|
||||
/* Enable Tx interrupts */
|
||||
#if CONFIG_NET_BUFSIZE > CONFIG_STM32_ETH_BUFSIZE
|
||||
if (priv->dev.d_len > CONFIG_STM32_ETH_BUFSIZE)
|
||||
{
|
||||
/* Yes... how many buffers will be need to send the packet? */
|
||||
|
||||
bufcount = (priv->dev.d_len + (CONFIG_STM32_ETH_BUFSIZE-1)) / CONFIG_STM32_ETH_BUFSIZE;
|
||||
lastsize = priv->dev.d_len - (bufcount - 1) * CONFIG_STM32_ETH_BUFSIZE;
|
||||
|
||||
/* Set the first segment bit in the first TX descriptor */
|
||||
|
||||
txdesc->tdes0 |= ETH_TDES0_FS;
|
||||
|
||||
/* Set up all but the last TX descriptor */
|
||||
|
||||
txnext = txdesc;
|
||||
buffer = priv->dev.d_buf;
|
||||
|
||||
for (i = 0; i < bufcount; i++)
|
||||
{
|
||||
/* This could be a normal event but the design does not handle it */
|
||||
|
||||
DEBUGASSERT((txnext->tdes0 & ETH_TDES0_OWN) == 0);
|
||||
|
||||
/* Set the Buffer1 address pointer */
|
||||
|
||||
txdesc->tdes2 = (uint32_t)buffer;
|
||||
|
||||
/* Set the buffer size in all TX descriptors, set the last segment
|
||||
* bit in the last TX descriptor
|
||||
*/
|
||||
|
||||
if (i == (bufcount-1))
|
||||
{
|
||||
txnext->tdes0 |= ETH_TDES0_LS;
|
||||
txnext->tdes1 = lastsize;
|
||||
buffer += lastsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
txnext->tdes1 = CONFIG_STM32_ETH_BUFSIZE;
|
||||
buffer += CONFIG_STM32_ETH_BUFSIZE;
|
||||
}
|
||||
|
||||
/* Give descriptor back to DMA */
|
||||
|
||||
txnext->tdes0 |= ETH_TDES0_OWN;
|
||||
txnext = (struct eth_txdesc_s *)txnext->tdes3;
|
||||
}
|
||||
|
||||
/* Remember the start of the next available TX descriptor */
|
||||
|
||||
txdesc = txnext;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* The single descriptor is both the first and last segment */
|
||||
|
||||
txdesc->tdes0 |= (ETH_TDES0_FS | ETH_TDES0_LS);
|
||||
|
||||
/* Set frame size */
|
||||
|
||||
DEBUGASSERT(priv->dev.d_len <= CONFIG_NET_BUFSIZE);
|
||||
txdesc->tdes1 = priv->dev.d_len;
|
||||
|
||||
/* Set the Buffer1 address pointer */
|
||||
|
||||
txdesc->tdes2 = (uint32_t)priv->dev.d_buf;
|
||||
|
||||
/* Set OWN bit of the TX descriptor tdes0. This gives the buffer to
|
||||
* Ethernet DMA
|
||||
*/
|
||||
|
||||
txdesc->tdes0 |= ETH_TDES0_OWN;
|
||||
|
||||
/* Point to the next available TX descriptor */
|
||||
|
||||
txdesc = (struct eth_txdesc_s *)txdesc->tdes3;
|
||||
}
|
||||
|
||||
/* Remember where we left off in the TX descriptor chain */
|
||||
|
||||
priv->txhead = txdesc;
|
||||
|
||||
/* Detach the buffer from priv->dev structure. That buffer is now
|
||||
* "in-flight".
|
||||
*/
|
||||
|
||||
priv->dev.d_buf = NULL;
|
||||
|
||||
/* If there is no other TX buffer, in flight, then remember this
|
||||
* as the location to check for TX done events.
|
||||
*/
|
||||
|
||||
if (!priv->txtail)
|
||||
{
|
||||
DEBUGASSERT(priv->inflight == 0);
|
||||
priv->txtail = txdesc;
|
||||
}
|
||||
|
||||
/* Increment the number of TX transfer in-flight */
|
||||
|
||||
priv->inflight++;
|
||||
|
||||
/* Check if the TX Buffer unavailable flag is set */
|
||||
|
||||
if ((getreg32(STM32_ETH_DMASR) & ETH_DMAINT_TBUI) != 0)
|
||||
{
|
||||
/* Clear TX Buffer unavailable flag */
|
||||
|
||||
putreg32(ETH_DMAINT_TBUI, STM32_ETH_DMASR);
|
||||
|
||||
/* Resume DMA transmission */
|
||||
|
||||
putreg32(0, STM32_ETH_DMATPDR);
|
||||
}
|
||||
|
||||
/* Enable TX interrupts */
|
||||
|
||||
regval = getreg32(STM32_ETH_DMAIER);
|
||||
regval |= ETH_DMAINT_XMIT_ENABLE;
|
||||
@ -758,12 +897,24 @@ static int stm32_uiptxpoll(struct uip_driver_s *dev)
|
||||
|
||||
if (priv->dev.d_len > 0)
|
||||
{
|
||||
/* Send the packet */
|
||||
|
||||
uip_arp_out(&priv->dev);
|
||||
stm32_transmit(priv);
|
||||
|
||||
/* Check if there is room in the device to hold another packet. If not,
|
||||
* return a non-zero value to terminate the poll.
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0)
|
||||
{
|
||||
/* There is room in the device to hold another packet. Return a non-
|
||||
* zero value to terminate the poll.
|
||||
*/
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
/* If zero is returned, the polling will continue until all connections have
|
||||
@ -792,7 +943,7 @@ static int stm32_uiptxpoll(struct uip_driver_s *dev)
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_freesegment(FAR struct stm32_ethmac_s *priv,
|
||||
FAR struct eth_rxdesc_s *rxfirst, int nsegments)
|
||||
FAR struct eth_rxdesc_s *rxfirst, int segments)
|
||||
{
|
||||
struct eth_rxdesc_s *rxdesc;
|
||||
int i;
|
||||
@ -800,7 +951,7 @@ static void stm32_freesegment(FAR struct stm32_ethmac_s *priv,
|
||||
/* Set OWN bit in RX descriptors. This gives the buffers back to DMA */
|
||||
|
||||
rxdesc = rxfirst;
|
||||
for (i = 0; i < nsegments; i++)
|
||||
for (i = 0; i < segments; i++)
|
||||
{
|
||||
rxdesc->rdes0 = ETH_RDES0_OWN;
|
||||
rxdesc = (struct eth_rxdesc_s *)rxdesc->rdes3;
|
||||
@ -808,8 +959,8 @@ static void stm32_freesegment(FAR struct stm32_ethmac_s *priv,
|
||||
|
||||
/* Reset the segment managment logic */
|
||||
|
||||
priv->rxfirst = NULL;
|
||||
priv->segcount = 0;
|
||||
priv->rxcurr = NULL;
|
||||
priv->segments = 0;
|
||||
|
||||
/* Check if the RX Buffer unavailable flag is set */
|
||||
|
||||
@ -849,7 +1000,7 @@ static void stm32_freesegment(FAR struct stm32_ethmac_s *priv,
|
||||
static int stm32_recvframe(FAR struct stm32_ethmac_s *priv)
|
||||
{
|
||||
struct eth_rxdesc_s *rxdesc;
|
||||
struct eth_rxdesc_s *rxfirst;
|
||||
struct eth_rxdesc_s *rxcurr;
|
||||
uint8_t *buffer;
|
||||
int i;
|
||||
|
||||
@ -865,7 +1016,7 @@ static int stm32_recvframe(FAR struct stm32_ethmac_s *priv)
|
||||
|
||||
/* Scan descriptors owned by the CPU */
|
||||
|
||||
rxdesc = priv->rxdesc;
|
||||
rxdesc = priv->rxhead;
|
||||
for (i = 0;
|
||||
(rxdesc->rdes0 & ETH_RDES0_OWN) == 0 && i < CONFIG_STM32_ETH_NRXDESC;
|
||||
i++)
|
||||
@ -875,8 +1026,8 @@ static int stm32_recvframe(FAR struct stm32_ethmac_s *priv)
|
||||
if ((rxdesc->rdes0 & ETH_RDES0_FS) != 0 &&
|
||||
(rxdesc->rdes0 & ETH_RDES0_LS) == 0)
|
||||
{
|
||||
priv->rxfirst = rxdesc;
|
||||
priv->segcount = 1;
|
||||
priv->rxcurr = rxdesc;
|
||||
priv->segments = 1;
|
||||
}
|
||||
|
||||
/* Check if this is an intermediate segment in the frame */
|
||||
@ -884,24 +1035,24 @@ static int stm32_recvframe(FAR struct stm32_ethmac_s *priv)
|
||||
else if (((rxdesc->rdes0 & ETH_RDES0_LS) == 0)&&
|
||||
((rxdesc->rdes0 & ETH_RDES0_FS) == 0))
|
||||
{
|
||||
priv->segcount++;
|
||||
priv->segments++;
|
||||
}
|
||||
|
||||
/* Otherwise, it is the last segment in the frame */
|
||||
|
||||
else
|
||||
{
|
||||
priv->segcount++;
|
||||
priv->segments++;
|
||||
|
||||
/* Check if the there is only one segment in the frame */
|
||||
|
||||
if (priv->segcount == 1)
|
||||
if (priv->segments == 1)
|
||||
{
|
||||
rxfirst = rxdesc;
|
||||
rxcurr = rxdesc;
|
||||
}
|
||||
else
|
||||
{
|
||||
rxfirst = priv->rxfirst;
|
||||
rxcurr = priv->rxcurr;
|
||||
}
|
||||
|
||||
/* Check if any errors are reported in the frame */
|
||||
@ -929,15 +1080,16 @@ static int stm32_recvframe(FAR struct stm32_ethmac_s *priv)
|
||||
* buffer.
|
||||
*/
|
||||
|
||||
dev->d_buf = (uint8_t*)rxfirst->rdes2;
|
||||
rxfirst->rdes2 = (uint32_t)buffer;
|
||||
DEBUGASSERT(dev->d_buf == NULL);
|
||||
dev->d_buf = (uint8_t*)rxcurr->rdes2;
|
||||
rxcurr->rdes2 = (uint32_t)buffer;
|
||||
|
||||
/* Return success, remebering where we should re-start scanning
|
||||
* and resetting the segment scanning logic
|
||||
*/
|
||||
|
||||
priv->rxdesc = (struct eth_rxdesc_s*)rxdesc->rdes3;
|
||||
stm32_freesegment(priv, rxfirst, priv->segcount);
|
||||
priv->rxhead = (struct eth_rxdesc_s*)rxdesc->rdes3;
|
||||
stm32_freesegment(priv, rxcurr, priv->segments);
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
@ -947,7 +1099,7 @@ static int stm32_recvframe(FAR struct stm32_ethmac_s *priv)
|
||||
*/
|
||||
|
||||
nlldbg("DROPPED: RX descriptor errors: %08x\n", rxdesc->rdes0);
|
||||
stm32_freesegment(priv, rxfirst, priv->segcount);
|
||||
stm32_freesegment(priv, rxcurr, priv->segments);
|
||||
}
|
||||
}
|
||||
|
||||
@ -956,11 +1108,11 @@ static int stm32_recvframe(FAR struct stm32_ethmac_s *priv)
|
||||
rxdesc = (struct eth_rxdesc_s*)rxdesc->rdes3;
|
||||
}
|
||||
|
||||
/* We get here after all of the descriptors have been scanned. Remember
|
||||
* where we left off.
|
||||
/* We get here after all of the descriptors have been scanned or when rxdesc points
|
||||
* to the first descriptor owned by the DMA. Remember where we left off.
|
||||
*/
|
||||
|
||||
priv->rxdesc = rxdesc;
|
||||
priv->rxhead = rxdesc;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
@ -1003,9 +1155,9 @@ static void stm32_receive(FAR struct stm32_ethmac_s *priv)
|
||||
/* We only accept IP packets of the configured type and ARP packets */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (BUF->type == HTONS(UIP_ETHTYPE_IP6))
|
||||
else if (BUF->type == HTONS(UIP_ETHTYPE_IP6))
|
||||
#else
|
||||
if (BUF->type == HTONS(UIP_ETHTYPE_IP))
|
||||
else if (BUF->type == HTONS(UIP_ETHTYPE_IP))
|
||||
#endif
|
||||
{
|
||||
uip_arp_ipin(&priv->dev);
|
||||
@ -1034,6 +1186,102 @@ static void stm32_receive(FAR struct stm32_ethmac_s *priv)
|
||||
stm32_transmit(priv);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nlldbg("DROPPED: Unknown type: %04x\n", BUF->type);
|
||||
}
|
||||
|
||||
/* We are finished with the RX buffer. NOTE: If the buffer is
|
||||
* re-used for transmission, the dev->d_buf field will have been
|
||||
* nullified.
|
||||
*/
|
||||
|
||||
if (dev->d_buf)
|
||||
{
|
||||
/* Free the receive packet buffer */
|
||||
|
||||
stm32_freebuffer(priv, dev->d_buf);
|
||||
dev->d_buf = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: stm32_freeframe
|
||||
*
|
||||
* Description:
|
||||
* Scans the TX descriptors and frees the buffers of completed TX transfers.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - Reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
* Assumptions:
|
||||
* Global interrupts are disabled by interrupt handling logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_freeframe(FAR struct stm32_ethmac_s *priv)
|
||||
{
|
||||
struct eth_txdesc_s *txdesc;
|
||||
int i;
|
||||
|
||||
/* Scan for "in-flight" descriptors owned by the CPU */
|
||||
|
||||
txdesc = priv->txtail;
|
||||
if (txdesc)
|
||||
{
|
||||
DEBUGASSERT(priv->inflight > 0);
|
||||
|
||||
for (i = 0; (txdesc->tdes0 & ETH_TDES0_OWN) == 0; i++)
|
||||
{
|
||||
/* There should be a buffer assigned to all in-flight
|
||||
* TX descriptors.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(txdesc->tdes2 != 0);
|
||||
|
||||
/* Check if this is the first segment of a TX frame. */
|
||||
|
||||
if ((txdesc->tdes0 & ETH_TDES0_FS) != 0)
|
||||
{
|
||||
/* Yes.. Free the buffer */
|
||||
|
||||
stm32_freebuffer(priv, (uint8_t*)txdesc->tdes2);
|
||||
}
|
||||
|
||||
/* In any event, make sure that TDES2 is nullified. */
|
||||
|
||||
txdesc->tdes2 = 0;
|
||||
|
||||
/* Check if this is the last segement of a TX frame */
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
if (--priv->inflight <= 0)
|
||||
{
|
||||
priv->txtail = NULL;
|
||||
priv->inflight = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try the next descriptor in the TX chain */
|
||||
|
||||
txdesc = (struct eth_txdesc_s*)txdesc->tdes3;
|
||||
}
|
||||
|
||||
/* We get here if (1) there are still frames "in-flight". Remember
|
||||
* where we left off.
|
||||
*/
|
||||
|
||||
priv->txtail = txdesc;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1058,17 +1306,24 @@ static void stm32_txdone(FAR struct stm32_ethmac_s *priv)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
/* Check for errors and update statistics */
|
||||
DEBUGASSERT(priv->txtail != NULL);
|
||||
|
||||
/* Scan the TX desciptor change, returning buffers to free list */
|
||||
|
||||
stm32_freeframe(priv);
|
||||
|
||||
/* If no further xmits are pending, then cancel the TX timeout */
|
||||
|
||||
wd_cancel(priv->txtimeout);
|
||||
if (priv->inflight <= 0)
|
||||
{
|
||||
wd_cancel(priv->txtimeout);
|
||||
|
||||
/* And disable further Tx interrupts. */
|
||||
/* And disable further TX interrupts. */
|
||||
|
||||
regval = getreg32(STM32_ETH_DMAIER);
|
||||
regval &= ~ETH_DMAINT_XMIT_DISABLE;
|
||||
putreg32(regval, STM32_ETH_DMAIER);
|
||||
regval = getreg32(STM32_ETH_DMAIER);
|
||||
regval &= ~ETH_DMAINT_XMIT_DISABLE;
|
||||
putreg32(regval, STM32_ETH_DMAIER);
|
||||
}
|
||||
|
||||
/* Then poll uIP for new XMIT data */
|
||||
|
||||
@ -1127,7 +1382,7 @@ static int stm32_interrupt(int irq, FAR void *context)
|
||||
}
|
||||
|
||||
/* Check if a packet transmission just completed. If so, call
|
||||
* stm32_txdone(). This may disable further Tx interrupts if there
|
||||
* stm32_txdone(). This may disable further TX interrupts if there
|
||||
* are no pending tansmissions.
|
||||
*/
|
||||
|
||||
@ -1194,9 +1449,12 @@ static void stm32_txtimeout(int argc, uint32_t arg, ...)
|
||||
{
|
||||
FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)arg;
|
||||
|
||||
/* Increment statistics and dump debug info */
|
||||
/* Then reset the hardware. Just take the interface down, then back
|
||||
* up again.
|
||||
*/
|
||||
|
||||
/* Then reset the hardware */
|
||||
stm32_ifdown(&priv->dev);
|
||||
stm32_ifup(&priv->dev);
|
||||
|
||||
/* Then poll uIP for new XMIT data */
|
||||
|
||||
@ -1225,16 +1483,20 @@ static void stm32_polltimer(int argc, uint32_t arg, ...)
|
||||
{
|
||||
FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)arg;
|
||||
|
||||
/* Check if there is room in the send another TX packet. We cannot perform
|
||||
* the TX poll if he are unable to accept another packet for transmission.
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* If so, update TCP timing states and poll uIP for new XMIT data. Hmmm..
|
||||
* might be bug here. Does this mean if there is a transmit in progress,
|
||||
* we will missing TCP time state updates?
|
||||
*/
|
||||
if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0)
|
||||
{
|
||||
/* If so, update TCP timing states and poll uIP for new XMIT data. Hmmm..
|
||||
* might be bug here. Does this mean if there is a transmit in progress,
|
||||
* we will missing TCP time state updates?
|
||||
*/
|
||||
|
||||
(void)uip_timer(&priv->dev, stm32_uiptxpoll, STM32_POLLHSEC);
|
||||
(void)uip_timer(&priv->dev, stm32_uiptxpoll, STM32_POLLHSEC);
|
||||
}
|
||||
|
||||
/* Setup the watchdog poll timer again */
|
||||
|
||||
@ -1365,11 +1627,18 @@ static int stm32_txavail(struct uip_driver_s *dev)
|
||||
|
||||
if (priv->ifup)
|
||||
{
|
||||
/* Check if there is room in the hardware to hold another outgoing packet. */
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* If so, then poll uIP for new XMIT data */
|
||||
if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0)
|
||||
{
|
||||
/* If we have the descriptor, then poll uIP for new XMIT data */
|
||||
|
||||
(void)uip_poll(&priv->dev, stm32_uiptxpoll);
|
||||
(void)uip_poll(&priv->dev, stm32_uiptxpoll);
|
||||
}
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
@ -1400,6 +1669,7 @@ static int stm32_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac)
|
||||
FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)dev->d_private;
|
||||
|
||||
/* Add the MAC address to the hardware multicast routing table */
|
||||
#error "Missing logic"
|
||||
|
||||
return OK;
|
||||
}
|
||||
@ -1429,6 +1699,7 @@ static int stm32_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac)
|
||||
FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)dev->d_private;
|
||||
|
||||
/* Add the MAC address to the hardware multicast routing table */
|
||||
#error "Missing logic"
|
||||
|
||||
return OK;
|
||||
}
|
||||
@ -1455,9 +1726,19 @@ static void stm32_txdescinit(FAR struct stm32_ethmac_s *priv)
|
||||
struct eth_txdesc_s *txdesc;
|
||||
int i;
|
||||
|
||||
/* Set the priv->txdesc pointer with the first descriptor in the table */
|
||||
/* priv->txhead will point to the first, available TX descriptor in the chain.
|
||||
* Set the priv->txhead pointer to the first descriptor in the table.
|
||||
*/
|
||||
|
||||
priv->txdesc = priv->txtable;
|
||||
priv->txhead = priv->txtable;
|
||||
|
||||
/* priv->txtail will point to the first segment of the oldest pending
|
||||
* "in-flight" TX transfer. NULL means that there are no active TX
|
||||
* transfers.
|
||||
*/
|
||||
|
||||
priv->txtail = NULL;
|
||||
priv->inflight = 0;
|
||||
|
||||
/* Initialize each TX descriptor */
|
||||
|
||||
@ -1470,7 +1751,7 @@ static void stm32_txdescinit(FAR struct stm32_ethmac_s *priv)
|
||||
txdesc->tdes0 = ETH_TDES0_TCH;
|
||||
|
||||
#ifdef CHECKSUM_BY_HARDWARE
|
||||
/* Enable the checksum insertion for the Tx frames */
|
||||
/* Enable the checksum insertion for the TX frames */
|
||||
|
||||
txdesc->tdes0 |= ETH_TDES0_CIC_ALL;
|
||||
#endif
|
||||
@ -1479,7 +1760,7 @@ static void stm32_txdescinit(FAR struct stm32_ethmac_s *priv)
|
||||
* are used)
|
||||
*/
|
||||
|
||||
txdesc->tdes2 = 0;;
|
||||
txdesc->tdes2 = 0;
|
||||
|
||||
/* Initialize the next descriptor with the Next Descriptor Polling Enable */
|
||||
|
||||
@ -1527,9 +1808,18 @@ static void stm32_rxdescinit(FAR struct stm32_ethmac_s *priv)
|
||||
struct eth_rxdesc_s *rxdesc;
|
||||
int i;
|
||||
|
||||
/* Set the priv->rxdesc pointer with the first one of the table list */
|
||||
/* priv->rxhead will point to the first, RX descriptor in the chain.
|
||||
* This will be where we receive the first incomplete frame.
|
||||
*/
|
||||
|
||||
priv->rxdesc = priv->rxtable;
|
||||
priv->rxhead = priv->rxtable;
|
||||
|
||||
/* If we accumulate the frame in segments, priv->rxcurr points to the
|
||||
* RX descriptor of the first segment in the current TX frame.
|
||||
*/
|
||||
|
||||
priv->rxcurr = NULL;
|
||||
priv->segments = 0;
|
||||
|
||||
/* Initialize each TX descriptor */
|
||||
|
||||
@ -1537,7 +1827,7 @@ static void stm32_rxdescinit(FAR struct stm32_ethmac_s *priv)
|
||||
{
|
||||
rxdesc = &priv->rxtable[i];
|
||||
|
||||
/* Set Own bit of the Rx descriptor rdes0 */
|
||||
/* Set Own bit of the RX descriptor rdes0 */
|
||||
|
||||
rxdesc->rdes0 = ETH_RDES0_OWN;
|
||||
|
||||
@ -2079,6 +2369,41 @@ static int stm32_macconfig(FAR struct stm32_ethmac_s *priv)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: stm32_macaddress
|
||||
*
|
||||
* Description:
|
||||
* Configure the selected MAC address.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - A reference to the private driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; Negated errno on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_macaddress(FAR struct stm32_ethmac_s *priv)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
/* Set the MAC address high register */
|
||||
|
||||
regval = ((uint32_t)priv->dev.d_mac.ether_addr_octet[5] << 8) |
|
||||
(uint32_t)priv->dev.d_mac.ether_addr_octet[4];
|
||||
putreg32(regval, STM32_ETH_MACA0HR);
|
||||
|
||||
/* Set the MAC address low register */
|
||||
|
||||
regval = ((uint32_t)priv->dev.d_mac.ether_addr_octet[3] << 24) |
|
||||
((uint32_t)priv->dev.d_mac.ether_addr_octet[2] << 16) |
|
||||
((uint32_t)priv->dev.d_mac.ether_addr_octet[1] << 8) |
|
||||
(uint32_t)priv->dev.d_mac.ether_addr_octet[0];
|
||||
putreg32(regval, STM32_ETH_MACA0LR);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: stm32_macenable
|
||||
*
|
||||
@ -2099,6 +2424,10 @@ static int stm32_macenable(FAR struct stm32_ethmac_s *priv)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
/* Set the MAC address */
|
||||
|
||||
stm32_macaddress(priv);
|
||||
|
||||
/* Enable transmit state machine of the MAC for transmission on the MII */
|
||||
|
||||
regval = getreg32(STM32_ETH_MACCR);
|
||||
@ -2203,11 +2532,11 @@ static int stm32_ethconfig(FAR struct stm32_ethmac_s *priv)
|
||||
|
||||
stm32_initbuffer(priv);
|
||||
|
||||
/* Initialize Tx Descriptors list: Chain Mode */
|
||||
/* Initialize TX Descriptors list: Chain Mode */
|
||||
|
||||
stm32_txdescinit(priv);
|
||||
|
||||
/* Initialize Rx Descriptors list: Chain Mode */
|
||||
/* Initialize RX Descriptors list: Chain Mode */
|
||||
|
||||
stm32_rxdescinit(priv);
|
||||
|
||||
|
@ -419,4 +419,12 @@ Where <subdir> is one of the following:
|
||||
examples/ostest. By default, this project assumes that you are
|
||||
using the DFU bootloader.
|
||||
|
||||
CONFIG_STM32_BUILDROOT=y : CodeSourcery under Windows
|
||||
CONFIG_STM32_CODESOURCERYW=y : CodeSourcery under Windows
|
||||
|
||||
nsh:
|
||||
---
|
||||
Configures the NuttShell (nsh) located at apps/examples/nsh. The
|
||||
Configuration enables both the serial and telnet NSH interfaces.
|
||||
|
||||
CONFIG_STM32_CODESOURCERYW=y : CodeSourcery under Windows
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user